boot2

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

parse.scm (62701B)


      1 ;; cc/parse.scm — recursive-descent + Pratt parser. Minimal scheme1.
      2 
      3 (define (make-pstate toks cg)
      4   (%pstate toks (list '()) (list '()) '() #f '() cg))
      5 
      6 (define (peek ps) (car (ps-toks ps)))
      7 (define (peek2 ps)
      8   (let ((r (cdr (ps-toks ps))))
      9     (if (null? r) (car (ps-toks ps)) (car r))))
     10 (define (advance ps)
     11   (let ((t (peek ps))) (ps-toks-set! ps (cdr (ps-toks ps))) t))
     12 (define (at-kw? ps s)
     13   (let ((t (peek ps)))
     14     (and (eq? (tok-kind t) 'KW) (eq? (tok-value t) s))))
     15 (define (at-punct? ps s)
     16   (let ((t (peek ps)))
     17     (and (eq? (tok-kind t) 'PUNCT) (eq? (tok-value t) s))))
     18 (define (expect-kw ps s)
     19   (let ((t (peek ps)))
     20     (if (and (eq? (tok-kind t) 'KW) (eq? (tok-value t) s))
     21         (advance ps) (die (tok-loc t) "expected kw" s))))
     22 (define (expect-punct ps s)
     23   (let ((t (peek ps)))
     24     (if (and (eq? (tok-kind t) 'PUNCT) (eq? (tok-value t) s))
     25         (advance ps) (die (tok-loc t) "expected punct" s))))
     26 
     27 (define (scope-enter! ps)
     28   (ps-scope-set! ps (cons '() (ps-scope ps)))
     29   (ps-tags-set!  ps (cons '() (ps-tags ps))))
     30 (define (scope-leave! ps)
     31   (ps-scope-set! ps (cdr (ps-scope ps)))
     32   (ps-tags-set!  ps (cdr (ps-tags ps))))
     33 (define (scope-bind! ps n s)
     34   (let* ((f (ps-scope ps)) (top (car f)) (r (cdr f)))
     35     (if (alist-ref n top) (die #f "dup decl" n)
     36         (ps-scope-set! ps (cons (alist-set n s top) r)))))
     37 (define (scope-lookup ps n)
     38   (let loop ((f (ps-scope ps)))
     39     (cond ((null? f) #f)
     40           (else
     41            (let ((v (alist-ref n (car f))))
     42              (if v v (loop (cdr f))))))))
     43 (define (tag-bind! ps n c)
     44   (let* ((f (ps-tags ps)) (top (car f)) (r (cdr f)))
     45     (ps-tags-set! ps (cons (alist-set n c top) r))))
     46 (define (tag-lookup ps n)
     47   (let loop ((f (ps-tags ps)))
     48     (cond ((null? f) #f)
     49           (else (let ((v (alist-ref n (car f))))
     50                   (if v v (loop (cdr f))))))))
     51 (define (typedef-add! ps n)
     52   (ps-typedefs-set! ps (alist-set n #t (ps-typedefs ps))))
     53 (define (typedef? ps n)
     54   (if (alist-ref n (ps-typedefs ps)) #t #f))
     55 
     56 (define (%mk-ptr p) (%ctype 'ptr 8 8 p))
     57 (define (%mk-arr e n)
     58   (%ctype 'arr (if (< n 0) -1 (* n (ctype-size e)))
     59           (ctype-align e) (cons e n)))
     60 (define (%mk-fn r p v) (%ctype 'fn -1 -1 (list r p v)))
     61 (define (ctype-is-ptr? t) (eq? (ctype-kind t) 'ptr))
     62 (define (ctype-is-fn?  t) (eq? (ctype-kind t) 'fn))
     63 (define (ctype-is-arr? t) (eq? (ctype-kind t) 'arr))
     64 
     65 (define (eat-cv-quals! ps)
     66   (cond ((or (at-kw? ps 'const) (at-kw? ps 'volatile)
     67              (at-kw? ps 'restrict))
     68          (advance ps) (eat-cv-quals! ps))
     69         (else #t)))
     70 
     71 (define (parse-decl-spec ps)
     72   (let loop ((sto #f) (sn #f) (lg 0) (b #f) (saw #f))
     73     (let ((t (peek ps)))
     74       (cond
     75         ((or (at-kw? ps 'auto) (at-kw? ps 'register))
     76          (advance ps) (loop sto sn lg b #t))
     77         ((at-kw? ps 'static)  (advance ps) (loop 'static sn lg b #t))
     78         ((at-kw? ps 'extern)  (advance ps) (loop 'extern sn lg b #t))
     79         ((at-kw? ps 'typedef) (advance ps) (loop 'typedef sn lg b #t))
     80         ((or (at-kw? ps 'const) (at-kw? ps 'volatile)
     81              (at-kw? ps 'restrict) (at-kw? ps 'inline))
     82          (advance ps) (loop sto sn lg b #t))
     83         ((at-kw? ps 'signed)   (advance ps) (loop sto 'signed lg b #t))
     84         ((at-kw? ps 'unsigned) (advance ps) (loop sto 'unsigned lg b #t))
     85         ((at-kw? ps 'short) (advance ps) (loop sto sn -1 b #t))
     86         ((at-kw? ps 'long)  (advance ps) (loop sto sn (+ lg 1) b #t))
     87         ((at-kw? ps 'void) (advance ps) (loop sto sn lg 'void #t))
     88         ((at-kw? ps 'char) (advance ps) (loop sto sn lg 'char #t))
     89         ((at-kw? ps 'int)  (advance ps) (loop sto sn lg 'int #t))
     90         ((at-kw? ps '_Bool) (advance ps) (loop sto sn lg 'bool #t))
     91         ((or (at-kw? ps 'float) (at-kw? ps 'double)
     92              (at-kw? ps '_Complex) (at-kw? ps '_Imaginary))
     93          (die (tok-loc t) "no float" (tok-value t)))
     94         ((or (at-kw? ps '_Atomic) (at-kw? ps '_Thread_local)
     95              (at-kw? ps '_Alignas) (at-kw? ps '_Generic)
     96              (at-kw? ps '_Alignof) (at-kw? ps '_Static_assert))
     97          (die (tok-loc t) "rejected" (tok-value t)))
     98         ((at-kw? ps 'struct)
     99          (loop sto sn lg (parse-aggregate-spec ps 'struct) #t))
    100         ((at-kw? ps 'union)
    101          (loop sto sn lg (parse-aggregate-spec ps 'union) #t))
    102         ((at-kw? ps 'enum)
    103          (loop sto sn lg (parse-enum-spec ps) #t))
    104         ((and (not b) (eq? (tok-kind t) 'IDENT)
    105               (typedef? ps (tok-value t)))
    106          (let* ((tk (advance ps)) (sm (scope-lookup ps (tok-value tk))))
    107            (if (and sm (eq? (sym-kind sm) 'typedef))
    108                (loop sto sn lg (sym-type sm) #t)
    109                (die (tok-loc tk) "typedef no sym" (tok-value tk)))))
    110         (else
    111          (cond ((not saw) (die (tok-loc t) "expected decl-spec"
    112                                (tok-value t)))
    113                (else (cons sto (resolve-base t sn lg b)))))))))
    114 
    115 (define (resolve-base loc sn lg b)
    116   (cond
    117     ((eq? b 'void)
    118      (if (or sn (not (zero? lg))) (die loc "void+qual") %t-void))
    119     ((eq? b 'bool)
    120      (if (or sn (not (zero? lg))) (die loc "bool+qual") %t-bool))
    121     ((eq? b 'char)
    122      (cond ((eq? sn 'unsigned) %t-u8) (else %t-i8)))
    123     ((or (eq? b 'int) (and (not b) (or sn (not (zero? lg)))))
    124      (cond ((= lg -1) (if (eq? sn 'unsigned) %t-u16 %t-i16))
    125            ((= lg 0)  (if (eq? sn 'unsigned) %t-u32 %t-i32))
    126            (else      (if (eq? sn 'unsigned) %t-u64 %t-i64))))
    127     ((ctype? b)
    128      (if (or sn (not (zero? lg))) (die loc "type+qual") b))
    129     (else (die loc "unknown decl-spec"))))
    130 
    131 (define (parse-aggregate-spec ps kind)
    132   (advance ps)
    133   (let ((tag (cond ((eq? (tok-kind (peek ps)) 'IDENT)
    134                     (tok-value (advance ps))) (else #f))))
    135     (cond
    136       ((at-punct? ps 'lbrace)
    137        (advance ps)
    138        (let* ((ex (and tag (tag-lookup ps tag)))
    139               (ct (cond ((and ex (eq? (ctype-kind ex) kind)) ex)
    140                         (else (let ((c (%ctype kind -1 -1
    141                                               (list (or tag #f) #f '()))))
    142                                 (if tag (tag-bind! ps tag c)) c))))
    143               (fields (parse-struct-fields ps)))
    144          (expect-punct ps 'rbrace)
    145          (complete-agg! ct kind tag fields) ct))
    146       (tag (let ((ex (tag-lookup ps tag)))
    147              (cond (ex ex)
    148                    (else (let ((c (%ctype kind -1 -1
    149                                          (list tag #f '()))))
    150                            (tag-bind! ps tag c) c)))))
    151       (else (die (tok-loc (peek ps)) "anon agg")))))
    152 
    153 (define (parse-struct-fields ps)
    154   (let loop ((acc '()) (off 0))
    155     (cond
    156       ((at-punct? ps 'rbrace) (reverse acc))
    157       (else
    158        (let ((spec (parse-decl-spec ps)))
    159          (let dl ((acc2 acc) (o2 off))
    160            (let* ((p (parse-declarator ps (cdr spec)))
    161                   (nm (car p)) (ty (cdr p))
    162                   (al (max (ctype-align ty) 1))
    163                   (sz (ctype-size ty))
    164                   (oa (align-up o2 al)))
    165              (cond
    166                ((at-punct? ps 'comma)
    167                 (advance ps)
    168                 (dl (cons (list nm ty oa) acc2)
    169                     (+ oa (max sz 0))))
    170                ((at-punct? ps 'semi)
    171                 (advance ps)
    172                 (loop (cons (list nm ty oa) acc2)
    173                       (+ oa (max sz 0))))
    174                (else (die (tok-loc (peek ps)) "field"))))))))))
    175 
    176 (define (complete-agg! ct k tag fs)
    177   (let* ((ma (let m ((xs fs) (a 1))
    178                (if (null? xs) a
    179                    (m (cdr xs) (max a (ctype-align (cadr (car xs))))))))
    180          (last (let l ((xs fs) (e 0))
    181                  (if (null? xs) e
    182                      (let* ((f (car xs)) (off (car (cddr f)))
    183                             (sz (ctype-size (cadr f))))
    184                        (l (cdr xs) (max e (+ off (max sz 0))))))))
    185          (sz (cond ((eq? k 'union)
    186                     (let u ((xs fs) (s 0))
    187                       (if (null? xs) s
    188                           (u (cdr xs)
    189                              (max s (ctype-size (cadr (car xs))))))))
    190                    (else (align-up last ma)))))
    191     (ctype-size-set! ct sz)
    192     (ctype-align-set! ct ma)
    193     (ctype-ext-set! ct (list tag #t fs))))
    194 
    195 (define (parse-enum-spec ps)
    196   (advance ps)
    197   (let ((tag (cond ((eq? (tok-kind (peek ps)) 'IDENT)
    198                     (tok-value (advance ps))) (else #f))))
    199     (cond
    200       ((at-punct? ps 'lbrace)
    201        (advance ps)
    202        (let ((ct (%ctype 'enum 4 4 (list tag '()))))
    203          (if tag (tag-bind! ps tag ct))
    204          (let loop ((vs '()) (nv 0))
    205            (cond
    206              ((at-punct? ps 'rbrace)
    207               (advance ps)
    208               (ctype-ext-set! ct (list tag (reverse vs))) ct)
    209              (else
    210               (let* ((nt (advance ps)) (nm (tok-value nt))
    211                      (val (cond ((at-punct? ps 'assign)
    212                                  (advance ps) (parse-const-int ps))
    213                                 (else nv))))
    214                 (scope-bind! ps nm
    215                              (%sym nm 'enum-const #f %t-i32 val))
    216                 (cond ((at-punct? ps 'comma) (advance ps))
    217                       ((at-punct? ps 'rbrace) #t)
    218                       (else (die (tok-loc (peek ps)) "enum")))
    219                 (loop (cons (cons nm val) vs) (+ val 1))))))))
    220       (tag (let ((e (tag-lookup ps tag)))
    221              (cond (e e)
    222                    (else (let ((c (%ctype 'enum 4 4 (list tag '()))))
    223                            (tag-bind! ps tag c) c)))))
    224       (else (die (tok-loc (peek ps)) "enum")))))
    225 
    226 (define (parse-const-int ps)
    227   (let ((t (peek ps)))
    228     (cond
    229       ((eq? (tok-kind t) 'INT) (tok-value (advance ps)))
    230       ((and (eq? (tok-kind t) 'PUNCT) (eq? (tok-value t) 'minus))
    231        (advance ps) (- 0 (parse-const-int ps)))
    232       ((and (eq? (tok-kind t) 'PUNCT) (eq? (tok-value t) 'plus))
    233        (advance ps) (parse-const-int ps))
    234       ((eq? (tok-kind t) 'IDENT)
    235        (let ((sm (scope-lookup ps (tok-value t))))
    236          (cond ((and sm (eq? (sym-kind sm) 'enum-const))
    237                 (advance ps) (sym-slot sm))
    238                (else (die (tok-loc t) "const?" (tok-value t))))))
    239       (else (die (tok-loc t) "const?" (tok-value t))))))
    240 
    241 (define (parse-declarator ps base)
    242   ((cdr (parse-decl-cont ps)) base
    243    (lambda (n t) (cons n t))))
    244 
    245 (define (parse-decl-cont ps)
    246   (cond
    247     ((at-punct? ps 'star)
    248      (advance ps) (eat-cv-quals! ps)
    249      (let* ((r (parse-decl-cont ps)) (rf (cdr r)))
    250        (cons (car r) (lambda (b k) (rf (%mk-ptr b) k)))))
    251     ((and (at-punct? ps 'lparen) (paren-is-group? ps))
    252      (advance ps)
    253      (let* ((i (parse-decl-cont ps)) (if- (cdr i)))
    254        (expect-punct ps 'rparen)
    255        (let ((s (parse-decl-suf-cont ps)))
    256          (cons (car i) (lambda (b k) (if- (s b) k))))))
    257     ((eq? (tok-kind (peek ps)) 'IDENT)
    258      (let* ((tk (advance ps)) (n (tok-value tk))
    259             (s (parse-decl-suf-cont ps)))
    260        (cons n (lambda (b k) (k n (s b))))))
    261     (else
    262      (let ((s (parse-decl-suf-cont ps)))
    263        (cons #f (lambda (b k) (k #f (s b))))))))
    264 
    265 (define (parse-decl-suf-cont ps)
    266   ;; C declarator suffixes apply RIGHT-TO-LEFT (innermost first):
    267   ;;   int a[2][3]  ⇒  arr (arr int 3) 2     (outer dim 2)
    268   ;; not arr (arr int 2) 3 (which would treat the leftmost suffix as
    269   ;; outermost). The recursive structure builds the inner suffix's
    270   ;; result first, then this level wraps.
    271   (cond
    272     ((at-punct? ps 'lbrack)
    273      (advance ps)
    274      (let* ((ln (cond ((at-punct? ps 'rbrack) -1)
    275                       (else (parse-const-int ps))))
    276             (_ (expect-punct ps 'rbrack))
    277             (r (parse-decl-suf-cont ps)))
    278        (lambda (b) (%mk-arr (r b) ln))))
    279     ((at-punct? ps 'lparen)
    280      (advance ps)
    281      (let* ((res (parse-fn-params ps))
    282             (p (car res)) (v (cdr res)))
    283        (expect-punct ps 'rparen)
    284        (let ((r (parse-decl-suf-cont ps)))
    285          (lambda (b) (%mk-fn (r b) p v)))))
    286     (else (lambda (b) b))))
    287 
    288 (define (paren-is-group? ps)
    289   (let ((t (peek2 ps)))
    290     (cond
    291       ((eq? (tok-kind t) 'KW)
    292        (let ((v (tok-value t)))
    293          (cond ((or (eq? v 'void) (eq? v 'char) (eq? v 'short)
    294                     (eq? v 'int) (eq? v 'long) (eq? v 'signed)
    295                     (eq? v 'unsigned) (eq? v '_Bool)
    296                     (eq? v 'struct) (eq? v 'union) (eq? v 'enum)
    297                     (eq? v 'const) (eq? v 'volatile)
    298                     (eq? v 'restrict) (eq? v 'static)
    299                     (eq? v 'extern) (eq? v 'register)) #f)
    300                (else #t))))
    301       ((eq? (tok-kind t) 'IDENT)
    302        (cond ((typedef? ps (tok-value t)) #f) (else #t)))
    303       ((eq? (tok-kind t) 'PUNCT)
    304        (let ((v (tok-value t)))
    305          (cond ((eq? v 'rparen) #f)
    306                ((or (eq? v 'star) (eq? v 'lparen) (eq? v 'lbrack)) #t)
    307                (else #f))))
    308       (else #f))))
    309 
    310 (define (parse-fn-params ps)
    311   (cond
    312     ((at-punct? ps 'rparen) (cons '() #f))
    313     ((and (at-kw? ps 'void)
    314           (eq? (tok-kind (peek2 ps)) 'PUNCT)
    315           (eq? (tok-value (peek2 ps)) 'rparen))
    316      (advance ps) (cons '() #f))
    317     (else
    318      (let loop ((acc '()))
    319        (cond
    320          ((at-punct? ps 'ellipsis)
    321           (advance ps) (cons (reverse acc) #t))
    322          (else
    323           (let* ((sp (parse-decl-spec ps))
    324                  (p (parse-declarator ps (cdr sp)))
    325                  (nm (car p)) (ty (cdr p))
    326                  (ty2 (cond ((ctype-is-arr? ty)
    327                              (%mk-ptr (car (ctype-ext ty))))
    328                             ((ctype-is-fn? ty) (%mk-ptr ty))
    329                             (else ty))))
    330             (cond
    331               ((at-punct? ps 'comma)
    332                (advance ps) (loop (cons (cons nm ty2) acc)))
    333               ((at-punct? ps 'rparen)
    334                (cons (reverse (cons (cons nm ty2) acc)) #f))
    335               (else (die (tok-loc (peek ps)) "param"))))))))))
    336 
    337 (define (parse-translation-unit ps)
    338   (cond
    339     ((eq? (tok-kind (peek ps)) 'EOF) #t)
    340     (else (parse-decl-or-fn ps) (parse-translation-unit ps))))
    341 
    342 (define (parse-decl-or-fn ps)
    343   (let* ((sp (parse-decl-spec ps))
    344          (sto (car sp)) (b (cdr sp)))
    345     (cond
    346       ((at-punct? ps 'semi) (advance ps) 'decl)
    347       (else
    348        (let* ((p (parse-declarator ps b))
    349               (n (car p)) (t (cdr p)))
    350          (cond
    351            ((and (ctype-is-fn? t) (at-punct? ps 'lbrace))
    352             (parse-fn-body ps n t) 'fn)
    353            (else
    354             (handle-decl ps sto n t)
    355             (let lp ()
    356               (cond
    357                 ((at-punct? ps 'comma)
    358                  (advance ps)
    359                  (let* ((p2 (parse-declarator ps b))
    360                         (n2 (car p2)) (t2 (cdr p2)))
    361                    (handle-decl ps sto n2 t2) (lp)))
    362                 (else (expect-punct ps 'semi) 'decl))))))))))
    363 
    364 (define (handle-decl ps sto n ty)
    365   (cond
    366     ((not n) (die #f "no name"))
    367     ((eq? sto 'typedef)
    368      (typedef-add! ps n)
    369      (scope-bind! ps n (%sym n 'typedef #f ty #f)))
    370     ((ctype-is-fn? ty)
    371      (scope-bind! ps n
    372                   (%sym n 'fn (or sto 'extern) ty
    373                         (bytevector-append "cc__" n))))
    374     ;; §I: block-scope `static` routes to a global with a name mangled
    375     ;; on the enclosing function so two functions can each have their
    376     ;; own `static int n;` without colliding. The sym's NAME holds the
    377     ;; mangled form (cg-push-sym / cg-emit-global both prefix "cc__"
    378     ;; onto sym-name to derive the emitted label); scope-bind!s key
    379     ;; remains the original identifier for source-level lookup.
    380     ((and (eq? sto 'static) (ps-fn-ctx ps))
    381      (let* ((fname (fn-ctx-name (ps-fn-ctx ps)))
    382             (mangled (bytevector-append fname "__" n))
    383             (sm (%sym mangled 'var 'static ty
    384                       (bytevector-append "cc__" mangled))))
    385        (scope-bind! ps n sm)
    386        (cond
    387          ((at-punct? ps 'assign)
    388           (advance ps)
    389           (cg-emit-global (ps-cg ps) sm (parse-init-global ps ty)))
    390          (else (cg-emit-global (ps-cg ps) sm #f)))))
    391     (else
    392      (cond
    393        ((not (ps-fn-ctx ps))
    394         (let ((sm (%sym n 'var (or sto 'extern) ty
    395                         (bytevector-append "cc__" n))))
    396           (scope-bind! ps n sm)
    397           (cond
    398             ((at-punct? ps 'assign)
    399              (advance ps)
    400              (cg-emit-global (ps-cg ps) sm
    401                              (parse-init-global ps ty)))
    402             ((eq? sto 'extern) (cg-emit-extern (ps-cg ps) sm))
    403             (else (cg-emit-global (ps-cg ps) sm #f)))))
    404        (else
    405         (let* ((sz (max (ctype-size ty) 1))
    406                (al (max (ctype-align ty) 1))
    407                (sl (cg-alloc-slot (ps-cg ps) sz al))
    408                (sm (%sym n 'var (or sto 'auto) ty sl)))
    409           (scope-bind! ps n sm)
    410           (cond
    411             ((at-punct? ps 'assign)
    412              (advance ps)
    413              (cond
    414                ;; Aggregate locals get the per-element store treatment.
    415                ((or (at-punct? ps 'lbrace)
    416                     (and (eq? (ctype-kind ty) 'arr)
    417                          (eq? (tok-kind (peek ps)) 'STR)))
    418                 (parse-init-local-aggregate ps sm ty))
    419                (else
    420                 (cg-push-sym (ps-cg ps) sm)
    421                 (parse-expr-bp ps 4) (rval! ps)
    422                 (cg-cast (ps-cg ps) ty)
    423                 (cg-assign (ps-cg ps))
    424                 (cg-pop (ps-cg ps)))))
    425             (else #t))))))))
    426 
    427 ;; ====================================================================
    428 ;; Initializers (CC.md §Variable initializers, §E of CC-PUNCHLIST).
    429 ;;
    430 ;; parse-init-global ps ty
    431 ;;   Reads the initializer following `=` for a file-scope or block-scope
    432 ;;   static var of static-storage type `ty` and returns a list of
    433 ;;   pieces suitable for cg-emit-global. See cg.scm §cg-emit-global for
    434 ;;   the piece grammar.
    435 ;;
    436 ;; parse-init-local ps sm ty
    437 ;;   Reads the initializer for an auto-storage variable bound to slot
    438 ;;   sym `sm` and emits per-element store cg ops. Returns unspecified.
    439 ;; ====================================================================
    440 
    441 (define (%int->le-bv n nbytes)
    442   ;; N-byte little-endian encoding of integer n into a fresh bv. Bytes
    443   ;; >= sign-bit are filled by repeated >>8 (works for both signed and
    444   ;; unsigned because we only keep the low N bytes).
    445   (let ((out (make-bytevector nbytes 0)))
    446     (let loop ((i 0) (v n))
    447       (cond
    448         ((= i nbytes) out)
    449         (else
    450          (bytevector-u8-set! out i (bit-and v 255))
    451          (loop (+ i 1) (arithmetic-shift v -8)))))))
    452 
    453 (define (%const-init-piece ps ty)
    454   ;; Parse a non-brace initializer expression for scalar type `ty` and
    455   ;; return a single piece. Recognised forms:
    456   ;;   - INT (with optional unary +/-)               -> N-byte LE bv
    457   ;;   - enum-const IDENT                            -> N-byte LE bv
    458   ;;   - &IDENT (address of a global var/fn)         -> (label-ref . cc__name)
    459   ;;   - IDENT  (function name; decays to fn ptr)    -> (label-ref . cc__name)
    460   ;;   - STR    (only for char* targets)             -> (label-ref . string-pool-label)
    461   (let ((t (peek ps)))
    462     (cond
    463       ;; Address initializer: &ident -> label-ref
    464       ((and (eq? (tok-kind t) 'PUNCT) (eq? (tok-value t) 'amp))
    465        (advance ps)
    466        (let ((it (peek ps)))
    467          (cond
    468            ((eq? (tok-kind it) 'IDENT)
    469             (advance ps)
    470             (let ((sm (scope-lookup ps (tok-value it))))
    471               (cond
    472                 ((not sm) (die (tok-loc it) "init: undecl" (tok-value it)))
    473                 ((or (eq? (sym-kind sm) 'fn)
    474                      (and (eq? (sym-kind sm) 'var)
    475                           (or (eq? (sym-storage sm) 'static)
    476                               (eq? (sym-storage sm) 'extern))))
    477                  (cons 'label-ref (sym-slot sm)))
    478                 (else
    479                  (die (tok-loc it) "init: &x must reference a global"
    480                       (tok-value it))))))
    481            (else (die (tok-loc it) "init: &?" (tok-value it))))))
    482       ;; Function name or array name as a label-ref initializer.
    483       ;; (Both decay to a pointer when used as a value.)
    484       ((and (eq? (tok-kind t) 'IDENT)
    485             (let ((sm (scope-lookup ps (tok-value t))))
    486               (and sm
    487                    (or (eq? (sym-kind sm) 'fn)
    488                        (and (eq? (sym-kind sm) 'var)
    489                             (eq? (ctype-kind (sym-type sm)) 'arr)
    490                             (or (eq? (sym-storage sm) 'static)
    491                                 (eq? (sym-storage sm) 'extern)))))))
    492        (advance ps)
    493        (let ((sm (scope-lookup ps (tok-value t))))
    494          (cons 'label-ref (sym-slot sm))))
    495       ;; Plain string literal as char* initializer.
    496       ((eq? (tok-kind t) 'STR)
    497        (advance ps)
    498        (let ((lbl (cg-intern-string (ps-cg ps) (tok-value t))))
    499          (cons 'label-ref lbl)))
    500       ;; Otherwise it's a const integer.
    501       (else
    502        (let ((v (parse-const-int ps)))
    503          (%int->le-bv v (max (ctype-size ty) 1)))))))
    504 
    505 (define (%init-array-elem-type ty)
    506   (cond ((eq? (ctype-kind ty) 'arr) (car (ctype-ext ty)))
    507         (else (die #f "init: not an array" ty))))
    508 
    509 (define (%init-array-decl-len ty)
    510   ;; Declared array length (-1 = inferred).
    511   (cond ((eq? (ctype-kind ty) 'arr) (cdr (ctype-ext ty))) (else -1)))
    512 
    513 (define (%init-fix-array-size! ty count)
    514   ;; Patch an inferred-length array to `count`.
    515   (let ((elem (car (ctype-ext ty))))
    516     (ctype-ext-set!  ty (cons elem count))
    517     (ctype-size-set! ty (* count (ctype-size elem)))))
    518 
    519 (define (%init-struct-fields ty)
    520   ;; Return ((name-bv ctype offset) ...) for a struct/union ctype.
    521   (let ((ext (ctype-ext ty)))
    522     (cond ((and (pair? ext) (pair? (cdr ext))) (car (cddr ext)))
    523           (else (die #f "init: not a struct" ty)))))
    524 
    525 (define (%find-field fields nm)
    526   (cond ((null? fields) #f)
    527         ((equal? (car (car fields)) nm) (car fields))
    528         (else (%find-field (cdr fields) nm))))
    529 
    530 (define (%pad-piece nbytes)
    531   (make-bytevector nbytes 0))
    532 
    533 ;; ----- Global initializers ---------------------------------------------
    534 (define (parse-init-global ps ty)
    535   (cond
    536     ;; String literal initializer for char[]
    537     ((and (eq? (ctype-kind ty) 'arr)
    538           (eq? (tok-kind (peek ps)) 'STR)
    539           (let ((et (car (ctype-ext ty))))
    540             (or (eq? et %t-i8) (eq? et %t-u8))))
    541      (let* ((t (advance ps))
    542             (s (tok-value t))
    543             (slen (bytevector-length s))
    544             (decl (cdr (ctype-ext ty)))
    545             (final (cond ((< decl 0) (+ slen 1)) (else decl))))
    546        (cond ((< decl 0) (%init-fix-array-size! ty final)))
    547        (let ((bv (make-bytevector final 0)))
    548          (let loop ((i 0))
    549            (cond
    550              ((or (= i slen) (>= i final)) (list bv))
    551              (else
    552               (bytevector-u8-set! bv i (bytevector-u8-ref s i))
    553               (loop (+ i 1))))))))
    554     ;; Brace-form
    555     ((at-punct? ps 'lbrace)
    556      (advance ps)
    557      (cond
    558        ((eq? (ctype-kind ty) 'arr)
    559         (%parse-init-array-list ps ty))
    560        ((or (eq? (ctype-kind ty) 'struct) (eq? (ctype-kind ty) 'union))
    561         (%parse-init-struct-list ps ty))
    562        (else
    563         ;; Brace-wrapped scalar: { expr }
    564         (let ((piece (%const-init-piece ps ty)))
    565           (cond ((at-punct? ps 'comma) (advance ps)))
    566           (expect-punct ps 'rbrace)
    567           (list piece)))))
    568     ;; Bare scalar initializer
    569     (else (list (%const-init-piece ps ty)))))
    570 
    571 (define (%parse-init-array-list ps ty)
    572   ;; Element-list array initializer; assumes `{` already consumed.
    573   (let* ((elem  (%init-array-elem-type ty))
    574          (esize (ctype-size elem))
    575          (decl  (%init-array-decl-len ty)))
    576     (let lp ((acc '()) (count 0))
    577       (cond
    578         ((at-punct? ps 'rbrace)
    579          (advance ps)
    580          (cond ((< decl 0) (%init-fix-array-size! ty count)))
    581          ;; Pad to declared length if longer than count.
    582          (let* ((final (cond ((< decl 0) count) (else decl)))
    583                 (pad (- final count)))
    584            (cond
    585              ((> pad 0)
    586               (reverse (cons (%pad-piece (* pad esize)) acc)))
    587              (else (reverse acc)))))
    588         (else
    589          (let ((piece
    590                 (cond
    591                   ((at-punct? ps 'lbrace)
    592                    ;; Nested aggregate: brace-flatten via recursion.
    593                    (advance ps)
    594                    ;; element is itself struct/array
    595                    (cond
    596                      ((eq? (ctype-kind elem) 'arr)
    597                       (%parse-init-array-list ps elem))
    598                      ((or (eq? (ctype-kind elem) 'struct)
    599                           (eq? (ctype-kind elem) 'union))
    600                       (%parse-init-struct-list ps elem))
    601                      (else
    602                       (let ((p (%const-init-piece ps elem)))
    603                         (cond ((at-punct? ps 'comma) (advance ps)))
    604                         (expect-punct ps 'rbrace)
    605                         (list p)))))
    606                   (else
    607                    (list (%const-init-piece ps elem))))))
    608            (cond ((at-punct? ps 'comma) (advance ps)))
    609            (lp (append (reverse piece) acc) (+ count 1))))))))
    610 
    611 (define (%parse-init-struct-list ps ty)
    612   ;; Struct/union initializer; assumes `{` already consumed.
    613   ;; Supports positional and `.field = expr` forms.
    614   (let* ((fields (%init-struct-fields ty))
    615          (size   (ctype-size ty)))
    616     (let lp ((acc '()) (filled 0) (rest fields))
    617       (cond
    618         ((at-punct? ps 'rbrace)
    619          (advance ps)
    620          (cond
    621            ((< filled size)
    622             (reverse (cons (%pad-piece (- size filled)) acc)))
    623            (else (reverse acc))))
    624         (else
    625          (let* ((designated? (at-punct? ps 'dot))
    626                 (target
    627                  (cond
    628                    (designated?
    629                     (advance ps)
    630                     (let ((nt (advance ps)))
    631                       (cond
    632                         ((not (eq? (tok-kind nt) 'IDENT))
    633                          (die (tok-loc nt) "init: .field expects ident")))
    634                       (let ((f (%find-field fields (tok-value nt))))
    635                         (cond
    636                           ((not f) (die (tok-loc nt) "init: no such field"
    637                                         (tok-value nt))))
    638                         (expect-punct ps 'assign)
    639                         f)))
    640                    ((null? rest)
    641                     (die (tok-loc (peek ps)) "init: too many fields"))
    642                    (else (car rest))))
    643                 (fname  (car target))
    644                 (fty    (car (cdr target)))
    645                 (foff   (car (cddr target)))
    646                 (fsize  (ctype-size fty))
    647                 ;; Pad from `filled` to `foff` if needed.
    648                 (pad-bytes (- foff filled))
    649                 (piece-list
    650                  (cond
    651                    ((at-punct? ps 'lbrace)
    652                     (advance ps)
    653                     (cond
    654                       ((eq? (ctype-kind fty) 'arr)
    655                        (%parse-init-array-list ps fty))
    656                       ((or (eq? (ctype-kind fty) 'struct)
    657                            (eq? (ctype-kind fty) 'union))
    658                        (%parse-init-struct-list ps fty))
    659                       (else
    660                        (let ((p (%const-init-piece ps fty)))
    661                          (cond ((at-punct? ps 'comma) (advance ps)))
    662                          (expect-punct ps 'rbrace)
    663                          (list p)))))
    664                    (else
    665                     (list (%const-init-piece ps fty)))))
    666                 (acc2 (cond ((> pad-bytes 0)
    667                              (cons (%pad-piece pad-bytes) acc))
    668                             (else acc)))
    669                 (acc3 (append (reverse piece-list) acc2)))
    670            (cond ((at-punct? ps 'comma) (advance ps)))
    671            (lp acc3 (+ foff fsize)
    672                (cond
    673                  (designated?
    674                   ;; designated init: drop fields up to and including target
    675                   (let drop ((xs fields))
    676                     (cond
    677                       ((null? xs) '())
    678                       ((equal? (car (car xs)) fname) (cdr xs))
    679                       (else (drop (cdr xs))))))
    680                  (else (cdr rest))))))))))
    681 
    682 ;; ----- Local aggregate initializers ------------------------------------
    683 ;; Emits per-element store sequences via cg ops into the slot of `sm`
    684 ;; (a 'var sym whose slot is the frame offset). Assumes the assignment
    685 ;; `=` has already been consumed.
    686 (define (parse-init-local-aggregate ps sm ty)
    687   (cond
    688     ;; Local char[] = "string" — fill from string bytes.
    689     ((and (eq? (ctype-kind ty) 'arr)
    690           (eq? (tok-kind (peek ps)) 'STR)
    691           (let ((et (car (ctype-ext ty))))
    692             (or (eq? et %t-i8) (eq? et %t-u8))))
    693      (let* ((t (advance ps))
    694             (s (tok-value t))
    695             (slen (bytevector-length s))
    696             (decl (cdr (ctype-ext ty)))
    697             (final (cond ((< decl 0) (+ slen 1)) (else decl))))
    698        (cond ((< decl 0) (%init-fix-array-size! ty final)))
    699        ;; Emit byte stores for each char in s, plus NUL for the
    700        ;; trailing slot if final > slen.
    701        (let loop ((i 0))
    702          (cond
    703            ((>= i final) #t)
    704            (else
    705             (let ((b (cond ((< i slen) (bytevector-u8-ref s i))
    706                            (else 0)))
    707                   (off (+ (sym-slot sm) i)))
    708               (%push-frame-elem-lval ps off %t-u8)
    709               (cg-push-imm (ps-cg ps) %t-u8 b)
    710               (cg-assign (ps-cg ps))
    711               (cg-pop (ps-cg ps))
    712               (loop (+ i 1))))))))
    713     ((at-punct? ps 'lbrace)
    714      (advance ps)
    715      (cond
    716        ((eq? (ctype-kind ty) 'arr)
    717         (%parse-init-local-array-list ps sm (sym-slot sm) ty))
    718        ((or (eq? (ctype-kind ty) 'struct) (eq? (ctype-kind ty) 'union))
    719         (%parse-init-local-struct-list ps sm (sym-slot sm) ty))
    720        (else (die #f "init local: brace on scalar?"))))
    721     (else (die (tok-loc (peek ps)) "init local aggregate?"))))
    722 
    723 (define (%emit-local-elem-store ps sm rel-off elem-ty piece-or-thunk)
    724   ;; Emit a single scalar store at slot[base + rel-off]. piece is the
    725   ;; raw initializer expression — but here we want to actually evaluate
    726   ;; it via parse-expr to allow non-const expressions for autos.
    727   ;; Caller handles this; this helper handles the store-into-frame ops.
    728   0)
    729 
    730 (define (%push-frame-elem-lval ps base-off ty)
    731   (cg-push (ps-cg ps) (%opnd 'frame ty base-off #t)))
    732 
    733 (define (%parse-init-local-array-list ps sm base-off ty)
    734   (let* ((elem (%init-array-elem-type ty))
    735          (esize (ctype-size elem))
    736          (decl  (%init-array-decl-len ty)))
    737     (let lp ((i 0))
    738       (cond
    739         ((at-punct? ps 'rbrace)
    740          (advance ps)
    741          (cond ((< decl 0) (%init-fix-array-size! ty i)))
    742          ;; Zero out remaining slots if any (declared length > i).
    743          (let ((final (cond ((< decl 0) i) (else decl))))
    744            (let zlp ((k i))
    745              (cond
    746                ((>= k final) #t)
    747                (else
    748                 (let ((off (+ base-off (* k esize))))
    749                   (cond
    750                     ((or (eq? (ctype-kind elem) 'arr)
    751                          (eq? (ctype-kind elem) 'struct)
    752                          (eq? (ctype-kind elem) 'union))
    753                      ;; Zero each byte in this aggregate slot.
    754                      (let zb ((j 0))
    755                        (cond
    756                          ((>= j esize) #t)
    757                          (else
    758                           (%push-frame-elem-lval ps (+ off j) %t-u8)
    759                           (cg-push-imm (ps-cg ps) %t-u8 0)
    760                           (cg-assign (ps-cg ps))
    761                           (cg-pop (ps-cg ps))
    762                           (zb (+ j 1))))))
    763                     (else
    764                      (%push-frame-elem-lval ps off elem)
    765                      (cg-push-imm (ps-cg ps) elem 0)
    766                      (cg-assign (ps-cg ps))
    767                      (cg-pop (ps-cg ps)))))
    768                 (zlp (+ k 1)))))))
    769         (else
    770          (let ((eoff (+ base-off (* i esize))))
    771            (cond
    772              ((at-punct? ps 'lbrace)
    773               (advance ps)
    774               (cond
    775                 ((eq? (ctype-kind elem) 'arr)
    776                  (%parse-init-local-array-list ps sm eoff elem))
    777                 ((or (eq? (ctype-kind elem) 'struct)
    778                      (eq? (ctype-kind elem) 'union))
    779                  (%parse-init-local-struct-list ps sm eoff elem))
    780                 (else
    781                  (%push-frame-elem-lval ps eoff elem)
    782                  (parse-expr-bp ps 4) (rval! ps)
    783                  (cg-cast (ps-cg ps) elem)
    784                  (cg-assign (ps-cg ps)) (cg-pop (ps-cg ps))
    785                  (cond ((at-punct? ps 'comma) (advance ps)))
    786                  (expect-punct ps 'rbrace))))
    787              (else
    788               (%push-frame-elem-lval ps eoff elem)
    789               (parse-expr-bp ps 4) (rval! ps)
    790               (cg-cast (ps-cg ps) elem)
    791               (cg-assign (ps-cg ps)) (cg-pop (ps-cg ps))))
    792            (cond ((at-punct? ps 'comma) (advance ps)))
    793            (lp (+ i 1))))))))
    794 
    795 (define (%parse-init-local-struct-list ps sm base-off ty)
    796   (let ((fields (%init-struct-fields ty)))
    797     (let lp ((rest fields))
    798       (cond
    799         ((at-punct? ps 'rbrace)
    800          (advance ps)
    801          ;; Zero any remaining fields.
    802          (let zlp ((xs rest))
    803            (cond
    804              ((null? xs) #t)
    805              (else
    806               (let* ((f (car xs)) (fty (car (cdr f)))
    807                      (foff (car (cddr f))) (fsize (ctype-size fty)))
    808                 (let zb ((j 0))
    809                   (cond
    810                     ((>= j fsize) #t)
    811                     (else
    812                      (%push-frame-elem-lval ps (+ base-off foff j) %t-u8)
    813                      (cg-push-imm (ps-cg ps) %t-u8 0)
    814                      (cg-assign (ps-cg ps))
    815                      (cg-pop (ps-cg ps))
    816                      (zb (+ j 1)))))
    817                 (zlp (cdr xs)))))))
    818         (else
    819          (let* ((designated? (at-punct? ps 'dot))
    820                 (target
    821                  (cond
    822                    (designated?
    823                     (advance ps)
    824                     (let ((nt (advance ps)))
    825                       (let ((f (%find-field fields (tok-value nt))))
    826                         (cond
    827                           ((not f) (die (tok-loc nt) "init: no such field"
    828                                         (tok-value nt))))
    829                         (expect-punct ps 'assign)
    830                         f)))
    831                    ((null? rest)
    832                     (die (tok-loc (peek ps)) "init: too many fields"))
    833                    (else (car rest))))
    834                 (fname (car target))
    835                 (fty   (car (cdr target)))
    836                 (foff  (car (cddr target)))
    837                 (eoff  (+ base-off foff)))
    838            (cond
    839              ((at-punct? ps 'lbrace)
    840               (advance ps)
    841               (cond
    842                 ((eq? (ctype-kind fty) 'arr)
    843                  (%parse-init-local-array-list ps sm eoff fty))
    844                 ((or (eq? (ctype-kind fty) 'struct)
    845                      (eq? (ctype-kind fty) 'union))
    846                  (%parse-init-local-struct-list ps sm eoff fty))
    847                 (else
    848                  (%push-frame-elem-lval ps eoff fty)
    849                  (parse-expr-bp ps 4) (rval! ps)
    850                  (cg-cast (ps-cg ps) fty)
    851                  (cg-assign (ps-cg ps)) (cg-pop (ps-cg ps))
    852                  (cond ((at-punct? ps 'comma) (advance ps)))
    853                  (expect-punct ps 'rbrace))))
    854              (else
    855               (%push-frame-elem-lval ps eoff fty)
    856               (parse-expr-bp ps 4) (rval! ps)
    857               (cg-cast (ps-cg ps) fty)
    858               (cg-assign (ps-cg ps)) (cg-pop (ps-cg ps))))
    859            (cond ((at-punct? ps 'comma) (advance ps)))
    860            (lp (cond
    861                  (designated?
    862                   (let drop ((xs fields))
    863                     (cond
    864                       ((null? xs) '())
    865                       ((equal? (car (car xs)) fname) (cdr xs))
    866                       (else (drop (cdr xs))))))
    867                  (else (cdr rest))))))))))
    868 
    869 
    870 (define (parse-fn-body ps name dt)
    871   (let* ((e (ctype-ext dt)) (ret (car e))
    872          (par (cadr e)) (var (car (cddr e))))
    873     (cond ((not (scope-lookup ps name))
    874            (scope-bind! ps name
    875                         (%sym name 'fn 'extern dt
    876                               (bytevector-append "cc__" name)))))
    877     (let ((psyms (cg-fn-begin/v (ps-cg ps) name par ret var)))
    878       (ps-fn-ctx-set! ps
    879         (%fn-ctx name ret (map cdr psyms) var '()))
    880       (scope-enter! ps)
    881       (for-each (lambda (p) (scope-bind! ps (car p) (cdr p)))
    882                 psyms)
    883       (expect-punct ps 'lbrace)
    884       (parse-cstmt-body ps)
    885       (expect-punct ps 'rbrace)
    886       (scope-leave! ps)
    887       (ps-fn-ctx-set! ps #f)
    888       (cg-fn-end (ps-cg ps)))))
    889 
    890 (define (parse-stmt ps)
    891   (cond
    892     ((at-punct? ps 'lbrace) (parse-cstmt ps))
    893     ((at-kw? ps 'if)        (parse-if-stmt ps))
    894     ((at-kw? ps 'while)     (parse-while-stmt ps))
    895     ((at-kw? ps 'do)        (parse-do-stmt ps))
    896     ((at-kw? ps 'for)       (parse-for-stmt ps))
    897     ((at-kw? ps 'switch)    (parse-switch-stmt ps))
    898     ((at-kw? ps 'return)    (parse-return-stmt ps))
    899     ((at-kw? ps 'goto)      (parse-goto-stmt ps))
    900     ((at-kw? ps 'break)
    901      (advance ps) (expect-punct ps 'semi) (do-break ps))
    902     ((at-kw? ps 'continue)
    903      (advance ps) (expect-punct ps 'semi) (do-continue ps))
    904     ((at-kw? ps 'case)      (parse-case-stmt ps))
    905     ((at-kw? ps 'default)   (parse-default-stmt ps))
    906     ((and (eq? (tok-kind (peek ps)) 'IDENT)
    907           (eq? (tok-kind (peek2 ps)) 'PUNCT)
    908           (eq? (tok-value (peek2 ps)) 'colon))
    909      (parse-labelled-stmt ps))
    910     ((stmt-starts-decl? ps) (parse-local-decl ps))
    911     (else (parse-expr-stmt ps))))
    912 
    913 (define (stmt-starts-decl? ps)
    914   (let ((t (peek ps)))
    915     (cond
    916       ((eq? (tok-kind t) 'KW)
    917        (let ((v (tok-value t)))
    918          (or (eq? v 'auto) (eq? v 'register) (eq? v 'static)
    919              (eq? v 'extern) (eq? v 'typedef) (eq? v 'const)
    920              (eq? v 'volatile) (eq? v 'restrict) (eq? v 'inline)
    921              (eq? v 'void) (eq? v 'char) (eq? v 'short) (eq? v 'int)
    922              (eq? v 'long) (eq? v 'signed) (eq? v 'unsigned)
    923              (eq? v '_Bool) (eq? v 'struct) (eq? v 'union)
    924              (eq? v 'enum))))
    925       ((eq? (tok-kind t) 'IDENT) (typedef? ps (tok-value t)))
    926       (else #f))))
    927 
    928 (define (parse-local-decl ps)
    929   (let* ((sp (parse-decl-spec ps))
    930          (sto (car sp)) (b (cdr sp)))
    931     (cond
    932       ((at-punct? ps 'semi) (advance ps) #t)
    933       (else
    934        (let lp ()
    935          (let* ((p (parse-declarator ps b))
    936                 (n (car p)) (t (cdr p)))
    937            (handle-decl ps sto n t)
    938            (cond ((at-punct? ps 'comma) (advance ps) (lp))
    939                  (else (expect-punct ps 'semi) #t))))))))
    940 
    941 (define (parse-cstmt ps)
    942   (expect-punct ps 'lbrace)
    943   (scope-enter! ps)
    944   (parse-cstmt-body ps)
    945   (scope-leave! ps)
    946   (expect-punct ps 'rbrace) #t)
    947 
    948 (define (parse-cstmt-body ps)
    949   (cond
    950     ((at-punct? ps 'rbrace) #t)
    951     ((eq? (tok-kind (peek ps)) 'EOF)
    952      (die (tok-loc (peek ps)) "EOF in cstmt"))
    953     (else (parse-stmt ps) (parse-cstmt-body ps))))
    954 
    955 (define (parse-compound-stmt ps) (parse-cstmt ps))
    956 
    957 (define (parse-if-stmt ps)
    958   (expect-kw ps 'if)
    959   (expect-punct ps 'lparen)
    960   (parse-expr ps) (rval! ps)
    961   (expect-punct ps 'rparen)
    962   (cg-ifelse (ps-cg ps)
    963              (lambda () (parse-stmt ps))
    964              (lambda ()
    965                (cond ((at-kw? ps 'else)
    966                       (advance ps) (parse-stmt ps))
    967                      (else #t)))))
    968 
    969 ;; cg-loop's body-thunk now receives the tag from cg (CC-CONTRACTS
    970 ;; §3.3); the parser threads it into break/continue via loop-ctx.
    971 
    972 (define (parse-while-stmt ps)
    973   (expect-kw ps 'while)
    974   (expect-punct ps 'lparen)
    975   (cg-loop (ps-cg ps)
    976            (lambda () (parse-expr ps) (rval! ps))
    977            (lambda (tag)
    978              (expect-punct ps 'rparen)
    979              (push-loop-ctx! ps 'while tag #t)
    980              (parse-stmt ps)
    981              (pop-loop-ctx! ps))) #t)
    982 
    983 (define (parse-do-stmt ps)
    984   (expect-kw ps 'do)
    985   ;; do-while needs its tag known *before* the body parses, so we
    986   ;; capture it inside the body-thunk and stash it for pop-loop-ctx
    987   ;; via a side cell.
    988   (cg-loop (ps-cg ps)
    989            (lambda () #t)
    990            (lambda (tag)
    991              (push-loop-ctx! ps 'do tag #t)
    992              (parse-stmt ps)
    993              (pop-loop-ctx! ps)
    994              (expect-kw ps 'while) (expect-punct ps 'lparen)
    995              (parse-expr ps) (rval! ps)
    996              (expect-punct ps 'rparen) (expect-punct ps 'semi)
    997              (cg-unop (ps-cg ps) 'lnot)
    998              (cg-if (ps-cg ps)
    999                     (lambda () (cg-break (ps-cg ps) tag)))))
   1000   #t)
   1001 
   1002 (define (parse-for-stmt ps)
   1003   (expect-kw ps 'for) (expect-punct ps 'lparen)
   1004   (scope-enter! ps)
   1005   (cond
   1006     ((at-punct? ps 'semi) (advance ps))
   1007     ((stmt-starts-decl? ps) (parse-local-decl ps))
   1008     (else (parse-expr ps) (cg-pop (ps-cg ps))
   1009           (expect-punct ps 'semi)))
   1010   (cg-loop (ps-cg ps)
   1011            (lambda ()
   1012              (cond ((at-punct? ps 'semi)
   1013                     (cg-push-imm (ps-cg ps) %t-i32 1))
   1014                    (else (parse-expr ps) (rval! ps)))
   1015              (expect-punct ps 'semi))
   1016            (lambda (tag)
   1017              (let ((stk (collect-til-rparen ps)))
   1018                (expect-punct ps 'rparen)
   1019                (push-loop-ctx! ps 'for tag #t)
   1020                (parse-stmt ps)
   1021                (pop-loop-ctx! ps)
   1022                (cond
   1023                  ((null? stk) #t)
   1024                  (else
   1025                   (let ((sv (ps-toks ps)))
   1026                     (ps-toks-set! ps
   1027                       (append stk (list (make-tok 'EOF #f #f))))
   1028                     (parse-expr ps) (cg-pop (ps-cg ps))
   1029                     (ps-toks-set! ps sv)))))))
   1030   (scope-leave! ps) #t)
   1031 
   1032 (define (collect-til-rparen ps)
   1033   (let loop ((acc '()) (d 0))
   1034     (let ((t (peek ps)))
   1035       (cond
   1036         ((eq? (tok-kind t) 'EOF)
   1037          (die (tok-loc t) "EOF in for-step"))
   1038         ((and (zero? d) (eq? (tok-kind t) 'PUNCT)
   1039               (eq? (tok-value t) 'rparen)) (reverse acc))
   1040         (else
   1041          (let ((nt (advance ps)))
   1042            (loop (cons nt acc)
   1043                  (cond ((not (eq? (tok-kind nt) 'PUNCT)) d)
   1044                        ((eq? (tok-value nt) 'lparen) (+ d 1))
   1045                        ((eq? (tok-value nt) 'rparen) (- d 1))
   1046                        (else d)))))))))
   1047 
   1048 (define (parse-switch-stmt ps)
   1049   (expect-kw ps 'switch) (expect-punct ps 'lparen)
   1050   (parse-expr ps) (rval! ps)
   1051   (expect-punct ps 'rparen)
   1052   ;; Switch's break-target tag is the swctx's end-tag — cg owns it,
   1053   ;; and we read it back so cg-break inside the switch body emits a
   1054   ;; tag cg actually labels.
   1055   (let* ((sw (cg-switch-begin (ps-cg ps)))
   1056          (tg (swctx-end-tag sw)))
   1057     (push-loop-ctx-sw! ps 'switch tg sw)
   1058     (parse-stmt ps)
   1059     (pop-loop-ctx! ps)
   1060     (cg-switch-end (ps-cg ps) sw)))
   1061 
   1062 (define (parse-case-stmt ps)
   1063   (expect-kw ps 'case)
   1064   (let ((v (parse-const-int ps)))
   1065     (expect-punct ps 'colon)
   1066     (cg-switch-case (ps-cg ps) (innermost-sw ps) v)
   1067     (parse-stmt ps)))
   1068 
   1069 (define (parse-default-stmt ps)
   1070   (expect-kw ps 'default) (expect-punct ps 'colon)
   1071   (cg-switch-default (ps-cg ps) (innermost-sw ps))
   1072   (parse-stmt ps))
   1073 
   1074 (define (parse-return-stmt ps)
   1075   (expect-kw ps 'return)
   1076   (cond
   1077     ((at-punct? ps 'semi) (advance ps) (cg-return (ps-cg ps)))
   1078     (else
   1079      (parse-expr ps) (rval! ps)
   1080      (let ((fc (ps-fn-ctx ps)))
   1081        (cond
   1082          ((and fc (not (eq? (ctype-kind (fn-ctx-return-type fc)) 'void)))
   1083           (cg-cast (ps-cg ps) (fn-ctx-return-type fc)))
   1084          (else #t)))
   1085      (cg-return (ps-cg ps))
   1086      (expect-punct ps 'semi))))
   1087 
   1088 (define (parse-goto-stmt ps)
   1089   (expect-kw ps 'goto)
   1090   (let ((t (advance ps)))
   1091     (cond ((eq? (tok-kind t) 'IDENT)
   1092            (cg-goto (ps-cg ps) (tok-value t)))
   1093           (else (die (tok-loc t) "label?"))))
   1094   (expect-punct ps 'semi))
   1095 
   1096 (define (parse-labelled-stmt ps)
   1097   (let ((t (advance ps)))
   1098     (expect-punct ps 'colon)
   1099     (cg-emit-label (ps-cg ps) (tok-value t))
   1100     (parse-stmt ps)))
   1101 
   1102 (define (parse-expr-stmt ps)
   1103   (cond
   1104     ((at-punct? ps 'semi) (advance ps) #t)
   1105     (else (parse-expr ps) (cg-pop (ps-cg ps))
   1106           (expect-punct ps 'semi))))
   1107 
   1108 (define (push-loop-ctx! ps k tg hc)
   1109   (ps-loops-set! ps (cons (%loop-ctx k tg hc) (ps-loops ps))))
   1110 (define (push-loop-ctx-sw! ps k tg sw)
   1111   (ps-loops-set! ps
   1112     (cons (%loop-ctx k (cons tg sw) #f) (ps-loops ps))))
   1113 (define (pop-loop-ctx! ps)
   1114   (ps-loops-set! ps (cdr (ps-loops ps))))
   1115 (define (do-break ps)
   1116   (let ((c (innermost-loop ps)))
   1117     (cond
   1118       ((not c) (die #f "break outside"))
   1119       ((eq? (loop-ctx-kind c) 'switch)
   1120        (cg-break (ps-cg ps) (car (loop-ctx-tag c))))
   1121       (else (cg-break (ps-cg ps) (loop-ctx-tag c))))))
   1122 (define (do-continue ps)
   1123   (let ((c (innermost-cont ps)))
   1124     (cond ((not c) (die #f "cont outside"))
   1125           (else (cg-continue (ps-cg ps) (loop-ctx-tag c))))))
   1126 (define (innermost-loop ps)
   1127   (cond ((null? (ps-loops ps)) #f) (else (car (ps-loops ps)))))
   1128 (define (innermost-cont ps)
   1129   (let lp ((xs (ps-loops ps)))
   1130     (cond ((null? xs) #f)
   1131           ((eq? (loop-ctx-kind (car xs)) 'switch) (lp (cdr xs)))
   1132           (else (car xs)))))
   1133 (define (innermost-sw ps)
   1134   (let lp ((xs (ps-loops ps)))
   1135     (cond ((null? xs) (die #f "case outside switch"))
   1136           ((eq? (loop-ctx-kind (car xs)) 'switch)
   1137            (cdr (loop-ctx-tag (car xs))))
   1138           (else (lp (cdr xs))))))
   1139 
   1140 (define %binop-bp
   1141   (list
   1142     (cons 'comma      (cons 1 2))
   1143     (cons 'assign     (cons 4 3)) (cons 'plus-eq (cons 4 3))
   1144     (cons 'minus-eq   (cons 4 3)) (cons 'star-eq (cons 4 3))
   1145     (cons 'slash-eq   (cons 4 3)) (cons 'pct-eq  (cons 4 3))
   1146     (cons 'shl-eq     (cons 4 3)) (cons 'shr-eq  (cons 4 3))
   1147     (cons 'amp-eq     (cons 4 3)) (cons 'caret-eq (cons 4 3))
   1148     (cons 'bar-eq     (cons 4 3)) (cons 'qmark   (cons 6 5))
   1149     (cons 'lor (cons 10 11)) (cons 'land (cons 20 21))
   1150     (cons 'bar (cons 30 31)) (cons 'caret (cons 40 41))
   1151     (cons 'amp (cons 50 51))
   1152     (cons 'eq2 (cons 60 61)) (cons 'ne (cons 60 61))
   1153     (cons 'lt (cons 70 71)) (cons 'le (cons 70 71))
   1154     (cons 'gt (cons 70 71)) (cons 'ge (cons 70 71))
   1155     (cons 'shl (cons 80 81)) (cons 'shr (cons 80 81))
   1156     (cons 'plus (cons 90 91)) (cons 'minus (cons 90 91))
   1157     (cons 'star (cons 100 101)) (cons 'slash (cons 100 101))
   1158     (cons 'pct (cons 100 101))))
   1159 
   1160 (define (binop-bp-of s) (alist-ref/eq s %binop-bp))
   1161 
   1162 (define (punct-to-cgop s)
   1163   (cond ((eq? s 'plus)  'add) ((eq? s 'minus) 'sub)
   1164         ((eq? s 'star)  'mul) ((eq? s 'slash) 'div)
   1165         ((eq? s 'pct)   'rem) ((eq? s 'amp)   'and)
   1166         ((eq? s 'bar)   'or)  ((eq? s 'caret) 'xor)
   1167         ((eq? s 'shl)   'shl) ((eq? s 'shr)   'shr)
   1168         ((eq? s 'eq2)   'eq)  ((eq? s 'ne)    'ne)
   1169         ((eq? s 'lt)    'lt)  ((eq? s 'le)    'le)
   1170         ((eq? s 'gt)    'gt)  ((eq? s 'ge)    'ge)
   1171         (else (die #f "binop" s))))
   1172 
   1173 (define (compound-op s)
   1174   (cond ((eq? s 'plus-eq)  'add) ((eq? s 'minus-eq) 'sub)
   1175         ((eq? s 'star-eq)  'mul) ((eq? s 'slash-eq) 'div)
   1176         ((eq? s 'pct-eq)   'rem) ((eq? s 'shl-eq)   'shl)
   1177         ((eq? s 'shr-eq)   'shr) ((eq? s 'amp-eq)   'and)
   1178         ((eq? s 'caret-eq) 'xor) ((eq? s 'bar-eq)   'or)
   1179         (else #f)))
   1180 
   1181 (define (parse-expr ps) (parse-expr-bp ps 0))
   1182 
   1183 (define (parse-expr-bp ps mn)
   1184   (parse-unary ps) (parse-binary-rhs ps mn))
   1185 
   1186 (define (parse-binary-rhs ps mn)
   1187   (let ((t (peek ps)))
   1188     (cond
   1189       ((not (eq? (tok-kind t) 'PUNCT)) #t)
   1190       (else
   1191        (let ((bp (binop-bp-of (tok-value t))))
   1192          (cond
   1193            ((not bp) #t)
   1194            ((< (car bp) mn) #t)
   1195            (else
   1196             (let ((op (tok-value t)) (rb (cdr bp)))
   1197               (advance ps)
   1198               (cond
   1199                 ((eq? op 'comma)
   1200                  ;; lhs has been parsed; discard it and evaluate rhs.
   1201                  ;; Result of the comma expr is the rhs's rval.
   1202                  (cg-pop (ps-cg ps))
   1203                  (parse-expr-bp ps rb) (rval! ps))
   1204                 ((eq? op 'assign)
   1205                  (parse-expr-bp ps rb) (rval! ps)
   1206                  (cg-assign (ps-cg ps)))
   1207                 ((compound-op op)
   1208                  (let ((b (compound-op op)))
   1209                    (cg-dup (ps-cg ps))
   1210                    (cg-load (ps-cg ps))
   1211                    (parse-expr-bp ps rb) (rval! ps)
   1212                    (cg-arith-conv (ps-cg ps))
   1213                    (cg-binop (ps-cg ps) b)
   1214                    (cg-assign (ps-cg ps))))
   1215                 ((eq? op 'qmark)
   1216                  (rval! ps)
   1217                  (cg-ifelse-merge (ps-cg ps)
   1218                             (lambda ()
   1219                               (parse-expr-bp ps 0) (rval! ps))
   1220                             (lambda ()
   1221                               (expect-punct ps 'colon)
   1222                               (parse-expr-bp ps rb) (rval! ps))))
   1223                 ((eq? op 'land)
   1224                  (rval! ps)
   1225                  ;; Both branches must push i32 0/1. Right side is
   1226                  ;; coerced via `cg-cast bool` so the merge slot
   1227                  ;; carries i32 (per §H.2).
   1228                  (cg-ifelse-merge (ps-cg ps)
   1229                             (lambda ()
   1230                               (parse-expr-bp ps rb) (rval! ps)
   1231                               (cg-cast (ps-cg ps) %t-bool)
   1232                               (cg-cast (ps-cg ps) %t-i32))
   1233                             (lambda ()
   1234                               (cg-push-imm (ps-cg ps) %t-i32 0))))
   1235                 ((eq? op 'lor)
   1236                  (rval! ps)
   1237                  (cg-ifelse-merge (ps-cg ps)
   1238                             (lambda ()
   1239                               (cg-push-imm (ps-cg ps) %t-i32 1))
   1240                             (lambda ()
   1241                               (parse-expr-bp ps rb) (rval! ps)
   1242                               (cg-cast (ps-cg ps) %t-bool)
   1243                               (cg-cast (ps-cg ps) %t-i32))))
   1244                 (else
   1245                  (rval! ps) (cg-promote (ps-cg ps))
   1246                  (parse-expr-bp ps rb) (rval! ps)
   1247                  (cg-promote (ps-cg ps))
   1248                  (cg-arith-conv (ps-cg ps))
   1249                  (cg-binop (ps-cg ps) (punct-to-cgop op))))
   1250               (parse-binary-rhs ps mn)))))))))
   1251 
   1252 (define (parse-unary ps)
   1253   (let ((t (peek ps)))
   1254     (cond
   1255       ((eq? (tok-kind t) 'PUNCT)
   1256        (let ((v (tok-value t)))
   1257          (cond
   1258            ((eq? v 'amp)
   1259             (advance ps) (parse-unary ps)
   1260             (cg-take-addr (ps-cg ps)))
   1261            ((eq? v 'star)
   1262             (advance ps) (parse-unary ps) (rval! ps)
   1263             (cg-push-deref (ps-cg ps)))
   1264            ((eq? v 'plus)
   1265             (advance ps) (parse-unary ps)
   1266             (rval! ps) (cg-promote (ps-cg ps)))
   1267            ((eq? v 'minus)
   1268             (advance ps) (parse-unary ps)
   1269             (rval! ps) (cg-promote (ps-cg ps))
   1270             (cg-unop (ps-cg ps) 'neg))
   1271            ((eq? v 'tilde)
   1272             (advance ps) (parse-unary ps)
   1273             (rval! ps) (cg-promote (ps-cg ps))
   1274             (cg-unop (ps-cg ps) 'bnot))
   1275            ((eq? v 'bang)
   1276             (advance ps) (parse-unary ps) (rval! ps)
   1277             (cg-unop (ps-cg ps) 'lnot))
   1278            ((eq? v 'inc) (advance ps) (parse-unary ps)
   1279             (cg-dup (ps-cg ps))
   1280             (cg-load (ps-cg ps))
   1281             (cg-push-imm (ps-cg ps) %t-i32 1)
   1282             (cg-binop (ps-cg ps) 'add) (cg-assign (ps-cg ps)))
   1283            ((eq? v 'dec) (advance ps) (parse-unary ps)
   1284             (cg-dup (ps-cg ps))
   1285             (cg-load (ps-cg ps))
   1286             (cg-push-imm (ps-cg ps) %t-i32 1)
   1287             (cg-binop (ps-cg ps) 'sub) (cg-assign (ps-cg ps)))
   1288            ((eq? v 'lparen) (parse-cast-or-unary ps))
   1289            (else (parse-postfix ps)))))
   1290       ((and (eq? (tok-kind t) 'KW) (eq? (tok-value t) 'sizeof))
   1291        (advance ps)
   1292        (cond
   1293          ((at-punct? ps 'lparen)
   1294           (advance ps)
   1295           (cond
   1296             ((token-is-decl? ps)
   1297              (let* ((sp (parse-decl-spec ps))
   1298                     (p (parse-declarator ps (cdr sp)))
   1299                     (ty (cdr p)))
   1300                (expect-punct ps 'rparen)
   1301                (cg-push-imm (ps-cg ps) %t-u64
   1302                             (max (ctype-size ty) 0))))
   1303             (else
   1304              (parse-expr ps) (expect-punct ps 'rparen)
   1305              (let* ((tp (cg-top (ps-cg ps)))
   1306                     (sz (max (ctype-size (opnd-type tp)) 0)))
   1307                (cg-pop (ps-cg ps))
   1308                (cg-push-imm (ps-cg ps) %t-u64 sz)))))
   1309          (else (parse-unary ps)
   1310                (let* ((tp (cg-top (ps-cg ps)))
   1311                       (sz (max (ctype-size (opnd-type tp)) 0)))
   1312                  (cg-pop (ps-cg ps))
   1313                  (cg-push-imm (ps-cg ps) %t-u64 sz)))))
   1314       (else (parse-postfix ps)))))
   1315 
   1316 (define (token-is-decl? ps)
   1317   (let ((t (peek ps)))
   1318     (cond
   1319       ((eq? (tok-kind t) 'KW)
   1320        (let ((v (tok-value t)))
   1321          (or (eq? v 'void) (eq? v 'char) (eq? v 'short) (eq? v 'int)
   1322              (eq? v 'long) (eq? v 'signed) (eq? v 'unsigned)
   1323              (eq? v '_Bool) (eq? v 'struct) (eq? v 'union)
   1324              (eq? v 'enum) (eq? v 'const) (eq? v 'volatile)
   1325              (eq? v 'restrict) (eq? v 'inline))))
   1326       ((eq? (tok-kind t) 'IDENT) (typedef? ps (tok-value t)))
   1327       (else #f))))
   1328 
   1329 (define (parse-cast-or-unary ps)
   1330   (let ((t (peek2 ps)))
   1331     (cond
   1332       ((and (eq? (tok-kind t) 'KW)
   1333             (let ((v (tok-value t)))
   1334               (or (eq? v 'void) (eq? v 'char) (eq? v 'short)
   1335                   (eq? v 'int) (eq? v 'long) (eq? v 'signed)
   1336                   (eq? v 'unsigned) (eq? v '_Bool)
   1337                   (eq? v 'struct) (eq? v 'union) (eq? v 'enum)
   1338                   (eq? v 'const) (eq? v 'volatile)
   1339                   (eq? v 'restrict))))
   1340        (advance ps)
   1341        (let* ((sp (parse-decl-spec ps))
   1342               (p (parse-declarator ps (cdr sp)))
   1343               (ty (cdr p)))
   1344          (expect-punct ps 'rparen)
   1345          (parse-unary ps)
   1346          ;; Cast operand undergoes lvalue conversion first (C semantics):
   1347          ;; arrays decay to pointers, lvals become rvals. cg-cast then
   1348          ;; bit-casts the resulting rval to the target type.
   1349          (rval! ps)
   1350          (cg-cast (ps-cg ps) ty)))
   1351       ((and (eq? (tok-kind t) 'IDENT) (typedef? ps (tok-value t)))
   1352        (advance ps)
   1353        (let* ((sp (parse-decl-spec ps))
   1354               (p (parse-declarator ps (cdr sp)))
   1355               (ty (cdr p)))
   1356          (expect-punct ps 'rparen)
   1357          (parse-unary ps)
   1358          ;; Cast operand undergoes lvalue conversion first (C semantics):
   1359          ;; arrays decay to pointers, lvals become rvals. cg-cast then
   1360          ;; bit-casts the resulting rval to the target type.
   1361          (rval! ps)
   1362          (cg-cast (ps-cg ps) ty)))
   1363       (else (advance ps) (parse-expr ps)
   1364             (expect-punct ps 'rparen)
   1365             (parse-postfix-rest ps)))))
   1366 
   1367 (define (parse-postfix ps)
   1368   (parse-primary ps) (parse-postfix-rest ps))
   1369 
   1370 (define (parse-postfix-rest ps)
   1371   (let lp ()
   1372     (let ((t (peek ps)))
   1373       (cond
   1374         ((not (eq? (tok-kind t) 'PUNCT)) #t)
   1375         (else
   1376          (let ((v (tok-value t)))
   1377            (cond
   1378              ((eq? v 'lbrack)
   1379               (advance ps) (rval! ps)
   1380               (parse-expr ps) (rval! ps)
   1381               (expect-punct ps 'rbrack)
   1382               (cg-binop (ps-cg ps) 'add)
   1383               (cg-push-deref (ps-cg ps)) (lp))
   1384              ((eq? v 'lparen)
   1385               (advance ps) (rval-not-fn! ps)
   1386               (let* ((fn-ty   (call-fn-type (ps-cg ps)))
   1387                      (n (parse-call-args ps fn-ty))
   1388                      ;; has-result? = #f for known void returns. Skips
   1389                      ;; the wasted ST a0 → frame-slot spill that
   1390                      ;; cg-call would otherwise emit for void calls.
   1391                      (has-result?
   1392                       (cond
   1393                         ((not fn-ty) #t)
   1394                         ((eq? (ctype-kind (car (ctype-ext fn-ty))) 'void) #f)
   1395                         (else #t))))
   1396                 (expect-punct ps 'rparen)
   1397                 (cg-call (ps-cg ps) n has-result?)
   1398                 ;; Maintain parse's "one rval per expression" invariant
   1399                 ;; so comma / parse-expr-stmt / for-init/step pop sites
   1400                 ;; stay simple. The placeholder is vstack-only and
   1401                 ;; never materialized (cg-pop is a vstack op, no emit).
   1402                 (cond ((not has-result?)
   1403                        (cg-push-imm (ps-cg ps) %t-i32 0)))
   1404                 (lp)))
   1405              ((eq? v 'dot)
   1406               (advance ps)
   1407               (let ((nt (advance ps)))
   1408                 (cond
   1409                   ((not (eq? (tok-kind nt) 'IDENT))
   1410                    (die (tok-loc nt) "expected field name"))
   1411                   (else
   1412                    (cg-push-field (ps-cg ps) (tok-value nt)) (lp)))))
   1413              ((eq? v 'arrow)
   1414               (advance ps)
   1415               (let ((nt (advance ps)))
   1416                 (cond
   1417                   ((not (eq? (tok-kind nt) 'IDENT))
   1418                    (die (tok-loc nt) "expected field name"))
   1419                   (else
   1420                    ;; ptr -> field: load the pointer to rval, deref to
   1421                    ;; reach the struct lval, then push the field.
   1422                    (rval! ps)
   1423                    (cg-push-deref (ps-cg ps))
   1424                    (cg-push-field (ps-cg ps) (tok-value nt)) (lp)))))
   1425              ((eq? v 'inc)
   1426               (advance ps)
   1427               (cg-postinc (ps-cg ps)) (lp))
   1428              ((eq? v 'dec)
   1429               (advance ps)
   1430               (cg-postdec (ps-cg ps)) (lp))
   1431              (else #t))))))))
   1432 
   1433 ;; call-fn-type cg -> ctype-or-#f
   1434 ;;   The function operand sits at the top of the vstack when
   1435 ;;   parse-call-args runs (just after rval-not-fn!). Its type may be
   1436 ;;   `fn` directly (named callee) or `ptr -> fn` (function pointer).
   1437 ;;   Returns the underlying `fn` ctype, or #f if the operand isn't
   1438 ;;   recognizably callable (callsite still works — no per-arg cast).
   1439 (define (call-fn-type cg)
   1440   (let* ((tp (cg-top cg)))
   1441     (cond
   1442       ((not tp) #f)
   1443       (else
   1444        (let* ((ty (opnd-type tp))
   1445               (k  (ctype-kind ty)))
   1446          (cond
   1447            ((eq? k 'fn) ty)
   1448            ((eq? k 'ptr)
   1449             (let ((pe (ctype-ext ty)))
   1450               (cond ((and pe (eq? (ctype-kind pe) 'fn)) pe)
   1451                     (else #f))))
   1452            (else #f)))))))
   1453 
   1454 ;; param-types-of fn-ty -> (params variadic?)  with a #f fallback.
   1455 (define (call-fn-param-info fn-ty)
   1456   (cond
   1457     ((not fn-ty) (cons '() #f))
   1458     (else
   1459      (let ((ext (ctype-ext fn-ty)))
   1460        (cons (cadr ext) (car (cddr ext)))))))
   1461 
   1462 ;; parse-call-args ps fn-ty -> arg-count
   1463 ;;   Casts each fixed arg to the declared param type (CC.md §K.5).
   1464 ;;   For variadic args (index >= named-arg count, when variadic? = #t)
   1465 ;;   applies cg-promote (CC.md §G.1).
   1466 (define (parse-call-args ps fn-ty)
   1467   (cond
   1468     ((at-punct? ps 'rparen) 0)
   1469     (else
   1470      (let* ((info  (call-fn-param-info fn-ty))
   1471             (params (car info))
   1472             (var?  (cdr info))
   1473             (nfix  (length params)))
   1474        (let lp ((n 0) (rem params))
   1475          (parse-expr-bp ps 4) (rval! ps)
   1476          (cond
   1477            ;; Fixed-arg: cast to declared param type. param entry shape
   1478            ;; is (name . ctype) per cg-fn-begin's contract.
   1479            ((not (null? rem))
   1480             (cg-cast (ps-cg ps) (cdr (car rem))))
   1481            ;; Variadic position (n >= nfix and var? is true): promote.
   1482            (var?
   1483             (cg-promote (ps-cg ps))))
   1484          (let ((m (+ n 1))
   1485                (rest (if (null? rem) '() (cdr rem))))
   1486            (cond ((at-punct? ps 'comma) (advance ps) (lp m rest))
   1487                  (else m))))))))
   1488 
   1489 ;; --------------------------------------------------------------------
   1490 ;; __builtin_va_* (§G.2). va_list / va_start / va_arg / va_end in
   1491 ;; <stdarg.h> alias these. Each is parsed as: name '(' args ')'.
   1492 ;; va_start(ap, last)  — last is parsed and discarded; cg only needs
   1493 ;;   the variadic-first-slot offset, which it already tracks.
   1494 ;; va_arg(ap, T)       — T is a type-name; result rval has that type.
   1495 ;; va_end(ap)          — no-op codegen; just consumes ap.
   1496 ;;
   1497 ;; Pushes a single imm 0 for va_start / va_end so they fit as
   1498 ;; expression statements; va_arg pushes the rval.
   1499 ;; --------------------------------------------------------------------
   1500 (define (parse-builtin-va-start ps)
   1501   (advance ps)                                 ; IDENT
   1502   (expect-punct ps 'lparen)
   1503   (parse-expr-bp ps 4)                         ; ap (must be lval)
   1504   (expect-punct ps 'comma)
   1505   ;; "last" is parsed for syntactic completeness then dropped — cg
   1506   ;; doesn't need it; the variadic-first-slot was determined at
   1507   ;; cg-fn-begin/v time.
   1508   (parse-expr-bp ps 4) (cg-pop (ps-cg ps))
   1509   (expect-punct ps 'rparen)
   1510   (cg-va-start (ps-cg ps))
   1511   ;; Push a placeholder rval so the call expression has a value
   1512   ;; (matches va_start's "void" but our parser expects all
   1513   ;; expressions to leave one rval).
   1514   (cg-push-imm (ps-cg ps) %t-i32 0))
   1515 
   1516 (define (parse-builtin-va-arg ps)
   1517   (advance ps)                                 ; IDENT
   1518   (expect-punct ps 'lparen)
   1519   (parse-expr-bp ps 4)                         ; ap (lval)
   1520   (expect-punct ps 'comma)
   1521   (let* ((sp (parse-decl-spec ps))
   1522          (p  (parse-declarator ps (cdr sp)))
   1523          (ty (cdr p)))
   1524     (expect-punct ps 'rparen)
   1525     (cg-va-arg (ps-cg ps) ty)))
   1526 
   1527 (define (parse-builtin-va-end ps)
   1528   (advance ps)                                 ; IDENT
   1529   (expect-punct ps 'lparen)
   1530   (parse-expr-bp ps 4)                         ; ap
   1531   (expect-punct ps 'rparen)
   1532   (cg-va-end (ps-cg ps))
   1533   (cg-push-imm (ps-cg ps) %t-i32 0))
   1534 
   1535 (define (parse-primary ps)
   1536   (let ((t (peek ps)))
   1537     (cond
   1538       ((eq? (tok-kind t) 'INT)
   1539        (advance ps)
   1540        (cg-push-imm (ps-cg ps) %t-i32 (tok-value t)))
   1541       ((eq? (tok-kind t) 'CHAR)
   1542        (advance ps)
   1543        (cg-push-imm (ps-cg ps) %t-i8 (tok-value t)))
   1544       ((eq? (tok-kind t) 'STR)
   1545        (advance ps)
   1546        (cg-push-string (ps-cg ps) (tok-value t)))
   1547       ((eq? (tok-kind t) 'IDENT)
   1548        (cond
   1549          ((bv= (tok-value t) "__builtin_va_start")
   1550           (parse-builtin-va-start ps))
   1551          ((bv= (tok-value t) "__builtin_va_arg")
   1552           (parse-builtin-va-arg ps))
   1553          ((bv= (tok-value t) "__builtin_va_end")
   1554           (parse-builtin-va-end ps))
   1555          (else
   1556           (let ((sm (scope-lookup ps (tok-value t))))
   1557             (advance ps)
   1558             (cond
   1559               ((not sm) (die (tok-loc t) "undecl" (tok-value t)))
   1560               ((eq? (sym-kind sm) 'enum-const)
   1561                (cg-push-imm (ps-cg ps) %t-i32 (sym-slot sm)))
   1562               (else (cg-push-sym (ps-cg ps) sm)))))))
   1563       ((eq? (tok-kind t) 'PUNCT)
   1564        (cond
   1565          ((eq? (tok-value t) 'lparen)
   1566           (advance ps) (parse-expr ps) (expect-punct ps 'rparen))
   1567          (else (die (tok-loc t) "unexp" (tok-value t)))))
   1568       (else (die (tok-loc t) "unexp" (tok-value t))))))
   1569 
   1570 (define (rval! ps)
   1571   (let ((tp (cg-top (ps-cg ps))))
   1572     (cond ((and tp (opnd? tp) (opnd-lval? tp))
   1573            (cg-load (ps-cg ps)))
   1574           (else #t))))
   1575 
   1576 (define (rval-not-fn! ps)
   1577   (let ((tp (cg-top (ps-cg ps))))
   1578     (cond ((and tp (opnd? tp) (opnd-lval? tp)
   1579                 (not (ctype-is-fn? (opnd-type tp))))
   1580            (cg-load (ps-cg ps)))
   1581           (else #t))))