12-braced-args.M1pp (1347B)
1 # Braced block arguments: 2 # - { ... } groups tokens into one arg, protecting commas inside 3 # - outer { ... } is stripped when the arg span begins with LBRACE and 4 # ends with its matching RBRACE 5 # - nesting: { { ... } } — outer is stripped, inner braces pass through 6 # (emit_token is a no-op on brace kinds, so inner braces never reach 7 # output either) 8 # - braces are independent of parens: st(r0, r3, 0) inside a braced arg 9 # is a single group, its commas are NOT arg separators 10 # - plain (non-braced) args still work unchanged 11 12 %macro IF_EQ_ELSE(a, b, t, e) 13 (= a b) t e 14 %endm 15 16 %macro WHILE_NEZ(r, body) 17 :@loop 18 body 19 bnez r &@loop 20 %endm 21 22 %macro ID(x) 23 x 24 %endm 25 26 # body with commas inside a brace — st(r0, r3, 0) carries two commas that 27 # MUST NOT split the outer call into more than 4 args 28 %IF_EQ_ELSE(r1, r2, { 29 li(r0, 5) 30 st(r0, r3, 0) 31 }, { 32 li(r0, 0) 33 }) 34 35 # nested braces — inner { inner_block } survives outer strip but its 36 # braces are no-op'd at emit time, so only the tokens appear 37 %WHILE_NEZ(rx, { 38 addi(rx, rx, -1) 39 { inner_block } 40 }) 41 42 # plain arg with no braces still works (sanity) 43 %ID(plain_token) 44 45 # arg that opens with { but does not close at the outer level is NOT 46 # stripped: { x } tail — the { and } are emitted as nothing (emit_token 47 # no-op) but the surrounding tokens pass through verbatim 48 %ID({ x } tail) 49 50 END