Explorar el Código

M2S compiles clean under V3: LENGTH/&/~ aliases, octal char literals, CAP/ORDL, empty bodies; fix ABS/CAP result propagation (110/110)

Eric Streit hace 2 semanas
padre
commit
dd7767cd45
Se han modificado 7 ficheros con 2210 adiciones y 2089 borrados
  1. 1 0
      compiler/run_tests.sh
  2. 26 16
      compiler/src/M2.atg
  3. 2083 2073
      compiler/src/M2.lst
  4. 3 0
      compiler/src/QbeGen.def
  5. 11 0
      compiler/src/QbeGen.mod
  6. 27 0
      compiler/tests/t_compat.mod
  7. 59 0
      docs/summary_m2s-clean.md

+ 1 - 0
compiler/run_tests.sh

@@ -63,6 +63,7 @@ expect_run t_real.mod 31
 expect_run t_array.mod 108
 expect_run t_nestidx.mod 42
 expect_run t_proctype.mod 42
+expect_run t_compat.mod 42
 expect_run t_constfold.mod 42
 expect_run t_emptystat.mod 42
 expect_run t_highlen.mod 18

+ 26 - 16
compiler/src/M2.atg

@@ -77,6 +77,7 @@ TOKENS
             [ ( "E" | "e" ) [ "+" | "-" ] digit { digit } ] .
   string  = "'" { noQuote1 } "'"
           | '"' { noQuote2 } '"' .
+  charConst = digit { digit } ( "C" | "c" ) .
 
 PRODUCTIONS
   M2
@@ -189,7 +190,8 @@ PRODUCTIONS
                                              AND NOT SymTab.ImportFrom(mod, n) THEN
                                              SemError(201) END; .)
     | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN"
-      | "CHR" | "ORD" | "VAL" | "ABS" | "INC" | "DEC" ) .
+      | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP"
+      | "INC" | "DEC" ) .
   ImpModList                            (. VAR n: SymTab.Name; .)
     = GetIdent<n>
       { "," GetIdent<n> } .
@@ -799,7 +801,7 @@ PRODUCTIONS
   WithStat                              (. VAR nW: CARDINAL; .)
     = "WITH"                            (. nW := 0; .)
       WithItem<nW> { "," WithItem<nW> }
-      "DO" StatSeq "END"
+      "DO" [ StatSeq ] "END"
                                         (. WHILE nW > 0 DO
                                              SymTab.PopScope;
                                              QbeGen.PopWith;
@@ -1091,7 +1093,7 @@ PRODUCTIONS
                                            QbeGen.NewLabel(lEnd);
                                            QbeGen.Jnz(q, lThen, lElse);
                                            QbeGen.EmitLabel(lThen); .)
-      "THEN" StatSeq                    (. QbeGen.Jmp(lEnd); .)
+      "THEN" [ StatSeq ]                (. QbeGen.Jmp(lEnd); .)
       { "ELSIF"                         (. QbeGen.EmitLabel(lElse);
                                            QbeGen.NewLabel(lElse); .)
         Expr<t, q>                      (. IF NOT SymTab.BoolCheck(t) THEN
@@ -1102,7 +1104,7 @@ PRODUCTIONS
         "THEN" StatSeq                  (. QbeGen.Jmp(lEnd); .) }
       [ "ELSE"                          (. QbeGen.EmitLabel(lElse);
                                            hasElse := TRUE; .)
-        StatSeq ]
+        [ StatSeq ] ]
       "END"                             (. IF hasElse THEN
                                              QbeGen.EmitLabel(lEnd)
                                            ELSE QbeGen.EmitLabel(lElse);
@@ -1119,14 +1121,14 @@ PRODUCTIONS
                                              SemError(214) END;
                                            QbeGen.Jnz(q, lBody, lEnd);
                                            QbeGen.EmitLabel(lBody); .)
-      "DO" StatSeq                      (. QbeGen.Jmp(lTop); .)
+      "DO" [ StatSeq ]                      (. QbeGen.Jmp(lTop); .)
       "END"                             (. QbeGen.EmitLabel(lEnd); .) .
   RepeatStat                            (. VAR t: SymTab.TypeIndex;
                                              q, lTop, lEnd: QbeGen.QVal; .)
     = "REPEAT"                          (. QbeGen.NewLabel(lTop);
                                            QbeGen.NewLabel(lEnd);
                                            QbeGen.EmitLabel(lTop); .)
-      StatSeq
+      [ StatSeq ]
       "UNTIL" Expr<t, q>                (. IF NOT SymTab.BoolCheck(t) THEN
                                              SemError(214) END;
                                            QbeGen.Jnz(q, lEnd, lTop);
@@ -1136,7 +1138,7 @@ PRODUCTIONS
                                            QbeGen.NewLabel(lEnd);
                                            QbeGen.PushLoop(lEnd);
                                            QbeGen.EmitLabel(lTop); .)
-      StatSeq
+      [ StatSeq ]
       "END"                             (. QbeGen.Jmp(lTop);
                                            QbeGen.PopLoop;
                                            QbeGen.EmitLabel(lEnd); .) .
@@ -1198,7 +1200,7 @@ PRODUCTIONS
                                            END;
                                            QbeGen.Jnz(qk, lBody, lEnd);
                                            QbeGen.EmitLabel(lBody); .)
