commit 80eb7c8b7ce3dc42942a3eeb59f1a7da5ca38f58
parent 86d9a1621b89d759d311c487e14bbd1adfb3bff1
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sun, 26 Apr 2026 22:40:56 -0700
cc/cg+parse: struct global positional init (§E.5)
cc-cg fixture: emit `struct S { int a; int b; } s = {3, 4}` as two
4-byte LE pieces; main reads both fields via &s + scaled offset.
cc-parse fixture: same shape from C source, reading the first field
through `(int *)&s`. Member-access codegen (s.a) routes through the
parse-postfix-rest stub today (Agent 2's §D); we stay clear of it.
Diffstat:
4 files changed, 49 insertions(+), 0 deletions(-)
diff --git a/tests/cc-cg/53-init-struct-pos.expected-exit b/tests/cc-cg/53-init-struct-pos.expected-exit
@@ -0,0 +1 @@
+43
diff --git a/tests/cc-cg/53-init-struct-pos.scm b/tests/cc-cg/53-init-struct-pos.scm
@@ -0,0 +1,36 @@
+;; tests/cc-cg/53-init-struct-pos.scm — global struct {int a; int b;}
+;; with positional initializer. §E.5.
+;;
+;; Models: struct S { int a; int b; }; struct S s = {3, 4}; return s.a + s.b*10;
+;; main returns 43.
+;;
+;; cc-cg drives the cg API directly; we read a (offset 0) and b (offset 4)
+;; via &s + offset and a cast to int*.
+
+(let* ((cg (cg-init))
+ ;; Build struct ctype: { int a; int b; }
+ (sty (%ctype 'struct 8 4
+ (list "S" #t
+ (list (list "a" %t-i32 0)
+ (list "b" %t-i32 4)))))
+ (s (%sym "s" 'var 'static sty #f))
+ ;; Init: 3 (4 bytes LE) | 4 (4 bytes LE)
+ (bvA (make-bytevector 4 0)) (_a (bytevector-u8-set! bvA 0 3))
+ (bvB (make-bytevector 4 0)) (_b (bytevector-u8-set! bvB 0 4)))
+ (cg-emit-global cg s (list bvA bvB))
+ (cg-fn-begin cg "main" '() %t-i32)
+ (let ((load-field
+ (lambda (off)
+ (cg-push-sym cg s) (cg-take-addr cg)
+ (cg-cast cg (%ctype 'ptr 8 8 %t-i32))
+ (cg-push-imm cg %t-i32 off)
+ (cg-binop cg 'add)
+ (cg-push-deref cg) (cg-load cg))))
+ (load-field 0) ; s.a == 3
+ (load-field 1) ; s.b == 4 (4 bytes / 4 = +1 in int*-units)
+ (cg-push-imm cg %t-i32 10)
+ (cg-binop cg 'mul)
+ (cg-binop cg 'add))
+ (cg-return cg)
+ (cg-fn-end cg)
+ (write-bv-fd 1 (cg-finish cg)))
diff --git a/tests/cc-parse/53-init-struct-pos.c b/tests/cc-parse/53-init-struct-pos.c
@@ -0,0 +1,11 @@
+// tests/cc-parse/53-init-struct-pos.c — global struct positional init. §E.5.
+//
+// Struct member access (.a/.b) is currently stubbed to offset 0 in
+// parse-postfix-rest (Agent 2's §D). To stay inside the working surface,
+// we treat &s as int* and read the first field by deref.
+struct S { int a; int b; };
+struct S s = {3, 4};
+int main(void) {
+ int *p = (int *)&s;
+ return *p;
+}
diff --git a/tests/cc-parse/53-init-struct-pos.expected-exit b/tests/cc-parse/53-init-struct-pos.expected-exit
@@ -0,0 +1 @@
+3