boot2

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

commit 0941b72ae2a2fe737f7a9affa37553da2bb78287
parent a835d6b3630add6a1700ddcb6103208e5bf9d9bf
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun, 26 Apr 2026 22:34:21 -0700

cc/parse: dot/arrow use cg-push-field (§D.1)

The dot and arrow arms in parse-postfix-rest previously dropped the
field-name token, pushed imm 0, added (no scaling — wrong type),
and called cg-push-deref — producing offset 0 for every field. This
worked accidentally for .x where x is the first field and lhs was
already a pointer, but blew up in all other cases.

Replace both arms with cg-push-field. The arrow arm first does
rval! (decays/loads the pointer) and cg-push-deref to reach the
struct lval through the pointer, then cg-push-field on the struct.

Lock with cc-parse/36-struct-load.c: s.a=1; s.b=2; return s.a + s.b*10;
exits 21.

Diffstat:
Mcc/parse.scm | 26++++++++++++++++++--------
Mdocs/CC-PUNCHLIST.md | 19+++++++++----------
Atests/cc-parse/36-struct-load.c | 14++++++++++++++
Atests/cc-parse/36-struct-load.expected-exit | 1+
4 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/cc/parse.scm b/cc/parse.scm @@ -909,15 +909,25 @@ (cg-call (ps-cg ps) n #t) (lp))) ((eq? v 'dot) - (advance ps) (advance ps) - (cg-push-imm (ps-cg ps) %t-i64 0) - (cg-binop (ps-cg ps) 'add) - (cg-push-deref (ps-cg ps)) (lp)) + (advance ps) + (let ((nt (advance ps))) + (cond + ((not (eq? (tok-kind nt) 'IDENT)) + (die (tok-loc nt) "expected field name")) + (else + (cg-push-field (ps-cg ps) (tok-value nt)) (lp))))) ((eq? v 'arrow) - (advance ps) (advance ps) (rval! ps) - (cg-push-imm (ps-cg ps) %t-i64 0) - (cg-binop (ps-cg ps) 'add) - (cg-push-deref (ps-cg ps)) (lp)) + (advance ps) + (let ((nt (advance ps))) + (cond + ((not (eq? (tok-kind nt) 'IDENT)) + (die (tok-loc nt) "expected field name")) + (else + ;; ptr -> field: load the pointer to rval, deref to + ;; reach the struct lval, then push the field. + (rval! ps) + (cg-push-deref (ps-cg ps)) + (cg-push-field (ps-cg ps) (tok-value nt)) (lp))))) ((eq? v 'inc) (advance ps) (cg-take-addr (ps-cg ps)) (cg-push-deref (ps-cg ps)) diff --git a/docs/CC-PUNCHLIST.md b/docs/CC-PUNCHLIST.md @@ -144,16 +144,15 @@ broken. Pick one fix and document it in ### D. Aggregates -- [ ] **Struct member load** - - cg: `cc-cg/NN-struct-load.scm` — pushes a struct frame lval at - offset, loads field-typed value. - - parse: `cc-parse/NN-struct-load.c` — `struct S {int a; int b;}; struct S s; - s.a=1; s.b=2; return s.a + s.b*10;` → exit 21. - - Needs: `cg-push-field cg fname` — pop struct/union lval, look up - `fname` in `ctype-ext`'s `(tag complete? fields)`, push frame - lval at the right offset with the field's ctype. Replaces the - parser stub at `parse.scm` lines 947–960 that ignores the field - name and uses offset 0. +- [x] **Struct member load** + - cg: `cc-cg/36-struct-load.scm` — two-int struct, fields at 0 and 4. + - parse: `cc-parse/36-struct-load.c` + - Done: added `cg-push-field cg fname` (cg.scm). Pops struct/union + lval, looks up `fname` in `ctype-ext`'s `(tag complete? fields)`. + Three input cases: direct frame lval shifts the slot offset; + indirect frame lval loads addr+fo into a new indirect slot; + global lval `la`'s the label, adds `fo`, stashes via indirect + slot. Parser `dot` arm replaced. - [ ] **Struct member store** - cg: `cc-cg/NN-struct-store.scm` diff --git a/tests/cc-parse/36-struct-load.c b/tests/cc-parse/36-struct-load.c @@ -0,0 +1,14 @@ +// tests/cc-parse/36-struct-load.c — struct member load via real C +// (§D.1 of docs/CC-PUNCHLIST.md). Two int fields at distinct offsets; +// reading both back in distinct positions of the result confirms the +// parser uses the field offset, not 0 for both. +// +// s.a=1; s.b=2; return s.a + s.b*10; => exit 21. + +int main() { + struct S { int a; int b; }; + struct S s; + s.a = 1; + s.b = 2; + return s.a + s.b * 10; +} diff --git a/tests/cc-parse/36-struct-load.expected-exit b/tests/cc-parse/36-struct-load.expected-exit @@ -0,0 +1 @@ +21