-      StatSeq
+      [ StatSeq ]
       "END"                             (. IF ok THEN
                                              QbeGen.LoadVar(lv, FALSE,
                                                qt);
@@ -1215,7 +1217,7 @@ PRODUCTIONS
     = "CASE" Expr<tsel, qsel>           (. QbeGen.NewLabel(lEnd); .)
       "OF" CaseAlt<tsel, qsel, lEnd>
       { "|" CaseAlt<tsel, qsel, lEnd> }
-      [ "ELSE" StatSeq ]
+      [ "ELSE" [ StatSeq ] ]
       "END"                             (. QbeGen.EmitLabel(lEnd); .) .
   (* Compare-chain lowering: each alternative ends its match-tests
      with "jmp lAfter", so the no-match fallthrough skips the body:
@@ -1229,7 +1231,7 @@ PRODUCTIONS
       { "," CaseLabel<tsel, qsel, lBody> }
       ":"                               (. QbeGen.Jmp(lAfter);
                                            QbeGen.EmitLabel(lBody); .)
-      StatSeq                           (. QbeGen.Jmp(lEnd);
+      [ StatSeq ]                       (. QbeGen.Jmp(lEnd);
                                            QbeGen.EmitLabel(lAfter); .) .
   CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
             lBody: QbeGen.QVal>         (. VAR t2, t3: SymTab.TypeIndex;
@@ -1848,7 +1850,7 @@ PRODUCTIONS
     | "/"                               (. op := SymTab.OpSlash; .)
     | "DIV"                             (. op := SymTab.OpDiv; .)
     | "MOD"                             (. op := SymTab.OpMod; .)
-    | "AND"                             (. op := SymTab.OpAnd; .) .
+    | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
   Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
                                         (. VAR s: ARRAY [0 .. 255] OF CHAR;
                                              et, dt, t2, st, ct2:
@@ -1859,11 +1861,14 @@ PRODUCTIONS
                                              qn, vn: SymTab.Name;
                                              vt: SymTab.TypeIndex;
                                              c1, c2: INTEGER;
-                                             called, isHigh, sfx:
+                                             called, isHigh, sfx, isCh:
                                                BOOLEAN; .)
     = integer                           (. LexString(s);
                                            QbeGen.NormInt(s, q);
                                            t := SymTab.IntType(); .)
+    | charConst                         (. LexString(s);
+                                           QbeGen.NormLit(s, q, isCh);
+                                           t := SymTab.CharType(); .)
     | real                              (. LexString(s);
                                            QbeGen.NormReal(s, q);
                                            t := SymTab.RealType(); .)
@@ -1952,7 +1957,7 @@ PRODUCTIONS
                                              END
                                            END; .)
     | ( "HIGH"                          (. isHigh := TRUE; .)
-      | "LEN"                           (. isHigh := FALSE; .) )
+      | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
       "(" Design<dt, dk, qd, qn, sfx> ")"
                                         (. IF dt = SymTab.InvalidType THEN
                                            ELSIF SymTab.ClassOf(dt) #
@@ -2010,7 +2015,7 @@ PRODUCTIONS
  AND NOT SymTab.IsIntFamily(et) THEN
                                              SemError(211) END;
                                            t := SymTab.CharType(); .)
-    | "ORD" "(" Expr<et, q> ")"
+    | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
                                         (. IF et # SymTab.InvalidType THEN
                                              IF (SymTab.ClassOf(et) #
                                                  SymTab.ClChar)
@@ -2022,6 +2027,10 @@ PRODUCTIONS
                                                SemError(211) END
                                            END;
                                            t := SymTab.IntType(); .)
+    | "CAP" "(" Expr<et, q> ")"
+                                        (. QbeGen.CapQ(q, qa);
+                                           QbeGen.CopyOp(qa, q);
+                                           t := SymTab.CharType(); .)
     | "ABS" "(" Expr<et, q> ")"
                                         (. IF (et # SymTab.InvalidType)
  AND NOT SymTab.IsIntFamily(et)
@@ -2030,7 +2039,8 @@ PRODUCTIONS
                                              SemError(211)
                                            ELSE QbeGen.AbsQ(q, qa,
                                                   SymTab.ClassOf(et) =
-                                                    SymTab.ClReal)
+                                                    SymTab.ClReal);
+                                             QbeGen.CopyOp(qa, q)
                                            END;
                                            t := et; .)
     | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
@@ -2075,7 +2085,7 @@ PRODUCTIONS
     | "(" Expr<et, q> ")"               (. t := et; .)
     | SetLit<st, sq>                    (. t := st;
                                            QbeGen.CopyOp(sq, q); .)
-    | "NOT" Fact<t2, q2>                (. IF SymTab.BoolCheck(t2) THEN
+    | ( "NOT" | "~" ) Fact<t2, q2>      (. IF SymTab.BoolCheck(t2) THEN
                                              t := SymTab.BoolType()
                                            ELSE SemError(212);
                                              t := SymTab.InvalidType END;

+ 2083 - 2073
compiler/src/M2.lst

@@ -94,2097 +94,2107 @@ Listing:
    77              [ ( "E" | "e" ) [ "+" | "-" ] digit { digit } ] .
    78    string  = "'" { noQuote1 } "'"
    79            | '"' { noQuote2 } '"' .
-   80  
-   81  PRODUCTIONS
-   82    M2
-   83      = Unit "." .
-   84    (* Units: program modules compile fully; DEFINITION and
-   85       IMPLEMENTATION modules parse + check now but lower in step 4
-   86       (each ends with one 230); same for nested local modules. *)
-   87    Unit
-   88      = DefUnit
-   89      | ImplUnit
-   90      | ProgModule .
-   91    (* Step 4.3: one session compiles DEFINITION, its IMPLEMENTATION
-   92       and one program (last) into one image. Units share the symbol
-   93       table; imports materialize exported names. *)
-   94    DefUnit                               (. VAR m1, m2, pn: SymTab.Name; .)
-   95      = "DEFINITION" "MODULE"
-   96        GetIdent<m1>                      (. IF NOT SymTab.BeginDef(m1) THEN
-   97                                               SemError(200) END;
-   98                                             QbeGen.SetModule(m1); .)
-   99        ";"
-  100        { Import }
-  101        { ConstBlock | TypeBlock<TRUE> | VarBlock
-  102        | ProcHeading<pn> ";"             (. SymTab.CloseProc;
-  103                                               QbeGen.AbortFunc; .) }
-  104        "END"
-  105        GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
-  106                                               SemError(202) END;
-  107                                             SymTab.EndUnit; .) .
-  108    ImplUnit                              (. VAR m1, m2: SymTab.Name; .)
-  109      = "IMPLEMENTATION" "MODULE"
-  110        GetIdent<m1>                      (. IF NOT SymTab.BeginImpl(m1) THEN
-  111                                               SemError(201) END;
-  112                                             QbeGen.SetModule(m1); .)
-  113        ";"
-  114        { Import }
-  115        DeclSeq
-  116        [ "BEGIN"                         (. QbeGen.BeginInit(m1); .)
-  117          [ StatSeq ]                       (. QbeGen.EndInit; .) ]
-  118        "END"
-  119        GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
-  120                                               SemError(202) END;
-  121                                             SymTab.EndUnit; .) .
-  122    ProgModule                            (. VAR m1, m2: SymTab.Name; .)
-  123      = "MODULE"
-  124        GetIdent<m1>                      (. IF NOT SymTab.BeginProg(m1) THEN
-  125                                               SemError(200) END;
-  126                                             QbeGen.SetModule(m1); .)
-  127        [ Priority ]
-  128        ";"
-  129        { Import }
-  130        DeclSeq
-  131        [ "BEGIN"                         (. QbeGen.BeginBody; .)
-  132          [ StatSeq ] ]
-  133        "END"
-  134        GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
-  135                                               SemError(202) END;
-  136                                             QbeGen.EndModule(m1);
-  137                                             SymTab.EndUnit; .) .
-  138    DeclSeq
-  139      = { ConstBlock | TypeBlock<FALSE> | VarBlock | ProcDecl ";"
-  140        | NestedModule ";" | ClassItem ";" } .
-  141    (* Local module, Wirth form. Parses + checks fully (own scope);
-  142       lowering waits for step 4, marked by one 230 at END. *)
-  143    NestedModule                          (. VAR m1, m2: SymTab.Name; .)
-  144      = "MODULE"
-  145        GetIdent<m1>                      (. IF NOT SymTab.Enter(m1,
-  146                                               SymTab.KindModule) THEN
-  147                                               SemError(200) END;
-  148                                             SymTab.PushScope; .)
-  149        [ Priority ]
-  150        ";"
-  151        { Import }
-  152        [ Export ]
-  153        DeclSeq
-  154        [ "BEGIN"
-  155          [ StatSeq ] ]
-  156        "END"
-  157        GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
-  158                                               SemError(202) END;
-  159                                             SymTab.PopScope;
-  160                                             SemError(230); .) .
-  161    Priority
-  162      = "[" integer "]"                   (. SemError(230); .) .
-  163    Export                                (. VAR nm: SymTab.Name; .)
-  164      = "EXPORT"                          (* names wire up in step 4 *)
-  165        [ "QUALIFIED" ]
-  166        GetIdent<nm>
-  167        { "," GetIdent<nm> }
-  168        ";" .
-  169    (* Imports (4.3): FROM materializes the names (unqualified use);
-  170       plain IMPORT only demands the module exists — qualified `L.x`
-  171       materializes on first use (Design). *)
-  172    (* Unknown modules stay unchecked stubs (legacy, so hand-written
-  173       import lines don't fail); a known module's missing export is
-  174       201. *)
-  175    Import                                (. VAR n: SymTab.Name; .)
-  176      = "FROM"
-  177        GetIdent<n>
-  178        "IMPORT"
-  179        ImpList<n> ";"
-  180      | "IMPORT"
-  181        ImpModList ";" .
-  182    ImpList<mod: SymTab.Name>             (. VAR n: SymTab.Name; .)
-  183      = ImpName<mod>
-  184        { "," ImpName<mod> } .
-  185    (* Pervasive built-ins imported from SYSTEM (e.g. TSIZE) are
-  186       accepted and ignored: the built-in applies regardless. *)
-  187    ImpName<mod: SymTab.Name>             (. VAR n: SymTab.Name; .)
-  188      = GetIdent<n>                       (. IF SymTab.ModKnown(mod)
-  189                                               AND NOT SymTab.ImportFrom(mod, n) THEN
-  190                                               SemError(201) END; .)
-  191      | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN"
-  192        | "CHR" | "ORD" | "VAL" | "ABS" | "INC" | "DEC" ) .
-  193    ImpModList                            (. VAR n: SymTab.Name; .)
-  194      = GetIdent<n>
-  195        { "," GetIdent<n> } .
-  196    (* Opaque TYPE declarations (definition modules). The targetless
-  197       alias resolves to InvalidType until step 4 completes it. *)
-  198    (* Scalar-phase TYPEs: named types, integer subranges, enumerations.
-  199       Opaque "TYPE T;" needs isDef (definition units); elsewhere 231.
-  200       Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *)
-  201    TypeBlock<isDef: BOOLEAN>
-  202      = "TYPE"                            (. SymTab.BeginTypeBlock; .)
-  203        { TypeItem<isDef> ";" | ClassItem ";" }
-  204                                          (. SymTab.EndTypeBlock; .) .
-  205    TypeItem<isDef: BOOLEAN>              (. VAR n: SymTab.Name;
-  206                                               t, op: SymTab.TypeIndex; .)
-  207      = GetIdent<n>                       (. op := SymTab.OpaqueBase(n);
-  208                                             IF op = SymTab.InvalidType THEN
-  209                                               IF NOT SymTab.Enter(n,
-  210                                                  SymTab.KindType) THEN
-  211                                                 SemError(200) END
-  212                                             END; .)
-  213        ( "=" Type<t, FALSE>              (. IF op # SymTab.InvalidType THEN
-  214                                               SymTab.SetTarget(op, t)
-  215                                             ELSE SymTab.SetSymType(n, t)
-  216                                             END; .)
-  217        |                                 (. IF op # SymTab.InvalidType THEN
-  218                                               (* stays opaque *)
-  219                                             ELSIF NOT isDef THEN
-  220                                               SemError(231)
-  221                                             ELSE SymTab.SetSymType(n,
-  222                                               SymTab.NewAlias()) END; .) ) .
-  223    Type<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
-  224      = TypeIdent<t>
-  225      | Subrange<t>
-  226      | Enum<t>
-  227      | ArrayType<t, allowOpen>
-  228      | SetType<t>
-  229      | RecordType<t>
-  230      | PointerType<t>
-  231      | ProcType<t> .
-  232    PointerType<VAR t: SymTab.TypeIndex>  (. VAR base: SymTab.TypeIndex; .)
-  233      = "POINTER" "TO" Type<base, FALSE>(. t := SymTab.NewPtr(base); .) .
-  234    (* Procedure types (step 8.5): PROCEDURE (params): result. Values
-  235       are code pointers; params are collected into the descriptor. *)
-  236    ProcType<VAR t: SymTab.TypeIndex>     (. VAR res, pt: SymTab.TypeIndex;
-  237                                               isV: BOOLEAN; .)
-  238      = "PROCEDURE"                       (. res := SymTab.InvalidType;
-  239                                             t := SymTab.NewProcType(res); .)
-  240        [ "(" [ ProcTypeSection<t> { ";" ProcTypeSection<t> } ] ")" ]
-  241        [ ":" TypeIdent<res>              (. SymTab.SetProcTypeRes(t, res); .) ] .
-  242    ProcTypeSection<t: SymTab.TypeIndex>  (. VAR pt: SymTab.TypeIndex;
-  243                                               isV: BOOLEAN;
-  244                                               cnt, k: CARDINAL;
-  245                                               names: ARRAY [0 .. 15] OF SymTab.Name; .)
-  246      =                                   (. isV := FALSE; cnt := 0; .)
-  247        [ "VAR"                           (. isV := TRUE; .) ]
-  248        GetIdent<names[cnt]>              (. INC(cnt); .)
-  249        { "," GetIdent<names[cnt]>        (. INC(cnt); .) }
-  250        ( ":" Type<pt, FALSE>             (. k := 0;
-  251                                             WHILE k < cnt DO
-  252                                               SymTab.ProcTypeAdd(t, isV, pt);
-  253                                               INC(k)
-  254                                             END; .)
-  255        |                                 (. (* type-only parameter list:
-  256                                                each name is a type (GNU
-  257                                                shorthand used by the
-  258                                                Coco/R scanner frame) *)
-  259                                             k := 0;
-  260                                             WHILE k < cnt DO
-  261                                               IF SymTab.Lookup(names[k])
-  262                                                  AND ((SymTab.SymKind(names[k]) = SymTab.KindType)
-  263    OR (SymTab.SymKind(names[k]) = SymTab.KindPredef)) THEN
-  264                                                 pt := SymTab.SymType(names[k])
-  265                                               ELSE SemError(201);
-  266                                                 pt := SymTab.InvalidType
-  267                                               END;
-  268                                               SymTab.ProcTypeAdd(t, isV, pt);
-  269                                               INC(k)
-  270                                             END; .) ) .
-  271    (* Arrays: "OF" without bounds is an open formal (allowed only
-  272       where allowOpen); "[lo..hi, ...]" nests bounded levels inside
-  273       out. Bounds are folded literals (int/char); anything else 230.
-  274       Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *)
-  275    ArrayType<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
-  276                                          (. VAR elem: SymTab.TypeIndex;
-  277                                               ok: BOOLEAN; .)
-  278      = "ARRAY"
-  279        ( "OF" Type<elem, FALSE>          (. IF NOT allowOpen THEN
-  280                                               SemError(230) END;
-  281                                             t := SymTab.NewOpenArray(elem); .)
-  282        | "["                             (. SymTab.BoundBegin; ok := TRUE; .)
-  283          BoundPair<ok>
-  284          { "," BoundPair<ok> }
-  285          "]" "OF" Type<elem, FALSE>
-  286                                          (. IF ok THEN
-  287                                               t := SymTab.NestArray(elem)
-  288                                             ELSE t := SymTab.InvalidType
-  289                                             END; .) ) .
-  290    BoundPair<VAR ok: BOOLEAN>            (. VAR tlo, thi: SymTab.TypeIndex;
-  291                                               qlo, qhi: QbeGen.QVal;
-  292                                               lo, hi: INTEGER;
-  293                                               cl, cl2: INTEGER; .)
-  294      = Expr<tlo, qlo> ".." Expr<thi, qhi>
-  295                                          (. IF (tlo = SymTab.InvalidType)
-  296                                              OR (thi = SymTab.InvalidType) THEN
-  297                                             ok := FALSE
-  298                                           ELSE cl := SymTab.ClassOf(tlo);
-  299                                             cl2 := SymTab.ClassOf(thi);
-  300                                             IF ((cl # SymTab.ClInt)
-  301   AND (cl # SymTab.ClChar))
-  302                                                OR ((cl2 # SymTab.ClInt)
-  303   AND (cl2 # SymTab.ClChar)) THEN
-  304                                               SemError(230); ok := FALSE
-  305                                             ELSIF NOT SymTab.ConstInt(qlo, lo)
-  306                                                OR NOT SymTab.ConstInt(qhi, hi)
-  307                                                OR (lo > hi) THEN
-  308                                               SemError(230); ok := FALSE
-  309                                              ELSIF NOT SymTab.BoundAdd(lo, hi) THEN
-  310                                                SemError(230); ok := FALSE
-  311                                              END;
-  312                                            END; .) .
-  313    (* Sets: multi-word masks over bases ≤ 256 values (bool, char,
-  314       bounded subranges; enums wait for ordinals, INTEGER is
-  315       unbounded). Literals are SET OF [0..255]; assignment and
-  316       comparison across suitable bases are lenient (masks over min
-  317       words + zero-check extras), out-of-span literals are 222. *)
-  318    SetType<VAR t: SymTab.TypeIndex>      (. VAR base: SymTab.TypeIndex;
-  319                                               blo, bhi, bspan: INTEGER;
-  320                                               bcls: INTEGER; .)
-  321      = "SET" "OF" Type<base, FALSE>
-  322                                          (. IF base = SymTab.InvalidType THEN
-  323                                               t := SymTab.InvalidType
-  324                                             ELSE bcls :=
-  325                                                    SymTab.ClassOf(base);
-  326                                               IF bcls = SymTab.ClBool THEN
-  327                                                 blo := 0; bspan := 2
-  328                                               ELSIF bcls = SymTab.ClChar THEN
-  329                                                 blo := 0; bspan := 256
-  330                                               ELSIF SymTab.SubBounds(base,
-  331                                                       blo, bhi) THEN
-  332                                                 bspan := bhi - blo + 1
-  333                                               ELSE bspan := 0 END;
-  334                                               IF (bspan <= 0)
-  335                                                  OR (bspan > 256) THEN
-  336                                                 SemError(230);
-  337                                                 t := SymTab.InvalidType
-  338                                               ELSE t := SymTab.NewSet(base)
-  339                                               END
-  340                                             END; .) .
-  341    (* Records: flat blobs; array fields are pointers to static
-  342       descriptors (locked amendment), nested records inline. Field
-  343       offsets static and declaration-ordered. *)
-  344    RecordType<VAR t: SymTab.TypeIndex>   (. VAR t2: SymTab.TypeIndex; .)
-  345      = "RECORD"                          (. t := SymTab.NewRecord(); .)
-  346        [ RecField<t> { ";" [ RecField<t> ] } ]
-  347        "END" .
-  348    RecField<rec: SymTab.TypeIndex>       (. VAR n: SymTab.Name;
-  349                                               t2: SymTab.TypeIndex; .)
-  350      = RecIdents<rec> ":" Type<t2, FALSE>(. SymTab.FixPendingF(rec, t2); .) .
-  351    RecIdents<rec: SymTab.TypeIndex>      (. VAR n: SymTab.Name; .)
-  352      = GetIdent<n>                       (. IF NOT SymTab.FieldPending(rec,
-  353                                               n) THEN
-  354                                               SemError(200) END; .)
-  355        { "," GetIdent<n>                 (. IF NOT SymTab.FieldPending(rec,
-  356                                               n) THEN
-  357                                               SemError(200) END; .) } .
-  358    TypeIdent<VAR t: SymTab.TypeIndex>    (. VAR n, qid: SymTab.Name;
-  359                                               k: INTEGER;
-  360                                               dotted: BOOLEAN; .)
-  361      = GetIdent<n>                       (. dotted := FALSE;
-  362                                             IF NOT SymTab.Lookup(n) THEN
-  363                                               k := -1;
-  364                                               t := SymTab.ForwardType(n);
-  365                                               IF t = SymTab.InvalidType THEN
-  366                                                 SemError(201)
-  367                                               END
-  368                                             ELSE k := SymTab.SymKind(n);
-  369                                               IF (k = SymTab.KindType)
-  370                                                  OR (k = SymTab.KindPredef) THEN
-  371                                                 t := SymTab.SymType(n)
-  372                                               ELSE t := SymTab.InvalidType
-  373                                               END
-  374                                             END; .)
-  375        [ "." GetIdent<qid>               (. dotted := TRUE;
-  376                                             IF k = SymTab.KindModule THEN
-  377                                               t := SymTab.QualType(n, qid);
-  378                                               IF t = SymTab.InvalidType THEN
-  379                                                 SemError(201)
-  380                                               END
-  381                                             ELSE SemError(221);
-  382                                               t := SymTab.InvalidType
-  383                                             END; .) ]
-  384                                          (. IF NOT dotted THEN
-  385                                               IF (k = SymTab.KindModule)
-  386                                                  OR ((k # SymTab.KindType)
-  387    AND (k # SymTab.KindPredef)
-  388    AND (k # SymTab.KindImport)
-  389    AND (k # -1)) THEN
-  390                                                 SemError(221)
-  391                                               END
-  392                                             END; .) .
-  393    Subrange<VAR t: SymTab.TypeIndex>     (. VAR tlo, thi: SymTab.TypeIndex;
-  394                                               qlo, qhi: QbeGen.QVal;
-  395                                               lo, hi: INTEGER; .)
-  396      = "[" Expr<tlo, qlo> ".." Expr<thi, qhi>
-  397                                          (. IF (tlo = SymTab.InvalidType)
-  398                                              OR (thi = SymTab.InvalidType) THEN
-  399                                             t := SymTab.InvalidType
-  400                                           ELSIF (SymTab.ClassOf(tlo) #
-  401                                                  SymTab.ClInt)
-  402                                              OR (SymTab.ClassOf(thi) #
-  403                                                  SymTab.ClInt) THEN
-  404                                             SemError(230);
-  405                                             t := SymTab.InvalidType
-  406                                           ELSIF NOT SymTab.ConstInt(qlo, lo)
-  407                                              OR NOT SymTab.ConstInt(qhi, hi)
-  408                                              OR (lo > hi) THEN
-  409                                             SemError(230);
-  410                                             t := SymTab.InvalidType
-  411                                           ELSE t := SymTab.NewSubR(lo, hi)
-  412                                           END; .)
-  413        "]" .
-  414    Enum<VAR t: SymTab.TypeIndex>         (. VAR n: SymTab.Name; .)
-  415      = "("                               (. t := SymTab.NewEnum(); .)
-  416        GetIdent<n>                       (. IF NOT SymTab.Enter(n,
-  417                                               SymTab.KindConst) THEN
-  418                                               SemError(200) END;
-  419                                             SymTab.SetSymType(n, t); .)
-  420        { "," GetIdent<n>                 (. IF NOT SymTab.Enter(n,
-  421                                               SymTab.KindConst) THEN
-  422                                               SemError(200) END;
-  423                                             SymTab.SetSymType(n, t); .) }
-  424        ")" .
-  425    (* Clarion-form classes (docs/OOP.txt): declaration + single
-  426       inheritance + IMPLEMENTATION blocks. Scopes and member checks
-  427       now; lowering (vtable, dispatch, THIS) later — one 230 per
-  428       class/impl block. Methods end with ";" per the Table example
-  429       (not "," as in the sketch). No underscores in identifiers. *)
-  430    (* Single CLASS item in both loops: separating declaration from
-  431       IMPLEMENTATION at the loop level needs 2-token lookahead
-  432       (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
-  433       The second token decides after CLASS is consumed. A misplaced
-  434       CLASS IMPLEMENTATION inside TYPE still parses (harmless: the
-  435       whole unit ends 230 until lowering). *)
-  436    ClassItem
-  437      = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
-  438    ClassRest                             (. VAR cn, m2, pn: SymTab.Name;
-  439                                               ct: SymTab.TypeIndex; .)
-  440      = GetIdent<cn>                      (. IF NOT SymTab.Enter(cn,
-  441                                               SymTab.KindType) THEN
-  442                                               SemError(200) END;
-  443                                             ct := SymTab.NewClass();
-  444                                             SymTab.SetSymType(cn, ct);
-  445                                             SymTab.PushClassScope(ct); .)
-  446        [ Parents<ct> ]
-  447        ";"
-  448        { ClassField<ct> ";" }
-  449        { MethodHeading<pn> ";"           (. SymTab.CloseProc;
-  450                                               QbeGen.AbortFunc; .) }
-  451        "END"
-  452        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
-  453                                               SemError(202) END;
-  454                                             SymTab.PopScope;
-  455                                             SemError(230); .) .
-  456    Parents<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name; .)
-  457      = "(" Parent1<ct>
-  458        { "," GetIdent<p>                 (. SemError(230); .) }
-  459        ")" .
-  460    Parent1<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name;
-  461                                               pt: SymTab.TypeIndex; .)
-  462      = GetIdent<p>                       (. IF NOT SymTab.Lookup(p) THEN
-  463                                               SemError(201)
-  464                                             ELSE pt := SymTab.SymType(p);
-  465                                               IF SymTab.ClassOf(pt) #
-  466                                                  SymTab.ClClass THEN
-  467                                                 SemError(230)
-  468                                               ELSE SymTab.SetParent(ct, pt)
-  469                                               END
-  470                                             END; .) .
-  471    ClassField<ct: SymTab.TypeIndex>      (. VAR n, rhs: SymTab.Name;
-  472                                               t: SymTab.TypeIndex; .)
-  473      = GetIdent<n>
-  474        ( "=" GetIdent<rhs>               (. IF NOT SymTab.Enter(n,
-  475                                               SymTab.KindConst) THEN
-  476                                               SemError(200) END;
-  477                                             IF SymTab.Lookup(rhs) THEN
-  478                                               SymTab.SetSymType(n,
-  479                                                 SymTab.SymType(rhs))
-  480                                             END; .)
-  481        |                                 (. IF NOT SymTab.FieldPending(ct,
-  482                                               n) THEN
-  483                                               SemError(200) END; .)
-  484          { "," GetIdent<n>               (. IF NOT SymTab.FieldPending(ct,
-  485                                               n) THEN
-  486                                               SemError(200) END; .) }
-  487          ":" Type<t, FALSE>              (. SymTab.FixPendingF(ct, t); .) ) .
-  488    MethodHeading<VAR pn: SymTab.Name>    (. VAR wantVirt: BOOLEAN; .)
-  489      =                                   (. wantVirt := FALSE; .)
-  490        [ "VIRTUAL"                       (. wantVirt := TRUE; .) ]
-  491        ProcHeading<pn>                   (. IF wantVirt THEN
-  492                                               SymTab.MarkVirtual END; .) .
-  493    ClassImplRest                         (. VAR cn, m2: SymTab.Name;
-  494                                               ct: SymTab.TypeIndex; .)
-  495      = GetIdent<cn>                      (. IF NOT SymTab.Lookup(cn) THEN
-  496                                               SemError(201);
-  497                                               ct := SymTab.InvalidType
-  498                                             ELSE ct := SymTab.SymType(cn);
-  499                                               IF SymTab.ClassOf(ct) #
-  500                                                  SymTab.ClClass THEN
-  501                                                 SemError(230);
-  502                                                 ct := SymTab.InvalidType
-  503                                               END
-  504                                             END;
-  505                                             IF ct #
-  506                                                SymTab.InvalidType THEN
-  507                                               IF NOT SymTab.PushClassMembers(
-  508                                                      ct) THEN
-  509                                                 SemError(230) END
-  510                                             END; .)
-  511        ";" { MethodImpl<ct> ";" }
-  512        [ "BEGIN"
-  513          [ StatSeq ] ]
-  514        "END"
-  515        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
-  516                                               SemError(202) END;
-  517                                             SymTab.PopScope;
-  518                                             SemError(230); .) .
-  519    MethodImpl<ct: SymTab.TypeIndex>      (. VAR pn: SymTab.Name; .)
-  520      =                                   (. QbeGen.SetNoEmit(TRUE); .)
-  521        MethodHeading<pn> ";"
-  522                                          (. IF (ct #
-  523                                                SymTab.InvalidType)
-  524   AND NOT SymTab.MethodExists(ct,
-  525                                                    pn) THEN
-  526                                               SemError(201) END; .)
-  527        ( "FORWARD"                       (. SymTab.MarkFwd;
-  528                                             SymTab.CloseProc; .)
-  529        | Block<pn>                       (. SymTab.CloseProc; .) )
-  530                                          (. QbeGen.AbortFunc;
-  531                                             QbeGen.SetNoEmit(FALSE);
-  532                                             SemError(230); .) .
-  533    ConstBlock
-  534      = "CONST" { ConstDecl ";" } .
-  535    ConstDecl                             (. VAR n: SymTab.Name;
-  536                                               t: SymTab.TypeIndex;
-  537                                               qv: QbeGen.QVal;
-  538                                               cls: INTEGER; .)
-  539      = GetIdent<n>                       (. IF NOT SymTab.Enter(n,
-  540                                               SymTab.KindConst) THEN
-  541                                               SemError(200) END; .)
-  542        "="
-  543        Expr<t, qv>                       (. SymTab.SetSymType(n, t);
-  544                                             cls := SymTab.ClassOf(t);
-  545                                             IF cls = SymTab.ClStr THEN
-  546                                               SemError(230)
-  547                                             ELSIF NOT QbeGen.IsImm(qv) THEN
-  548                                               SemError(230) END;
-  549                                             SymTab.SetSymVal(n, qv);
-  550                                             QbeGen.DeclConst(n, qv, t); .) .
-  551    VarBlock
-  552      = "VAR" { VarDecl ";" } .
-  553    VarDecl                               (. VAR nm: SymTab.Name;
-  554                                               t: SymTab.TypeIndex;
-  555                                               i: CARDINAL;
-  556                                               cls: INTEGER; .)
-  557      = VarIdents ":"
-  558        Type<t, FALSE>                    (. cls := SymTab.ClassOf(t);
-  559                                             IF (t # SymTab.InvalidType)
-  560   AND (cls # SymTab.ClInt)
-  561   AND (cls # SymTab.ClBool)
-  562   AND (cls # SymTab.ClChar)
-  563   AND (cls # SymTab.ClReal)
-  564   AND (cls # SymTab.ClArray)
-  565   AND (cls # SymTab.ClSet)
-  566   AND (cls # SymTab.ClRecord)
-  567   AND (cls # SymTab.ClPtr)
-  568   AND (cls # SymTab.ClLong)
-  569   AND (cls # SymTab.ClProc) THEN
-  570                                               SemError(230) END;
-  571                                             IF QbeGen.LocFull() THEN
-  572                                               SemError(233) END;
-  573                                             i := 0;
-  574                                             WHILE i < SymTab.PendCount() DO
-  575                                               SymTab.PendName(i, nm);
-  576                                               QbeGen.DeclVar(nm, t);
-  577                                               INC(i)
-  578                                             END;
-  579                                             SymTab.FixPending(t); .) .
-  580    VarIdents                             (. VAR n: SymTab.Name; .)
-  581      = GetIdent<n>                       (. IF NOT SymTab.EnterPending(n,
-  582                                               SymTab.KindVar) THEN
-  583                                               SemError(200) END; .)
-  584        { ","
-  585          GetIdent<n>                     (. IF NOT SymTab.EnterPending(n,
-  586                                               SymTab.KindVar) THEN
-  587                                               SemError(200) END; .) } .
-  588    ParIdents<isV: BOOLEAN>               (. VAR n: SymTab.Name; .)
-  589      = GetIdent<n>                       (. IF NOT SymTab.EnterParam(n, isV) THEN
-  590                                               SemError(200) END; .)
-  591        { "," GetIdent<n>                 (. IF NOT SymTab.EnterParam(n, isV) THEN
-  592                                               SemError(200) END; .) } .
-  593    (* Procedure headings enter scopes/params/result and buffer the
-  594       QBE header; bodies lower to functions (4.1, module level only).
-  595       FORWARD marks; the body heading re-enters (signature compare
-  596       deferred). Nested procedures parse + check, lowering = 4.2. *)
-  597    ProcHeading<VAR pn: SymTab.Name>      (. VAR t: SymTab.TypeIndex;
-  598                                               mg: QbeGen.QVal; .)
-  599      = "PROCEDURE"
-  600        GetIdent<pn>                      (. IF NOT SymTab.EnterProc(pn) THEN
-  601                                             IF NOT SymTab.ReenterProc(pn) THEN
-  602                                               IF NOT SymTab.ResumeProc(pn) THEN
-  603                                                 SemError(200) END
-  604                                               END
-  605                                             END;
-  606                                             QbeGen.Mangled(pn,
-  607                                               SymTab.ProcUid(pn), mg);
-  608                                             QbeGen.BeginFunc(mg); .)
-  609        [ FormalParams ]
-  610        [ ":" TypeIdent<t>                (. SymTab.SetProcRes(t);
-  611                                             QbeGen.SetFuncRes(t);
-  612                                             IF (t #
-  613                                                SymTab.InvalidType)
-  614   AND ((SymTab.ClassOf(t)
-  615                                                   = SymTab.ClArray)
-  616                                                OR (SymTab.ClassOf(t)
-  617                                                   = SymTab.ClRecord)
+   80    charConst = digit { digit } ( "C" | "c" ) .
+   81  
+   82  PRODUCTIONS
+   83    M2
+   84      = Unit "." .
+   85    (* Units: program modules compile fully; DEFINITION and
+   86       IMPLEMENTATION modules parse + check now but lower in step 4
+   87       (each ends with one 230); same for nested local modules. *)
+   88    Unit
+   89      = DefUnit
+   90      | ImplUnit
+   91      | ProgModule .
+   92    (* Step 4.3: one session compiles DEFINITION, its IMPLEMENTATION
+   93       and one program (last) into one image. Units share the symbol
+   94       table; imports materialize exported names. *)
+   95    DefUnit                               (. VAR m1, m2, pn: SymTab.Name; .)
+   96      = "DEFINITION" "MODULE"
+   97        GetIdent<m1>                      (. IF NOT SymTab.BeginDef(m1) THEN
+   98                                               SemError(200) END;
+   99                                             QbeGen.SetModule(m1); .)
+  100        ";"
+  101        { Import }
+  102        { ConstBlock | TypeBlock<TRUE> | VarBlock
+  103        | ProcHeading<pn> ";"             (. SymTab.CloseProc;
+  104                                               QbeGen.AbortFunc; .) }
+  105        "END"
+  106        GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
+  107                                               SemError(202) END;
+  108                                             SymTab.EndUnit; .) .
+  109    ImplUnit                              (. VAR m1, m2: SymTab.Name; .)
+  110      = "IMPLEMENTATION" "MODULE"
+  111        GetIdent<m1>                      (. IF NOT SymTab.BeginImpl(m1) THEN
+  112                                               SemError(201) END;
+  113                                             QbeGen.SetModule(m1); .)
+  114        ";"
+  115        { Import }
+  116        DeclSeq
+  117        [ "BEGIN"                         (. QbeGen.BeginInit(m1); .)
+  118          [ StatSeq ]                       (. QbeGen.EndInit; .) ]
+  119        "END"
+  120        GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
+  121                                               SemError(202) END;
+  122                                             SymTab.EndUnit; .) .
+  123    ProgModule                            (. VAR m1, m2: SymTab.Name; .)
+  124      = "MODULE"
+  125        GetIdent<m1>                      (. IF NOT SymTab.BeginProg(m1) THEN
+  126                                               SemError(200) END;
+  127                                             QbeGen.SetModule(m1); .)
+  128        [ Priority ]
+  129        ";"
+  130        { Import }
+  131        DeclSeq
+  132        [ "BEGIN"                         (. QbeGen.BeginBody; .)
+  133          [ StatSeq ] ]
+  134        "END"
+  135        GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
+  136                                               SemError(202) END;
+  137                                             QbeGen.EndModule(m1);
+  138                                             SymTab.EndUnit; .) .
+  139    DeclSeq
+  140      = { ConstBlock | TypeBlock<FALSE> | VarBlock | ProcDecl ";"
+  141        | NestedModule ";" | ClassItem ";" } .
+  142    (* Local module, Wirth form. Parses + checks fully (own scope);
+  143       lowering waits for step 4, marked by one 230 at END. *)
+  144    NestedModule                          (. VAR m1, m2: SymTab.Name; .)
+  145      = "MODULE"
+  146        GetIdent<m1>                      (. IF NOT SymTab.Enter(m1,
+  147                                               SymTab.KindModule) THEN
+  148                                               SemError(200) END;
+  149                                             SymTab.PushScope; .)
+  150        [ Priority ]
+  151        ";"
+  152        { Import }
+  153        [ Export ]
+  154        DeclSeq
+  155        [ "BEGIN"
+  156          [ StatSeq ] ]
+  157        "END"
+  158        GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
+  159                                               SemError(202) END;
+  160                                             SymTab.PopScope;
+  161                                             SemError(230); .) .
+  162    Priority
+  163      = "[" integer "]"                   (. SemError(230); .) .
+  164    Export                                (. VAR nm: SymTab.Name; .)
+  165      = "EXPORT"                          (* names wire up in step 4 *)
+  166        [ "QUALIFIED" ]
+  167        GetIdent<nm>
+  168        { "," GetIdent<nm> }
+  169        ";" .
+  170    (* Imports (4.3): FROM materializes the names (unqualified use);
+  171       plain IMPORT only demands the module exists — qualified `L.x`
+  172       materializes on first use (Design). *)
+  173    (* Unknown modules stay unchecked stubs (legacy, so hand-written
+  174       import lines don't fail); a known module's missing export is
+  175       201. *)
+  176    Import                                (. VAR n: SymTab.Name; .)
+  177      = "FROM"
+  178        GetIdent<n>
+  179        "IMPORT"
+  180        ImpList<n> ";"
+  181      | "IMPORT"
+  182        ImpModList ";" .
+  183    ImpList<mod: SymTab.Name>             (. VAR n: SymTab.Name; .)
+  184      = ImpName<mod>
+  185        { "," ImpName<mod> } .
+  186    (* Pervasive built-ins imported from SYSTEM (e.g. TSIZE) are
+  187       accepted and ignored: the built-in applies regardless. *)
+  188    ImpName<mod: SymTab.Name>             (. VAR n: SymTab.Name; .)
+  189      = GetIdent<n>                       (. IF SymTab.ModKnown(mod)
+  190                                               AND NOT SymTab.ImportFrom(mod, n) THEN
+  191                                               SemError(201) END; .)
+  192      | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN"
+  193        | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP"
+  194        | "INC" | "DEC" ) .
+  195    ImpModList                            (. VAR n: SymTab.Name; .)
+  196      = GetIdent<n>
+  197        { "," GetIdent<n> } .
+  198    (* Opaque TYPE declarations (definition modules). The targetless
+  199       alias resolves to InvalidType until step 4 completes it. *)
+  200    (* Scalar-phase TYPEs: named types, integer subranges, enumerations.
+  201       Opaque "TYPE T;" needs isDef (definition units); elsewhere 231.
+  202       Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *)
+  203    TypeBlock<isDef: BOOLEAN>
+  204      = "TYPE"                            (. SymTab.BeginTypeBlock; .)
+  205        { TypeItem<isDef> ";" | ClassItem ";" }
+  206                                          (. SymTab.EndTypeBlock; .) .
+  207    TypeItem<isDef: BOOLEAN>              (. VAR n: SymTab.Name;
+  208                                               t, op: SymTab.TypeIndex; .)
+  209      = GetIdent<n>                       (. op := SymTab.OpaqueBase(n);
+  210                                             IF op = SymTab.InvalidType THEN
+  211                                               IF NOT SymTab.Enter(n,
+  212                                                  SymTab.KindType) THEN
+  213                                                 SemError(200) END
+  214                                             END; .)
+  215        ( "=" Type<t, FALSE>              (. IF op # SymTab.InvalidType THEN
+  216                                               SymTab.SetTarget(op, t)
+  217                                             ELSE SymTab.SetSymType(n, t)
+  218                                             END; .)
+  219        |                                 (. IF op # SymTab.InvalidType THEN
+  220                                               (* stays opaque *)
+  221                                             ELSIF NOT isDef THEN
+  222                                               SemError(231)
+  223                                             ELSE SymTab.SetSymType(n,
+  224                                               SymTab.NewAlias()) END; .) ) .
+  225    Type<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
+  226      = TypeIdent<t>
+  227      | Subrange<t>
+  228      | Enum<t>
+  229      | ArrayType<t, allowOpen>
+  230      | SetType<t>
+  231      | RecordType<t>
+  232      | PointerType<t>
+  233      | ProcType<t> .
+  234    PointerType<VAR t: SymTab.TypeIndex>  (. VAR base: SymTab.TypeIndex; .)
+  235      = "POINTER" "TO" Type<base, FALSE>(. t := SymTab.NewPtr(base); .) .
+  236    (* Procedure types (step 8.5): PROCEDURE (params): result. Values
+  237       are code pointers; params are collected into the descriptor. *)
+  238    ProcType<VAR t: SymTab.TypeIndex>     (. VAR res, pt: SymTab.TypeIndex;
+  239                                               isV: BOOLEAN; .)
+  240      = "PROCEDURE"                       (. res := SymTab.InvalidType;
+  241                                             t := SymTab.NewProcType(res); .)
+  242        [ "(" [ ProcTypeSection<t> { ";" ProcTypeSection<t> } ] ")" ]
+  243        [ ":" TypeIdent<res>              (. SymTab.SetProcTypeRes(t, res); .) ] .
+  244    ProcTypeSection<t: SymTab.TypeIndex>  (. VAR pt: SymTab.TypeIndex;
+  245                                               isV: BOOLEAN;
+  246                                               cnt, k: CARDINAL;
+  247                                               names: ARRAY [0 .. 15] OF SymTab.Name; .)
+  248      =                                   (. isV := FALSE; cnt := 0; .)
+  249        [ "VAR"                           (. isV := TRUE; .) ]
+  250        GetIdent<names[cnt]>              (. INC(cnt); .)
+  251        { "," GetIdent<names[cnt]>        (. INC(cnt); .) }
+  252        ( ":" Type<pt, FALSE>             (. k := 0;
+  253                                             WHILE k < cnt DO
+  254                                               SymTab.ProcTypeAdd(t, isV, pt);
+  255                                               INC(k)
+  256                                             END; .)
+  257        |                                 (. (* type-only parameter list:
+  258                                                each name is a type (GNU
+  259                                                shorthand used by the
+  260                                                Coco/R scanner frame) *)
+  261                                             k := 0;
+  262                                             WHILE k < cnt DO
+  263                                               IF SymTab.Lookup(names[k])
+  264                                                  AND ((SymTab.SymKind(names[k]) = SymTab.KindType)
+  265    OR (SymTab.SymKind(names[k]) = SymTab.KindPredef)) THEN
+  266                                                 pt := SymTab.SymType(names[k])
+  267                                               ELSE SemError(201);
+  268                                                 pt := SymTab.InvalidType
+  269                                               END;
+  270                                               SymTab.ProcTypeAdd(t, isV, pt);
+  271                                               INC(k)
+  272                                             END; .) ) .
+  273    (* Arrays: "OF" without bounds is an open formal (allowed only
+  274       where allowOpen); "[lo..hi, ...]" nests bounded levels inside
+  275       out. Bounds are folded literals (int/char); anything else 230.
+  276       Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *)
+  277    ArrayType<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
+  278                                          (. VAR elem: SymTab.TypeIndex;
+  279                                               ok: BOOLEAN; .)
+  280      = "ARRAY"
+  281        ( "OF" Type<elem, FALSE>          (. IF NOT allowOpen THEN
+  282                                               SemError(230) END;
+  283                                             t := SymTab.NewOpenArray(elem); .)
+  284        | "["                             (. SymTab.BoundBegin; ok := TRUE; .)
+  285          BoundPair<ok>
+  286          { "," BoundPair<ok> }
+  287          "]" "OF" Type<elem, FALSE>
+  288                                          (. IF ok THEN
+  289                                               t := SymTab.NestArray(elem)
+  290                                             ELSE t := SymTab.InvalidType
+  291                                             END; .) ) .
+  292    BoundPair<VAR ok: BOOLEAN>            (. VAR tlo, thi: SymTab.TypeIndex;
+  293                                               qlo, qhi: QbeGen.QVal;
+  294                                               lo, hi: INTEGER;
+  295                                               cl, cl2: INTEGER; .)
+  296      = Expr<tlo, qlo> ".." Expr<thi, qhi>
+  297                                          (. IF (tlo = SymTab.InvalidType)
+  298                                              OR (thi = SymTab.InvalidType) THEN
+  299                                             ok := FALSE
+  300                                           ELSE cl := SymTab.ClassOf(tlo);
+  301                                             cl2 := SymTab.ClassOf(thi);
+  302                                             IF ((cl # SymTab.ClInt)
+  303   AND (cl # SymTab.ClChar))
+  304                                                OR ((cl2 # SymTab.ClInt)
+  305   AND (cl2 # SymTab.ClChar)) THEN
+  306                                               SemError(230); ok := FALSE
+  307                                             ELSIF NOT SymTab.ConstInt(qlo, lo)
+  308                                                OR NOT SymTab.ConstInt(qhi, hi)
+  309                                                OR (lo > hi) THEN
+  310                                               SemError(230); ok := FALSE
+  311                                              ELSIF NOT SymTab.BoundAdd(lo, hi) THEN
+  312                                                SemError(230); ok := FALSE
+  313                                              END;
+  314                                            END; .) .
+  315    (* Sets: multi-word masks over bases ≤ 256 values (bool, char,
+  316       bounded subranges; enums wait for ordinals, INTEGER is
+  317       unbounded). Literals are SET OF [0..255]; assignment and
+  318       comparison across suitable bases are lenient (masks over min
+  319       words + zero-check extras), out-of-span literals are 222. *)
+  320    SetType<VAR t: SymTab.TypeIndex>      (. VAR base: SymTab.TypeIndex;
+  321                                               blo, bhi, bspan: INTEGER;
+  322                                               bcls: INTEGER; .)
+  323      = "SET" "OF" Type<base, FALSE>
+  324                                          (. IF base = SymTab.InvalidType THEN
+  325                                               t := SymTab.InvalidType
+  326                                             ELSE bcls :=
+  327                                                    SymTab.ClassOf(base);
+  328                                               IF bcls = SymTab.ClBool THEN
+  329                                                 blo := 0; bspan := 2
+  330                                               ELSIF bcls = SymTab.ClChar THEN
+  331                                                 blo := 0; bspan := 256
+  332                                               ELSIF SymTab.SubBounds(base,
+  333                                                       blo, bhi) THEN
+  334                                                 bspan := bhi - blo + 1
+  335                                               ELSE bspan := 0 END;
+  336                                               IF (bspan <= 0)
+  337                                                  OR (bspan > 256) THEN
+  338                                                 SemError(230);
+  339                                                 t := SymTab.InvalidType
+  340                                               ELSE t := SymTab.NewSet(base)
+  341                                               END
+  342                                             END; .) .
+  343    (* Records: flat blobs; array fields are pointers to static
+  344       descriptors (locked amendment), nested records inline. Field
+  345       offsets static and declaration-ordered. *)
+  346    RecordType<VAR t: SymTab.TypeIndex>   (. VAR t2: SymTab.TypeIndex; .)
+  347      = "RECORD"                          (. t := SymTab.NewRecord(); .)
+  348        [ RecField<t> { ";" [ RecField<t> ] } ]
+  349        "END" .
+  350    RecField<rec: SymTab.TypeIndex>       (. VAR n: SymTab.Name;
+  351                                               t2: SymTab.TypeIndex; .)
+  352      = RecIdents<rec> ":" Type<t2, FALSE>(. SymTab.FixPendingF(rec, t2); .) .
+  353    RecIdents<rec: SymTab.TypeIndex>      (. VAR n: SymTab.Name; .)
+  354      = GetIdent<n>                       (. IF NOT SymTab.FieldPending(rec,
+  355                                               n) THEN
+  356                                               SemError(200) END; .)
+  357        { "," GetIdent<n>                 (. IF NOT SymTab.FieldPending(rec,
+  358                                               n) THEN
+  359                                               SemError(200) END; .) } .
+  360    TypeIdent<VAR t: SymTab.TypeIndex>    (. VAR n, qid: SymTab.Name;
+  361                                               k: INTEGER;
+  362                                               dotted: BOOLEAN; .)
+  363      = GetIdent<n>                       (. dotted := FALSE;
+  364                                             IF NOT SymTab.Lookup(n) THEN
+  365                                               k := -1;
+  366                                               t := SymTab.ForwardType(n);
+  367                                               IF t = SymTab.InvalidType THEN
+  368                                                 SemError(201)
+  369                                               END
+  370                                             ELSE k := SymTab.SymKind(n);
+  371                                               IF (k = SymTab.KindType)
+  372                                                  OR (k = SymTab.KindPredef) THEN
+  373                                                 t := SymTab.SymType(n)
+  374                                               ELSE t := SymTab.InvalidType
+  375                                               END
+  376                                             END; .)
+  377        [ "." GetIdent<qid>               (. dotted := TRUE;
+  378                                             IF k = SymTab.KindModule THEN
+  379                                               t := SymTab.QualType(n, qid);
+  380                                               IF t = SymTab.InvalidType THEN
+  381                                                 SemError(201)
+  382                                               END
+  383                                             ELSE SemError(221);
+  384                                               t := SymTab.InvalidType
+  385                                             END; .) ]
+  386                                          (. IF NOT dotted THEN
+  387                                               IF (k = SymTab.KindModule)
+  388                                                  OR ((k # SymTab.KindType)
+  389    AND (k # SymTab.KindPredef)
+  390    AND (k # SymTab.KindImport)
+  391    AND (k # -1)) THEN
+  392                                                 SemError(221)
+  393                                               END
+  394                                             END; .) .
+  395    Subrange<VAR t: SymTab.TypeIndex>     (. VAR tlo, thi: SymTab.TypeIndex;
+  396                                               qlo, qhi: QbeGen.QVal;
+  397                                               lo, hi: INTEGER; .)
+  398      = "[" Expr<tlo, qlo> ".." Expr<thi, qhi>
+  399                                          (. IF (tlo = SymTab.InvalidType)
+  400                                              OR (thi = SymTab.InvalidType) THEN
+  401                                             t := SymTab.InvalidType
+  402                                           ELSIF (SymTab.ClassOf(tlo) #
+  403                                                  SymTab.ClInt)
+  404                                              OR (SymTab.ClassOf(thi) #
+  405                                                  SymTab.ClInt) THEN
+  406                                             SemError(230);
+  407                                             t := SymTab.InvalidType
+  408                                           ELSIF NOT SymTab.ConstInt(qlo, lo)
+  409                                              OR NOT SymTab.ConstInt(qhi, hi)
+  410                                              OR (lo > hi) THEN
+  411                                             SemError(230);
+  412                                             t := SymTab.InvalidType
+  413                                           ELSE t := SymTab.NewSubR(lo, hi)
+  414                                           END; .)
+  415        "]" .
+  416    Enum<VAR t: SymTab.TypeIndex>         (. VAR n: SymTab.Name; .)
+  417      = "("                               (. t := SymTab.NewEnum(); .)
+  418        GetIdent<n>                       (. IF NOT SymTab.Enter(n,
+  419                                               SymTab.KindConst) THEN
+  420                                               SemError(200) END;
+  421                                             SymTab.SetSymType(n, t); .)
+  422        { "," GetIdent<n>                 (. IF NOT SymTab.Enter(n,
+  423                                               SymTab.KindConst) THEN
+  424                                               SemError(200) END;
+  425                                             SymTab.SetSymType(n, t); .) }
+  426        ")" .
+  427    (* Clarion-form classes (docs/OOP.txt): declaration + single
+  428       inheritance + IMPLEMENTATION blocks. Scopes and member checks
+  429       now; lowering (vtable, dispatch, THIS) later — one 230 per
+  430       class/impl block. Methods end with ";" per the Table example
+  431       (not "," as in the sketch). No underscores in identifiers. *)
+  432    (* Single CLASS item in both loops: separating declaration from
+  433       IMPLEMENTATION at the loop level needs 2-token lookahead
+  434       (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
+  435       The second token decides after CLASS is consumed. A misplaced
+  436       CLASS IMPLEMENTATION inside TYPE still parses (harmless: the
+  437       whole unit ends 230 until lowering). *)
+  438    ClassItem
+  439      = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
+  440    ClassRest                             (. VAR cn, m2, pn: SymTab.Name;
+  441                                               ct: SymTab.TypeIndex; .)
+  442      = GetIdent<cn>                      (. IF NOT SymTab.Enter(cn,
+  443                                               SymTab.KindType) THEN
+  444                                               SemError(200) END;
+  445                                             ct := SymTab.NewClass();
+  446                                             SymTab.SetSymType(cn, ct);
+  447                                             SymTab.PushClassScope(ct); .)
+  448        [ Parents<ct> ]
+  449        ";"
+  450        { ClassField<ct> ";" }
+  451        { MethodHeading<pn> ";"           (. SymTab.CloseProc;
+  452                                               QbeGen.AbortFunc; .) }
+  453        "END"
+  454        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
+  455                                               SemError(202) END;
+  456                                             SymTab.PopScope;
+  457                                             SemError(230); .) .
+  458    Parents<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name; .)
+  459      = "(" Parent1<ct>
+  460        { "," GetIdent<p>                 (. SemError(230); .) }
+  461        ")" .
+  462    Parent1<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name;
+  463                                               pt: SymTab.TypeIndex; .)
+  464      = GetIdent<p>                       (. IF NOT SymTab.Lookup(p) THEN
+  465                                               SemError(201)
+  466                                             ELSE pt := SymTab.SymType(p);
+  467                                               IF SymTab.ClassOf(pt) #
+  468                                                  SymTab.ClClass THEN
+  469                                                 SemError(230)
+  470                                               ELSE SymTab.SetParent(ct, pt)
+  471                                               END
+  472                                             END; .) .
+  473    ClassField<ct: SymTab.TypeIndex>      (. VAR n, rhs: SymTab.Name;
+  474                                               t: SymTab.TypeIndex; .)
+  475      = GetIdent<n>
+  476        ( "=" GetIdent<rhs>               (. IF NOT SymTab.Enter(n,
+  477                                               SymTab.KindConst) THEN
+  478                                               SemError(200) END;
+  479                                             IF SymTab.Lookup(rhs) THEN
+  480                                               SymTab.SetSymType(n,
+  481                                                 SymTab.SymType(rhs))
+  482                                             END; .)
+  483        |                                 (. IF NOT SymTab.FieldPending(ct,
+  484                                               n) THEN
+  485                                               SemError(200) END; .)
+  486          { "," GetIdent<n>               (. IF NOT SymTab.FieldPending(ct,
+  487                                               n) THEN
+  488                                               SemError(200) END; .) }
+  489          ":" Type<t, FALSE>              (. SymTab.FixPendingF(ct, t); .) ) .
+  490    MethodHeading<VAR pn: SymTab.Name>    (. VAR wantVirt: BOOLEAN; .)
+  491      =                                   (. wantVirt := FALSE; .)
+  492        [ "VIRTUAL"                       (. wantVirt := TRUE; .) ]
+  493        ProcHeading<pn>                   (. IF wantVirt THEN
+  494                                               SymTab.MarkVirtual END; .) .
+  495    ClassImplRest                         (. VAR cn, m2: SymTab.Name;
+  496                                               ct: SymTab.TypeIndex; .)
+  497      = GetIdent<cn>                      (. IF NOT SymTab.Lookup(cn) THEN
+  498                                               SemError(201);
+  499                                               ct := SymTab.InvalidType
+  500                                             ELSE ct := SymTab.SymType(cn);
+  501                                               IF SymTab.ClassOf(ct) #
+  502                                                  SymTab.ClClass THEN
+  503                                                 SemError(230);
+  504                                                 ct := SymTab.InvalidType
+  505                                               END
+  506                                             END;
+  507                                             IF ct #
+  508                                                SymTab.InvalidType THEN
+  509                                               IF NOT SymTab.PushClassMembers(
+  510                                                      ct) THEN
+  511                                                 SemError(230) END
+  512                                             END; .)
+  513        ";" { MethodImpl<ct> ";" }
+  514        [ "BEGIN"
+  515          [ StatSeq ] ]
+  516        "END"
+  517        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
+  518                                               SemError(202) END;
+  519                                             SymTab.PopScope;
+  520                                             SemError(230); .) .
+  521    MethodImpl<ct: SymTab.TypeIndex>      (. VAR pn: SymTab.Name; .)
+  522      =                                   (. QbeGen.SetNoEmit(TRUE); .)
+  523        MethodHeading<pn> ";"
+  524                                          (. IF (ct #
+  525                                                SymTab.InvalidType)
+  526   AND NOT SymTab.MethodExists(ct,
+  527                                                    pn) THEN
+  528                                               SemError(201) END; .)
+  529        ( "FORWARD"                       (. SymTab.MarkFwd;
+  530                                             SymTab.CloseProc; .)
+  531        | Block<pn>                       (. SymTab.CloseProc; .) )
+  532                                          (. QbeGen.AbortFunc;
+  533                                             QbeGen.SetNoEmit(FALSE);
+  534                                             SemError(230); .) .
+  535    ConstBlock
+  536      = "CONST" { ConstDecl ";" } .
+  537    ConstDecl                             (. VAR n: SymTab.Name;
+  538                                               t: SymTab.TypeIndex;
+  539                                               qv: QbeGen.QVal;
+  540                                               cls: INTEGER; .)
+  541      = GetIdent<n>                       (. IF NOT SymTab.Enter(n,
+  542                                               SymTab.KindConst) THEN
+  543                                               SemError(200) END; .)
+  544        "="
+  545        Expr<t, qv>                       (. SymTab.SetSymType(n, t);
+  546                                             cls := SymTab.ClassOf(t);
+  547                                             IF cls = SymTab.ClStr THEN
+  548                                               SemError(230)
+  549                                             ELSIF NOT QbeGen.IsImm(qv) THEN
+  550                                               SemError(230) END;
+  551                                             SymTab.SetSymVal(n, qv);
+  552                                             QbeGen.DeclConst(n, qv, t); .) .
+  553    VarBlock
+  554      = "VAR" { VarDecl ";" } .
+  555    VarDecl                               (. VAR nm: SymTab.Name;
+  556                                               t: SymTab.TypeIndex;
+  557                                               i: CARDINAL;
+  558                                               cls: INTEGER; .)
+  559      = VarIdents ":"
+  560        Type<t, FALSE>                    (. cls := SymTab.ClassOf(t);
+  561                                             IF (t # SymTab.InvalidType)
+  562   AND (cls # SymTab.ClInt)
+  563   AND (cls # SymTab.ClBool)
+  564   AND (cls # SymTab.ClChar)
+  565   AND (cls # SymTab.ClReal)
+  566   AND (cls # SymTab.ClArray)
+  567   AND (cls # SymTab.ClSet)
+  568   AND (cls # SymTab.ClRecord)
+  569   AND (cls # SymTab.ClPtr)
+  570   AND (cls # SymTab.ClLong)
+  571   AND (cls # SymTab.ClProc) THEN
+  572                                               SemError(230) END;
+  573                                             IF QbeGen.LocFull() THEN
+  574                                               SemError(233) END;
+  575                                             i := 0;
+  576                                             WHILE i < SymTab.PendCount() DO
+  577                                               SymTab.PendName(i, nm);
+  578                                               QbeGen.DeclVar(nm, t);
+  579                                               INC(i)
+  580                                             END;
+  581                                             SymTab.FixPending(t); .) .
+  582    VarIdents                             (. VAR n: SymTab.Name; .)
+  583      = GetIdent<n>                       (. IF NOT SymTab.EnterPending(n,
+  584                                               SymTab.KindVar) THEN
+  585                                               SemError(200) END; .)
+  586        { ","
+  587          GetIdent<n>                     (. IF NOT SymTab.EnterPending(n,
+  588                                               SymTab.KindVar) THEN
+  589                                               SemError(200) END; .) } .
+  590    ParIdents<isV: BOOLEAN>               (. VAR n: SymTab.Name; .)
+  591      = GetIdent<n>                       (. IF NOT SymTab.EnterParam(n, isV) THEN
+  592                                               SemError(200) END; .)
+  593        { "," GetIdent<n>                 (. IF NOT SymTab.EnterParam(n, isV) THEN
+  594                                               SemError(200) END; .) } .
+  595    (* Procedure headings enter scopes/params/result and buffer the
+  596       QBE header; bodies lower to functions (4.1, module level only).
+  597       FORWARD marks; the body heading re-enters (signature compare
+  598       deferred). Nested procedures parse + check, lowering = 4.2. *)
+  599    ProcHeading<VAR pn: SymTab.Name>      (. VAR t: SymTab.TypeIndex;
+  600                                               mg: QbeGen.QVal; .)
+  601      = "PROCEDURE"
+  602        GetIdent<pn>                      (. IF NOT SymTab.EnterProc(pn) THEN
+  603                                             IF NOT SymTab.ReenterProc(pn) THEN
+  604                                               IF NOT SymTab.ResumeProc(pn) THEN
+  605                                                 SemError(200) END
+  606                                               END
+  607                                             END;
+  608                                             QbeGen.Mangled(pn,
+  609                                               SymTab.ProcUid(pn), mg);
+  610                                             QbeGen.BeginFunc(mg); .)
+  611        [ FormalParams ]
+  612        [ ":" TypeIdent<t>                (. SymTab.SetProcRes(t);
+  613                                             QbeGen.SetFuncRes(t);
+  614                                             IF (t #
+  615                                                SymTab.InvalidType)
+  616   AND ((SymTab.ClassOf(t)
+  617                                                   = SymTab.ClArray)
   618                                                OR (SymTab.ClassOf(t)
-  619                                                   = SymTab.ClSet)
+  619                                                   = SymTab.ClRecord)
   620                                                OR (SymTab.ClassOf(t)
-  621                                                   = SymTab.ClClass)) THEN
-  622                                               SemError(230) END; .) ] .
-  623    FormalParams
-  624      = "(" [ ParamSection { ";" ParamSection } ] ")" .
-  625    ParamSection                          (. VAR t: SymTab.TypeIndex;
-  626                                               nm: SymTab.Name;
-  627                                               i: CARDINAL;
-  628                                               isV: BOOLEAN; .)
-  629      =                                   (. isV := FALSE; .)
-  630        [ "VAR"                           (. isV := TRUE; .) ]
-  631        ParIdents<isV> ":" Type<t, TRUE>  (. i := 0;
-  632                                             WHILE i < SymTab.PendCount() DO
-  633                                               SymTab.PendName(i, nm);
-  634                                               (* value open arrays are
-  635                                                  passed as descriptor
-  636                                                  addresses (no copy):
-  637                                                  same representation as
-  638                                                  VAR formals *)
-  639                                               IF NOT QbeGen.FuncParam(nm,
-  640                                                    isV
-  641                                                    OR SymTab.IsOpenArray(t),
-  642                                                    t) THEN
-  643                                                 SemError(233) END;
-  644                                               INC(i)
-  645                                             END;
-  646                                             SymTab.FixPending(t); .) .
-  647    (* Nested procedures lower like top-level ones (4.2): the
-  648       static link gives them their parent's frame. Methods keep
-  649       parse-now/230-later. *)
-  650    ProcDecl                              (. VAR pn: SymTab.Name; .)
-  651      = ProcHeading<pn> ";"
-  652        ( "FORWARD"                       (. SymTab.MarkFwd;
-  653                                             SymTab.CloseProc;
-  654                                             QbeGen.AbortFunc; .)
-  655        | "EXTERNAL"                      (. SymTab.MarkExternal("");
-  656                                             SymTab.CloseProc;
-  657                                             QbeGen.AbortFunc; .)
-  658        |                                 (. QbeGen.EndFuncHeader; .)
-  659          Block<pn>                       (. SymTab.CloseProc;
-  660                                             QbeGen.EndFunc(
-  661                                               SymTab.ProcRes(pn)); .) ) .
-  662    Block<pn: SymTab.Name>                (. VAR m2: SymTab.Name; .)
-  663      = DeclSeq
-  664        [ "BEGIN"
-  665          [ StatSeq ] ]
-  666        "END"
-  667        GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
-  668                                               SemError(202) END; .) .
-  669    StatSeq
-  670      = Statement { ";" [ Statement ] } .
-  671    (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
-  672       are accepted: the statement after ';' is optional. *)
-  673    Statement                             (. VAR lx: QbeGen.QVal; .)
-  674      = AssOrCall
-  675      | IfStat
-  676      | WhileStat
-  677      | RepeatStat
-  678      | LoopStat
-  679      | ForStat
-  680      | CaseStat
-  681      | WithStat
-  682      | ReturnStat
-  683      | NewStat
-  684      | DisposeStat
-  685      | IncDecStat
-  686      | "EXIT"                            (. IF QbeGen.TopLoop(lx) THEN
-  687                                               QbeGen.Jmp(lx)
-  688                                             ELSE SemError(230) END; .) .
-  689    (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an
-  690       integer designator. *)
-  691    IncDecStat                            (. VAR dt, et2: SymTab.TypeIndex;
-  692                                               dk: INTEGER;
-  693                                               qd, qv, qn2, qstep:
-  694                                                 QbeGen.QVal;
-  695                                               qn: SymTab.Name;
-  696                                               sfx, isInc: BOOLEAN; .)
-  697      =                                   (. isInc := TRUE; .)
-  698        ( "INC"                           (. isInc := TRUE; .)
-  699        | "DEC"                           (. isInc := FALSE; .) )
-  700        "("                               (. QbeGen.CopyOp("1", qstep); .)
-  701        Design<dt, dk, qd, qn, sfx>
-  702        [ "," Expr<et2, qstep> ]
-  703        ")"                               (. IF dt = SymTab.InvalidType THEN
-  704                                             ELSIF (dk # SymTab.KindVar)
-  705   AND (dk # SymTab.KindParam)
-  706   AND (dk # SymTab.KindField) THEN
-  707                                               SemError(210)
-  708                                             ELSIF NOT SymTab.IsIntFamily(dt) THEN
-  709                                               SemError(211)
-  710                                             ELSE
-  711                                               IF sfx
-  712                                                  OR (dk = SymTab.KindField) THEN
-  713                                                 QbeGen.ElemLoad(qd, dt, qv)
-  714                                               ELSE QbeGen.LoadVar(qn,
-  715                                                 FALSE, qv)
-  716                                               END;
-  717                                               QbeGen.NewTemp(qn2);
-  718                                               IF isInc THEN
-  719                                                 QbeGen.Op3("add", qn2, qv,
-  720                                                   qstep, FALSE)
-  721                                               ELSE QbeGen.Op3("sub", qn2, qv,
+  621                                                   = SymTab.ClSet)
+  622                                                OR (SymTab.ClassOf(t)
+  623                                                   = SymTab.ClClass)) THEN
+  624                                               SemError(230) END; .) ] .
+  625    FormalParams
+  626      = "(" [ ParamSection { ";" ParamSection } ] ")" .
+  627    ParamSection                          (. VAR t: SymTab.TypeIndex;
+  628                                               nm: SymTab.Name;
+  629                                               i: CARDINAL;
+  630                                               isV: BOOLEAN; .)
+  631      =                                   (. isV := FALSE; .)
+  632        [ "VAR"                           (. isV := TRUE; .) ]
+  633        ParIdents<isV> ":" Type<t, TRUE>  (. i := 0;
+  634                                             WHILE i < SymTab.PendCount() DO
+  635                                               SymTab.PendName(i, nm);
+  636                                               (* value open arrays are
+  637                                                  passed as descriptor
+  638                                                  addresses (no copy):
+  639                                                  same representation as
+  640                                                  VAR formals *)
+  641                                               IF NOT QbeGen.FuncParam(nm,
+  642                                                    isV
+  643                                                    OR SymTab.IsOpenArray(t),
+  644                                                    t) THEN
+  645                                                 SemError(233) END;
+  646                                               INC(i)
+  647                                             END;
+  648                                             SymTab.FixPending(t); .) .
+  649    (* Nested procedures lower like top-level ones (4.2): the
+  650       static link gives them their parent's frame. Methods keep
+  651       parse-now/230-later. *)
+  652    ProcDecl                              (. VAR pn: SymTab.Name; .)
+  653      = ProcHeading<pn> ";"
+  654        ( "FORWARD"                       (. SymTab.MarkFwd;
+  655                                             SymTab.CloseProc;
+  656                                             QbeGen.AbortFunc; .)
+  657        | "EXTERNAL"                      (. SymTab.MarkExternal("");
+  658                                             SymTab.CloseProc;
+  659                                             QbeGen.AbortFunc; .)
+  660        |                                 (. QbeGen.EndFuncHeader; .)
+  661          Block<pn>                       (. SymTab.CloseProc;
+  662                                             QbeGen.EndFunc(
+  663                                               SymTab.ProcRes(pn)); .) ) .
+  664    Block<pn: SymTab.Name>                (. VAR m2: SymTab.Name; .)
+  665      = DeclSeq
+  666        [ "BEGIN"
+  667          [ StatSeq ] ]
+  668        "END"
+  669        GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
+  670                                               SemError(202) END; .) .
+  671    StatSeq
+  672      = Statement { ";" [ Statement ] } .
+  673    (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
+  674       are accepted: the statement after ';' is optional. *)
+  675    Statement                             (. VAR lx: QbeGen.QVal; .)
+  676      = AssOrCall
+  677      | IfStat
+  678      | WhileStat
+  679      | RepeatStat
+  680      | LoopStat
+  681      | ForStat
+  682      | CaseStat
+  683      | WithStat
+  684      | ReturnStat
+  685      | NewStat
+  686      | DisposeStat
+  687      | IncDecStat
+  688      | "EXIT"                            (. IF QbeGen.TopLoop(lx) THEN
+  689                                               QbeGen.Jmp(lx)
+  690                                             ELSE SemError(230) END; .) .
+  691    (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an
+  692       integer designator. *)
+  693    IncDecStat                            (. VAR dt, et2: SymTab.TypeIndex;
+  694                                               dk: INTEGER;
+  695                                               qd, qv, qn2, qstep:
+  696                                                 QbeGen.QVal;
+  697                                               qn: SymTab.Name;
+  698                                               sfx, isInc: BOOLEAN; .)
+  699      =                                   (. isInc := TRUE; .)
+  700        ( "INC"                           (. isInc := TRUE; .)
+  701        | "DEC"                           (. isInc := FALSE; .) )
+  702        "("                               (. QbeGen.CopyOp("1", qstep); .)
+  703        Design<dt, dk, qd, qn, sfx>
+  704        [ "," Expr<et2, qstep> ]
+  705        ")"                               (. IF dt = SymTab.InvalidType THEN
+  706                                             ELSIF (dk # SymTab.KindVar)
+  707   AND (dk # SymTab.KindParam)
+  708   AND (dk # SymTab.KindField) THEN
+  709                                               SemError(210)
+  710                                             ELSIF NOT SymTab.IsIntFamily(dt) THEN
+  711                                               SemError(211)
+  712                                             ELSE
+  713                                               IF sfx
+  714                                                  OR (dk = SymTab.KindField) THEN
+  715                                                 QbeGen.ElemLoad(qd, dt, qv)
+  716                                               ELSE QbeGen.LoadVar(qn,
+  717                                                 FALSE, qv)
+  718                                               END;
+  719                                               QbeGen.NewTemp(qn2);
+  720                                               IF isInc THEN
+  721                                                 QbeGen.Op3("add", qn2, qv,
   722                                                   qstep, FALSE)
-  723                                               END;
-  724                                               IF sfx
-  725                                                  OR (dk = SymTab.KindField) THEN
-  726                                                 QbeGen.ElemStore(qd, qn2,
-  727                                                   dt)
-  728                                               ELSE QbeGen.StoreVar(qn,
-  729                                                 qn2, FALSE)
-  730                                               END
-  731                                             END; .) .
-  732    (* NEW/DISPOSE as builtin statements (no call syntax until step 4).
-  733       Targets are pointer designators; DISPOSE nils afterwards (safer
-  734       than Wirth-undefined; documented). DISPOSE is shallow. *)
-  735    NewStat                               (. VAR dt: SymTab.TypeIndex;
-  736                                               dk: INTEGER;
-  737                                               qd, qm: QbeGen.QVal;
-  738                                               qn: SymTab.Name;
-  739                                               sfx: BOOLEAN;
-  740                                               bt: SymTab.TypeIndex; .)
-  741      = "NEW" "(" Design<dt, dk, qd, qn, sfx> ")"
-  742                                          (. IF dt = SymTab.InvalidType THEN
-  743                                             ELSIF (dk # SymTab.KindVar)
-  744   AND (dk # SymTab.KindParam)
-  745   AND (dk # SymTab.KindField) THEN
-  746                                               SemError(210)
-  747                                             ELSIF SymTab.ClassOf(dt) #
-  748                                                   SymTab.ClPtr THEN
-  749                                               SemError(219)
-  750                                             ELSE bt := SymTab.PtrBase(dt);
-  751                                               IF bt #
-  752                                                  SymTab.InvalidType THEN
-  753                                                 QbeGen.NewHeap(bt, qm);
-  754                                                 QbeGen.InitHeap(qm, bt);
-  755                                                 IF sfx
-  756                                                    OR (dk =
-  757                                                       SymTab.KindField) THEN
-  758                                                   QbeGen.ElemStore(qd, qm,
-  759                                                     dt)
-  760                                                 ELSE QbeGen.StorePtr(qn,
-  761                                                   qm)
-  762                                                 END
-  763                                               END
-  764                                             END; .) .
-  765    DisposeStat                           (. VAR dt: SymTab.TypeIndex;
-  766                                               dk: INTEGER;
-  767                                               qd, qv: QbeGen.QVal;
-  768                                               qn: SymTab.Name;
-  769                                               sfx: BOOLEAN; .)
-  770      = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> ")"
-  771                                          (. IF dt = SymTab.InvalidType THEN
-  772                                             ELSIF (dk # SymTab.KindVar)
-  773   AND (dk # SymTab.KindParam)
-  774   AND (dk # SymTab.KindField) THEN
-  775                                               SemError(210)
-  776                                             ELSIF SymTab.ClassOf(dt) #
-  777                                                   SymTab.ClPtr THEN
-  778                                               SemError(219)
-  779                                             ELSE
-  780                                               IF sfx
-  781                                                  OR (dk =
-  782                                                     SymTab.KindField) THEN
-  783                                                 QbeGen.ElemLoad(qd, dt,
-  784                                                   qv)
-  785                                               ELSE QbeGen.LoadPtr(qn, qv)
-  786                                               END;
-  787                                               QbeGen.FreeHeap(qv);
-  788                                               IF sfx
-  789                                                  OR (dk =
-  790                                                     SymTab.KindField) THEN
-  791                                                 QbeGen.ElemStore(qd, "0",
-  792                                                   dt)
-  793                                               ELSE QbeGen.StorePtr(qn,
-  794                                                 "0")
-  795                                               END
-  796                                             END; .) .
-  797    (* WITH pushes each record's fields (inner wins) plus its base
-  798       address; field designators resolve through both stacks. *)
-  799    WithStat                              (. VAR nW: CARDINAL; .)
-  800      = "WITH"                            (. nW := 0; .)
-  801        WithItem<nW> { "," WithItem<nW> }
-  802        "DO" StatSeq "END"
-  803                                          (. WHILE nW > 0 DO
-  804                                               SymTab.PopScope;
-  805                                               QbeGen.PopWith;
-  806                                               DEC(nW)
-  807                                             END; .) .
-  808    WithItem<VAR nW: CARDINAL>            (. VAR dt: SymTab.TypeIndex;
-  809                                               dk: INTEGER;
-  810                                               qd, qe: QbeGen.QVal;
-  811                                               qn: SymTab.Name;
-  812                                               sfx: BOOLEAN; .)
-  813      = Design<dt, dk, qd, qn, sfx>
-  814                                          (. IF dt = SymTab.InvalidType THEN
-  815                                             ELSIF (SymTab.ClassOf(dt) #
-  816                                                    SymTab.ClRecord)
-  817   AND (SymTab.ClassOf(dt) #
-  818                                                   SymTab.ClClass) THEN
-  819                                               SemError(215)
-  820                                             ELSIF SymTab.PushRecord(dt) THEN
-  821                                               QbeGen.PushWith(qd);
-  822                                               INC(nW)
-  823                                             END; .) .
-  824    (* Assignment or procedure-statement call (4.1, module level).
-  825       Bare `P;` is a syntax error; function-as-statement is 233. *)
-  826    AssOrCall                             (. VAR dt, et: SymTab.TypeIndex;
-  827                                               dk: INTEGER;
-  828                                               qd, qe, qt, ql: QbeGen.QVal;
-  829                                               qn: SymTab.Name;
-  830                                               ct2, res0: SymTab.TypeIndex;
-  831                                               q2, mg0: QbeGen.QVal;
-  832                                               isR, conv, wconv: BOOLEAN;
-  833                                               called, sfx: BOOLEAN; .)
-  834      = Design<dt, dk, qd, qn, sfx>
-  835        ( ":="
-  836          Expr<et, qe>                    (. IF (dt # SymTab.InvalidType)
-  837   AND (dk # SymTab.KindVar)
-  838   AND (dk # SymTab.KindParam)
-  839   AND (dk # SymTab.KindField) THEN
-  840                                             SemError(210)
-  841                                           ELSIF NOT SymTab.Assignable(et,
-  842                                                    dt) THEN
-  843                                             SemError(210)
-  844                                           ELSIF (dt # SymTab.InvalidType)
-  845   AND (SymTab.ClassOf(dt) =
-  846                                                 SymTab.ClClass) THEN
-  847                                             SemError(230) END;
-  848                                           isR := (dt #
-  849                                                   SymTab.InvalidType)
-  850   AND (SymTab.ClassOf(dt)
-  851                                                     = SymTab.ClReal);
-  852                                           conv := isR
-  853   AND SymTab.IsIntFamily(et);
-  854                                           wconv := (dt #
-  855                                                     SymTab.InvalidType)
-  856   AND SymTab.IsLongFamily(dt)
-  857   AND SymTab.IsIntFamily(et);
-  858                                           IF ((dk = SymTab.KindVar)
-  859                                               OR (dk = SymTab.KindParam)
-  860                                               OR (dk = SymTab.KindField))
-  861   AND (dt # SymTab.InvalidType)
-  862   AND (et # SymTab.InvalidType)
-  863   AND (SymTab.ClassOf(dt) #
-  864                                                 SymTab.ClClass) THEN
-  865                                             IF sfx
-  866                                                OR (dk = SymTab.KindField) THEN
-  867                                               IF SymTab.ClassOf(dt) =
-  868                                                  SymTab.ClArray THEN
-  869                                                 QbeGen.CopyArray(qd, qe,
-  870                                                   dt)
-  871                                               ELSIF SymTab.ClassOf(dt) =
-  872                                                   SymTab.ClSet THEN
-  873                                                 QbeGen.CopySet(qd, qe,
-  874                                                   SymTab.SetWords(dt),
-  875                                                   SymTab.SetWords(et))
-  876                                               ELSIF SymTab.ClassOf(dt) =
-  877                                                   SymTab.ClRecord THEN
-  878                                                 QbeGen.CopyRecord(qd, qe,
-  879                                                   dt)
-  880                                               ELSIF SymTab.IsLongFamily(dt) THEN
-  881                                                 IF wconv THEN
-  882                                                   QbeGen.WidenLong(qe, ql);
-  883                                                   QbeGen.ElemStore(qd, ql,
-  884                                                     dt)
-  885                                                 ELSE QbeGen.ElemStore(qd, qe,
-  886                                                   dt)
-  887                                                 END
-  888                                               ELSIF conv THEN
-  889                                                 QbeGen.ConvIR(qe, qt);
-  890                                                 QbeGen.ElemStore(qd, qt,
-  891                                                   dt)
-  892                                               ELSE QbeGen.ElemStore(qd, qe,
-  893                                                 dt)
-  894                                               END
-  895                                             ELSIF SymTab.ClassOf(dt) =
-  896                                                   SymTab.ClArray THEN
-  897                                               QbeGen.CopyArray(qd, qe, dt)
-  898                                             ELSIF SymTab.ClassOf(dt) =
-  899                                                   SymTab.ClSet THEN
-  900                                               QbeGen.CopySet(qd, qe,
-  901                                                 SymTab.SetWords(dt),
-  902                                                 SymTab.SetWords(et))
-  903                                             ELSIF SymTab.ClassOf(dt) =
-  904                                                   SymTab.ClRecord THEN
-  905                                               QbeGen.CopyRecord(qd, qe, dt)
-  906                                             ELSIF (SymTab.ClassOf(dt) =
-  907                                                   SymTab.ClPtr)
-  908                                                OR (SymTab.ClassOf(dt) =
-  909                                                   SymTab.ClProc) THEN
-  910                                               QbeGen.StorePtr(qn, qe)
-  911                                             ELSIF SymTab.IsLongFamily(dt) THEN
-  912                                               IF wconv THEN
-  913                                                 QbeGen.WidenLong(qe, ql);
-  914                                                 QbeGen.StoreLong(qn, ql)
-  915                                               ELSE QbeGen.StoreLong(qn, qe)
-  916                                               END
-  917                                             ELSIF conv THEN
-  918                                               QbeGen.ConvIR(qe, qt);
-  919                                               QbeGen.StoreVar(qn, qt, TRUE)
-  920                                             ELSE
-  921                                               QbeGen.StoreVar(qn, qe, isR)
-  922                                             END
-  923                                           END; .)
-  924        | ArgList<qn, dt, qd, FALSE, ct2, q2, called>
-  925        |                                 (* bare `P;`: proper parameterless
-  926                                              procedure call; anything else
-  927                                              here is 233 (was a bare syntax
-  928                                              error before 4.2) *)
-  929                                          (. IF (dk = SymTab.KindProc)
-  930   AND NOT sfx THEN
-  931                                               res0 := SymTab.ProcRes(qn);
-  932                                               IF res0 #
-  933                                                  SymTab.InvalidType THEN
-  934                                                 SemError(233)
-  935                                               ELSIF SymTab.ProcNPar(qn) #
-  936                                                       0 THEN
-  937                                                 SemError(233)
-  938                                               ELSE QbeGen.Mangled(qn,
-  939                                                 SymTab.ProcUid(qn), mg0);
-  940                                                 QbeGen.CallBegin(mg0,
-  941                                                   res0,
-  942                                                   SymTab.ProcDepthOf(qn),
-  943                                                   SymTab.IsExternal(qn));
-  944                                                 QbeGen.CallEnd(FALSE, q2)
-  945                                               END
-  946                                             ELSE SemError(233)
-  947                                             END; .) ) .
-  948    (* Actual-parameter list shared by statement and expression calls.
-  949       want selects CallEnd's result handling; t/q carry the call
-  950       value (statement calls discard). Arity/type failures are 233;
-  951       evaluation code still emits so the .ssa stays assembleable. *)
-  952    ArgList<pn: SymTab.Name; pt: SymTab.TypeIndex; callee: QbeGen.QVal;
-  953            want: BOOLEAN;
-  954            VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
-  955            VAR called: BOOLEAN>          (. VAR i: CARDINAL;
-  956                                               res: SymTab.TypeIndex;
-  957                                               mg: QbeGen.QVal;
-  958                                               ok, ind: BOOLEAN; .)
-  959      = "("                               (. called := TRUE;
-  960                                             ok := TRUE;
-  961                                             ind := FALSE;
-  962                                             IF SymTab.SymKind(pn) =
-  963                                                SymTab.KindProc THEN
-  964                                               res := SymTab.ProcRes(pn);
-  965                                               QbeGen.Mangled(pn,
-  966                                                 SymTab.ProcUid(pn), mg);
-  967                                               QbeGen.CallBegin(mg, res,
-  968                                                 SymTab.ProcDepthOf(pn),
-  969                                                 SymTab.IsExternal(pn))
-  970                                             ELSIF (pt # SymTab.InvalidType)
-  971    AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN
-  972                                               ind := TRUE;
-  973                                               res :=
-  974                                                 SymTab.ProcTypeRes(pt);
-  975                                               QbeGen.CallBeginInd(callee,
-  976                                                 res, FALSE)
-  977                                             ELSE SemError(233);
-  978                                               ok := FALSE;
-  979                                               res := SymTab.InvalidType
-  980                                             END;
-  981                                             i := 0; .)
-  982        [ ActParam<pn, pt, ind, i>        (. INC(i); .)
-  983          { "," ActParam<pn, pt, ind, i>  (. INC(i); .) } ]
-  984        ")"                               (. IF ok THEN
-  985                                               IF ind THEN
-  986                                                 IF i #
-  987                                                    SymTab.ProcTypeNPar(pt) THEN
-  988                                                   SemError(233); ok := FALSE
-  989                                                 END
-  990                                               ELSIF i #
-  991                                                  SymTab.ProcNPar(pn) THEN
-  992                                                 SemError(233); ok := FALSE
-  993                                               END
-  994                                             END;
-  995                                             IF NOT ok THEN
-  996                                               t := SymTab.InvalidType;
-  997                                               QbeGen.CopyOp("0", q)
-  998                                             ELSIF want THEN
-  999                                               IF res =
- 1000                                                  SymTab.InvalidType THEN
- 1001                                                 SemError(233);
- 1002                                                 t := SymTab.InvalidType;
- 1003                                                 QbeGen.CopyOp("0", q)
- 1004                                               ELSE t := res;
- 1005                                                 QbeGen.CallEnd(TRUE, q)
- 1006                                               END
- 1007                                             ELSE
- 1008                                               IF res #
- 1009                                                  SymTab.InvalidType THEN
- 1010                                                 SemError(233)
- 1011                                               END;
- 1012                                               t := SymTab.InvalidType;
- 1013                                               QbeGen.CopyOp("0", q);
- 1014                                               QbeGen.CallEnd(FALSE, q)
- 1015                                             END; .) .
- 1016    (* One actual: VAR formals take recorded designator addresses
- 1017       (233 otherwise); value formals take converted expressions. *)
- 1018    ActParam<pn: SymTab.Name; pt: SymTab.TypeIndex; ind: BOOLEAN;
- 1019             i: CARDINAL>                 (. VAR at, ft: SymTab.TypeIndex;
- 1020                                               qe, qa, qt: QbeGen.QVal;
- 1021                                               isV, conv: BOOLEAN; .)
- 1022      = Expr<at, qe>                      (. IF ind THEN
- 1023                                               ft :=
- 1024                                                 SymTab.ProcTypeParamType(pt,
- 1025                                                   i);
- 1026                                               isV :=
- 1027                                                 SymTab.ProcTypeParamIsVar(pt,
- 1028                                                   i)
- 1029                                             ELSE
- 1030                                               ft := SymTab.ParamType(pn, i);
- 1031                                               isV := SymTab.ParamIsVar(pn, i)
- 1032                                             END;
- 1033                                             IF (at = SymTab.InvalidType)
- 1034                                                OR (ft =
- 1035                                                   SymTab.InvalidType) THEN
- 1036                                             ELSIF isV THEN
- 1037                                               IF NOT QbeGen.AddrOfVal(qe,
- 1038                                                    qa) THEN
- 1039                                                 SemError(233)
- 1040                                               ELSIF NOT SymTab.VarParamOk(at,
- 1041                                                        ft) THEN
- 1042                                                 SemError(233)
- 1043                                               ELSIF NOT QbeGen.CallArg(qa,
- 1044                                                        "l") THEN
- 1045                                                 SemError(233)
- 1046                                               END
- 1047                                             ELSE
- 1048                                               IF (SymTab.ClassOf(at)
- 1049                                                  = SymTab.ClChar)
- 1050    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
- 1051    AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
- 1052         = SymTab.ClChar)
- 1053    AND QbeGen.IsImm(qe) THEN
- 1054                                                 (* 1-char string
- 1055                                                    literal passed to
- 1056                                                    ARRAY OF CHAR *)
- 1057                                                 QbeGen.DeclCharStr(qe,
- 1058                                                      qa);
- 1059                                                 IF NOT QbeGen.CallArg(qa,
- 1060                                                    "l") THEN
- 1061                                                   SemError(233)
- 1062                                                 END
- 1063                                               ELSIF NOT SymTab.Assignable(at,
- 1064                                                    ft) THEN
- 1065                                                 SemError(233)
- 1066                                               ELSE
- 1067                                                 conv := (SymTab.ClassOf(
- 1068                                                   ft) = SymTab.ClReal)
- 1069   AND SymTab.IsIntFamily(at);
- 1070                                                 IF conv THEN
- 1071                                                   QbeGen.ConvIR(qe, qt);
- 1072                                                   IF NOT QbeGen.CallArg(qt,
- 1073                                                      "d") THEN
- 1074                                                     SemError(233)
- 1075                                                   END
- 1076                                                 ELSIF NOT QbeGen.CallArg(qe,
- 1077                                                   QbeGen.ArgClass(ft)) THEN
- 1078                                                   SemError(233)
- 1079                                                 END
- 1080                                               END
- 1081                                             END; .) .
- 1082    IfStat                                (. VAR t: SymTab.TypeIndex;
- 1083                                               q, lThen, lElse, lEnd:
- 1084                                                 QbeGen.QVal;
- 1085                                               hasElse: BOOLEAN; .)
- 1086      = "IF"                              (. hasElse := FALSE; .)
- 1087        Expr<t, q>                        (. IF NOT SymTab.BoolCheck(t) THEN
- 1088                                               SemError(214) END;
- 1089                                             QbeGen.NewLabel(lThen);
- 1090                                             QbeGen.NewLabel(lElse);
- 1091                                             QbeGen.NewLabel(lEnd);
- 1092                                             QbeGen.Jnz(q, lThen, lElse);
- 1093                                             QbeGen.EmitLabel(lThen); .)
- 1094        "THEN" StatSeq                    (. QbeGen.Jmp(lEnd); .)
- 1095        { "ELSIF"                         (. QbeGen.EmitLabel(lElse);
- 1096                                             QbeGen.NewLabel(lElse); .)
- 1097          Expr<t, q>                      (. IF NOT SymTab.BoolCheck(t) THEN
- 1098                                               SemError(214) END;
- 1099                                             QbeGen.NewLabel(lThen);
- 1100                                             QbeGen.Jnz(q, lThen, lElse);
- 1101                                             QbeGen.EmitLabel(lThen); .)
- 1102          "THEN" StatSeq                  (. QbeGen.Jmp(lEnd); .) }
- 1103        [ "ELSE"                          (. QbeGen.EmitLabel(lElse);
- 1104                                             hasElse := TRUE; .)
- 1105          StatSeq ]
- 1106        "END"                             (. IF hasElse THEN
- 1107                                               QbeGen.EmitLabel(lEnd)
- 1108                                             ELSE QbeGen.EmitLabel(lElse);
+  723                                               ELSE QbeGen.Op3("sub", qn2, qv,
+  724                                                   qstep, FALSE)
+  725                                               END;
+  726                                               IF sfx
+  727                                                  OR (dk = SymTab.KindField) THEN
+  728                                                 QbeGen.ElemStore(qd, qn2,
+  729                                                   dt)
+  730                                               ELSE QbeGen.StoreVar(qn,
+  731                                                 qn2, FALSE)
+  732                                               END
+  733                                             END; .) .
+  734    (* NEW/DISPOSE as builtin statements (no call syntax until step 4).
+  735       Targets are pointer designators; DISPOSE nils afterwards (safer
+  736       than Wirth-undefined; documented). DISPOSE is shallow. *)
+  737    NewStat                               (. VAR dt: SymTab.TypeIndex;
+  738                                               dk: INTEGER;
+  739                                               qd, qm: QbeGen.QVal;
+  740                                               qn: SymTab.Name;
+  741                                               sfx: BOOLEAN;
+  742                                               bt: SymTab.TypeIndex; .)
+  743      = "NEW" "(" Design<dt, dk, qd, qn, sfx> ")"
+  744                                          (. IF dt = SymTab.InvalidType THEN
+  745                                             ELSIF (dk # SymTab.KindVar)
+  746   AND (dk # SymTab.KindParam)
+  747   AND (dk # SymTab.KindField) THEN
+  748                                               SemError(210)
+  749                                             ELSIF SymTab.ClassOf(dt) #
+  750                                                   SymTab.ClPtr THEN
+  751                                               SemError(219)
+  752                                             ELSE bt := SymTab.PtrBase(dt);
+  753                                               IF bt #
+  754                                                  SymTab.InvalidType THEN
+  755                                                 QbeGen.NewHeap(bt, qm);
+  756                                                 QbeGen.InitHeap(qm, bt);
+  757                                                 IF sfx
+  758                                                    OR (dk =
+  759                                                       SymTab.KindField) THEN
+  760                                                   QbeGen.ElemStore(qd, qm,
+  761                                                     dt)
+  762                                                 ELSE QbeGen.StorePtr(qn,
+  763                                                   qm)
+  764                                                 END
+  765                                               END
+  766                                             END; .) .
+  767    DisposeStat                           (. VAR dt: SymTab.TypeIndex;
+  768                                               dk: INTEGER;
+  769                                               qd, qv: QbeGen.QVal;
+  770                                               qn: SymTab.Name;
+  771                                               sfx: BOOLEAN; .)
+  772      = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> ")"
+  773                                          (. IF dt = SymTab.InvalidType THEN
+  774                                             ELSIF (dk # SymTab.KindVar)
+  775   AND (dk # SymTab.KindParam)
+  776   AND (dk # SymTab.KindField) THEN
+  777                                               SemError(210)
+  778                                             ELSIF SymTab.ClassOf(dt) #
+  779                                                   SymTab.ClPtr THEN
+  780                                               SemError(219)
+  781                                             ELSE
+  782                                               IF sfx
+  783                                                  OR (dk =
+  784                                                     SymTab.KindField) THEN
+  785                                                 QbeGen.ElemLoad(qd, dt,
+  786                                                   qv)
+  787                                               ELSE QbeGen.LoadPtr(qn, qv)
+  788                                               END;
+  789                                               QbeGen.FreeHeap(qv);
+  790                                               IF sfx
+  791                                                  OR (dk =
+  792                                                     SymTab.KindField) THEN
+  793                                                 QbeGen.ElemStore(qd, "0",
+  794                                                   dt)
+  795                                               ELSE QbeGen.StorePtr(qn,
+  796                                                 "0")
+  797                                               END
+  798                                             END; .) .
+  799    (* WITH pushes each record's fields (inner wins) plus its base
+  800       address; field designators resolve through both stacks. *)
+  801    WithStat                              (. VAR nW: CARDINAL; .)
+  802      = "WITH"                            (. nW := 0; .)
+  803        WithItem<nW> { "," WithItem<nW> }
+  804        "DO" [ StatSeq ] "END"
+  805                                          (. WHILE nW > 0 DO
+  806                                               SymTab.PopScope;
+  807                                               QbeGen.PopWith;
+  808                                               DEC(nW)
+  809                                             END; .) .
+  810    WithItem<VAR nW: CARDINAL>            (. VAR dt: SymTab.TypeIndex;
+  811                                               dk: INTEGER;
+  812                                               qd, qe: QbeGen.QVal;
+  813                                               qn: SymTab.Name;
+  814                                               sfx: BOOLEAN; .)
+  815      = Design<dt, dk, qd, qn, sfx>
+  816                                          (. IF dt = SymTab.InvalidType THEN
+  817                                             ELSIF (SymTab.ClassOf(dt) #
+  818                                                    SymTab.ClRecord)
+  819   AND (SymTab.ClassOf(dt) #
+  820                                                   SymTab.ClClass) THEN
+  821                                               SemError(215)
+  822                                             ELSIF SymTab.PushRecord(dt) THEN
+  823                                               QbeGen.PushWith(qd);
+  824                                               INC(nW)
+  825                                             END; .) .
+  826    (* Assignment or procedure-statement call (4.1, module level).
+  827       Bare `P;` is a syntax error; function-as-statement is 233. *)
+  828    AssOrCall                             (. VAR dt, et: SymTab.TypeIndex;
+  829                                               dk: INTEGER;
+  830                                               qd, qe, qt, ql: QbeGen.QVal;
+  831                                               qn: SymTab.Name;
+  832                                               ct2, res0: SymTab.TypeIndex;
+  833                                               q2, mg0: QbeGen.QVal;
+  834                                               isR, conv, wconv: BOOLEAN;
+  835                                               called, sfx: BOOLEAN; .)
+  836      = Design<dt, dk, qd, qn, sfx>
+  837        ( ":="
+  838          Expr<et, qe>                    (. IF (dt # SymTab.InvalidType)
+  839   AND (dk # SymTab.KindVar)
+  840   AND (dk # SymTab.KindParam)
+  841   AND (dk # SymTab.KindField) THEN
+  842                                             SemError(210)
+  843                                           ELSIF NOT SymTab.Assignable(et,
+  844                                                    dt) THEN
+  845                                             SemError(210)
+  846                                           ELSIF (dt # SymTab.InvalidType)
+  847   AND (SymTab.ClassOf(dt) =
+  848                                                 SymTab.ClClass) THEN
+  849                                             SemError(230) END;
+  850                                           isR := (dt #
+  851                                                   SymTab.InvalidType)
+  852   AND (SymTab.ClassOf(dt)
+  853                                                     = SymTab.ClReal);
+  854                                           conv := isR
+  855   AND SymTab.IsIntFamily(et);
+  856                                           wconv := (dt #
+  857                                                     SymTab.InvalidType)
+  858   AND SymTab.IsLongFamily(dt)
+  859   AND SymTab.IsIntFamily(et);
+  860                                           IF ((dk = SymTab.KindVar)
+  861                                               OR (dk = SymTab.KindParam)
+  862                                               OR (dk = SymTab.KindField))
+  863   AND (dt # SymTab.InvalidType)
+  864   AND (et # SymTab.InvalidType)
+  865   AND (SymTab.ClassOf(dt) #
+  866                                                 SymTab.ClClass) THEN
+  867                                             IF sfx
+  868                                                OR (dk = SymTab.KindField) THEN
+  869                                               IF SymTab.ClassOf(dt) =
+  870                                                  SymTab.ClArray THEN
+  871                                                 QbeGen.CopyArray(qd, qe,
+  872                                                   dt)
+  873                                               ELSIF SymTab.ClassOf(dt) =
+  874                                                   SymTab.ClSet THEN
+  875                                                 QbeGen.CopySet(qd, qe,
+  876                                                   SymTab.SetWords(dt),
+  877                                                   SymTab.SetWords(et))
+  878                                               ELSIF SymTab.ClassOf(dt) =
+  879                                                   SymTab.ClRecord THEN
+  880                                                 QbeGen.CopyRecord(qd, qe,
+  881                                                   dt)
+  882                                               ELSIF SymTab.IsLongFamily(dt) THEN
+  883                                                 IF wconv THEN
+  884                                                   QbeGen.WidenLong(qe, ql);
+  885                                                   QbeGen.ElemStore(qd, ql,
+  886                                                     dt)
+  887                                                 ELSE QbeGen.ElemStore(qd, qe,
+  888                                                   dt)
+  889                                                 END
+  890                                               ELSIF conv THEN
+  891                                                 QbeGen.ConvIR(qe, qt);
+  892                                                 QbeGen.ElemStore(qd, qt,
+  893                                                   dt)
+  894                                               ELSE QbeGen.ElemStore(qd, qe,
+  895                                                 dt)
+  896                                               END
+  897                                             ELSIF SymTab.ClassOf(dt) =
+  898                                                   SymTab.ClArray THEN
+  899                                               QbeGen.CopyArray(qd, qe, dt)
+  900                                             ELSIF SymTab.ClassOf(dt) =
+  901                                                   SymTab.ClSet THEN
+  902                                               QbeGen.CopySet(qd, qe,
+  903                                                 SymTab.SetWords(dt),
+  904                                                 SymTab.SetWords(et))
+  905                                             ELSIF SymTab.ClassOf(dt) =
+  906                                                   SymTab.ClRecord THEN
+  907                                               QbeGen.CopyRecord(qd, qe, dt)
+  908                                             ELSIF (SymTab.ClassOf(dt) =
+  909                                                   SymTab.ClPtr)
+  910                                                OR (SymTab.ClassOf(dt) =
+  911                                                   SymTab.ClProc) THEN
+  912                                               QbeGen.StorePtr(qn, qe)
+  913                                             ELSIF SymTab.IsLongFamily(dt) THEN
+  914                                               IF wconv THEN
+  915                                                 QbeGen.WidenLong(qe, ql);
+  916                                                 QbeGen.StoreLong(qn, ql)
+  917                                               ELSE QbeGen.StoreLong(qn, qe)
+  918                                               END
+  919                                             ELSIF conv THEN
+  920                                               QbeGen.ConvIR(qe, qt);
+  921                                               QbeGen.StoreVar(qn, qt, TRUE)
+  922                                             ELSE
+  923                                               QbeGen.StoreVar(qn, qe, isR)
+  924                                             END
+  925                                           END; .)
+  926        | ArgList<qn, dt, qd, FALSE, ct2, q2, called>
+  927        |                                 (* bare `P;`: proper parameterless
+  928                                              procedure call; anything else
+  929                                              here is 233 (was a bare syntax
+  930                                              error before 4.2) *)
+  931                                          (. IF (dk = SymTab.KindProc)
+  932   AND NOT sfx THEN
+  933                                               res0 := SymTab.ProcRes(qn);
+  934                                               IF res0 #
+  935                                                  SymTab.InvalidType THEN
+  936                                                 SemError(233)
+  937                                               ELSIF SymTab.ProcNPar(qn) #
+  938                                                       0 THEN
+  939                                                 SemError(233)
+  940                                               ELSE QbeGen.Mangled(qn,
+  941                                                 SymTab.ProcUid(qn), mg0);
+  942                                                 QbeGen.CallBegin(mg0,
+  943                                                   res0,
+  944                                                   SymTab.ProcDepthOf(qn),
+  945                                                   SymTab.IsExternal(qn));
+  946                                                 QbeGen.CallEnd(FALSE, q2)
+  947                                               END
+  948                                             ELSE SemError(233)
+  949                                             END; .) ) .
+  950    (* Actual-parameter list shared by statement and expression calls.
+  951       want selects CallEnd's result handling; t/q carry the call
+  952       value (statement calls discard). Arity/type failures are 233;
+  953       evaluation code still emits so the .ssa stays assembleable. *)
+  954    ArgList<pn: SymTab.Name; pt: SymTab.TypeIndex; callee: QbeGen.QVal;
+  955            want: BOOLEAN;
+  956            VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
+  957            VAR called: BOOLEAN>          (. VAR i: CARDINAL;
+  958                                               res: SymTab.TypeIndex;
+  959                                               mg: QbeGen.QVal;
+  960                                               ok, ind: BOOLEAN; .)
+  961      = "("                               (. called := TRUE;
+  962                                             ok := TRUE;
+  963                                             ind := FALSE;
+  964                                             IF SymTab.SymKind(pn) =
+  965                                                SymTab.KindProc THEN
+  966                                               res := SymTab.ProcRes(pn);
+  967                                               QbeGen.Mangled(pn,
+  968                                                 SymTab.ProcUid(pn), mg);
+  969                                               QbeGen.CallBegin(mg, res,
+  970                                                 SymTab.ProcDepthOf(pn),
+  971                                                 SymTab.IsExternal(pn))
+  972                                             ELSIF (pt # SymTab.InvalidType)
+  973    AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN
+  974                                               ind := TRUE;
+  975                                               res :=
+  976                                                 SymTab.ProcTypeRes(pt);
+  977                                               QbeGen.CallBeginInd(callee,
+  978                                                 res, FALSE)
+  979                                             ELSE SemError(233);
+  980                                               ok := FALSE;
+  981                                               res := SymTab.InvalidType
+  982                                             END;
+  983                                             i := 0; .)
+  984        [ ActParam<pn, pt, ind, i>        (. INC(i); .)
+  985          { "," ActParam<pn, pt, ind, i>  (. INC(i); .) } ]
+  986        ")"                               (. IF ok THEN
+  987                                               IF ind THEN
+  988                                                 IF i #
+  989                                                    SymTab.ProcTypeNPar(pt) THEN
+  990                                                   SemError(233); ok := FALSE
+  991                                                 END
+  992                                               ELSIF i #
+  993                                                  SymTab.ProcNPar(pn) THEN
+  994                                                 SemError(233); ok := FALSE
+  995                                               END
+  996                                             END;
+  997                                             IF NOT ok THEN
+  998                                               t := SymTab.InvalidType;
+  999                                               QbeGen.CopyOp("0", q)
+ 1000                                             ELSIF want THEN
+ 1001                                               IF res =
+ 1002                                                  SymTab.InvalidType THEN
+ 1003                                                 SemError(233);
+ 1004                                                 t := SymTab.InvalidType;
+ 1005                                                 QbeGen.CopyOp("0", q)
+ 1006                                               ELSE t := res;
+ 1007                                                 QbeGen.CallEnd(TRUE, q)
+ 1008                                               END
+ 1009                                             ELSE
+ 1010                                               IF res #
+ 1011                                                  SymTab.InvalidType THEN
+ 1012                                                 SemError(233)
+ 1013                                               END;
+ 1014                                               t := SymTab.InvalidType;
+ 1015                                               QbeGen.CopyOp("0", q);
+ 1016                                               QbeGen.CallEnd(FALSE, q)
+ 1017                                             END; .) .
+ 1018    (* One actual: VAR formals take recorded designator addresses
+ 1019       (233 otherwise); value formals take converted expressions. *)
+ 1020    ActParam<pn: SymTab.Name; pt: SymTab.TypeIndex; ind: BOOLEAN;
+ 1021             i: CARDINAL>                 (. VAR at, ft: SymTab.TypeIndex;
+ 1022                                               qe, qa, qt: QbeGen.QVal;
+ 1023                                               isV, conv: BOOLEAN; .)
+ 1024      = Expr<at, qe>                      (. IF ind THEN
+ 1025                                               ft :=
+ 1026                                                 SymTab.ProcTypeParamType(pt,
+ 1027                                                   i);
+ 1028                                               isV :=
+ 1029                                                 SymTab.ProcTypeParamIsVar(pt,
+ 1030                                                   i)
+ 1031                                             ELSE
+ 1032                                               ft := SymTab.ParamType(pn, i);
+ 1033                                               isV := SymTab.ParamIsVar(pn, i)
+ 1034                                             END;
+ 1035                                             IF (at = SymTab.InvalidType)
+ 1036                                                OR (ft =
+ 1037                                                   SymTab.InvalidType) THEN
+ 1038                                             ELSIF isV THEN
+ 1039                                               IF NOT QbeGen.AddrOfVal(qe,
+ 1040                                                    qa) THEN
+ 1041                                                 SemError(233)
+ 1042                                               ELSIF NOT SymTab.VarParamOk(at,
+ 1043                                                        ft) THEN
+ 1044                                                 SemError(233)
+ 1045                                               ELSIF NOT QbeGen.CallArg(qa,
+ 1046                                                        "l") THEN
+ 1047                                                 SemError(233)
+ 1048                                               END
+ 1049                                             ELSE
+ 1050                                               IF (SymTab.ClassOf(at)
+ 1051                                                  = SymTab.ClChar)
+ 1052    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
+ 1053    AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
+ 1054         = SymTab.ClChar)
+ 1055    AND QbeGen.IsImm(qe) THEN
+ 1056                                                 (* 1-char string
+ 1057                                                    literal passed to
+ 1058                                                    ARRAY OF CHAR *)
+ 1059                                                 QbeGen.DeclCharStr(qe,
+ 1060                                                      qa);
+ 1061                                                 IF NOT QbeGen.CallArg(qa,
+ 1062                                                    "l") THEN
+ 1063                                                   SemError(233)
+ 1064                                                 END
+ 1065                                               ELSIF NOT SymTab.Assignable(at,
+ 1066                                                    ft) THEN
+ 1067                                                 SemError(233)
+ 1068                                               ELSE
+ 1069                                                 conv := (SymTab.ClassOf(
+ 1070                                                   ft) = SymTab.ClReal)
+ 1071   AND SymTab.IsIntFamily(at);
+ 1072                                                 IF conv THEN
+ 1073                                                   QbeGen.ConvIR(qe, qt);
+ 1074                                                   IF NOT QbeGen.CallArg(qt,
+ 1075                                                      "d") THEN
+ 1076                                                     SemError(233)
+ 1077                                                   END
+ 1078                                                 ELSIF NOT QbeGen.CallArg(qe,
+ 1079                                                   QbeGen.ArgClass(ft)) THEN
+ 1080                                                   SemError(233)
+ 1081                                                 END
+ 1082                                               END
+ 1083                                             END; .) .
+ 1084    IfStat                                (. VAR t: SymTab.TypeIndex;
+ 1085                                               q, lThen, lElse, lEnd:
+ 1086                                                 QbeGen.QVal;
+ 1087                                               hasElse: BOOLEAN; .)
+ 1088      = "IF"                              (. hasElse := FALSE; .)
+ 1089        Expr<t, q>                        (. IF NOT SymTab.BoolCheck(t) THEN
+ 1090                                               SemError(214) END;
+ 1091                                             QbeGen.NewLabel(lThen);
+ 1092                                             QbeGen.NewLabel(lElse);
+ 1093                                             QbeGen.NewLabel(lEnd);
+ 1094                                             QbeGen.Jnz(q, lThen, lElse);
+ 1095                                             QbeGen.EmitLabel(lThen); .)
+ 1096        "THEN" [ StatSeq ]                (. QbeGen.Jmp(lEnd); .)
+ 1097        { "ELSIF"                         (. QbeGen.EmitLabel(lElse);
+ 1098                                             QbeGen.NewLabel(lElse); .)
+ 1099          Expr<t, q>                      (. IF NOT SymTab.BoolCheck(t) THEN
+ 1100                                               SemError(214) END;
+ 1101                                             QbeGen.NewLabel(lThen);
+ 1102                                             QbeGen.Jnz(q, lThen, lElse);
+ 1103                                             QbeGen.EmitLabel(lThen); .)
+ 1104          "THEN" StatSeq                  (. QbeGen.Jmp(lEnd); .) }
+ 1105        [ "ELSE"                          (. QbeGen.EmitLabel(lElse);
+ 1106                                             hasElse := TRUE; .)
+ 1107          [ StatSeq ] ]
+ 1108        "END"                             (. IF hasElse THEN
  1109                                               QbeGen.EmitLabel(lEnd)
- 1110                                             END; .) .
- 1111    WhileStat                             (. VAR t: SymTab.TypeIndex;
- 1112                                               q, lTop, lBody, lEnd:
- 1113                                                 QbeGen.QVal; .)
- 1114      = "WHILE"                           (. QbeGen.NewLabel(lTop);
- 1115                                             QbeGen.NewLabel(lBody);
- 1116                                             QbeGen.NewLabel(lEnd);
- 1117                                             QbeGen.EmitLabel(lTop); .)
- 1118        Expr<t, q>                        (. IF NOT SymTab.BoolCheck(t) THEN
- 1119                                               SemError(214) END;
- 1120                                             QbeGen.Jnz(q, lBody, lEnd);
- 1121                                             QbeGen.EmitLabel(lBody); .)
- 1122        "DO" StatSeq                      (. QbeGen.Jmp(lTop); .)
- 1123        "END"                             (. QbeGen.EmitLabel(lEnd); .) .
- 1124    RepeatStat                            (. VAR t: SymTab.TypeIndex;
- 1125                                               q, lTop, lEnd: QbeGen.QVal; .)
- 1126      = "REPEAT"                          (. QbeGen.NewLabel(lTop);
- 1127                                             QbeGen.NewLabel(lEnd);
- 1128                                             QbeGen.EmitLabel(lTop); .)
- 1129        StatSeq
- 1130        "UNTIL" Expr<t, q>                (. IF NOT SymTab.BoolCheck(t) THEN
- 1131                                               SemError(214) END;
- 1132                                             QbeGen.Jnz(q, lEnd, lTop);
- 1133                                             QbeGen.EmitLabel(lEnd); .) .
- 1134    LoopStat                              (. VAR lTop, lEnd: QbeGen.QVal; .)
- 1135      = "LOOP"                            (. QbeGen.NewLabel(lTop);
- 1136                                             QbeGen.NewLabel(lEnd);
- 1137                                             QbeGen.PushLoop(lEnd);
- 1138                                             QbeGen.EmitLabel(lTop); .)
- 1139        StatSeq
- 1140        "END"                             (. QbeGen.Jmp(lTop);
- 1141                                             QbeGen.PopLoop;
- 1142                                             QbeGen.EmitLabel(lEnd); .) .
- 1143    (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
- 1144       Runtime direction would need a compare-select; the literal
- 1145       sign picks cslew/csegew at "DO" time. *)
- 1146    ForStat                               (. VAR lv: SymTab.Name;
- 1147                                               tlo, thi, tby:
- 1148                                                 SymTab.TypeIndex;
- 1149                                               qlo, qhi, qby, qt, qk, qb:
- 1150                                                 QbeGen.QVal;
- 1151                                               lTop, lBody, lEnd:
+ 1110                                             ELSE QbeGen.EmitLabel(lElse);
+ 1111                                               QbeGen.EmitLabel(lEnd)
+ 1112                                             END; .) .
+ 1113    WhileStat                             (. VAR t: SymTab.TypeIndex;
+ 1114                                               q, lTop, lBody, lEnd:
+ 1115                                                 QbeGen.QVal; .)
+ 1116      = "WHILE"                           (. QbeGen.NewLabel(lTop);
+ 1117                                             QbeGen.NewLabel(lBody);
+ 1118                                             QbeGen.NewLabel(lEnd);
+ 1119                                             QbeGen.EmitLabel(lTop); .)
+ 1120        Expr<t, q>                        (. IF NOT SymTab.BoolCheck(t) THEN
+ 1121                                               SemError(214) END;
+ 1122                                             QbeGen.Jnz(q, lBody, lEnd);
+ 1123                                             QbeGen.EmitLabel(lBody); .)
+ 1124        "DO" [ StatSeq ]                      (. QbeGen.Jmp(lTop); .)
+ 1125        "END"                             (. QbeGen.EmitLabel(lEnd); .) .
+ 1126    RepeatStat                            (. VAR t: SymTab.TypeIndex;
+ 1127                                               q, lTop, lEnd: QbeGen.QVal; .)
+ 1128      = "REPEAT"                          (. QbeGen.NewLabel(lTop);
+ 1129                                             QbeGen.NewLabel(lEnd);
+ 1130                                             QbeGen.EmitLabel(lTop); .)
+ 1131        [ StatSeq ]
+ 1132        "UNTIL" Expr<t, q>                (. IF NOT SymTab.BoolCheck(t) THEN
+ 1133                                               SemError(214) END;
+ 1134                                             QbeGen.Jnz(q, lEnd, lTop);
+ 1135                                             QbeGen.EmitLabel(lEnd); .) .
+ 1136    LoopStat                              (. VAR lTop, lEnd: QbeGen.QVal; .)
+ 1137      = "LOOP"                            (. QbeGen.NewLabel(lTop);
+ 1138                                             QbeGen.NewLabel(lEnd);
+ 1139                                             QbeGen.PushLoop(lEnd);
+ 1140                                             QbeGen.EmitLabel(lTop); .)
+ 1141        [ StatSeq ]
+ 1142        "END"                             (. QbeGen.Jmp(lTop);
+ 1143                                             QbeGen.PopLoop;
+ 1144                                             QbeGen.EmitLabel(lEnd); .) .
+ 1145    (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
+ 1146       Runtime direction would need a compare-select; the literal
+ 1147       sign picks cslew/csegew at "DO" time. *)
+ 1148    ForStat                               (. VAR lv: SymTab.Name;
+ 1149                                               tlo, thi, tby:
+ 1150                                                 SymTab.TypeIndex;
+ 1151                                               qlo, qhi, qby, qt, qk, qb:
  1152                                                 QbeGen.QVal;
- 1153                                               by: INTEGER;
- 1154                                               ok: BOOLEAN; .)
- 1155      = "FOR"                             (. by := 1; .)
- 1156        GetIdent<lv>                      (. ok := SymTab.Lookup(lv);
- 1157                                             IF NOT ok THEN
- 1158                                               SemError(201)
- 1159                                             ELSIF (SymTab.SymKind(lv) #
- 1160                                                    SymTab.KindVar)
- 1161   AND (SymTab.SymKind(lv) #
- 1162                                                   SymTab.KindParam) THEN
- 1163                                               SemError(220); ok := FALSE
- 1164                                             ELSIF NOT SymTab.IsIntFamily(
- 1165                                                     SymTab.SymType(lv)) THEN
- 1166                                               SemError(220); ok := FALSE
- 1167                                             END; .)
- 1168        ":=" Expr<tlo, qlo>               (. IF NOT SymTab.IsIntFamily(tlo) THEN
- 1169                                               SemError(220); ok := FALSE
- 1170                                             END; .)
- 1171        "TO" Expr<thi, qhi>               (. IF NOT SymTab.IsIntFamily(thi) THEN
- 1172                                               SemError(220); ok := FALSE
- 1173                                             END; .)
- 1174        [ "BY" Expr<tby, qby>             (. IF (tby #
- 1175                                               SymTab.InvalidType)
- 1176   AND NOT SymTab.IsIntFamily(tby) THEN
- 1177                                               SemError(220); ok := FALSE
- 1178                                             END;
- 1179                                             IF NOT SymTab.ConstInt(qby, by) THEN
- 1180                                               SemError(230); by := 1
- 1181                                             ELSIF by = 0 THEN
- 1182                                               SemError(220); by := 1
- 1183                                             END; .) ]
- 1184        "DO"                              (. IF ok THEN
- 1185                                               QbeGen.StoreVar(lv, qlo,
- 1186                                                 FALSE) END;
- 1187                                             QbeGen.NewLabel(lTop);
- 1188                                             QbeGen.NewLabel(lBody);
- 1189                                             QbeGen.NewLabel(lEnd);
- 1190                                             QbeGen.EmitLabel(lTop);
- 1191                                             QbeGen.LoadVar(lv, FALSE, qt);
- 1192                                             QbeGen.NewTemp(qk);
- 1193                                             IF by > 0 THEN
- 1194                                               QbeGen.Op3("cslew", qk,
- 1195                                                 qt, qhi, FALSE)
- 1196                                             ELSE QbeGen.Op3("csgew", qk,
- 1197                                               qt, qhi, FALSE)
- 1198                                             END;
- 1199                                             QbeGen.Jnz(qk, lBody, lEnd);
- 1200                                             QbeGen.EmitLabel(lBody); .)
- 1201        StatSeq
- 1202        "END"                             (. IF ok THEN
- 1203                                               QbeGen.LoadVar(lv, FALSE,
- 1204                                                 qt);
- 1205                                               QbeGen.IntStr(by, qb);
- 1206                                               QbeGen.NewTemp(qk);
- 1207                                               QbeGen.Op3("add", qk,
- 1208                                                 qt, qb, FALSE);
- 1209                                               QbeGen.StoreVar(lv, qk,
- 1210                                                 FALSE) END;
- 1211                                             QbeGen.Jmp(lTop);
- 1212                                             QbeGen.EmitLabel(lEnd); .) .
- 1213    CaseStat                              (. VAR tsel: SymTab.TypeIndex;
- 1214                                               qsel, lEnd: QbeGen.QVal; .)
- 1215      = "CASE" Expr<tsel, qsel>           (. QbeGen.NewLabel(lEnd); .)
- 1216        "OF" CaseAlt<tsel, qsel, lEnd>
- 1217        { "|" CaseAlt<tsel, qsel, lEnd> }
- 1218        [ "ELSE" StatSeq ]
- 1219        "END"                             (. QbeGen.EmitLabel(lEnd); .) .
- 1220    (* Compare-chain lowering: each alternative ends its match-tests
- 1221       with "jmp lAfter", so the no-match fallthrough skips the body:
- 1222       "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
- 1223       lAfter:". Falls into the next alternative, ELSE, or END. *)
- 1224    CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
- 1225            lEnd: QbeGen.QVal>            (. VAR lBody, lAfter: QbeGen.QVal; .)
- 1226      =                                   (. QbeGen.NewLabel(lBody);
- 1227                                             QbeGen.NewLabel(lAfter); .)
- 1228        CaseLabel<tsel, qsel, lBody>
- 1229        { "," CaseLabel<tsel, qsel, lBody> }
- 1230        ":"                               (. QbeGen.Jmp(lAfter);
- 1231                                             QbeGen.EmitLabel(lBody); .)
- 1232        StatSeq                           (. QbeGen.Jmp(lEnd);
- 1233                                             QbeGen.EmitLabel(lAfter); .) .
- 1234    CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
- 1235              lBody: QbeGen.QVal>         (. VAR t2, t3: SymTab.TypeIndex;
- 1236                                               q2, q3, qc, qd, qe:
- 1237                                                 QbeGen.QVal;
- 1238                                               lNext: QbeGen.QVal; .)
- 1239      = Expr<t2, q2>                      (. IF (t2 #
- 1240                                               SymTab.InvalidType)
- 1241   AND (tsel #
- 1242                                                 SymTab.InvalidType)
- 1243   AND ((SymTab.ClassOf(t2) =
- 1244                                                  SymTab.ClSet)
- 1245                                                 OR (SymTab.ClassOf(tsel) =
- 1246                                                     SymTab.ClSet)) THEN
- 1247                                               SemError(230)
- 1248                                             ELSIF (t2 #
- 1249                                               SymTab.InvalidType)
- 1250   AND (tsel #
- 1251                                                 SymTab.InvalidType)
- 1252   AND NOT SymTab.EqCheck(t2,
- 1253                                                   tsel) THEN
- 1254                                               SemError(213) END;
- 1255                                             IF NOT QbeGen.IsImm(q2) THEN
- 1256                                               SemError(230);
- 1257                                               QbeGen.CopyOp("0", q2)
- 1258                                             END;
- 1259                                             QbeGen.NewLabel(lNext);
- 1260                                             QbeGen.Cmp(SymTab.OpEq,
- 1261                                               qsel, q2, qc, FALSE);
- 1262                                             QbeGen.Jnz(qc, lBody, lNext);
- 1263                                             QbeGen.EmitLabel(lNext); .)
- 1264        [ ".." Expr<t3, q3>               (. IF (t3 #
- 1265                                               SymTab.InvalidType)
- 1266   AND (tsel #
- 1267                                                 SymTab.InvalidType)
- 1268   AND NOT SymTab.EqCheck(t3,
- 1269                                                   tsel) THEN
- 1270                                               SemError(213) END;
- 1271                                             IF NOT QbeGen.IsImm(q3) THEN
- 1272                                               SemError(230);
- 1273                                               QbeGen.CopyOp("0", q3)
- 1274                                             END;
- 1275                                             QbeGen.Cmp(SymTab.OpGe,
- 1276                                               qsel, q2, qc, FALSE);
- 1277                                             QbeGen.Cmp(SymTab.OpLe,
- 1278                                               qsel, q3, qd, FALSE);
- 1279                                             QbeGen.NewTemp(qe);
- 1280                                             QbeGen.Op3("and", qe, qc, qd,
- 1281                                               FALSE);
- 1282                                             QbeGen.NewLabel(lNext);
- 1283                                             QbeGen.Jnz(qe, lBody, lNext);
- 1284                                             QbeGen.EmitLabel(lNext); .) ] .
- 1285    ReturnStat                            (. VAR t: SymTab.TypeIndex;
- 1286                                               q, qt: QbeGen.QVal;
- 1287                                               res: SymTab.TypeIndex;
- 1288                                               hadE, conv: BOOLEAN; .)
- 1289      = "RETURN"                          (. hadE := FALSE; .)
- 1290        [ Expr<t, q>                      (. hadE := TRUE; .) ]
- 1291                                          (. conv := FALSE;
- 1292                                             IF NOT SymTab.InProc() THEN
- 1293                                               SemError(232)
- 1294                                             ELSE res := SymTab.CurRes();
- 1295                                               IF NOT hadE THEN
- 1296                                                 IF res #
- 1297                                                    SymTab.InvalidType THEN
- 1298                                                   SemError(232)
- 1299                                                 ELSE QbeGen.EmitRet(q,
- 1300                                                   FALSE)
- 1301                                                 END
- 1302                                               ELSIF (res =
- 1303                                                      SymTab.InvalidType)
- 1304                                                  OR (t #
+ 1153                                               lTop, lBody, lEnd:
+ 1154                                                 QbeGen.QVal;
+ 1155                                               by: INTEGER;
+ 1156                                               ok: BOOLEAN; .)
+ 1157      = "FOR"                             (. by := 1; .)
+ 1158        GetIdent<lv>                      (. ok := SymTab.Lookup(lv);
+ 1159                                             IF NOT ok THEN
+ 1160                                               SemError(201)
+ 1161                                             ELSIF (SymTab.SymKind(lv) #
+ 1162                                                    SymTab.KindVar)
+ 1163   AND (SymTab.SymKind(lv) #
+ 1164                                                   SymTab.KindParam) THEN
+ 1165                                               SemError(220); ok := FALSE
+ 1166                                             ELSIF NOT SymTab.IsIntFamily(
+ 1167                                                     SymTab.SymType(lv)) THEN
+ 1168                                               SemError(220); ok := FALSE
+ 1169                                             END; .)
+ 1170        ":=" Expr<tlo, qlo>               (. IF NOT SymTab.IsIntFamily(tlo) THEN
+ 1171                                               SemError(220); ok := FALSE
+ 1172                                             END; .)
+ 1173        "TO" Expr<thi, qhi>               (. IF NOT SymTab.IsIntFamily(thi) THEN
+ 1174                                               SemError(220); ok := FALSE
+ 1175                                             END; .)
+ 1176        [ "BY" Expr<tby, qby>             (. IF (tby #
+ 1177                                               SymTab.InvalidType)
+ 1178   AND NOT SymTab.IsIntFamily(tby) THEN
+ 1179                                               SemError(220); ok := FALSE
+ 1180                                             END;
+ 1181                                             IF NOT SymTab.ConstInt(qby, by) THEN
+ 1182                                               SemError(230); by := 1
+ 1183                                             ELSIF by = 0 THEN
+ 1184                                               SemError(220); by := 1
+ 1185                                             END; .) ]
+ 1186        "DO"                              (. IF ok THEN
+ 1187                                               QbeGen.StoreVar(lv, qlo,
+ 1188                                                 FALSE) END;
+ 1189                                             QbeGen.NewLabel(lTop);
+ 1190                                             QbeGen.NewLabel(lBody);
+ 1191                                             QbeGen.NewLabel(lEnd);
+ 1192                                             QbeGen.EmitLabel(lTop);
+ 1193                                             QbeGen.LoadVar(lv, FALSE, qt);
+ 1194                                             QbeGen.NewTemp(qk);
+ 1195                                             IF by > 0 THEN
+ 1196                                               QbeGen.Op3("cslew", qk,
+ 1197                                                 qt, qhi, FALSE)
+ 1198                                             ELSE QbeGen.Op3("csgew", qk,
+ 1199                                               qt, qhi, FALSE)
+ 1200                                             END;
+ 1201                                             QbeGen.Jnz(qk, lBody, lEnd);
+ 1202                                             QbeGen.EmitLabel(lBody); .)
+ 1203        [ StatSeq ]
+ 1204        "END"                             (. IF ok THEN
+ 1205                                               QbeGen.LoadVar(lv, FALSE,
+ 1206                                                 qt);
+ 1207                                               QbeGen.IntStr(by, qb);
+ 1208                                               QbeGen.NewTemp(qk);
+ 1209                                               QbeGen.Op3("add", qk,
+ 1210                                                 qt, qb, FALSE);
+ 1211                                               QbeGen.StoreVar(lv, qk,
+ 1212                                                 FALSE) END;
+ 1213                                             QbeGen.Jmp(lTop);
+ 1214                                             QbeGen.EmitLabel(lEnd); .) .
+ 1215    CaseStat                              (. VAR tsel: SymTab.TypeIndex;
+ 1216                                               qsel, lEnd: QbeGen.QVal; .)
+ 1217      = "CASE" Expr<tsel, qsel>           (. QbeGen.NewLabel(lEnd); .)
+ 1218        "OF" CaseAlt<tsel, qsel, lEnd>
+ 1219        { "|" CaseAlt<tsel, qsel, lEnd> }
+ 1220        [ "ELSE" [ StatSeq ] ]
+ 1221        "END"                             (. QbeGen.EmitLabel(lEnd); .) .
+ 1222    (* Compare-chain lowering: each alternative ends its match-tests
+ 1223       with "jmp lAfter", so the no-match fallthrough skips the body:
+ 1224       "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
+ 1225       lAfter:". Falls into the next alternative, ELSE, or END. *)
+ 1226    CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
+ 1227            lEnd: QbeGen.QVal>            (. VAR lBody, lAfter: QbeGen.QVal; .)
+ 1228      =                                   (. QbeGen.NewLabel(lBody);
+ 1229                                             QbeGen.NewLabel(lAfter); .)
+ 1230        CaseLabel<tsel, qsel, lBody>
+ 1231        { "," CaseLabel<tsel, qsel, lBody> }
+ 1232        ":"                               (. QbeGen.Jmp(lAfter);
+ 1233                                             QbeGen.EmitLabel(lBody); .)
+ 1234        [ StatSeq ]                       (. QbeGen.Jmp(lEnd);
+ 1235                                             QbeGen.EmitLabel(lAfter); .) .
+ 1236    CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
+ 1237              lBody: QbeGen.QVal>         (. VAR t2, t3: SymTab.TypeIndex;
+ 1238                                               q2, q3, qc, qd, qe:
+ 1239                                                 QbeGen.QVal;
+ 1240                                               lNext: QbeGen.QVal; .)
+ 1241      = Expr<t2, q2>                      (. IF (t2 #
+ 1242                                               SymTab.InvalidType)
+ 1243   AND (tsel #
+ 1244                                                 SymTab.InvalidType)
+ 1245   AND ((SymTab.ClassOf(t2) =
+ 1246                                                  SymTab.ClSet)
+ 1247                                                 OR (SymTab.ClassOf(tsel) =
+ 1248                                                     SymTab.ClSet)) THEN
+ 1249                                               SemError(230)
+ 1250                                             ELSIF (t2 #
+ 1251                                               SymTab.InvalidType)
+ 1252   AND (tsel #
+ 1253                                                 SymTab.InvalidType)
+ 1254   AND NOT SymTab.EqCheck(t2,
+ 1255                                                   tsel) THEN
+ 1256                                               SemError(213) END;
+ 1257                                             IF NOT QbeGen.IsImm(q2) THEN
+ 1258                                               SemError(230);
+ 1259                                               QbeGen.CopyOp("0", q2)
+ 1260                                             END;
+ 1261                                             QbeGen.NewLabel(lNext);
+ 1262                                             QbeGen.Cmp(SymTab.OpEq,
+ 1263                                               qsel, q2, qc, FALSE);
+ 1264                                             QbeGen.Jnz(qc, lBody, lNext);
+ 1265                                             QbeGen.EmitLabel(lNext); .)
+ 1266        [ ".." Expr<t3, q3>               (. IF (t3 #
+ 1267                                               SymTab.InvalidType)
+ 1268   AND (tsel #
+ 1269                                                 SymTab.InvalidType)
+ 1270   AND NOT SymTab.EqCheck(t3,
+ 1271                                                   tsel) THEN
+ 1272                                               SemError(213) END;
+ 1273                                             IF NOT QbeGen.IsImm(q3) THEN
+ 1274                                               SemError(230);
+ 1275                                               QbeGen.CopyOp("0", q3)
+ 1276                                             END;
+ 1277                                             QbeGen.Cmp(SymTab.OpGe,
+ 1278                                               qsel, q2, qc, FALSE);
+ 1279                                             QbeGen.Cmp(SymTab.OpLe,
+ 1280                                               qsel, q3, qd, FALSE);
+ 1281                                             QbeGen.NewTemp(qe);
+ 1282                                             QbeGen.Op3("and", qe, qc, qd,
+ 1283                                               FALSE);
+ 1284                                             QbeGen.NewLabel(lNext);
+ 1285                                             QbeGen.Jnz(qe, lBody, lNext);
+ 1286                                             QbeGen.EmitLabel(lNext); .) ] .
+ 1287    ReturnStat                            (. VAR t: SymTab.TypeIndex;
+ 1288                                               q, qt: QbeGen.QVal;
+ 1289                                               res: SymTab.TypeIndex;
+ 1290                                               hadE, conv: BOOLEAN; .)
+ 1291      = "RETURN"                          (. hadE := FALSE; .)
+ 1292        [ Expr<t, q>                      (. hadE := TRUE; .) ]
+ 1293                                          (. conv := FALSE;
+ 1294                                             IF NOT SymTab.InProc() THEN
+ 1295                                               SemError(232)
+ 1296                                             ELSE res := SymTab.CurRes();
+ 1297                                               IF NOT hadE THEN
+ 1298                                                 IF res #
+ 1299                                                    SymTab.InvalidType THEN
+ 1300                                                   SemError(232)
+ 1301                                                 ELSE QbeGen.EmitRet(q,
+ 1302                                                   FALSE)
+ 1303                                                 END
+ 1304                                               ELSIF (res =
  1305                                                      SymTab.InvalidType)
- 1306   AND NOT SymTab.Assignable(t,
- 1307                                                       res) THEN
- 1308                                                 SemError(232)
- 1309                                               ELSE
- 1310                                                 conv := (SymTab.ClassOf(
- 1311                                                   res) = SymTab.ClReal)
- 1312   AND SymTab.IsIntFamily(t);
- 1313                                                 IF conv THEN
- 1314                                                   QbeGen.ConvIR(q, qt);
- 1315                                                   QbeGen.EmitRet(qt, TRUE)
- 1316                                                 ELSE QbeGen.EmitRet(q, TRUE)
- 1317                                                 END
- 1318                                               END
- 1319                                             END; .) .
- 1320    (* Designator: scalar loads, array addresses, and index suffixes.
- 1321       Each index descends one level (bounds-checked, trap on breach);
- 1322       nested levels reload the inner descriptor address. q ends as the
- 1323       value (scalars), the descriptor address (plain arrays), or the
- 1324       element address (indexed); sfx marks the indexed form. *)
- 1325    Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
- 1326           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
- 1327                                          (. VAR n, fn, mal: SymTab.Name;
- 1328                                               cls: INTEGER;
- 1329                                               curT, it, eT, bt:
- 1330                                                 SymTab.TypeIndex;
- 1331                                               iq, ql, qlo, qhi, qe:
- 1332                                                 QbeGen.QVal;
- 1333                                               lo, hi: INTEGER;
- 1334                                               fo: INTEGER;
- 1335                                               isOpen: BOOLEAN;
- 1336                                               qb, cv: QbeGen.QVal; .)
- 1337      = GetIdent<n>                       (. QbeGen.CopyOp(n, qn);
- 1338                                             sfx := FALSE;
- 1339                                             IF NOT SymTab.Lookup(n) THEN
- 1340                                               SemError(201);
- 1341                                               t := SymTab.InvalidType;
- 1342                                               k := -1;
- 1343                                               QbeGen.CopyOp("0", q)
- 1344                                             ELSE
- 1345                                               t := SymTab.SymType(n);
- 1346                                               k := SymTab.SymKind(n);
- 1347                                               IF k = SymTab.KindConst THEN
- 1348                                                 IF SymTab.Equal(n,
- 1349                                                    "TRUE") THEN
- 1350                                                   t := SymTab.BoolType();
- 1351                                                   QbeGen.CopyOp("1", q)
- 1352                                                 ELSIF SymTab.Equal(n,
- 1353                                                    "FALSE") THEN
- 1354                                                   t := SymTab.BoolType();
- 1355                                                   QbeGen.CopyOp("0", q)
- 1356                                                 ELSIF SymTab.Equal(n,
- 1357                                                    "NIL") THEN
- 1358                                                   QbeGen.CopyOp("0", q)
- 1359                                                 ELSE
- 1360                                                   cls :=
- 1361                                                     SymTab.ClassOf(t);
- 1362                                                   IF (t #
- 1363                                                       SymTab.InvalidType)
- 1364   AND ((cls = SymTab.ClInt)
- 1365                                                      OR (cls
- 1366                                                          = SymTab.ClChar)
+ 1306                                                  OR (t #
+ 1307                                                      SymTab.InvalidType)
+ 1308   AND NOT SymTab.Assignable(t,
+ 1309                                                       res) THEN
+ 1310                                                 SemError(232)
+ 1311                                               ELSE
+ 1312                                                 conv := (SymTab.ClassOf(
+ 1313                                                   res) = SymTab.ClReal)
+ 1314   AND SymTab.IsIntFamily(t);
+ 1315                                                 IF conv THEN
+ 1316                                                   QbeGen.ConvIR(q, qt);
+ 1317                                                   QbeGen.EmitRet(qt, TRUE)
+ 1318                                                 ELSE QbeGen.EmitRet(q, TRUE)
+ 1319                                                 END
+ 1320                                               END
+ 1321                                             END; .) .
+ 1322    (* Designator: scalar loads, array addresses, and index suffixes.
+ 1323       Each index descends one level (bounds-checked, trap on breach);
+ 1324       nested levels reload the inner descriptor address. q ends as the
+ 1325       value (scalars), the descriptor address (plain arrays), or the
+ 1326       element address (indexed); sfx marks the indexed form. *)
+ 1327    Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
+ 1328           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
+ 1329                                          (. VAR n, fn, mal: SymTab.Name;
+ 1330                                               cls: INTEGER;
+ 1331                                               curT, it, eT, bt:
+ 1332                                                 SymTab.TypeIndex;
+ 1333                                               iq, ql, qlo, qhi, qe:
+ 1334                                                 QbeGen.QVal;
+ 1335                                               lo, hi: INTEGER;
+ 1336                                               fo: INTEGER;
+ 1337                                               isOpen: BOOLEAN;
+ 1338                                               qb, cv: QbeGen.QVal; .)
+ 1339      = GetIdent<n>                       (. QbeGen.CopyOp(n, qn);
+ 1340                                             sfx := FALSE;
+ 1341                                             IF NOT SymTab.Lookup(n) THEN
+ 1342                                               SemError(201);
+ 1343                                               t := SymTab.InvalidType;
+ 1344                                               k := -1;
+ 1345                                               QbeGen.CopyOp("0", q)
+ 1346                                             ELSE
+ 1347                                               t := SymTab.SymType(n);
+ 1348                                               k := SymTab.SymKind(n);
+ 1349                                               IF k = SymTab.KindConst THEN
+ 1350                                                 IF SymTab.Equal(n,
+ 1351                                                    "TRUE") THEN
+ 1352                                                   t := SymTab.BoolType();
+ 1353                                                   QbeGen.CopyOp("1", q)
+ 1354                                                 ELSIF SymTab.Equal(n,
+ 1355                                                    "FALSE") THEN
+ 1356                                                   t := SymTab.BoolType();
+ 1357                                                   QbeGen.CopyOp("0", q)
+ 1358                                                 ELSIF SymTab.Equal(n,
+ 1359                                                    "NIL") THEN
+ 1360                                                   QbeGen.CopyOp("0", q)
+ 1361                                                 ELSE
+ 1362                                                   cls :=
+ 1363                                                     SymTab.ClassOf(t);
+ 1364                                                   IF (t #
+ 1365                                                       SymTab.InvalidType)
+ 1366   AND ((cls = SymTab.ClInt)
  1367                                                      OR (cls
- 1368                                                          = SymTab.ClReal)
+ 1368                                                          = SymTab.ClChar)
  1369                                                      OR (cls
- 1370                                                          = SymTab.ClNil)) THEN
- 1371                                                     IF cls = SymTab.ClNil THEN
- 1372                                                       QbeGen.CopyOp("0", q)
- 1373                                                     ELSIF ((cls
- 1374                                                         = SymTab.ClInt)
- 1375                                                       OR (cls
- 1376                                                         = SymTab.ClChar))
- 1377    AND SymTab.GetSymVal(n, cv)
- 1378    AND QbeGen.IsImm(cv) THEN
- 1379                                                       QbeGen.CopyOp(cv, q)
- 1380                                                     ELSE
- 1381                                                       QbeGen.LoadVar(n,
- 1382                                                         cls = SymTab.ClReal,
- 1383                                                         q)
- 1384                                                     END
- 1385                                                   ELSE
- 1386                                                     IF t #
- 1387                                                        SymTab.InvalidType THEN
- 1388                                                       SemError(230)
- 1389                                                     END;
- 1390                                                     QbeGen.CopyOp("0", q)
- 1391                                                   END
- 1392                                                 END
- 1393                                               ELSIF (k = SymTab.KindVar)
- 1394                                                  OR (k = SymTab.KindParam) THEN
- 1395                                                 cls :=
- 1396                                                   SymTab.ClassOf(t);
- 1397                                                 IF (cls = SymTab.ClInt)
- 1398                                                    OR (cls = SymTab.ClBool)
- 1399                                                    OR (cls = SymTab.ClChar)
- 1400                                                    OR (cls
- 1401                                                        = SymTab.ClReal) THEN
- 1402                                                   QbeGen.LoadVar(n,
- 1403                                                     cls = SymTab.ClReal, q)
- 1404                                                 ELSIF (cls = SymTab.ClPtr)
- 1405                                                    OR (cls = SymTab.ClProc) THEN
- 1406                                                   QbeGen.LoadPtr(n, q)
- 1407                                                 ELSIF cls = SymTab.ClLong THEN
- 1408                                                   QbeGen.LoadLong(n, q)
- 1409                                                 ELSIF (cls
- 1410                                                         = SymTab.ClArray)
- 1411                                                    OR (cls
- 1412                                                        = SymTab.ClSet)
+ 1370                                                          = SymTab.ClReal)
+ 1371                                                      OR (cls
+ 1372                                                          = SymTab.ClNil)) THEN
+ 1373                                                     IF cls = SymTab.ClNil THEN
+ 1374                                                       QbeGen.CopyOp("0", q)
+ 1375                                                     ELSIF ((cls
+ 1376                                                         = SymTab.ClInt)
+ 1377                                                       OR (cls
+ 1378                                                         = SymTab.ClChar))
+ 1379    AND SymTab.GetSymVal(n, cv)
+ 1380    AND QbeGen.IsImm(cv) THEN
+ 1381                                                       QbeGen.CopyOp(cv, q)
+ 1382                                                     ELSE
+ 1383                                                       QbeGen.LoadVar(n,
+ 1384                                                         cls = SymTab.ClReal,
+ 1385                                                         q)
+ 1386                                                     END
+ 1387                                                   ELSE
+ 1388                                                     IF t #
+ 1389                                                        SymTab.InvalidType THEN
+ 1390                                                       SemError(230)
+ 1391                                                     END;
+ 1392                                                     QbeGen.CopyOp("0", q)
+ 1393                                                   END
+ 1394                                                 END
+ 1395                                               ELSIF (k = SymTab.KindVar)
+ 1396                                                  OR (k = SymTab.KindParam) THEN
+ 1397                                                 cls :=
+ 1398                                                   SymTab.ClassOf(t);
+ 1399                                                 IF (cls = SymTab.ClInt)
+ 1400                                                    OR (cls = SymTab.ClBool)
+ 1401                                                    OR (cls = SymTab.ClChar)
+ 1402                                                    OR (cls
+ 1403                                                        = SymTab.ClReal) THEN
+ 1404                                                   QbeGen.LoadVar(n,
+ 1405                                                     cls = SymTab.ClReal, q)
+ 1406                                                 ELSIF (cls = SymTab.ClPtr)
+ 1407                                                    OR (cls = SymTab.ClProc) THEN
+ 1408                                                   QbeGen.LoadPtr(n, q)
+ 1409                                                 ELSIF cls = SymTab.ClLong THEN
+ 1410                                                   QbeGen.LoadLong(n, q)
+ 1411                                                 ELSIF (cls
+ 1412                                                         = SymTab.ClArray)
  1413                                                    OR (cls
- 1414                                                        = SymTab.ClRecord)
+ 1414                                                        = SymTab.ClSet)
  1415                                                    OR (cls
- 1416                                                        = SymTab.ClClass) THEN
- 1417                                                   QbeGen.AddrOf(n, q)
- 1418                                                 ELSE SemError(230);
- 1419                                                   QbeGen.CopyOp("0", q)
- 1420                                                 END
- 1421                                               ELSE QbeGen.CopyOp("0", q);
- 1422                                                 IF k = SymTab.KindImport THEN
- 1423                                                   SemError(230)
- 1424                                                 ELSIF k =
- 1425                                                    SymTab.KindProc THEN
- 1426                                                   (* bare procedure name:
- 1427                                                      a following ArgList
- 1428                                                      makes it a call;
- 1429                                                      otherwise Fact
- 1430                                                      reports 230 *)
- 1431                                                 ELSE
- 1432                                                   IF k = SymTab.KindField THEN
- 1433                                                     IF QbeGen.TopWith(qb) THEN
- 1434                                                       fo :=
- 1435                                                         SymTab.FieldOffset(
- 1436                                                         SymTab.FieldOwner(n),
- 1437                                                         n);
- 1438                                                       QbeGen.FieldAddr(qb,
- 1439                                                         fo, q);
- 1440                                                       sfx := TRUE
- 1441                                                     ELSE SemError(230);
- 1442                                                       QbeGen.CopyOp("0", q)
- 1443                                                     END
- 1444                                                   END
- 1445                                                 END
- 1446                                               END
- 1447                                             END; .)
- 1448        { "[" Expr<it, iq>
- 1449                                          (. IF t = SymTab.InvalidType THEN
- 1450                                             ELSIF SymTab.ClassOf(t) #
- 1451                                                   SymTab.ClArray THEN
- 1452                                               SemError(217);
- 1453                                               t := SymTab.InvalidType
- 1454                                             ELSIF NOT SymTab.IsIntFamily(it)
- 1455   AND (SymTab.ClassOf(it) #
- 1456                                                   SymTab.ClChar) THEN
- 1457                                               SemError(218);
- 1458                                               t := SymTab.InvalidType
- 1459                                             ELSE
- 1460                                               QbeGen.WidenIndex(iq, ql);
- 1461                                               isOpen :=
- 1462                                                 SymTab.IsOpenArray(t);
- 1463                                               IF isOpen THEN
- 1464                                                 QbeGen.CopyOp("0", qlo);
- 1465                                                 QbeGen.OpenHi(q, qhi)
- 1466                                               ELSE
- 1467                                                 lo := SymTab.ArrayLo(t);
- 1468                                                 hi := SymTab.ArrayHi(t);
- 1469                                                 QbeGen.IntStr(lo, qlo);
- 1470                                                 QbeGen.IntStr(hi, qhi)
- 1471                                               END;
- 1472                                               QbeGen.CheckRange(ql, qlo,
- 1473                                                 qhi);
- 1474                                               eT := SymTab.ArrayElem(t);
- 1475                                               QbeGen.ElemAddr(q, ql, qlo,
- 1476                                                 t, qe);
- 1477                                               IF SymTab.ClassOf(eT) =
- 1478                                                  SymTab.ClArray THEN
- 1479                                                 QbeGen.ElemLoad(qe, eT, q)
- 1480                                               ELSE QbeGen.CopyOp(qe, q)
- 1481                                               END;
- 1482                                               t := eT; sfx := TRUE
- 1483                                             END; .)
- 1484          { "," Expr<it, iq>
- 1485                                          (. IF t = SymTab.InvalidType THEN
- 1486                                             ELSIF SymTab.ClassOf(t) #
- 1487                                                   SymTab.ClArray THEN
- 1488                                               SemError(217);
- 1489                                               t := SymTab.InvalidType
- 1490                                             ELSIF NOT SymTab.IsIntFamily(it)
- 1491   AND (SymTab.ClassOf(it) #
- 1492                                                   SymTab.ClChar) THEN
- 1493                                               SemError(218);
- 1494                                               t := SymTab.InvalidType
- 1495                                             ELSE
- 1496                                               QbeGen.WidenIndex(iq, ql);
- 1497                                               isOpen :=
- 1498                                                 SymTab.IsOpenArray(t);
- 1499                                               IF isOpen THEN
- 1500                                                 QbeGen.CopyOp("0", qlo);
- 1501                                                 QbeGen.OpenHi(q, qhi)
- 1502                                               ELSE
- 1503                                                 lo := SymTab.ArrayLo(t);
- 1504                                                 hi := SymTab.ArrayHi(t);
- 1505                                                 QbeGen.IntStr(lo, qlo);
- 1506                                                 QbeGen.IntStr(hi, qhi)
- 1507                                               END;
- 1508                                               QbeGen.CheckRange(ql, qlo,
- 1509                                                 qhi);
- 1510                                               eT := SymTab.ArrayElem(t);
- 1511                                               QbeGen.ElemAddr(q, ql, qlo,
- 1512                                                 t, qe);
- 1513                                               IF SymTab.ClassOf(eT) =
- 1514                                                  SymTab.ClArray THEN
- 1515                                                 QbeGen.ElemLoad(qe, eT, q)
- 1516                                               ELSE QbeGen.CopyOp(qe, q)
- 1517                                               END;
- 1518                                               t := eT; sfx := TRUE
- 1519                                             END; .) }
- 1520          "]"
- 1521        | "." GetIdent<fn>
- 1522                                          (. IF k = SymTab.KindModule THEN
- 1523                                               (* qualified L.x: materialize
- 1524                                                  the export, then load it *)
- 1525                                               IF NOT SymTab.MaterializeAlias(n,
- 1526                                                    fn, mal) THEN
- 1527                                                 SemError(201);
- 1528                                                 t := SymTab.InvalidType;
- 1529                                                 QbeGen.CopyOp("0", q)
- 1530                                               ELSE
- 1531                                                 QbeGen.CopyOp(mal, qn);
- 1532                                                 t := SymTab.SymType(mal);
- 1533                                                 k := SymTab.SymKind(mal);
- 1534                                                 sfx := FALSE;
- 1535                                                 IF k = SymTab.KindProc THEN
- 1536                                                   (* call: ArgList supplies
- 1537                                                      the value *)
- 1538                                                   QbeGen.CopyOp("0", q)
- 1539                                                 ELSIF NOT QbeGen.LoadDesignator(
- 1540                                                      mal, t, k, q) THEN
- 1541                                                   SemError(230);
- 1542                                                   QbeGen.CopyOp("0", q)
- 1543                                                 END
- 1544                                               END
- 1545                                             ELSIF t = SymTab.InvalidType THEN
- 1546                                             ELSIF (SymTab.ClassOf(t) #
- 1547                                                    SymTab.ClRecord)
- 1548   AND (SymTab.ClassOf(t) #
- 1549                                                   SymTab.ClClass) THEN
- 1550                                               SemError(215);
- 1551                                               t := SymTab.InvalidType
- 1552                                             ELSIF NOT SymTab.FieldExists(t,
- 1553                                                      fn) THEN
- 1554                                               SemError(216);
- 1555                                               t := SymTab.InvalidType
- 1556                                             ELSE
- 1557                                               fo := SymTab.FieldOffset(t,
- 1558                                                 fn);
- 1559                                               t := SymTab.FieldType(t, fn);
- 1560                                               QbeGen.FieldAddr(q, fo, qe);
- 1561                                               IF SymTab.ClassOf(t) =
- 1562                                                  SymTab.ClArray THEN
- 1563                                                 QbeGen.ElemLoad(qe, t, q)
- 1564                                               ELSE QbeGen.CopyOp(qe, q)
- 1565                                               END;
- 1566                                               sfx := TRUE
- 1567                                             END; .)
- 1568        | "^"
- 1569                                          (. IF t = SymTab.InvalidType THEN
- 1570                                             ELSIF SymTab.ClassOf(t) #
- 1571                                                   SymTab.ClPtr THEN
- 1572                                               SemError(219);
- 1573                                               t := SymTab.InvalidType
- 1574                                             ELSE
- 1575                                               bt := SymTab.PtrBase(t);
- 1576                                               IF bt = SymTab.InvalidType THEN
- 1577                                               ELSE
- 1578                                                 IF sfx THEN
- 1579                                                   QbeGen.ElemLoad(q, t,
- 1580                                                     qb);
- 1581                                                   QbeGen.CopyOp(qb, q)
- 1582                                                 END;
- 1583                                                 t := bt;
- 1584                                                 IF (SymTab.ClassOf(bt) =
- 1585                                                    SymTab.ClInt)
- 1586                                                    OR (SymTab.ClassOf(bt) =
- 1587                                                        SymTab.ClBool)
+ 1416                                                        = SymTab.ClRecord)
+ 1417                                                    OR (cls
+ 1418                                                        = SymTab.ClClass) THEN
+ 1419                                                   QbeGen.AddrOf(n, q)
+ 1420                                                 ELSE SemError(230);
+ 1421                                                   QbeGen.CopyOp("0", q)
+ 1422                                                 END
+ 1423                                               ELSE QbeGen.CopyOp("0", q);
+ 1424                                                 IF k = SymTab.KindImport THEN
+ 1425                                                   SemError(230)
+ 1426                                                 ELSIF k =
+ 1427                                                    SymTab.KindProc THEN
+ 1428                                                   (* bare procedure name:
+ 1429                                                      a following ArgList
+ 1430                                                      makes it a call;
+ 1431                                                      otherwise Fact
+ 1432                                                      reports 230 *)
+ 1433                                                 ELSE
+ 1434                                                   IF k = SymTab.KindField THEN
+ 1435                                                     IF QbeGen.TopWith(qb) THEN
+ 1436                                                       fo :=
+ 1437                                                         SymTab.FieldOffset(
+ 1438                                                         SymTab.FieldOwner(n),
+ 1439                                                         n);
+ 1440                                                       QbeGen.FieldAddr(qb,
+ 1441                                                         fo, q);
+ 1442                                                       sfx := TRUE
+ 1443                                                     ELSE SemError(230);
+ 1444                                                       QbeGen.CopyOp("0", q)
+ 1445                                                     END
+ 1446                                                   END
+ 1447                                                 END
+ 1448                                               END
+ 1449                                             END; .)
+ 1450        { "[" Expr<it, iq>
+ 1451                                          (. IF t = SymTab.InvalidType THEN
+ 1452                                             ELSIF SymTab.ClassOf(t) #
+ 1453                                                   SymTab.ClArray THEN
+ 1454                                               SemError(217);
+ 1455                                               t := SymTab.InvalidType
+ 1456                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 1457   AND (SymTab.ClassOf(it) #
+ 1458                                                   SymTab.ClChar) THEN
+ 1459                                               SemError(218);
+ 1460                                               t := SymTab.InvalidType
+ 1461                                             ELSE
+ 1462                                               QbeGen.WidenIndex(iq, ql);
+ 1463                                               isOpen :=
+ 1464                                                 SymTab.IsOpenArray(t);
+ 1465                                               IF isOpen THEN
+ 1466                                                 QbeGen.CopyOp("0", qlo);
+ 1467                                                 QbeGen.OpenHi(q, qhi)
+ 1468                                               ELSE
+ 1469                                                 lo := SymTab.ArrayLo(t);
+ 1470                                                 hi := SymTab.ArrayHi(t);
+ 1471                                                 QbeGen.IntStr(lo, qlo);
+ 1472                                                 QbeGen.IntStr(hi, qhi)
+ 1473                                               END;
+ 1474                                               QbeGen.CheckRange(ql, qlo,
+ 1475                                                 qhi);
+ 1476                                               eT := SymTab.ArrayElem(t);
+ 1477                                               QbeGen.ElemAddr(q, ql, qlo,
+ 1478                                                 t, qe);
+ 1479                                               IF SymTab.ClassOf(eT) =
+ 1480                                                  SymTab.ClArray THEN
+ 1481                                                 QbeGen.ElemLoad(qe, eT, q)
+ 1482                                               ELSE QbeGen.CopyOp(qe, q)
+ 1483                                               END;
+ 1484                                               t := eT; sfx := TRUE
+ 1485                                             END; .)
+ 1486          { "," Expr<it, iq>
+ 1487                                          (. IF t = SymTab.InvalidType THEN
+ 1488                                             ELSIF SymTab.ClassOf(t) #
+ 1489                                                   SymTab.ClArray THEN
+ 1490                                               SemError(217);
+ 1491                                               t := SymTab.InvalidType
+ 1492                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 1493   AND (SymTab.ClassOf(it) #
+ 1494                                                   SymTab.ClChar) THEN
+ 1495                                               SemError(218);
+ 1496                                               t := SymTab.InvalidType
+ 1497                                             ELSE
+ 1498                                               QbeGen.WidenIndex(iq, ql);
+ 1499                                               isOpen :=
+ 1500                                                 SymTab.IsOpenArray(t);
+ 1501                                               IF isOpen THEN
+ 1502                                                 QbeGen.CopyOp("0", qlo);
+ 1503                                                 QbeGen.OpenHi(q, qhi)
+ 1504                                               ELSE
+ 1505                                                 lo := SymTab.ArrayLo(t);
+ 1506                                                 hi := SymTab.ArrayHi(t);
+ 1507                                                 QbeGen.IntStr(lo, qlo);
+ 1508                                                 QbeGen.IntStr(hi, qhi)
+ 1509                                               END;
+ 1510                                               QbeGen.CheckRange(ql, qlo,
+ 1511                                                 qhi);
+ 1512                                               eT := SymTab.ArrayElem(t);
+ 1513                                               QbeGen.ElemAddr(q, ql, qlo,
+ 1514                                                 t, qe);
+ 1515                                               IF SymTab.ClassOf(eT) =
+ 1516                                                  SymTab.ClArray THEN
+ 1517                                                 QbeGen.ElemLoad(qe, eT, q)
+ 1518                                               ELSE QbeGen.CopyOp(qe, q)
+ 1519                                               END;
+ 1520                                               t := eT; sfx := TRUE
+ 1521                                             END; .) }
+ 1522          "]"
+ 1523        | "." GetIdent<fn>
+ 1524                                          (. IF k = SymTab.KindModule THEN
+ 1525                                               (* qualified L.x: materialize
+ 1526                                                  the export, then load it *)
+ 1527                                               IF NOT SymTab.MaterializeAlias(n,
+ 1528                                                    fn, mal) THEN
+ 1529                                                 SemError(201);
+ 1530                                                 t := SymTab.InvalidType;
+ 1531                                                 QbeGen.CopyOp("0", q)
+ 1532                                               ELSE
+ 1533                                                 QbeGen.CopyOp(mal, qn);
+ 1534                                                 t := SymTab.SymType(mal);
+ 1535                                                 k := SymTab.SymKind(mal);
+ 1536                                                 sfx := FALSE;
+ 1537                                                 IF k = SymTab.KindProc THEN
+ 1538                                                   (* call: ArgList supplies
+ 1539                                                      the value *)
+ 1540                                                   QbeGen.CopyOp("0", q)
+ 1541                                                 ELSIF NOT QbeGen.LoadDesignator(
+ 1542                                                      mal, t, k, q) THEN
+ 1543                                                   SemError(230);
+ 1544                                                   QbeGen.CopyOp("0", q)
+ 1545                                                 END
+ 1546                                               END
+ 1547                                             ELSIF t = SymTab.InvalidType THEN
+ 1548                                             ELSIF (SymTab.ClassOf(t) #
+ 1549                                                    SymTab.ClRecord)
+ 1550   AND (SymTab.ClassOf(t) #
+ 1551                                                   SymTab.ClClass) THEN
+ 1552                                               SemError(215);
+ 1553                                               t := SymTab.InvalidType
+ 1554                                             ELSIF NOT SymTab.FieldExists(t,
+ 1555                                                      fn) THEN
+ 1556                                               SemError(216);
+ 1557                                               t := SymTab.InvalidType
+ 1558                                             ELSE
+ 1559                                               fo := SymTab.FieldOffset(t,
+ 1560                                                 fn);
+ 1561                                               t := SymTab.FieldType(t, fn);
+ 1562                                               QbeGen.FieldAddr(q, fo, qe);
+ 1563                                               IF SymTab.ClassOf(t) =
+ 1564                                                  SymTab.ClArray THEN
+ 1565                                                 QbeGen.ElemLoad(qe, t, q)
+ 1566                                               ELSE QbeGen.CopyOp(qe, q)
+ 1567                                               END;
+ 1568                                               sfx := TRUE
+ 1569                                             END; .)
+ 1570        | "^"
+ 1571                                          (. IF t = SymTab.InvalidType THEN
+ 1572                                             ELSIF SymTab.ClassOf(t) #
+ 1573                                                   SymTab.ClPtr THEN
+ 1574                                               SemError(219);
+ 1575                                               t := SymTab.InvalidType
+ 1576                                             ELSE
+ 1577                                               bt := SymTab.PtrBase(t);
+ 1578                                               IF bt = SymTab.InvalidType THEN
+ 1579                                               ELSE
+ 1580                                                 IF sfx THEN
+ 1581                                                   QbeGen.ElemLoad(q, t,
+ 1582                                                     qb);
+ 1583                                                   QbeGen.CopyOp(qb, q)
+ 1584                                                 END;
+ 1585                                                 t := bt;
+ 1586                                                 IF (SymTab.ClassOf(bt) =
+ 1587                                                    SymTab.ClInt)
  1588                                                    OR (SymTab.ClassOf(bt) =
- 1589                                                        SymTab.ClChar)
+ 1589                                                        SymTab.ClBool)
  1590                                                    OR (SymTab.ClassOf(bt) =
- 1591                                                        SymTab.ClReal) THEN
- 1592                                                   sfx := TRUE
- 1593                                                 ELSE sfx := FALSE
- 1594                                                 END
- 1595                                               END
- 1596                                             END; .) } .
- 1597    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1598                                          (. VAR t2: SymTab.TypeIndex;
- 1599                                               op: INTEGER;
- 1600                                               q2, qt, wl: QbeGen.QVal;
- 1601                                               isR: BOOLEAN; .)
- 1602      = SimExpr<t, q>
- 1603        [ Rel<op> SimExpr<t2, q2>
- 1604          (. IF op = SymTab.OpIn THEN
- 1605               IF SymTab.InCheck(t, t2) THEN
- 1606                 IF (t = SymTab.InvalidType)
- 1607                    OR (t2 = SymTab.InvalidType) THEN
- 1608                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 1609                 ELSE
- 1610                   QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2),
- 1611                     SymTab.SetCount(t2), qt);
- 1612                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 1613                 END
- 1614               ELSE SemError(222); t := SymTab.InvalidType;
- 1615                 QbeGen.CopyOp("0", q)
- 1616               END
- 1617             ELSIF SymTab.RelCheck(t, t2, op) THEN
- 1618               IF (t = SymTab.InvalidType)
- 1619                  OR (t2 = SymTab.InvalidType) THEN
- 1620                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 1621               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
- 1622                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
- 1623                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
- 1624   AND (op # SymTab.OpNeq2) THEN
- 1625                   SemError(213); t := SymTab.InvalidType;
- 1626                   QbeGen.CopyOp("0", q)
- 1627                 ELSE
- 1628                   QbeGen.CmpL(op, q, q2, qt);
- 1629                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 1630                 END
- 1631               ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
- 1632                  OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 1633                 QbeGen.CmpSet(op, q, q2,
- 1634                   SymTab.SetWords(t), SymTab.SetWords(t2), qt);
- 1635                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 1636               ELSIF SymTab.IsLongFamily(t)
- 1637                  OR SymTab.IsLongFamily(t2) THEN
- 1638                 IF SymTab.IsIntFamily(t) THEN
- 1639                   QbeGen.WidenLong(q, wl); QbeGen.CopyOp(wl, q)
- 1640                 END;
- 1641                 IF SymTab.IsIntFamily(t2) THEN
- 1642                   QbeGen.WidenLong(q2, wl); QbeGen.CopyOp(wl, q2)
- 1643                 END;
- 1644                 QbeGen.CmpLong(op, q, q2, qt);
- 1645                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 1646               ELSE
- 1647                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 1648                 t := SymTab.BoolType();
- 1649                 QbeGen.Cmp(op, q, q2, qt, isR);
- 1650                 QbeGen.CopyOp(qt, q)
- 1651               END
- 1652             ELSE SemError(213); t := SymTab.InvalidType;
- 1653               QbeGen.CopyOp("0", q)
- 1654             END; .) ] .
- 1655    Rel<VAR op: INTEGER>
- 1656      = "="                               (. op := SymTab.OpEq; .)
- 1657      | "#"                               (. op := SymTab.OpNeq1; .)
- 1658      | "<"                               (. op := SymTab.OpLt; .)
- 1659      | "<="                              (. op := SymTab.OpLe; .)
- 1660      | ">"                               (. op := SymTab.OpGt; .)
- 1661      | ">="                              (. op := SymTab.OpGe; .)
- 1662      | "IN"                              (. op := SymTab.OpIn; .) .
- 1663    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1664                                          (. VAR t2, res2, lt, rt:
- 1665                                                 SymTab.TypeIndex;
- 1666                                               op: INTEGER;
- 1667                                               q2, qt, wq, qf:
- 1668                                                 QbeGen.QVal;
- 1669                                               neg, isR, isL, folded:
- 1670                                                 BOOLEAN;
- 1671                                               lw, rw, mw: CARDINAL; .)
- 1672      =                                   (. neg := FALSE; .)
- 1673        [ "+" | "-"                       (. neg := TRUE; .) ]
- 1674        Term<t, q>                        (. IF neg THEN
- 1675                                             IF QbeGen.IsImm(q) THEN
- 1676                                               QbeGen.NegFold(q, q)
- 1677                                             ELSE QbeGen.NewTemp(qt);
- 1678                                               QbeGen.NegQ(q, qt,
- 1679                                                 SymTab.ClassOf(t)
- 1680                                                 = SymTab.ClReal);
- 1681                                               QbeGen.CopyOp(qt, q)
- 1682                                             END
- 1683                                           END; .)
- 1684        { AddOp<op> Term<t2, q2>
- 1685          (. IF op = SymTab.OpOr THEN
- 1686               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 1687                 t := SymTab.BoolType()
- 1688               ELSE SemError(212); t := SymTab.InvalidType END;
- 1689               IF t # SymTab.InvalidType THEN
- 1690                 QbeGen.NewTemp(qt);
- 1691                 QbeGen.Op3("or", qt, q, q2, FALSE);
- 1692                 QbeGen.CopyOp(qt, q)
- 1693               ELSE QbeGen.CopyOp("0", q)
- 1694               END
- 1695             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 1696   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 1697   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 1698               lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 1699               mw := lw;
- 1700               IF rw > mw THEN mw := rw END;
- 1701               IF op = SymTab.OpAdd THEN
- 1702                 QbeGen.SetBinOp(0, q, q2, lw, rw, qt)
- 1703               ELSE
- 1704                 QbeGen.SetBinOp(2, q, q2, lw, rw, qt)
- 1705               END;
- 1706               t := SymTab.NewSet(
- 1707                      SymTab.NewSubR(0,
- 1708                        VAL(INTEGER, mw) * 32 - 1));
- 1709               QbeGen.CopyOp(qt, q)
- 1710             ELSE
- 1711               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
- 1712                 lt := t; rt := t2; t := res2
- 1713               ELSE SemError(211); t := SymTab.InvalidType END;
- 1714               IF t # SymTab.InvalidType THEN
- 1715                 isL := SymTab.IsLongFamily(t);
- 1716                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 1717                 folded := FALSE;
- 1718                 IF (NOT isL) AND (NOT isR)
- 1719    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 1720                   IF op = SymTab.OpAdd THEN
- 1721                     folded := QbeGen.Fold2(0, q, q2, qf)
- 1722                   ELSE
- 1723                     folded := QbeGen.Fold2(1, q, q2, qf)
- 1724                   END
- 1725                 END;
- 1726                 IF folded THEN QbeGen.CopyOp(qf, q)
- 1727                 ELSE
- 1728                 IF isL THEN
- 1729                   IF SymTab.IsIntFamily(lt) THEN
- 1730                     QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
- 1731                   END;
- 1732                   IF SymTab.IsIntFamily(rt) THEN
- 1733                     QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
- 1734                   END;
- 1735                   QbeGen.NewTemp(qt);
- 1736                   IF op = SymTab.OpAdd THEN
- 1737                     QbeGen.Op3L("add", qt, q, q2)
- 1738                   ELSE
- 1739                     QbeGen.Op3L("sub", qt, q, q2)
- 1740                   END
- 1741                 ELSE
- 1742                   QbeGen.NewTemp(qt);
- 1743                   IF op = SymTab.OpAdd THEN
- 1744                     QbeGen.Op3("add", qt, q, q2, isR)
- 1745                   ELSE
- 1746                     QbeGen.Op3("sub", qt, q, q2, isR)
- 1747                   END
- 1748                 END;
- 1749                 QbeGen.CopyOp(qt, q)
- 1750                 END
- 1751               ELSE QbeGen.CopyOp("0", q)
- 1752               END
- 1753             END; .) } .
- 1754    AddOp<VAR op: INTEGER>
- 1755      = "+"                               (. op := SymTab.OpAdd; .)
- 1756      | "-"                               (. op := SymTab.OpSub; .)
- 1757      | "OR"                              (. op := SymTab.OpOr; .) .
- 1758    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1759                                          (. VAR t2, res2, lt, rt:
- 1760                                                 SymTab.TypeIndex;
- 1761                                               op: INTEGER;
- 1762                                               q2, qt, wq, qf:
- 1763                                                 QbeGen.QVal;
- 1764                                               isR, isL, folded: BOOLEAN;
- 1765                                               lw, rw, mw: CARDINAL; .)
- 1766      = Fact<t, q> { MulOp<op> Fact<t2, q2>
- 1767        (. IF op = SymTab.OpAnd THEN
- 1768             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 1769               t := SymTab.BoolType()
- 1770             ELSE SemError(212); t := SymTab.InvalidType END;
- 1771             IF t # SymTab.InvalidType THEN
- 1772               QbeGen.NewTemp(qt);
- 1773               QbeGen.Op3("and", qt, q, q2, FALSE);
- 1774               QbeGen.CopyOp(qt, q)
- 1775             ELSE QbeGen.CopyOp("0", q)
- 1776             END
- 1777           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 1778   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 1779   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 1780             lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 1781             mw := lw;
- 1782             IF rw > mw THEN mw := rw END;
- 1783             IF op = SymTab.OpTimes THEN
- 1784               QbeGen.SetBinOp(1, q, q2, lw, rw, qt)
- 1785             ELSE
- 1786               QbeGen.SetBinOp(3, q, q2, lw, rw, qt)
- 1787             END;
- 1788             t := SymTab.NewSet(
- 1789                    SymTab.NewSubR(0,
- 1790                      VAL(INTEGER, mw) * 32 - 1));
- 1791             QbeGen.CopyOp(qt, q)
- 1792           ELSE
- 1793             IF SymTab.ArithCheck(t, t2,
- 1794                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
- 1795                  res2) THEN
- 1796               lt := t; rt := t2; t := res2
- 1797             ELSE SemError(211); t := SymTab.InvalidType END;
- 1798             IF t # SymTab.InvalidType THEN
- 1799               isL := SymTab.IsLongFamily(t);
- 1800               isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 1801               folded := FALSE;
- 1802               IF (NOT isL) AND (NOT isR)
- 1803    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 1804                 IF op = SymTab.OpTimes THEN
- 1805                   folded := QbeGen.Fold2(2, q, q2, qf)
- 1806                 ELSIF op = SymTab.OpDiv THEN
- 1807                   folded := QbeGen.Fold2(3, q, q2, qf)
- 1808                 ELSIF op = SymTab.OpMod THEN
- 1809                   folded := QbeGen.Fold2(4, q, q2, qf)
- 1810                 END
- 1811               END;
- 1812               IF folded THEN QbeGen.CopyOp(qf, q)
- 1813               ELSE
- 1814               IF isL THEN
- 1815                 IF SymTab.IsIntFamily(lt) THEN
- 1816                   QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
- 1817                 END;
- 1818                 IF SymTab.IsIntFamily(rt) THEN
- 1819                   QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
- 1820                 END;
- 1821                 QbeGen.NewTemp(qt);
- 1822                 IF op = SymTab.OpTimes THEN
- 1823                   QbeGen.Op3L("mul", qt, q, q2)
- 1824                 ELSIF (op = SymTab.OpDiv)
- 1825                    OR (op = SymTab.OpSlash) THEN
- 1826                   QbeGen.Op3L("div", qt, q, q2)
- 1827                 ELSE
- 1828                   QbeGen.Op3L("rem", qt, q, q2)
- 1829                 END
- 1830               ELSE
- 1831                 QbeGen.NewTemp(qt);
- 1832                 IF op = SymTab.OpTimes THEN
- 1833                   QbeGen.Op3("mul", qt, q, q2, isR)
- 1834                 ELSIF (op = SymTab.OpDiv)
- 1835                    OR (op = SymTab.OpSlash) THEN
- 1836                   QbeGen.Op3("div", qt, q, q2, isR)
- 1837                 ELSE
- 1838                   QbeGen.Op3("rem", qt, q, q2, isR)
- 1839                 END
- 1840               END;
- 1841               QbeGen.CopyOp(qt, q)
- 1842               END
- 1843             ELSE QbeGen.CopyOp("0", q)
- 1844             END
- 1845           END; .) } .
- 1846    MulOp<VAR op: INTEGER>
- 1847      = "*"                               (. op := SymTab.OpTimes; .)
- 1848      | "/"                               (. op := SymTab.OpSlash; .)
- 1849      | "DIV"                             (. op := SymTab.OpDiv; .)
- 1850      | "MOD"                             (. op := SymTab.OpMod; .)
- 1851      | "AND"                             (. op := SymTab.OpAnd; .) .
- 1852    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1853                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
- 1854                                               et, dt, t2, st, ct2:
- 1855                                                 SymTab.TypeIndex;
- 1856                                               dk: INTEGER;
- 1857                                               qd, q2, sq, qa, qm0, qr:
- 1858                                                 QbeGen.QVal;
- 1859                                               qn, vn: SymTab.Name;
- 1860                                               vt: SymTab.TypeIndex;
- 1861                                               c1, c2: INTEGER;
- 1862                                               called, isHigh, sfx:
- 1863                                                 BOOLEAN; .)
- 1864      = integer                           (. LexString(s);
- 1865                                             QbeGen.NormInt(s, q);
- 1866                                             t := SymTab.IntType(); .)
- 1867      | real                              (. LexString(s);
- 1868                                             QbeGen.NormReal(s, q);
- 1869                                             t := SymTab.RealType(); .)
- 1870      | string                            (. LexString(s);
- 1871                                             IF SymTab.StrLen(s) = 3 THEN
- 1872                                               t := SymTab.CharType();
- 1873                                               QbeGen.IntStr(
- 1874                                                 QbeGen.CharVal(s), q)
- 1875                                             ELSE t := SymTab.NewStr();
- 1876                                               QbeGen.DeclStr(s, q);
- 1877                                               (* a literal's value IS its
- 1878                                                  static descriptor address *)
- 1879                                               QbeGen.NoteAddr(q, q)
- 1880                                             END; .)
- 1881      | Design<dt, dk, qd, qn, sfx>       (. called := FALSE;
- 1882                                             t := dt;
- 1883                                             IF sfx THEN
- 1884                                               IF dt =
- 1885                                                  SymTab.InvalidType THEN
- 1886                                                 QbeGen.CopyOp("0", q)
- 1887                                               ELSIF (SymTab.ClassOf(dt) =
- 1888                                                      SymTab.ClRecord)
- 1889                                                  OR (SymTab.ClassOf(dt) =
- 1890                                                      SymTab.ClSet)
- 1891                                                  OR (SymTab.ClassOf(dt) =
- 1892                                                      SymTab.ClArray)
- 1893                                                  OR (SymTab.ClassOf(dt) =
- 1894                                                      SymTab.ClClass) THEN
- 1895                                                 QbeGen.CopyOp(qd, q)
- 1896                                               ELSE QbeGen.ElemLoad(qd, dt,
- 1897                                                 q)
- 1898                                               END
- 1899                                             ELSE QbeGen.CopyOp(qd, q)
- 1900                                             END;
- 1901                                             IF (dk = SymTab.KindVar)
- 1902                                                OR (dk = SymTab.KindParam)
- 1903                                                OR (dk =
- 1904                                                   SymTab.KindField) THEN
- 1905                                               IF sfx THEN
- 1906                                                 QbeGen.NoteAddr(q, qd)
- 1907                                               ELSE
- 1908                                                 QbeGen.AddrOf(qn, qa);
- 1909                                                 QbeGen.NoteAddr(q, qa)
- 1910                                               END
- 1911                                             ELSIF sfx
- 1912   AND (dt #
- 1913                                                   SymTab.InvalidType)
- 1914   AND ((SymTab.ClassOf(dt) =
- 1915                                                    SymTab.ClArray)
- 1916                                                   OR (SymTab.ClassOf(dt) =
- 1917                                                       SymTab.ClSet)
- 1918                                                   OR (SymTab.ClassOf(dt) =
- 1919                                                       SymTab.ClRecord)) THEN
- 1920                                               QbeGen.NoteAddr(qd, qd)
- 1921                                             END; .)
- 1922        [ ArgList<qn, dt, qd, TRUE, ct2, q2, called>
- 1923                                          (. t := ct2;
- 1924                                             QbeGen.CopyOp(q2, q); .) ]
- 1925                                          (. IF NOT called
- 1926   AND (dk = SymTab.KindProc) THEN
- 1927                                               (* bare zero-arg function
- 1928                                                  call (parentheses may be
- 1929                                                  omitted); a proper or
- 1930                                                  parameterised proc here
- 1931                                                  is 230 *)
- 1932                                               IF (SymTab.ProcNPar(qn) = 0)
- 1933   AND (SymTab.ProcRes(qn) #
- 1934                                                     SymTab.InvalidType) THEN
- 1935                                                 QbeGen.Mangled(qn,
- 1936                                                   SymTab.ProcUid(qn), qm0);
- 1937                                                 QbeGen.CallBegin(qm0,
- 1938                                                   SymTab.ProcRes(qn),
- 1939                                                   SymTab.ProcDepthOf(qn),
- 1940                                                   SymTab.IsExternal(qn));
- 1941                                                 QbeGen.CallEnd(TRUE, q);
- 1942                                                 t := SymTab.ProcRes(qn)
- 1943                                               ELSE
- 1944                                                 (* procedure used as a
- 1945                                                    value (assign to a
- 1946                                                    procedure variable):
- 1947                                                    its code address *)
- 1948                                                 t := SymTab.ProcTypeOf(qn);
- 1949                                                 QbeGen.Mangled(qn,
- 1950                                                   SymTab.ProcUid(qn), qm0);
- 1951                                                 QbeGen.ProcAddr(qm0, q)
- 1952                                               END
- 1953                                             END; .)
- 1954      | ( "HIGH"                          (. isHigh := TRUE; .)
- 1955        | "LEN"                           (. isHigh := FALSE; .) )
- 1956        "(" Design<dt, dk, qd, qn, sfx> ")"
- 1957                                          (. IF dt = SymTab.InvalidType THEN
- 1958                                             ELSIF SymTab.ClassOf(dt) #
- 1959                                                   SymTab.ClArray THEN
- 1960                                               SemError(217);
- 1961                                               t := SymTab.InvalidType;
- 1962                                               QbeGen.CopyOp("0", q)
- 1963                                             ELSE
- 1964                                               IF isHigh THEN
- 1965                                                 IF SymTab.IsOpenArray(dt) THEN
- 1966                                                   QbeGen.OpenHi(qd, qr)
- 1967                                                 ELSE
- 1968                                                   QbeGen.IntStr(
- 1969                                                     SymTab.ArrayHi(dt), qr)
- 1970                                                 END
- 1971                                               ELSE
- 1972                                                 IF SymTab.IsOpenArray(dt) THEN
- 1973                                                   QbeGen.LoadCount(qd, qr)
- 1974                                                 ELSE
- 1975                                                   QbeGen.IntStr(VAL(
- 1976                                                     INTEGER,
- 1977                                                     SymTab.ArrayLen(dt)),
- 1978                                                     qr)
- 1979                                                 END
- 1980                                               END;
- 1981                                                t := SymTab.IntType();
- 1982                                                QbeGen.CopyOp(qr, q)
- 1983                                              END; .)
- 1984      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
- 1985                                          (. IF dt = SymTab.InvalidType THEN
- 1986                                               t := SymTab.InvalidType;
- 1987                                               QbeGen.CopyOp("0", q)
- 1988                                             ELSE
- 1989                                               QbeGen.IntStr(VAL(INTEGER,
- 1990                                                 SymTab.ObjectSize(dt)), q);
- 1991                                               t := SymTab.IntType()
- 1992                                             END; .)
- 1993      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
- 1994                                          (. IF dt = SymTab.InvalidType THEN
- 1995                                               t := SymTab.InvalidType;
- 1996                                               QbeGen.CopyOp("0", q)
- 1997                                             ELSE
- 1998                                               IF sfx THEN
- 1999                                                 QbeGen.CopyOp(qd, q)
- 2000                                               ELSIF (dk = SymTab.KindVar)
- 2001                                                  OR (dk = SymTab.KindParam) THEN
- 2002                                                 QbeGen.AddrOf(qn, q)
- 2003                                               ELSE SemError(230);
- 2004                                                 QbeGen.CopyOp("0", q)
- 2005                                               END;
- 2006                                               t := SymTab.AddrType()
- 2007                                             END; .)
- 2008      | "CHR" "(" Expr<et, q> ")"
- 2009                                          (. IF (et # SymTab.InvalidType)
- 2010   AND NOT SymTab.IsIntFamily(et) THEN
- 2011                                               SemError(211) END;
- 2012                                             t := SymTab.CharType(); .)
- 2013      | "ORD" "(" Expr<et, q> ")"
- 2014                                          (. IF et # SymTab.InvalidType THEN
- 2015                                               IF (SymTab.ClassOf(et) #
- 2016                                                   SymTab.ClChar)
- 2017   AND (SymTab.ClassOf(et) #
- 2018                                                     SymTab.ClBool)
- 2019   AND (SymTab.ClassOf(et) #
- 2020                                                     SymTab.ClEnum)
- 2021   AND NOT SymTab.IsIntFamily(et) THEN
- 2022                                                 SemError(211) END
- 2023                                             END;
- 2024                                             t := SymTab.IntType(); .)
- 2025      | "ABS" "(" Expr<et, q> ")"
- 2026                                          (. IF (et # SymTab.InvalidType)
- 2027   AND NOT SymTab.IsIntFamily(et)
- 2028   AND (SymTab.ClassOf(et) #
- 2029                                                  SymTab.ClReal) THEN
- 2030                                               SemError(211)
- 2031                                             ELSE QbeGen.AbsQ(q, qa,
- 2032                                                    SymTab.ClassOf(et) =
- 2033                                                      SymTab.ClReal)
- 2034                                             END;
- 2035                                             t := et; .)
- 2036      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
- 2037                                          (. IF NOT SymTab.Lookup(vn) THEN
- 2038                                               SemError(201);
- 2039                                               t := SymTab.InvalidType
- 2040                                             ELSE vt := SymTab.SymType(vn);
- 2041                                               IF vt = SymTab.InvalidType THEN
- 2042                                                 t := SymTab.InvalidType
- 2043                                               ELSIF et =
- 2044                                                  SymTab.InvalidType THEN
- 2045                                                 t := vt
- 2046                                               ELSE
- 2047                                                 c1 := SymTab.ClassOf(et);
- 2048                                                 c2 := SymTab.ClassOf(vt);
- 2049                                                 IF ((c1 = SymTab.ClInt)
- 2050                                                     OR (c1 =
- 2051                                                        SymTab.ClChar)
- 2052                                                     OR (c1 =
- 2053                                                        SymTab.ClBool)
- 2054                                                     OR (c1 =
- 2055                                                        SymTab.ClEnum))
- 2056   AND ((c2 = SymTab.ClInt)
- 2057                                                     OR (c2 =
- 2058                                                        SymTab.ClChar)
- 2059                                                     OR (c2 =
- 2060                                                        SymTab.ClBool)
- 2061                                                     OR (c2 =
- 2062                                                        SymTab.ClEnum)) THEN
- 2063                                                   t := vt
- 2064                                                 ELSIF (c1 = SymTab.ClPtr)
- 2065   AND (c2 = SymTab.ClPtr) THEN
- 2066                                                   t := vt
- 2067                                                 ELSIF (c1 = SymTab.ClReal)
- 2068   AND (c2 = SymTab.ClReal) THEN
- 2069                                                   t := vt
- 2070                                                 ELSE SemError(230);
- 2071                                                   t := SymTab.InvalidType
- 2072                                                 END
- 2073                                               END
- 2074                                             END; .)
- 2075      | "(" Expr<et, q> ")"               (. t := et; .)
- 2076      | SetLit<st, sq>                    (. t := st;
- 2077                                             QbeGen.CopyOp(sq, q); .)
- 2078      | "NOT" Fact<t2, q2>                (. IF SymTab.BoolCheck(t2) THEN
- 2079                                               t := SymTab.BoolType()
- 2080                                             ELSE SemError(212);
- 2081                                               t := SymTab.InvalidType END;
- 2082                                             IF t # SymTab.InvalidType THEN
- 2083                                               QbeGen.NotQ(q2, q)
- 2084                                             ELSE QbeGen.CopyOp("0", q)
- 2085                                             END; .) .
- 2086    (* Set literals are SET OF [0..255] (8 words); elements validated
- 2087       0..255 statically when foldable (222 otherwise), runtime trap
- 2088       for computed elements. Ranges always lower via SetRange. *)
- 2089    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2090      = "{"                               (. t := SymTab.NewSet(
- 2091                                               SymTab.NewSubR(0, 255));
- 2092                                             QbeGen.NewSetTemp(8, q);
- 2093                                             QbeGen.SetZero(q, 8); .)
- 2094        [ SetElem<t, q> { "," SetElem<t, q> } ]
- 2095        "}" .
- 2096    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
- 2097                                               qe, q2: QbeGen.QVal;
- 2098                                               v, v2: INTEGER;
- 2099                                               lo: INTEGER;
- 2100                                               span: CARDINAL;
- 2101                                               cl, cl2: INTEGER;
- 2102                                               hasR: BOOLEAN; .)
- 2103      =                                   (. hasR := FALSE; .)
- 2104        Expr<et, qe>
- 2105        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
- 2106                                          (. lo := SymTab.SetBaseLo(st);
- 2107                                             span := SymTab.SetCount(st);
- 2108                                             IF (et = SymTab.InvalidType)
- 2109                                                OR (hasR AND (et2 =
- 2110                                                   SymTab.InvalidType)) THEN
- 2111                                             ELSE cl :=
- 2112                                                    SymTab.ClassOf(et);
- 2113                                               IF hasR THEN
- 2114                                                 cl2 :=
- 2115                                                   SymTab.ClassOf(et2)
- 2116                                               ELSE cl2 := SymTab.ClInt
- 2117                                               END;
- 2118                                               IF ((cl # SymTab.ClInt)
- 2119   AND (cl # SymTab.ClChar)
- 2120   AND (cl # SymTab.ClBool))
- 2121                                                  OR (hasR AND 
- 2122                                                     ((cl2
- 2123                                                       # SymTab.ClInt)
- 2124   AND (cl2
- 2125                                                        # SymTab.ClChar)
- 2126   AND (cl2
- 2127                                                        # SymTab.ClBool))) THEN
- 2128                                                 SemError(222)
- 2129                                               ELSIF hasR
- 2130   AND SymTab.ConstInt(qe, v)
- 2131   AND SymTab.ConstInt(q2,
- 2132                                                     v2)
- 2133   AND ((v < lo)
- 2134                                                     OR (v2 < lo)
- 2135                                                     OR (v >= lo +
- 2136                                                        VAL(INTEGER, span))
- 2137                                                     OR (v2 >= lo +
- 2138                                                        VAL(INTEGER, span))
- 2139                                                     OR (v > v2)) THEN
- 2140                                                 SemError(222)
- 2141                                                ELSIF hasR THEN
- 2142                                                  QbeGen.SetRange(sq, qe, q2,
- 2143                                                    lo, span)
- 2144                                                ELSIF SymTab.ConstInt(qe,
- 2145                                                        v)
- 2146   AND ((v < lo)
- 2147                                                      OR (v >= lo +
- 2148                                                         VAL(INTEGER,
- 2149                                                           span))) THEN
- 2150                                                  SemError(222)
- 2151                                                ELSE QbeGen.SetBit(sq, qe,
- 2152                                                  lo, span)
- 2153                                               END
- 2154                                             END; .) .
- 2155    GetIdent<VAR n: SymTab.Name>
- 2156      = ident                             (. LexName(n); .) .
- 2157  
- 2158  END M2.
+ 1591                                                        SymTab.ClChar)
+ 1592                                                    OR (SymTab.ClassOf(bt) =
+ 1593                                                        SymTab.ClReal) THEN
+ 1594                                                   sfx := TRUE
+ 1595                                                 ELSE sfx := FALSE
+ 1596                                                 END
+ 1597                                               END
+ 1598                                             END; .) } .
+ 1599    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1600                                          (. VAR t2: SymTab.TypeIndex;
+ 1601                                               op: INTEGER;
+ 1602                                               q2, qt, wl: QbeGen.QVal;
+ 1603                                               isR: BOOLEAN; .)
+ 1604      = SimExpr<t, q>
+ 1605        [ Rel<op> SimExpr<t2, q2>
+ 1606          (. IF op = SymTab.OpIn THEN
+ 1607               IF SymTab.InCheck(t, t2) THEN
+ 1608                 IF (t = SymTab.InvalidType)
+ 1609                    OR (t2 = SymTab.InvalidType) THEN
+ 1610                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 1611                 ELSE
+ 1612                   QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2),
+ 1613                     SymTab.SetCount(t2), qt);
+ 1614                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 1615                 END
+ 1616               ELSE SemError(222); t := SymTab.InvalidType;
+ 1617                 QbeGen.CopyOp("0", q)
+ 1618               END
+ 1619             ELSIF SymTab.RelCheck(t, t2, op) THEN
+ 1620               IF (t = SymTab.InvalidType)
+ 1621                  OR (t2 = SymTab.InvalidType) THEN
+ 1622                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 1623               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
+ 1624                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
+ 1625                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
+ 1626   AND (op # SymTab.OpNeq2) THEN
+ 1627                   SemError(213); t := SymTab.InvalidType;
+ 1628                   QbeGen.CopyOp("0", q)
+ 1629                 ELSE
+ 1630                   QbeGen.CmpL(op, q, q2, qt);
+ 1631                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 1632                 END
+ 1633               ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
+ 1634                  OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 1635                 QbeGen.CmpSet(op, q, q2,
+ 1636                   SymTab.SetWords(t), SymTab.SetWords(t2), qt);
+ 1637                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 1638               ELSIF SymTab.IsLongFamily(t)
+ 1639                  OR SymTab.IsLongFamily(t2) THEN
+ 1640                 IF SymTab.IsIntFamily(t) THEN
+ 1641                   QbeGen.WidenLong(q, wl); QbeGen.CopyOp(wl, q)
+ 1642                 END;
+ 1643                 IF SymTab.IsIntFamily(t2) THEN
+ 1644                   QbeGen.WidenLong(q2, wl); QbeGen.CopyOp(wl, q2)
+ 1645                 END;
+ 1646                 QbeGen.CmpLong(op, q, q2, qt);
+ 1647                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 1648               ELSE
+ 1649                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 1650                 t := SymTab.BoolType();
+ 1651                 QbeGen.Cmp(op, q, q2, qt, isR);
+ 1652                 QbeGen.CopyOp(qt, q)
+ 1653               END
+ 1654             ELSE SemError(213); t := SymTab.InvalidType;
+ 1655               QbeGen.CopyOp("0", q)
+ 1656             END; .) ] .
+ 1657    Rel<VAR op: INTEGER>
+ 1658      = "="                               (. op := SymTab.OpEq; .)
+ 1659      | "#"                               (. op := SymTab.OpNeq1; .)
+ 1660      | "<"                               (. op := SymTab.OpLt; .)
+ 1661      | "<="                              (. op := SymTab.OpLe; .)
+ 1662      | ">"                               (. op := SymTab.OpGt; .)
+ 1663      | ">="                              (. op := SymTab.OpGe; .)
+ 1664      | "IN"                              (. op := SymTab.OpIn; .) .
+ 1665    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1666                                          (. VAR t2, res2, lt, rt:
+ 1667                                                 SymTab.TypeIndex;
+ 1668                                               op: INTEGER;
+ 1669                                               q2, qt, wq, qf:
+ 1670                                                 QbeGen.QVal;
+ 1671                                               neg, isR, isL, folded:
+ 1672                                                 BOOLEAN;
+ 1673                                               lw, rw, mw: CARDINAL; .)
+ 1674      =                                   (. neg := FALSE; .)
+ 1675        [ "+" | "-"                       (. neg := TRUE; .) ]
+ 1676        Term<t, q>                        (. IF neg THEN
+ 1677                                             IF QbeGen.IsImm(q) THEN
+ 1678                                               QbeGen.NegFold(q, q)
+ 1679                                             ELSE QbeGen.NewTemp(qt);
+ 1680                                               QbeGen.NegQ(q, qt,
+ 1681                                                 SymTab.ClassOf(t)
+ 1682                                                 = SymTab.ClReal);
+ 1683                                               QbeGen.CopyOp(qt, q)
+ 1684                                             END
+ 1685                                           END; .)
+ 1686        { AddOp<op> Term<t2, q2>
+ 1687          (. IF op = SymTab.OpOr THEN
+ 1688               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 1689                 t := SymTab.BoolType()
+ 1690               ELSE SemError(212); t := SymTab.InvalidType END;
+ 1691               IF t # SymTab.InvalidType THEN
+ 1692                 QbeGen.NewTemp(qt);
+ 1693                 QbeGen.Op3("or", qt, q, q2, FALSE);
+ 1694                 QbeGen.CopyOp(qt, q)
+ 1695               ELSE QbeGen.CopyOp("0", q)
+ 1696               END
+ 1697             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 1698   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 1699   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 1700               lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 1701               mw := lw;
+ 1702               IF rw > mw THEN mw := rw END;
+ 1703               IF op = SymTab.OpAdd THEN
+ 1704                 QbeGen.SetBinOp(0, q, q2, lw, rw, qt)
+ 1705               ELSE
+ 1706                 QbeGen.SetBinOp(2, q, q2, lw, rw, qt)
+ 1707               END;
+ 1708               t := SymTab.NewSet(
+ 1709                      SymTab.NewSubR(0,
+ 1710                        VAL(INTEGER, mw) * 32 - 1));
+ 1711               QbeGen.CopyOp(qt, q)
+ 1712             ELSE
+ 1713               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
+ 1714                 lt := t; rt := t2; t := res2
+ 1715               ELSE SemError(211); t := SymTab.InvalidType END;
+ 1716               IF t # SymTab.InvalidType THEN
+ 1717                 isL := SymTab.IsLongFamily(t);
+ 1718                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 1719                 folded := FALSE;
+ 1720                 IF (NOT isL) AND (NOT isR)
+ 1721    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 1722                   IF op = SymTab.OpAdd THEN
+ 1723                     folded := QbeGen.Fold2(0, q, q2, qf)
+ 1724                   ELSE
+ 1725                     folded := QbeGen.Fold2(1, q, q2, qf)
+ 1726                   END
+ 1727                 END;
+ 1728                 IF folded THEN QbeGen.CopyOp(qf, q)
+ 1729                 ELSE
+ 1730                 IF isL THEN
+ 1731                   IF SymTab.IsIntFamily(lt) THEN
+ 1732                     QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
+ 1733                   END;
+ 1734                   IF SymTab.IsIntFamily(rt) THEN
+ 1735                     QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
+ 1736                   END;
+ 1737                   QbeGen.NewTemp(qt);
+ 1738                   IF op = SymTab.OpAdd THEN
+ 1739                     QbeGen.Op3L("add", qt, q, q2)
+ 1740                   ELSE
+ 1741                     QbeGen.Op3L("sub", qt, q, q2)
+ 1742                   END
+ 1743                 ELSE
+ 1744                   QbeGen.NewTemp(qt);
+ 1745                   IF op = SymTab.OpAdd THEN
+ 1746                     QbeGen.Op3("add", qt, q, q2, isR)
+ 1747                   ELSE
+ 1748                     QbeGen.Op3("sub", qt, q, q2, isR)
+ 1749                   END
+ 1750                 END;
+ 1751                 QbeGen.CopyOp(qt, q)
+ 1752                 END
+ 1753               ELSE QbeGen.CopyOp("0", q)
+ 1754               END
+ 1755             END; .) } .
+ 1756    AddOp<VAR op: INTEGER>
+ 1757      = "+"                               (. op := SymTab.OpAdd; .)
+ 1758      | "-"                               (. op := SymTab.OpSub; .)
+ 1759      | "OR"                              (. op := SymTab.OpOr; .) .
+ 1760    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1761                                          (. VAR t2, res2, lt, rt:
+ 1762                                                 SymTab.TypeIndex;
+ 1763                                               op: INTEGER;
+ 1764                                               q2, qt, wq, qf:
+ 1765                                                 QbeGen.QVal;
+ 1766                                               isR, isL, folded: BOOLEAN;
+ 1767                                               lw, rw, mw: CARDINAL; .)
+ 1768      = Fact<t, q> { MulOp<op> Fact<t2, q2>
+ 1769        (. IF op = SymTab.OpAnd THEN
+ 1770             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 1771               t := SymTab.BoolType()
+ 1772             ELSE SemError(212); t := SymTab.InvalidType END;
+ 1773             IF t # SymTab.InvalidType THEN
+ 1774               QbeGen.NewTemp(qt);
+ 1775               QbeGen.Op3("and", qt, q, q2, FALSE);
+ 1776               QbeGen.CopyOp(qt, q)
+ 1777             ELSE QbeGen.CopyOp("0", q)
+ 1778             END
+ 1779           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 1780   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 1781   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 1782             lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 1783             mw := lw;
+ 1784             IF rw > mw THEN mw := rw END;
+ 1785             IF op = SymTab.OpTimes THEN
+ 1786               QbeGen.SetBinOp(1, q, q2, lw, rw, qt)
+ 1787             ELSE
+ 1788               QbeGen.SetBinOp(3, q, q2, lw, rw, qt)
+ 1789             END;
+ 1790             t := SymTab.NewSet(
+ 1791                    SymTab.NewSubR(0,
+ 1792                      VAL(INTEGER, mw) * 32 - 1));
+ 1793             QbeGen.CopyOp(qt, q)
+ 1794           ELSE
+ 1795             IF SymTab.ArithCheck(t, t2,
+ 1796                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
+ 1797                  res2) THEN
+ 1798               lt := t; rt := t2; t := res2
+ 1799             ELSE SemError(211); t := SymTab.InvalidType END;
+ 1800             IF t # SymTab.InvalidType THEN
+ 1801               isL := SymTab.IsLongFamily(t);
+ 1802               isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 1803               folded := FALSE;
+ 1804               IF (NOT isL) AND (NOT isR)
+ 1805    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 1806                 IF op = SymTab.OpTimes THEN
+ 1807                   folded := QbeGen.Fold2(2, q, q2, qf)
+ 1808                 ELSIF op = SymTab.OpDiv THEN
+ 1809                   folded := QbeGen.Fold2(3, q, q2, qf)
+ 1810                 ELSIF op = SymTab.OpMod THEN
+ 1811                   folded := QbeGen.Fold2(4, q, q2, qf)
+ 1812                 END
+ 1813               END;
+ 1814               IF folded THEN QbeGen.CopyOp(qf, q)
+ 1815               ELSE
+ 1816               IF isL THEN
+ 1817                 IF SymTab.IsIntFamily(lt) THEN
+ 1818                   QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
+ 1819                 END;
+ 1820                 IF SymTab.IsIntFamily(rt) THEN
+ 1821                   QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
+ 1822                 END;
+ 1823                 QbeGen.NewTemp(qt);
+ 1824                 IF op = SymTab.OpTimes THEN
+ 1825                   QbeGen.Op3L("mul", qt, q, q2)
+ 1826                 ELSIF (op = SymTab.OpDiv)
+ 1827                    OR (op = SymTab.OpSlash) THEN
+ 1828                   QbeGen.Op3L("div", qt, q, q2)
+ 1829                 ELSE
+ 1830                   QbeGen.Op3L("rem", qt, q, q2)
+ 1831                 END
+ 1832               ELSE
+ 1833                 QbeGen.NewTemp(qt);
+ 1834                 IF op = SymTab.OpTimes THEN
+ 1835                   QbeGen.Op3("mul", qt, q, q2, isR)
+ 1836                 ELSIF (op = SymTab.OpDiv)
+ 1837                    OR (op = SymTab.OpSlash) THEN
+ 1838                   QbeGen.Op3("div", qt, q, q2, isR)
+ 1839                 ELSE
+ 1840                   QbeGen.Op3("rem", qt, q, q2, isR)
+ 1841                 END
+ 1842               END;
+ 1843               QbeGen.CopyOp(qt, q)
+ 1844               END
+ 1845             ELSE QbeGen.CopyOp("0", q)
+ 1846             END
+ 1847           END; .) } .
+ 1848    MulOp<VAR op: INTEGER>
+ 1849      = "*"                               (. op := SymTab.OpTimes; .)
+ 1850      | "/"                               (. op := SymTab.OpSlash; .)
+ 1851      | "DIV"                             (. op := SymTab.OpDiv; .)
+ 1852      | "MOD"                             (. op := SymTab.OpMod; .)
+ 1853      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
+ 1854    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1855                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
+ 1856                                               et, dt, t2, st, ct2:
+ 1857                                                 SymTab.TypeIndex;
+ 1858                                               dk: INTEGER;
+ 1859                                               qd, q2, sq, qa, qm0, qr:
+ 1860                                                 QbeGen.QVal;
+ 1861                                               qn, vn: SymTab.Name;
+ 1862                                               vt: SymTab.TypeIndex;
+ 1863                                               c1, c2: INTEGER;
+ 1864                                               called, isHigh, sfx, isCh:
+ 1865                                                 BOOLEAN; .)
+ 1866      = integer                           (. LexString(s);
+ 1867                                             QbeGen.NormInt(s, q);
+ 1868                                             t := SymTab.IntType(); .)
+ 1869      | charConst                         (. LexString(s);
+ 1870                                             QbeGen.NormLit(s, q, isCh);
+ 1871                                             t := SymTab.CharType(); .)
+ 1872      | real                              (. LexString(s);
+ 1873                                             QbeGen.NormReal(s, q);
+ 1874                                             t := SymTab.RealType(); .)
+ 1875      | string                            (. LexString(s);
+ 1876                                             IF SymTab.StrLen(s) = 3 THEN
+ 1877                                               t := SymTab.CharType();
+ 1878                                               QbeGen.IntStr(
+ 1879                                                 QbeGen.CharVal(s), q)
+ 1880                                             ELSE t := SymTab.NewStr();
+ 1881                                               QbeGen.DeclStr(s, q);
+ 1882                                               (* a literal's value IS its
+ 1883                                                  static descriptor address *)
+ 1884                                               QbeGen.NoteAddr(q, q)
+ 1885                                             END; .)
+ 1886      | Design<dt, dk, qd, qn, sfx>       (. called := FALSE;
+ 1887                                             t := dt;
+ 1888                                             IF sfx THEN
+ 1889                                               IF dt =
+ 1890                                                  SymTab.InvalidType THEN
+ 1891                                                 QbeGen.CopyOp("0", q)
+ 1892                                               ELSIF (SymTab.ClassOf(dt) =
+ 1893                                                      SymTab.ClRecord)
+ 1894                                                  OR (SymTab.ClassOf(dt) =
+ 1895                                                      SymTab.ClSet)
+ 1896                                                  OR (SymTab.ClassOf(dt) =
+ 1897                                                      SymTab.ClArray)
+ 1898                                                  OR (SymTab.ClassOf(dt) =
+ 1899                                                      SymTab.ClClass) THEN
+ 1900                                                 QbeGen.CopyOp(qd, q)
+ 1901                                               ELSE QbeGen.ElemLoad(qd, dt,
+ 1902                                                 q)
+ 1903                                               END
+ 1904                                             ELSE QbeGen.CopyOp(qd, q)
+ 1905                                             END;
+ 1906                                             IF (dk = SymTab.KindVar)
+ 1907                                                OR (dk = SymTab.KindParam)
+ 1908                                                OR (dk =
+ 1909                                                   SymTab.KindField) THEN
+ 1910                                               IF sfx THEN
+ 1911                                                 QbeGen.NoteAddr(q, qd)
+ 1912                                               ELSE
+ 1913                                                 QbeGen.AddrOf(qn, qa);
+ 1914                                                 QbeGen.NoteAddr(q, qa)
+ 1915                                               END
+ 1916                                             ELSIF sfx
+ 1917   AND (dt #
+ 1918                                                   SymTab.InvalidType)
+ 1919   AND ((SymTab.ClassOf(dt) =
+ 1920                                                    SymTab.ClArray)
+ 1921                                                   OR (SymTab.ClassOf(dt) =
+ 1922                                                       SymTab.ClSet)
+ 1923                                                   OR (SymTab.ClassOf(dt) =
+ 1924                                                       SymTab.ClRecord)) THEN
+ 1925                                               QbeGen.NoteAddr(qd, qd)
+ 1926                                             END; .)
+ 1927        [ ArgList<qn, dt, qd, TRUE, ct2, q2, called>
+ 1928                                          (. t := ct2;
+ 1929                                             QbeGen.CopyOp(q2, q); .) ]
+ 1930                                          (. IF NOT called
+ 1931   AND (dk = SymTab.KindProc) THEN
+ 1932                                               (* bare zero-arg function
+ 1933                                                  call (parentheses may be
+ 1934                                                  omitted); a proper or
+ 1935                                                  parameterised proc here
+ 1936                                                  is 230 *)
+ 1937                                               IF (SymTab.ProcNPar(qn) = 0)
+ 1938   AND (SymTab.ProcRes(qn) #
+ 1939                                                     SymTab.InvalidType) THEN
+ 1940                                                 QbeGen.Mangled(qn,
+ 1941                                                   SymTab.ProcUid(qn), qm0);
+ 1942                                                 QbeGen.CallBegin(qm0,
+ 1943                                                   SymTab.ProcRes(qn),
+ 1944                                                   SymTab.ProcDepthOf(qn),
+ 1945                                                   SymTab.IsExternal(qn));
+ 1946                                                 QbeGen.CallEnd(TRUE, q);
+ 1947                                                 t := SymTab.ProcRes(qn)
+ 1948                                               ELSE
+ 1949                                                 (* procedure used as a
+ 1950                                                    value (assign to a
+ 1951                                                    procedure variable):
+ 1952                                                    its code address *)
+ 1953                                                 t := SymTab.ProcTypeOf(qn);
+ 1954                                                 QbeGen.Mangled(qn,
+ 1955                                                   SymTab.ProcUid(qn), qm0);
+ 1956                                                 QbeGen.ProcAddr(qm0, q)
+ 1957                                               END
+ 1958                                             END; .)
+ 1959      | ( "HIGH"                          (. isHigh := TRUE; .)
+ 1960        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
+ 1961        "(" Design<dt, dk, qd, qn, sfx> ")"
+ 1962                                          (. IF dt = SymTab.InvalidType THEN
+ 1963                                             ELSIF SymTab.ClassOf(dt) #
+ 1964                                                   SymTab.ClArray THEN
+ 1965                                               SemError(217);
+ 1966                                               t := SymTab.InvalidType;
+ 1967                                               QbeGen.CopyOp("0", q)
+ 1968                                             ELSE
+ 1969                                               IF isHigh THEN
+ 1970                                                 IF SymTab.IsOpenArray(dt) THEN
+ 1971                                                   QbeGen.OpenHi(qd, qr)
+ 1972                                                 ELSE
+ 1973                                                   QbeGen.IntStr(
+ 1974                                                     SymTab.ArrayHi(dt), qr)
+ 1975                                                 END
+ 1976                                               ELSE
+ 1977                                                 IF SymTab.IsOpenArray(dt) THEN
+ 1978                                                   QbeGen.LoadCount(qd, qr)
+ 1979                                                 ELSE
+ 1980                                                   QbeGen.IntStr(VAL(
+ 1981                                                     INTEGER,
+ 1982                                                     SymTab.ArrayLen(dt)),
+ 1983                                                     qr)
+ 1984                                                 END
+ 1985                                               END;
+ 1986                                                t := SymTab.IntType();
+ 1987                                                QbeGen.CopyOp(qr, q)
+ 1988                                              END; .)
+ 1989      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
+ 1990                                          (. IF dt = SymTab.InvalidType THEN
+ 1991                                               t := SymTab.InvalidType;
+ 1992                                               QbeGen.CopyOp("0", q)
+ 1993                                             ELSE
+ 1994                                               QbeGen.IntStr(VAL(INTEGER,
+ 1995                                                 SymTab.ObjectSize(dt)), q);
+ 1996                                               t := SymTab.IntType()
+ 1997                                             END; .)
+ 1998      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 1999                                          (. IF dt = SymTab.InvalidType THEN
+ 2000                                               t := SymTab.InvalidType;
+ 2001                                               QbeGen.CopyOp("0", q)
+ 2002                                             ELSE
+ 2003                                               IF sfx THEN
+ 2004                                                 QbeGen.CopyOp(qd, q)
+ 2005                                               ELSIF (dk = SymTab.KindVar)
+ 2006                                                  OR (dk = SymTab.KindParam) THEN
+ 2007                                                 QbeGen.AddrOf(qn, q)
+ 2008                                               ELSE SemError(230);
+ 2009                                                 QbeGen.CopyOp("0", q)
+ 2010                                               END;
+ 2011                                               t := SymTab.AddrType()
+ 2012                                             END; .)
+ 2013      | "CHR" "(" Expr<et, q> ")"
+ 2014                                          (. IF (et # SymTab.InvalidType)
+ 2015   AND NOT SymTab.IsIntFamily(et) THEN
+ 2016                                               SemError(211) END;
+ 2017                                             t := SymTab.CharType(); .)
+ 2018      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
+ 2019                                          (. IF et # SymTab.InvalidType THEN
+ 2020                                               IF (SymTab.ClassOf(et) #
+ 2021                                                   SymTab.ClChar)
+ 2022   AND (SymTab.ClassOf(et) #
+ 2023                                                     SymTab.ClBool)
+ 2024   AND (SymTab.ClassOf(et) #
+ 2025                                                     SymTab.ClEnum)
+ 2026   AND NOT SymTab.IsIntFamily(et) THEN
+ 2027                                                 SemError(211) END
+ 2028                                             END;
+ 2029                                             t := SymTab.IntType(); .)
+ 2030      | "CAP" "(" Expr<et, q> ")"
+ 2031                                          (. QbeGen.CapQ(q, qa);
+ 2032                                             QbeGen.CopyOp(qa, q);
+ 2033                                             t := SymTab.CharType(); .)
+ 2034      | "ABS" "(" Expr<et, q> ")"
+ 2035                                          (. IF (et # SymTab.InvalidType)
+ 2036   AND NOT SymTab.IsIntFamily(et)
+ 2037   AND (SymTab.ClassOf(et) #
+ 2038                                                  SymTab.ClReal) THEN
+ 2039                                               SemError(211)
+ 2040                                             ELSE QbeGen.AbsQ(q, qa,
+ 2041                                                    SymTab.ClassOf(et) =
+ 2042                                                      SymTab.ClReal);
+ 2043                                               QbeGen.CopyOp(qa, q)
+ 2044                                             END;
+ 2045                                             t := et; .)
+ 2046      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
+ 2047                                          (. IF NOT SymTab.Lookup(vn) THEN
+ 2048                                               SemError(201);
+ 2049                                               t := SymTab.InvalidType
+ 2050                                             ELSE vt := SymTab.SymType(vn);
+ 2051                                               IF vt = SymTab.InvalidType THEN
+ 2052                                                 t := SymTab.InvalidType
+ 2053                                               ELSIF et =
+ 2054                                                  SymTab.InvalidType THEN
+ 2055                                                 t := vt
+ 2056                                               ELSE
+ 2057                                                 c1 := SymTab.ClassOf(et);
+ 2058                                                 c2 := SymTab.ClassOf(vt);
+ 2059                                                 IF ((c1 = SymTab.ClInt)
+ 2060                                                     OR (c1 =
+ 2061                                                        SymTab.ClChar)
+ 2062                                                     OR (c1 =
+ 2063                                                        SymTab.ClBool)
+ 2064                                                     OR (c1 =
+ 2065                                                        SymTab.ClEnum))
+ 2066   AND ((c2 = SymTab.ClInt)
+ 2067                                                     OR (c2 =
+ 2068                                                        SymTab.ClChar)
+ 2069                                                     OR (c2 =
+ 2070                                                        SymTab.ClBool)
+ 2071                                                     OR (c2 =
+ 2072                                                        SymTab.ClEnum)) THEN
+ 2073                                                   t := vt
+ 2074                                                 ELSIF (c1 = SymTab.ClPtr)
+ 2075   AND (c2 = SymTab.ClPtr) THEN
+ 2076                                                   t := vt
+ 2077                                                 ELSIF (c1 = SymTab.ClReal)
+ 2078   AND (c2 = SymTab.ClReal) THEN
+ 2079                                                   t := vt
+ 2080                                                 ELSE SemError(230);
+ 2081                                                   t := SymTab.InvalidType
+ 2082                                                 END
+ 2083                                               END
+ 2084                                             END; .)
+ 2085      | "(" Expr<et, q> ")"               (. t := et; .)
+ 2086      | SetLit<st, sq>                    (. t := st;
+ 2087                                             QbeGen.CopyOp(sq, q); .)
+ 2088      | ( "NOT" | "~" ) Fact<t2, q2>      (. IF SymTab.BoolCheck(t2) THEN
+ 2089                                               t := SymTab.BoolType()
+ 2090                                             ELSE SemError(212);
+ 2091                                               t := SymTab.InvalidType END;
+ 2092                                             IF t # SymTab.InvalidType THEN
+ 2093                                               QbeGen.NotQ(q2, q)
+ 2094                                             ELSE QbeGen.CopyOp("0", q)
+ 2095                                             END; .) .
+ 2096    (* Set literals are SET OF [0..255] (8 words); elements validated
+ 2097       0..255 statically when foldable (222 otherwise), runtime trap
+ 2098       for computed elements. Ranges always lower via SetRange. *)
+ 2099    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2100      = "{"                               (. t := SymTab.NewSet(
+ 2101                                               SymTab.NewSubR(0, 255));
+ 2102                                             QbeGen.NewSetTemp(8, q);
+ 2103                                             QbeGen.SetZero(q, 8); .)
+ 2104        [ SetElem<t, q> { "," SetElem<t, q> } ]
+ 2105        "}" .
+ 2106    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
+ 2107                                               qe, q2: QbeGen.QVal;
+ 2108                                               v, v2: INTEGER;
+ 2109                                               lo: INTEGER;
+ 2110                                               span: CARDINAL;
+ 2111                                               cl, cl2: INTEGER;
+ 2112                                               hasR: BOOLEAN; .)
+ 2113      =                                   (. hasR := FALSE; .)
+ 2114        Expr<et, qe>
+ 2115        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
+ 2116                                          (. lo := SymTab.SetBaseLo(st);
+ 2117                                             span := SymTab.SetCount(st);
+ 2118                                             IF (et = SymTab.InvalidType)
+ 2119                                                OR (hasR AND (et2 =
+ 2120                                                   SymTab.InvalidType)) THEN
+ 2121                                             ELSE cl :=
+ 2122                                                    SymTab.ClassOf(et);
+ 2123                                               IF hasR THEN
+ 2124                                                 cl2 :=
+ 2125                                                   SymTab.ClassOf(et2)
+ 2126                                               ELSE cl2 := SymTab.ClInt
+ 2127                                               END;
+ 2128                                               IF ((cl # SymTab.ClInt)
+ 2129   AND (cl # SymTab.ClChar)
+ 2130   AND (cl # SymTab.ClBool))
+ 2131                                                  OR (hasR AND 
+ 2132                                                     ((cl2
+ 2133                                                       # SymTab.ClInt)
+ 2134   AND (cl2
+ 2135                                                        # SymTab.ClChar)
+ 2136   AND (cl2
+ 2137                                                        # SymTab.ClBool))) THEN
+ 2138                                                 SemError(222)
+ 2139                                               ELSIF hasR
+ 2140   AND SymTab.ConstInt(qe, v)
+ 2141   AND SymTab.ConstInt(q2,
+ 2142                                                     v2)
+ 2143   AND ((v < lo)
+ 2144                                                     OR (v2 < lo)
+ 2145                                                     OR (v >= lo +
+ 2146                                                        VAL(INTEGER, span))
+ 2147                                                     OR (v2 >= lo +
+ 2148                                                        VAL(INTEGER, span))
+ 2149                                                     OR (v > v2)) THEN
+ 2150                                                 SemError(222)
+ 2151                                                ELSIF hasR THEN
+ 2152                                                  QbeGen.SetRange(sq, qe, q2,
+ 2153                                                    lo, span)
+ 2154                                                ELSIF SymTab.ConstInt(qe,
+ 2155                                                        v)
+ 2156   AND ((v < lo)
+ 2157                                                      OR (v >= lo +
+ 2158                                                         VAL(INTEGER,
+ 2159                                                           span))) THEN
+ 2160                                                  SemError(222)
+ 2161                                                ELSE QbeGen.SetBit(sq, qe,
+ 2162                                                  lo, span)
+ 2163                                               END
+ 2164                                             END; .) .
+ 2165    GetIdent<VAR n: SymTab.Name>
+ 2166      = ident                             (. LexName(n); .) .
+ 2167  
+ 2168  END M2.
 
     0 errors
 
 
 Statistics:
 
-  nr of terminals:        87 (limit   400)
+  nr of terminals:        93 (limit   400)
   nr of non-terminals:    77 (limit   210)
-  nr of pragmas:           0 (limit   413)
-  nr of symbolnodes:     164 (limit   500)
-  nr of graphnodes:      804 (limit  1500)
-  nr of conditionsets:     8 (limit   100)
-  nr of charactersets:    11 (limit   250)
+  nr of pragmas:           0 (limit   407)
+  nr of symbolnodes:     170 (limit   500)
+  nr of graphnodes:      838 (limit  1500)
+  nr of conditionsets:     9 (limit   100)
+  nr of charactersets:    12 (limit   250)
 
 

+ 3 - 0
compiler/src/QbeGen.def

@@ -143,6 +143,9 @@ PROCEDURE InitHeap (addr: ARRAY OF CHAR; t: INTEGER);
 PROCEDURE NotQ (a: ARRAY OF CHAR; VAR q: QVal);
 (* q := fresh w holding "NOT a" (xor 1, a). *)
 
+PROCEDURE CapQ (a: ARRAY OF CHAR; VAR q: QVal);
+(* q := fresh w holding UPCASE(a): ASCII a-z mapped to A-Z. *)
+
 PROCEDURE PushLoop (exit: ARRAY OF CHAR);
 PROCEDURE PopLoop;
 PROCEDURE TopLoop (VAR exit: QVal): BOOLEAN;

+ 11 - 0
compiler/src/QbeGen.mod

@@ -1423,6 +1423,17 @@ PROCEDURE NotQ (a: ARRAY OF CHAR; VAR q: QVal);
     Op3("xor", q, "1", a, FALSE)
   END NotQ;
 
+PROCEDURE CapQ (a: ARRAY OF CHAR; VAR q: QVal);
+(* Branchless UPCASE: q := a - 32 * (a >= 'a' AND a <= 'z'). *)
+  VAR lo, hi, in1, delta: QVal;
+  BEGIN
+    NewTemp(lo); Op3("csgew", lo, a, "97", FALSE);
+    NewTemp(hi); Op3("cslew", hi, a, "122", FALSE);
+    NewTemp(in1); Op3("and", in1, lo, hi, FALSE);
+    NewTemp(delta); Op3("mul", delta, in1, "32", FALSE);
+    NewTemp(q); Op3("sub", q, a, delta, FALSE)
+  END CapQ;
+
 PROCEDURE NewLabel (VAR l: QVal);
   BEGIN
     Cpy(l, "@L");

+ 27 - 0
compiler/tests/t_compat.mod

@@ -0,0 +1,27 @@
+MODULE TCompat;
+// GNU/classic compatibility accepted by V3 for self-hosting the
+// Coco/R-generated sources: '&' (AND) and '~' (NOT), LENGTH (alias of
+// LEN), CAP, ORDL, the octal character literal 0C, and empty
+// THEN/ELSE bodies. Exit 42.
+VAR ExitCode : INTEGER;
+VAR s : ARRAY [0..2] OF CHAR;
+VAR c : CHAR;
+VAR n : INTEGER;
+
+PROCEDURE Len (a : ARRAY OF CHAR) : INTEGER;
+BEGIN RETURN LENGTH(a) END Len;
+
+BEGIN
+  s := "abc";
+  n := Len(s);                       // 3 (LENGTH alias)
+  c := CAP("q");                     // 'Q'
+  IF (n = 3) & (c = "Q") THEN
+    n := n + 39                      // & = AND -> 42
+  ELSE
+  END;                               // empty ELSE
+  c := 0C;                           // octal char literal -> NUL
+  IF ~(c = CHR(0)) THEN n := 0 END;  // ~ = NOT
+  n := n + ORDL(0);                  // ORDL
+  IF n = 42 THEN ELSE n := 0 END;    // empty THEN + ELSE
+  ExitCode := n
+END TCompat.

+ 59 - 0
docs/summary_m2s-clean.md

@@ -0,0 +1,59 @@
+# M2S compiles clean under V3 (compatibility additions)
+
+Tag `v3-m2s-clean`. Main suite 110/110 (new `t_compat`).
+
+With this, **`SymTab`, `QbeGen` and `M2S` (the Coco/R scanner) all
+compile clean under V3.** `M2P`/`M2` remain (see below).
+
+## Items knocked out (the 3 remaining, plus what they uncovered)
+
+The three known `M2S` items — and, once those parsed, a few more
+GNU-isms in CR's *generated* scanner tables:
+
+1. **`LENGTH`** — accepted as an alias of `LEN`.
+2. **Empty statement bodies** — `IF … THEN ELSIF/ELSE`, `WHILE … DO`,
+   `REPEAT`, `LOOP`, `FOR` and `CASE` alternatives may now have empty
+   bodies (`StatSeq` optional), matching CR's generated code.
+3. **`&` = `AND`, `~` = `NOT`** — GNU/classic synonyms.
+4. **Octal character literals** — new `charConst` token
+   (`0C`, `03C`, `012C`) handled by `NormLit` → `CHAR` value
+   (`0C` = NUL).
+5. **`ORDL`** — alias of `ORD`.
+6. **`CAP`** — new builtin, branchless UPCASE
+   (`q := a - 32*(a>='a' AND a<='z')`, since QBE has no `select`).
+
+Also fixed a latent bug found via `CAP`: **`ABS` (and now `CAP`) wrote
+their result to a temp but `Fact` never copied it back to `q`**, so
+`ABS` silently returned its operand. Both now `CopyOp(qa, q)`.
+
+## Verification
+
+- `tests/t_compat.mod` (exit 42) exercises `&`, `~`, `LENGTH`, `CAP`,
+  `ORDL`, `0C`, and empty THEN/ELSE.
+- `M2S.def` + `M2S.mod` under V3: **0 errors**.
+- `SymTab` / `QbeGen` under V3: still 0 errors.
+- `tools/m2make` unaffected; main suite 110/110.
+
+## Remaining (M2P, M2)
+
+`M2P.mod` (the Coco/R parser) is 107 errors, dominated by 102
+`undeclared identifier` — **within-module forward procedure calls**
+in CR's generated recursive-descent parser (gm2 hoists these; ISO
+wants declaration-before-use or `FORWARD`). Also `BITSET{…}`
+constructors and `symSet[0,0]` nested-array assignment. This is the
+next self-hosting chunk; the driver `M2.mod` additionally needs
+nested procedure values (`Error := StoreError`, `StoreError` nested in
+`ListHandler`) which the current proc-type support doesn't yet
+provide (static link).
+
+## Where the compatibility additions came from
+
+`&`, `0C`, empty bodies and forward refs are all emitted by the CR
+binary's built-in scanner/parser templates — not by our `scanner.frm`
+(which has none of them). So V3 accepting them is the only way to
+self-host CR's output short of patching the toolchain.
+
+## Files
+
+`compiler/src/{M2.atg,QbeGen.def,QbeGen.mod}`,
+`compiler/tests/t_compat.mod`, `compiler/run_tests.sh`.