boot2

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

commit d0c704cfef090603c28aae04be29a82233d07761
parent ce22557fc8cb164acd92288a244669cc4651ec03
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 23 Apr 2026 17:20:31 -0700

m1pp.M1: port strlen expression op

Diffstat:
Mm1pp/m1pp.M1 | 92++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 89 insertions(+), 3 deletions(-)

diff --git a/m1pp/m1pp.M1 b/m1pp/m1pp.M1 @@ -105,7 +105,8 @@ DEFINE EXPR_LT 0D00000000000000 DEFINE EXPR_LE 0E00000000000000 DEFINE EXPR_GT 0F00000000000000 DEFINE EXPR_GE 1000000000000000 -DEFINE EXPR_INVALID 1100000000000000 +DEFINE EXPR_STRLEN 1100000000000000 +DEFINE EXPR_INVALID 1200000000000000 ## --- Runtime shell: argv, read input, call pipeline, write output, exit ------ @@ -2547,9 +2548,9 @@ DEFINE EXPR_INVALID 1100000000000000 :pit_done ret -## expr_op_code(a0=tok) -> a0 = EXPR_ADD..EXPR_GE, or EXPR_INVALID. +## expr_op_code(a0=tok) -> a0 = EXPR_ADD..EXPR_STRLEN, or EXPR_INVALID. ## Accepts operator tokens: + - * / % << >> & | ^ ~ = != -## < <= > >=. Non-WORD tok or unknown operator -> EXPR_INVALID. +## < <= > >= strlen. Non-WORD tok or unknown operator -> EXPR_INVALID. ## ## tok_eq_const is a leaf but clobbers a0..a3,t0..t2; spill tok to eoc_tok ## once, reload before each compare. Needs an enter_0 frame because it @@ -2734,6 +2735,16 @@ DEFINE EXPR_INVALID 1100000000000000 la_br &eoc_gt bnez_a0 + # "strlen" -> EXPR_STRLEN + la_a0 &eoc_tok + ld_a0,a0,0 + la_a1 &op_strlen + li_a2 %6 %0 + la_br &tok_eq_const + call + la_br &eoc_strlen + bnez_a0 + :eoc_invalid li_a0 EXPR_INVALID leave @@ -2806,6 +2817,10 @@ DEFINE EXPR_INVALID 1100000000000000 li_a0 EXPR_GE leave ret +:eoc_strlen + li_a0 EXPR_STRLEN + leave + ret ## apply_expr_op(a0=op_code, a1=args_ptr, a2=argc) -> a0 = i64 result ## Reduce args[0..argc) per op: @@ -3585,6 +3600,11 @@ DEFINE EXPR_INVALID 1100000000000000 li_t0 EXPR_INVALID la_br &err_bad_macro_header beq_a0,t0 + # if (op == EXPR_STRLEN) handle inline — strlen's argument is a + # TOK_STRING atom, not a recursive expression. Yield text.len - 2. + li_t0 EXPR_STRLEN + la_br &eer_strlen + beq_a0,t0 # frame stack overflow check: if (expr_frame_top >= 16) fatal # (the global expr_frames[] array has 16 slots, shared across recursive # eval_expr_range calls) @@ -3653,6 +3673,71 @@ DEFINE EXPR_INVALID 1100000000000000 la_br &eer_loop b +:eer_strlen + # (strlen "literal") — degenerate unary op whose argument is a + # TOK_STRING atom, not a recursive expression. + # pos++ past the "strlen" operator word. + ld_t0,sp,16 + addi_t0,t0,24 + st_t0,sp,16 + # skip_expr_newlines(pos, end) + ld_a0,sp,16 + ld_a1,sp,24 + la_br &skip_expr_newlines + call + st_a0,sp,16 + # if (pos >= end) fatal + ld_t0,sp,16 + ld_t1,sp,24 + la_br &err_bad_macro_header + beq_t0,t1 + # if (pos->kind != TOK_STRING) fatal + ld_t2,t0,0 + li_a3 TOK_STRING + la_br &err_bad_macro_header + bne_t2,a3 + # if (pos->text.len < 2) fatal + ld_a1,t0,16 + li_a2 %2 %0 + la_br &err_bad_macro_header + blt_a1,a2 + # if (pos->text.ptr[0] != '"') fatal — rejects single-quoted '..' hex + ld_a2,t0,8 + lb_a3,a2,0 + li_a0 %34 %0 + la_br &err_bad_macro_header + bne_a3,a0 + # value = pos->text.len - 2 + addi_a1,a1,neg2 + st_a1,sp,32 + # pos++ + addi_t0,t0,24 + st_t0,sp,16 + # skip_expr_newlines(pos, end) + ld_a0,sp,16 + ld_a1,sp,24 + la_br &skip_expr_newlines + call + st_a0,sp,16 + # if (pos >= end) fatal + ld_t0,sp,16 + ld_t1,sp,24 + la_br &err_bad_macro_header + beq_t0,t1 + # if (pos->kind != TOK_RPAREN) fatal + ld_t2,t0,0 + li_a3 TOK_RPAREN + la_br &err_bad_macro_header + bne_t2,a3 + # pos++ + addi_t0,t0,24 + st_t0,sp,16 + # have_value = 1 + li_t0 %1 %0 + st_t0,sp,48 + la_br &eer_loop + b + :eer_loop_done # frame_top must equal entry_frame_top la_a0 &expr_frame_top @@ -4253,6 +4338,7 @@ DEFINE EXPR_INVALID 1100000000000000 :op_le "<=" :op_gt ">" :op_ge ">=" +:op_strlen "strlen" ## Nibble-to-hex lookup table for emit_hex_value. :hex_chars "0123456789ABCDEF"