commit e0551cf953f0fb6e572cfef301d18e25f50a25b2
parent b2c896610d2cc0cf6422e6a0a5e68ebbc4cccdab
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sun, 26 Apr 2026 22:37:22 -0700
cc/cg+parse: array global from element list (§E.3)
cc-cg fixture drives a 3-element int[] global through cg-emit-global
with three 4-byte LE bytevector pieces, then verifies all three slots
via &a + scaled offsets.
cc-parse fixture exercises `int a[3] = {...}; int *p = a;` — the array
data section is correct, and a manually-decayed pointer reads element 0.
Wider ptr+int arithmetic and a[i] indexing stay out of scope here per
§D / §K ownership.
%const-init-piece extends bare-IDENT recognition to array names so that
`int *p = a;` produces a label-ref piece pointing at cc__a.
Diffstat:
5 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/cc/parse.scm b/cc/parse.scm
@@ -471,10 +471,16 @@
(die (tok-loc it) "init: &x must reference a global"
(tok-value it))))))
(else (die (tok-loc it) "init: &?" (tok-value it))))))
- ;; Function name as a fn-ptr initializer.
+ ;; Function name or array name as a label-ref initializer.
+ ;; (Both decay to a pointer when used as a value.)
((and (eq? (tok-kind t) 'IDENT)
(let ((sm (scope-lookup ps (tok-value t))))
- (and sm (eq? (sym-kind sm) 'fn))))
+ (and sm
+ (or (eq? (sym-kind sm) 'fn)
+ (and (eq? (sym-kind sm) 'var)
+ (eq? (ctype-kind (sym-type sm)) 'arr)
+ (or (eq? (sym-storage sm) 'static)
+ (eq? (sym-storage sm) 'extern)))))))
(advance ps)
(let ((sm (scope-lookup ps (tok-value t))))
(cons 'label-ref (sym-slot sm))))
diff --git a/tests/cc-cg/51-init-array-list.expected-exit b/tests/cc-cg/51-init-array-list.expected-exit
@@ -0,0 +1 @@
+7
diff --git a/tests/cc-cg/51-init-array-list.scm b/tests/cc-cg/51-init-array-list.scm
@@ -0,0 +1,32 @@
+;; tests/cc-cg/51-init-array-list.scm — global int[3] = {1,2,4};
+;; main returns a[0]+a[1]+a[2]. §E.3.
+;; Runtime: exits 7.
+
+(let* ((cg (cg-init))
+ (elem %t-i32)
+ (aty (%ctype 'arr 12 4 (cons elem 3)))
+ (a (%sym "a" 'var 'static aty #f))
+ ;; Three 4-byte LE pieces.
+ (e1 (make-bytevector 4 0)) (_1 (bytevector-u8-set! e1 0 1))
+ (e2 (make-bytevector 4 0)) (_2 (bytevector-u8-set! e2 0 2))
+ (e3 (make-bytevector 4 0)) (_3 (bytevector-u8-set! e3 0 4)))
+ (cg-emit-global cg a (list e1 e2 e3))
+ (cg-fn-begin cg "main" '() %t-i32)
+ ;; Sum a[0]+a[1]+a[2]. We avoid array→ptr decay (which is a
+ ;; parser-side concern) by taking &a explicitly, casting to int*,
+ ;; then doing ordinary pointer arithmetic.
+ (let ((emit-elem
+ (lambda (idx)
+ (cg-push-sym cg a) (cg-take-addr cg) ; rval ptr-to-arr
+ (cg-cast cg (%ctype 'ptr 8 8 elem)) ; relabel as int*
+ (cg-push-imm cg %t-i32 idx)
+ (cg-binop cg 'add) ; int* (scaling x 4)
+ (cg-push-deref cg) (cg-load cg)))) ; rval int
+ (emit-elem 0)
+ (emit-elem 1)
+ (cg-binop cg 'add)
+ (emit-elem 2)
+ (cg-binop cg 'add))
+ (cg-return cg)
+ (cg-fn-end cg)
+ (write-bv-fd 1 (cg-finish cg)))
diff --git a/tests/cc-parse/51-init-array-list.c b/tests/cc-parse/51-init-array-list.c
@@ -0,0 +1,10 @@
+// tests/cc-parse/51-init-array-list.c — global int array initialised
+// from element list. §E.3.
+//
+// Array indexing (a[i]) and ptr+int arith inside expressions are owned
+// by other agents (§D, §K). To stay inside the available surface, we
+// just verify the first element by dereffing a manually-decayed
+// pointer.
+int a[3] = {7, 22, 99};
+int *p = a;
+int main(void) { return *p; }
diff --git a/tests/cc-parse/51-init-array-list.expected-exit b/tests/cc-parse/51-init-array-list.expected-exit
@@ -0,0 +1 @@
+7