boot2

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

commit f18b740fb0d49db51a671bf3ab0dac51646bdcac
parent db4d877362e9b952d72f15507e5e5fa481cd7b5d
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun, 26 Apr 2026 22:39:41 -0700

cc/parse: arrow + nested struct access fixtures (§D.3 §D.4)

§D.3: cc-parse/38-arrow.c locks in p->a / p->b via the §D.1 arrow
arm rewrite. p = &s; p->a = 4; p->b = 9; return p->b - p->a; -> 5.

§D.4: cc-parse/39-struct-nested.c chains s.inner.x and p->inner.x.
The outer struct has a leading int padding before the inner, so
each field-access step's offset must be summed correctly across
the chain. Distinct *1/*10/*100/*1000 multipliers in the readback
isolate every component, compared to a known constant for exit 1.

Diffstat:
Mdocs/CC-PUNCHLIST.md | 21++++++++++++++-------
Atests/cc-parse/38-arrow.c | 14++++++++++++++
Atests/cc-parse/38-arrow.expected-exit | 1+
Atests/cc-parse/39-struct-nested.c | 20++++++++++++++++++++
Atests/cc-parse/39-struct-nested.expected-exit | 1+
5 files changed, 50 insertions(+), 7 deletions(-)

diff --git a/docs/CC-PUNCHLIST.md b/docs/CC-PUNCHLIST.md @@ -161,13 +161,20 @@ broken. Pick one fix and document it in - Done: cg-push-field from §D.1 plus the width-aware store path from §A.1. No new primitive. -- [ ] **Pointer-to-struct (`p->x`)** - - cg: `cc-cg/NN-arrow.scm` - - parse: `cc-parse/NN-arrow.c` - - Needs: parser does ptr → deref → field via `cg-push-field`. - -- [ ] **Nested struct access (`s.inner.x`, `s->inner.x`)** - - parse: `cc-parse/NN-struct-nested.c` +- [x] **Pointer-to-struct (`p->x`)** + - cg: `cc-cg/38-arrow.scm` + - parse: `cc-parse/38-arrow.c` + - Done: arrow arm in `parse-postfix-rest` calls rval! (loads ptr), + cg-push-deref (struct lval through ptr), then cg-push-field. + Indirect-frame branch of cg-push-field (added in §D.1) handles + the deref-result struct lval correctly. + +- [x] **Nested struct access (`s.inner.x`, `s->inner.x`)** + - parse: `cc-parse/39-struct-nested.c` + - Done: cg-push-field pushes a new lval whose ctype is the field's + type; if that's a struct, a subsequent `.x` chains naturally. + The fixture exercises both s.inner.x (direct frame) and + p->inner.x (indirect frame, via the §D.1 indirect path). - [ ] **Array element access at non-zero index** - cg: `cc-cg/NN-array-index.scm` — `int a[3]; a[0]=1; a[1]=2; a[2]=4; diff --git a/tests/cc-parse/38-arrow.c b/tests/cc-parse/38-arrow.c @@ -0,0 +1,14 @@ +// tests/cc-parse/38-arrow.c — pointer-to-struct field access via real C +// (§D.3 of docs/CC-PUNCHLIST.md). Validates the arrow arm: rval the +// pointer, deref to reach the struct, push-field at the right offset. +// +// p->a=4; p->b=9; return p->b - p->a; => exit 5. + +int main() { + struct S { int a; int b; }; + struct S s; + struct S *p = &s; + p->a = 4; + p->b = 9; + return p->b - p->a; +} diff --git a/tests/cc-parse/38-arrow.expected-exit b/tests/cc-parse/38-arrow.expected-exit @@ -0,0 +1 @@ +5 diff --git a/tests/cc-parse/39-struct-nested.c b/tests/cc-parse/39-struct-nested.c @@ -0,0 +1,20 @@ +// tests/cc-parse/39-struct-nested.c — nested struct field access via +// real C (§D.4 of docs/CC-PUNCHLIST.md). Tests both `s.inner.x` and +// `p->inner.x` chains. Padding ensures the inner struct is at a +// non-zero offset, so each step's offset must be summed correctly. +// +// outer.lead = 0; outer.inner.x=2; outer.inner.y=3; +// return p->inner.x + p->inner.y*10 + s.inner.x*100 + s.inner.y*1000; +// = 2 + 30 + 200 + 3000 = 3232. We compare to 3232 -> exit 1. + +int main() { + struct Inner { int x; int y; }; + struct Outer { int lead; struct Inner inner; }; + struct Outer s; + struct Outer *p = &s; + s.lead = 99; + s.inner.x = 2; + s.inner.y = 3; + return (p->inner.x + p->inner.y * 10 + s.inner.x * 100 + s.inner.y * 1000) + == 3232; +} diff --git a/tests/cc-parse/39-struct-nested.expected-exit b/tests/cc-parse/39-struct-nested.expected-exit @@ -0,0 +1 @@ +1