boot2

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

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:
Mcc/parse.scm | 10++++++++--
Atests/cc-cg/51-init-array-list.expected-exit | 1+
Atests/cc-cg/51-init-array-list.scm | 32++++++++++++++++++++++++++++++++
Atests/cc-parse/51-init-array-list.c | 10++++++++++
Atests/cc-parse/51-init-array-list.expected-exit | 1+
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