boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs

commit 0948ad4bcc40d174469f825a24cf35415eea6f44
parent 968ba690fb1865bd72df6f2486c58db5807445f6
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 23 Apr 2026 17:19:25 -0700

m1pp.M1: port braced block arguments

Diffstat:
Mm1pp/m1pp.M1 | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 213 insertions(+), 5 deletions(-)

diff --git a/m1pp/m1pp.M1 b/m1pp/m1pp.M1 @@ -50,6 +50,8 @@ DEFINE TOK_LPAREN 0300000000000000 DEFINE TOK_RPAREN 0400000000000000 DEFINE TOK_COMMA 0500000000000000 DEFINE TOK_PASTE 0600000000000000 +DEFINE TOK_LBRACE 0700000000000000 +DEFINE TOK_RBRACE 0800000000000000 ## Token record stride (kind + text_ptr + text_len). Advance a Token* by this. DEFINE M1PP_TOK_SIZE 1800000000000000 @@ -431,6 +433,12 @@ DEFINE EXPR_INVALID 1100000000000000 li_a1 %44 %0 la_br &lex_comma beq_a0,a1 + li_a1 %123 %0 + la_br &lex_lbrace + beq_a0,a1 + li_a1 %125 %0 + la_br &lex_rbrace + beq_a0,a1 # otherwise: word la_br &lex_word @@ -599,6 +607,30 @@ DEFINE EXPR_INVALID 1100000000000000 li_a2 %1 %0 la_br &push_source_token call + la_br &lex_advance_one_then_loop + b +:lex_lbrace + la_a0 &const_lbrace + li_a1 %1 %0 + la_br &append_text + call + mov_a1,a0 + li_a0 TOK_LBRACE + li_a2 %1 %0 + la_br &push_source_token + call + la_br &lex_advance_one_then_loop + b +:lex_rbrace + la_a0 &const_rbrace + li_a1 %1 %0 + la_br &append_text + call + mov_a1,a0 + li_a0 TOK_RBRACE + li_a2 %1 %0 + la_br &push_source_token + call :lex_advance_one_then_loop # lex_ptr++ la_a0 &lex_ptr @@ -650,6 +682,12 @@ DEFINE EXPR_INVALID 1100000000000000 li_a1 %44 %0 la_br &lex_word_finish beq_a0,a1 + li_a1 %123 %0 + la_br &lex_word_finish + beq_a0,a1 + li_a1 %125 %0 + la_br &lex_word_finish + beq_a0,a1 # else lex_ptr++ addi_t0,t0,1 la_br &lex_word_scan @@ -715,6 +753,15 @@ DEFINE EXPR_INVALID 1100000000000000 ## emit_token(a0=token_ptr). Leaf. :emit_token + # brace tokens are no-ops at emit time (belt-and-braces with arg-strip) + ld_t0,a0,0 + li_t1 TOK_LBRACE + la_br &emit_token_skip + beq_t0,t1 + li_t1 TOK_RBRACE + la_br &emit_token_skip + beq_t0,t1 + # if (output_need_space) emit ' ' (skip the space for the first token on a line) la_a1 &output_need_space ld_t0,a1,0 @@ -769,6 +816,8 @@ DEFINE EXPR_INVALID 1100000000000000 li_a1 %1 %0 st_a1,a0,0 ret +:emit_token_skip + ret ## --- Main processor ---------------------------------------------------------- ## Stream-driven loop. Pushes source_tokens as the initial stream, then drives @@ -1480,7 +1529,7 @@ DEFINE EXPR_INVALID 1100000000000000 ## ## Fatal on: > 16 args, reaching limit without matching RPAREN. :parse_args - # tok = lparen + 1; arg_start = tok; depth = 1; arg_index = 0 + # tok = lparen + 1; arg_start = tok; depth = 1; arg_index = 0; brace_depth = 0 addi_a0,a0,24 la_a2 &pa_pos st_a0,a2,0 @@ -1494,6 +1543,9 @@ DEFINE EXPR_INVALID 1100000000000000 li_a2 %0 %0 la_a3 &pa_arg_index st_a2,a3,0 + li_a2 %0 %0 + la_a3 &pa_brace_depth + st_a2,a3,0 :pa_loop # if (tok >= limit) fatal unterminated @@ -1517,6 +1569,12 @@ DEFINE EXPR_INVALID 1100000000000000 li_a3 TOK_COMMA la_br &pa_maybe_comma beq_a2,a3 + li_a3 TOK_LBRACE + la_br &pa_lbrace + beq_a2,a3 + li_a3 TOK_RBRACE + la_br &pa_rbrace + beq_a2,a3 # default: tok++ addi_t0,t0,24 @@ -1552,7 +1610,12 @@ DEFINE EXPR_INVALID 1100000000000000 b :pa_rparen_close - # depth == 0: close out the call. + # depth == 0: if brace_depth != 0 -> unbalanced braces + la_a0 &pa_brace_depth + ld_t1,a0,0 + la_br &err_unbalanced_braces + bnez_t1 + # close out the call. # arg_start (BSS), arg_index (BSS), tok = current pos. la_a0 &pa_arg_start ld_a1,a0,0 @@ -1607,8 +1670,13 @@ DEFINE EXPR_INVALID 1100000000000000 li_a3 %1 %0 la_br &pa_default_advance bne_t1,a3 + # and only when brace_depth == 0 + la_a0 &pa_brace_depth + ld_t1,a0,0 + la_br &pa_default_advance + bnez_t1 - # depth == 1 split: append (arg_start, tok) at arg_index + # depth == 1 && brace_depth == 0 split: append (arg_start, tok) at arg_index la_a0 &pa_arg_index ld_a2,a0,0 li_a3 M1PP_MAX_PARAMS @@ -1647,6 +1715,33 @@ DEFINE EXPR_INVALID 1100000000000000 la_br &pa_loop b +:pa_lbrace + # brace_depth++; tok++ + la_a0 &pa_brace_depth + ld_t1,a0,0 + addi_t1,t1,1 + st_t1,a0,0 + addi_t0,t0,24 + la_a0 &pa_pos + st_t0,a0,0 + la_br &pa_loop + b + +:pa_rbrace + # if (brace_depth <= 0) fatal unbalanced braces + la_a0 &pa_brace_depth + ld_t1,a0,0 + la_br &err_unbalanced_braces + beqz_t1 + # brace_depth--; tok++ + addi_t1,t1,neg1 + st_t1,a0,0 + addi_t0,t0,24 + la_a0 &pa_pos + st_t0,a0,0 + la_br &pa_loop + b + ## ============================================================================ ## --- Macro lookup + call expansion ------------------------------------------ ## ============================================================================ @@ -1823,22 +1918,125 @@ DEFINE EXPR_INVALID 1100000000000000 li_a0 %0 %0 ret +## arg_is_braced(a0=start, a1=end) -> a0 = 1 if the span wraps in a matching +## outer { ... } pair (outer RBRACE is the same-level mate of the leading +## LBRACE), else 0. Leaf. +:arg_is_braced + # if (end - start < 2 tokens = 48 bytes) return 0 + sub_a2,a1,a0 + li_a3 %48 %0 + la_br &aib_zero + blt_a2,a3 + + # if (start->kind != TOK_LBRACE) return 0 + ld_a2,a0,0 + li_a3 TOK_LBRACE + la_br &aib_zero + bne_a2,a3 + + # if ((end - 24)->kind != TOK_RBRACE) return 0 + addi_t0,a1,neg24 + ld_a2,t0,0 + li_a3 TOK_RBRACE + la_br &aib_zero + bne_a2,a3 + + # walk tokens tracking depth; if depth hits 0 before reaching end-24, + # the leading LBRACE doesn't match the trailing RBRACE -> return 0. + # t0 = tok, t1 = depth, t2 = last_tok = end - 24 + mov_t0,a0 + li_t1 %0 %0 + addi_t2,a1,neg24 +:aib_loop + la_br &aib_done + beq_t0,a1 + ld_a2,t0,0 + li_a3 TOK_LBRACE + la_br &aib_incr + beq_a2,a3 + li_a3 TOK_RBRACE + la_br &aib_decr + beq_a2,a3 + # non-brace: advance + addi_t0,t0,24 + la_br &aib_loop + b +:aib_incr + addi_t1,t1,1 + addi_t0,t0,24 + la_br &aib_loop + b +:aib_decr + addi_t1,t1,neg1 + # if (depth == 0 && tok != end - 24) -> not wrapping + la_br &aib_decr_skip + bnez_t1 + la_br &aib_zero + bne_t0,t2 +:aib_decr_skip + addi_t0,t0,24 + la_br &aib_loop + b +:aib_done + # return (depth == 0) ? 1 : 0 + la_br &aib_zero + bnez_t1 + li_a0 %1 %0 + ret +:aib_zero + li_a0 %0 %0 + ret + ## copy_arg_tokens_to_pool(a0=arg_start, a1=arg_end) -> void (fatal if empty) ## Non-leaf (calls copy_span_to_pool). Empty arg is an error. +## If the span is wrapped in a matching outer { ... } pair, strip the outer +## braces before copying; an empty inner span is a no-op. :copy_arg_tokens_to_pool - enter_0 + enter_16 # if (arg_start == arg_end) fatal la_br &err_bad_macro_header beq_a0,a1 + # spill a0/a1 so arg_is_braced can clobber regs + st_a0,sp,16 + st_a1,sp,24 + la_br &arg_is_braced + call + la_br &catp_plain + beqz_a0 + # braced: strip outer braces (start+24, end-24) + ld_a0,sp,16 + ld_a1,sp,24 + addi_a0,a0,24 + addi_a1,a1,neg24 + la_br &catp_done + beq_a0,a1 la_br &copy_span_to_pool call + la_br &catp_done + b +:catp_plain + ld_a0,sp,16 + ld_a1,sp,24 + la_br &copy_span_to_pool + call +:catp_done leave ret ## copy_paste_arg_to_pool(a0=arg_start, a1=arg_end) -> void (fatal unless len 1) ## Enforces the single-token-argument rule for params adjacent to ##. +## Braced args are rejected — pasting onto a block is nonsense. :copy_paste_arg_to_pool - enter_0 + enter_16 + # spill a0/a1 for the arg_is_braced call + st_a0,sp,16 + st_a1,sp,24 + la_br &arg_is_braced + call + la_br &err_bad_macro_header + bnez_a0 + ld_a0,sp,16 + ld_a1,sp,24 # if ((arg_end - arg_start) != 24) fatal sub_a2,a1,a0 li_a3 M1PP_TOK_SIZE @@ -4181,6 +4379,11 @@ DEFINE EXPR_INVALID 1100000000000000 li_a1 %15 %0 la_br &fatal b +:err_unbalanced_braces + la_a0 &msg_unbalanced_braces + li_a1 %17 %0 + la_br &fatal + b ## fatal(a0=msg_ptr, a1=msg_len): writes "m1pp: <msg>\n" to stderr, exits 1. ## Saves args across the three syscalls since a0..a3 are caller-saved. @@ -4227,6 +4430,8 @@ DEFINE EXPR_INVALID 1100000000000000 :const_lparen "(" :const_rparen ")" :const_comma "," +:const_lbrace "{" +:const_rbrace "}" :const_bang "!" :const_at "@" :const_pct "%" @@ -4274,6 +4479,7 @@ DEFINE EXPR_INVALID 1100000000000000 :msg_too_many_macros "too many macros" :msg_macro_body_overflow "macro body overflow" :msg_not_implemented "not implemented" +:msg_unbalanced_braces "unbalanced braces" ## --- BSS --------------------------------------------------------------------- ## Placed before :ELF_end so filesz/memsz (which this ELF header sets equal) @@ -4412,6 +4618,8 @@ ZERO8 ZERO8 :pa_limit ZERO8 +:pa_brace_depth +ZERO8 :emt_call_tok ZERO8 :emt_limit