Просмотр исходного кода

cleanup: remove the vestigial Check pass and L7 scaffolding

Measured first: gutting Check.Resolve left the emitted .ssa byte-
identical across all 141 suite files (Check re-typed Ty=-1 nodes but
Lower recomputes what it needs, and Check emitted no diagnostics).
So Check.def/.mod are deleted along with the driver calls, the
-noresolve option, and the atg import; build.sh drops Check
(fixpoint.sh stages sources dynamically). Also removed the unused
procNest and the always-true twoPhase flag (13 inert guards).

Pipeline is now Parse -> Lower -> Emit. Suite 201/201; fixpoint OK
(3,555,791 bytes).
Eric Streit 19 часов назад
Родитель
Сommit
a89a1c0b65

+ 3 - 3
compiler/build.sh

@@ -24,16 +24,16 @@ mkdir -p gen_ssa
 
 
 echo "=== Compiling ==="
 echo "=== Compiling ==="
 rm -f ./*.o
 rm -f ./*.o
-for m in FileIO AST Lower SymTab QbeGen Check M2S M2P M2; do
+for m in FileIO AST Lower SymTab QbeGen M2S M2P M2; do
   gm2 -fiso -I src -c "src/$m.mod" || exit 1
   gm2 -fiso -I src -c "src/$m.mod" || exit 1
 done
 done
 
 
 echo "=== Phase 1: generating the module list ==="
 echo "=== Phase 1: generating the module list ==="
 gm2 -fiso -I src -fgen-module-list=src/modules.lst -o /dev/null \
 gm2 -fiso -I src -fgen-module-list=src/modules.lst -o /dev/null \
-    M2S.o M2P.o FileIO.o AST.o Lower.o SymTab.o QbeGen.o Check.o src/M2.mod || exit 1
+    M2S.o M2P.o FileIO.o AST.o Lower.o SymTab.o QbeGen.o src/M2.mod || exit 1
 
 
 echo "=== Phase 2: compiling main module and linking ==="
 echo "=== Phase 2: compiling main module and linking ==="
 gm2 -fiso -I src -fuse-list=src/modules.lst -o M2 \
 gm2 -fiso -I src -fuse-list=src/modules.lst -o M2 \
-    M2S.o M2P.o FileIO.o AST.o Lower.o SymTab.o QbeGen.o Check.o src/M2.mod || exit 1
+    M2S.o M2P.o FileIO.o AST.o Lower.o SymTab.o QbeGen.o src/M2.mod || exit 1
 
 
 echo "=== M2 built ==="
 echo "=== M2 built ==="

+ 0 - 22
compiler/src/Check.def

@@ -1,22 +0,0 @@
-DEFINITION MODULE Check;
-
-(* Resolve / check pass (two-phase, part 2).  A walk over a parsed unit's
-   AST that binds identifiers to symbols, resolves and completes types,
-   and emits the 2xx diagnostics -- run by the driver between Parse and
-   Lower.  See docs/plan-resolve-check.md. *)
-
-IMPORT AST;
-
-PROCEDURE BeginSession (progName: ARRAY OF CHAR);
-(* Per-session setup (alongside Lower.BeginSession). *)
-
-PROCEDURE BeginUnit;
-(* Per-unit setup (called before Parse). *)
-
-PROCEDURE Resolve (unit: AST.Node);
-(* Resolve and check the parsed unit. *)
-
-PROCEDURE EndSession;
-(* Per-session teardown. *)
-
-END Check.

+ 0 - 134
compiler/src/Check.mod

@@ -1,134 +0,0 @@
-IMPLEMENTATION MODULE Check;
-
-(* Resolve / check pass (two-phase, part 2).  Forward module-level
-   references (a procedure body naming a variable declared further down)
-   are resolved here, after the unit has been parsed and before Lower:
-   the designator's real type is computed from the now-visible symbol and
-   its selectors, and stored on the AST node.  See
-   docs/plan-resolve-check.md. *)
-
-IMPORT AST, SymTab, M2S;
-
-PROCEDURE RelOp (op: INTEGER; VAR sop: INTEGER): BOOLEAN;
-(* AST relation operator -> SymTab relation operator. *)
-BEGIN
-  IF op = AST.OpEq THEN sop := SymTab.OpEq; RETURN TRUE
-  ELSIF op = AST.OpNe THEN sop := SymTab.OpNeq1; RETURN TRUE
-  ELSIF op = AST.OpLt THEN sop := SymTab.OpLt; RETURN TRUE
-  ELSIF op = AST.OpLe THEN sop := SymTab.OpLe; RETURN TRUE
-  ELSIF op = AST.OpGt THEN sop := SymTab.OpGt; RETURN TRUE
-  ELSIF op = AST.OpGe THEN sop := SymTab.OpGe; RETURN TRUE
-  END;
-  RETURN FALSE
-END RelOp;
-
-PROCEDURE EvalExpr (n: AST.Node): SymTab.TypeIndex;
-(* The type of an expression node: its stored type when known, else the
-   result of combining its (now typed) operands by the operator rules.
-   Mirrors the grammar's typing; set operators are left unknown. *)
-  VAR t, t2, res: SymTab.TypeIndex; op, k, sop: INTEGER;
-BEGIN
-  IF n < 0 THEN RETURN SymTab.InvalidType END;
-  t := AST.Ty(n);
-  IF t # -1 THEN RETURN t END;
-  k := AST.Kind(n);
-  op := AST.Op(n);
-  IF k = AST.NkBinExpr THEN
-    IF AST.Child(n, 0) < 0 THEN RETURN SymTab.InvalidType END;
-    t := EvalExpr(AST.Child(n, 0));
-    t2 := EvalExpr(AST.Child(n, 1));
-    IF (t = SymTab.InvalidType) OR (t2 = SymTab.InvalidType) THEN
-      RETURN SymTab.InvalidType
-    END;
-    IF (op = AST.OpAnd) OR (op = AST.OpOr) THEN
-      IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
-        RETURN SymTab.BoolType()
-      END
-    ELSIF op = AST.OpIn THEN
-      IF SymTab.InCheck(t, t2) THEN RETURN SymTab.BoolType() END
-    ELSIF RelOp(op, sop) THEN
-      IF SymTab.RelCheck(t, t2, sop) THEN RETURN SymTab.BoolType() END
-    ELSIF SymTab.ArithCheck(t, t2, (op = AST.OpDiv) OR (op = AST.OpMod),
-                            res) THEN
-      RETURN res
-    END;
-    RETURN SymTab.InvalidType
-  ELSIF k = AST.NkUnary THEN
-    IF AST.Child(n, 0) < 0 THEN RETURN SymTab.InvalidType END;
-    t := EvalExpr(AST.Child(n, 0));
-    IF t = SymTab.InvalidType THEN RETURN t END;
-    IF op = AST.OpNot THEN
-      IF SymTab.BoolCheck(t) THEN RETURN SymTab.BoolType() END;
-      RETURN SymTab.InvalidType
-    END;
-    RETURN t
-  END;
-  RETURN t
-END EvalExpr;
-
-PROCEDURE CheckAssign (n: AST.Node);
-(* Re-check a designator assignment whose operand types were unknown at
-   parse time (a forward reference): the parser skipped it. *)
-  VAR lt, vt: SymTab.TypeIndex;
-BEGIN
-  IF AST.Child(n, 0) < 0 THEN RETURN END;
-  IF AST.Kind(AST.Child(n, 0)) # AST.NkDesignator THEN RETURN END;
-  lt := AST.Ty(AST.Child(n, 0));
-  vt := AST.Ty(AST.Child(n, 1));
-  IF (lt = SymTab.InvalidType) OR (vt = SymTab.InvalidType) THEN RETURN END;
-  IF NOT SymTab.Assignable(vt, lt) THEN
-    M2S.Error(210, M2S.line, M2S.col, M2S.pos)
-  ELSIF SymTab.ClassOf(lt) = SymTab.ClClass THEN
-    M2S.Error(230, M2S.line, M2S.col, M2S.pos)
-  END
-END CheckAssign;
-
-PROCEDURE PropNode (n: AST.Node): BOOLEAN;
-(* Post-order: re-type any expression node whose type is still unknown
-   (i.e. one whose operands included a forward reference), and re-check an
-   assignment statement whose operands were so affected.  Returns TRUE
-   when this subtree was touched by a forward reference. *)
-  VAR i: CARDINAL; k: INTEGER; t: SymTab.TypeIndex; tn: BOOLEAN;
-BEGIN
-  IF n < 0 THEN RETURN FALSE END;
-  k := AST.Kind(n);
-  IF (k >= AST.NkIdent) AND (k <= AST.NkCharLit) THEN
-    RETURN FALSE   (* a leaf: child 0 is a text index, not a node *)
-  END;
-  tn := (k = AST.NkDesignator) AND (AST.Op(n) = 1);
-  i := 0;
-  WHILE i < AST.NChild(n) DO
-    IF PropNode(AST.Child(n, i)) THEN tn := TRUE END;
-    INC(i)
-  END;
-  IF (k >= AST.NkBinExpr) AND (k <= AST.NkSetLit)
-     AND (AST.Ty(n) = -1) THEN
-    t := EvalExpr(n);
-    IF t # -1 THEN AST.SetTy(n, t); tn := TRUE END
-  END;
-  IF (k = AST.NkAssign) AND tn THEN CheckAssign(n) END;
-  RETURN tn
-END PropNode;
-
-PROCEDURE BeginSession (progName: ARRAY OF CHAR);
-BEGIN
-END BeginSession;
-
-PROCEDURE BeginUnit;
-BEGIN
-END BeginUnit;
-
-PROCEDURE Resolve (unit: AST.Node);
-(* Two-phase parse defers procedure bodies to unit end, so forward
-   references bind normally and no pre-pass fix-up is needed here; the
-   walk is kept for the type propagation it still performs. *)
-  VAR touched: BOOLEAN;
-BEGIN
-  touched := PropNode(unit)
-END Resolve;
-
-PROCEDURE EndSession;
-BEGIN
-END EndSession;
-
-END Check.

+ 18 - 34
compiler/src/M2.atg

@@ -51,22 +51,15 @@ COMPILER M2
    init; DISPOSE shallow and nils, deviating from Wirth-undefined);
    init; DISPOSE shallow and nils, deviating from Wirth-undefined);
    nil-deref is raw (no check). *)
    nil-deref is raw (no check). *)
 
 
-IMPORT SymTab, QbeGen, AST, Lower, Check;
+IMPORT SymTab, QbeGen, AST, Lower;
 
 
 VAR
 VAR
-  (* Two-phase frontend (docs/plan-two-phase.md).  When TRUE the
-     productions ALSO build AST nodes alongside the legacy emit path.
-     Slice 1: the nodes are inert scaffolding — nothing reads them, so
-     the emitted output is unchanged. *)
-  twoPhase: BOOLEAN;
-
   (* Two-phase parse (docs/plan-two-phase-parse.md), milestone 1.  When
   (* Two-phase parse (docs/plan-two-phase-parse.md), milestone 1.  When
      TRUE each outermost procedure/method body is shadow-skipped at the
      TRUE each outermost procedure/method body is shadow-skipped at the
      token level and the skip verified before the body parses normally.
      token level and the skip verified before the body parses normally.
-     Set by the driver (-twophase); default off.  `procNest` counts the
+     Set by the driver (-notwophase turns it off); default on.
      Blocks being parsed so only outermost bodies probe. *)
      Blocks being parsed so only outermost bodies probe. *)
   twoPhaseParse: BOOLEAN;
   twoPhaseParse: BOOLEAN;
-  procNest: CARDINAL;
 
 
   (* Two-phase parse spans (milestone 2a): one entry per outermost body
   (* Two-phase parse spans (milestone 2a): one entry per outermost body
      shadow-skipped while twoPhaseParse is on — procedure name and the
      shadow-skipped while twoPhaseParse is on — procedure name and the
@@ -471,10 +464,10 @@ TOKENS
 
 
 PRODUCTIONS
 PRODUCTIONS
   M2
   M2
-    = (. twoPhase := TRUE; astCur := AST.NoNode; astStmt := AST.NoNode; astDecl := AST.NoNode; astImp := AST.NoNode; astImpTail := AST.NoNode;
+    = (. astCur := AST.NoNode; astStmt := AST.NoNode; astDecl := AST.NoNode; astImp := AST.NoNode; astImpTail := AST.NoNode;
                                            astImp := AST.NoNode;
                                            astImp := AST.NoNode;
                                            astImpTail := AST.NoNode;
                                            astImpTail := AST.NoNode;
-                                           procNest := 0; nSpans := 0;
+                                           nSpans := 0;
                                            SymTab.DeferReset; .)
                                            SymTab.DeferReset; .)
       Unit "." .
       Unit "." .
   (* Units: program modules compile fully; DEFINITION and
   (* Units: program modules compile fully; DEFINITION and
@@ -1679,7 +1672,7 @@ PRODUCTIONS
                                              dfr := DeferSkip(pn)
                                              dfr := DeferSkip(pn)
                                            END;
                                            END;
                                            allowDefer := FALSE;
                                            allowDefer := FALSE;
-                                           IF NOT dfr THEN INC(procNest) END; .)
+                                           .)
       DeclSeq                           (. astBlkDecls := astDecl;
       DeclSeq                           (. astBlkDecls := astDecl;
                                            astStmt := AST.NoNode;
                                            astStmt := AST.NoNode;
                                            nLab := 0; nGot := 0; .)
                                            nLab := 0; nGot := 0; .)
@@ -1697,7 +1690,6 @@ PRODUCTIONS
       "END"
       "END"
       GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
       GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
                                              SemError(202) END;
                                              SemError(202) END;
-                                           IF NOT dfr THEN DEC(procNest) END;
                                            CheckGotos; .) .
                                            CheckGotos; .) .
   (* Two-phase, phase 2 (milestone 2c): re-parse every deferred module-
   (* Two-phase, phase 2 (milestone 2c): re-parse every deferred module-
      level body once the unit's declarations are complete.  Inlined at
      level body once the unit's declarations are complete.  Inlined at
@@ -3008,30 +3000,24 @@ PRODUCTIONS
                                               astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN; .)
                                               astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN; .)
     = (. astIsLit := FALSE; .)
     = (. astIsLit := FALSE; .)
     ( integer                           (. LexString(s);
     ( integer                           (. LexString(s);
-                                           QbeGen.NormInt(s, q); IF twoPhase THEN astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s) END;
+                                           QbeGen.NormInt(s, q); astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s);
                                            t := SymTab.IntType(); .)
                                            t := SymTab.IntType(); .)
     | charConst                         (. LexString(s);
     | charConst                         (. LexString(s);
                                            QbeGen.NormLit(s, q, isCh);
                                            QbeGen.NormLit(s, q, isCh);
-                                           IF twoPhase THEN
-                                             astIsLit := TRUE;
-                                             astCur := AST.MakeLeaf(
-                                               AST.NkCharLit, s)
-                                           END;
+                                           astIsLit := TRUE;
+                                           astCur := AST.MakeLeaf(
+                                             AST.NkCharLit, s);
                                            t := SymTab.CharType(); .)
                                            t := SymTab.CharType(); .)
     | real                              (. LexString(s);
     | real                              (. LexString(s);
                                            QbeGen.NormReal(s, q);
                                            QbeGen.NormReal(s, q);
-                                           IF twoPhase THEN
-                                             astIsLit := TRUE;
-                                             astCur := AST.MakeLeaf(
-                                               AST.NkRealLit, s)
-                                           END;
+                                           astIsLit := TRUE;
+                                           astCur := AST.MakeLeaf(
+                                             AST.NkRealLit, s);
                                            t := SymTab.RealType(); .)
                                            t := SymTab.RealType(); .)
     | string                            (. LexString(s);
     | string                            (. LexString(s);
-                                           IF twoPhase THEN
-                                             astIsLit := TRUE;
-                                             astCur := AST.MakeLeaf(
-                                               AST.NkStrLit, s)
-                                           END;
+                                           astIsLit := TRUE;
+                                           astCur := AST.MakeLeaf(
+                                             AST.NkStrLit, s);
                                            IF SymTab.StrLen(s) = 3 THEN
                                            IF SymTab.StrLen(s) = 3 THEN
                                              t := SymTab.CharType();
                                              t := SymTab.CharType();
                                              QbeGen.IntStr(
                                              QbeGen.IntStr(
@@ -3042,11 +3028,9 @@ PRODUCTIONS
                                                 static descriptor address *)
                                                 static descriptor address *)
                                            END; .)
                                            END; .)
     | ustring                           (. LexString(s);
     | ustring                           (. LexString(s);
-                                           IF twoPhase THEN
-                                             astIsLit := TRUE;
-                                             astCur := AST.MakeLeaf(
-                                               AST.NkStrLit, s)
-                                           END;
+                                           astIsLit := TRUE;
+                                           astCur := AST.MakeLeaf(
+                                             AST.NkStrLit, s);
                                            QbeGen.DeclUStr(s, q, isU, ucp,
                                            QbeGen.DeclUStr(s, q, isU, ucp,
                                              uok);
                                              uok);
                                            IF NOT uok THEN
                                            IF NOT uok THEN

+ 3602 - 3618
compiler/src/M2.lst

@@ -70,3655 +70,3639 @@ Listing:
    51     init; DISPOSE shallow and nils, deviating from Wirth-undefined);
    51     init; DISPOSE shallow and nils, deviating from Wirth-undefined);
    52     nil-deref is raw (no check). *)
    52     nil-deref is raw (no check). *)
    53  
    53  
-   54  IMPORT SymTab, QbeGen, AST, Lower, Check;
+   54  IMPORT SymTab, QbeGen, AST, Lower;
    55  
    55  
    56  VAR
    56  VAR
-   57    (* Two-phase frontend (docs/plan-two-phase.md).  When TRUE the
-   58       productions ALSO build AST nodes alongside the legacy emit path.
-   59       Slice 1: the nodes are inert scaffolding — nothing reads them, so
-   60       the emitted output is unchanged. *)
-   61    twoPhase: BOOLEAN;
-   62  
-   63    (* Two-phase parse (docs/plan-two-phase-parse.md), milestone 1.  When
-   64       TRUE each outermost procedure/method body is shadow-skipped at the
-   65       token level and the skip verified before the body parses normally.
-   66       Set by the driver (-twophase); default off.  `procNest` counts the
-   67       Blocks being parsed so only outermost bodies probe. *)
-   68    twoPhaseParse: BOOLEAN;
-   69    procNest: CARDINAL;
-   70  
-   71    (* Two-phase parse spans (milestone 2a): one entry per outermost body
-   72       shadow-skipped while twoPhaseParse is on — procedure name and the
-   73       buffer offset its body starts at (the lookahead token's nextPos).
-   74       Per-parse; nothing consumes the table yet. *)
-   75    nSpans: CARDINAL;
-   76    spanName: ARRAY [0 .. 1023] OF SymTab.Name;
-   77    spanStart: ARRAY [0 .. 1023] OF M2S.INT32;
-   78    spanIdx: ARRAY [0 .. 1023] OF CARDINAL;
-   79    spanTy: ARRAY [0 .. 1023] OF INTEGER;
-   80    spanNode: ARRAY [0 .. 1023] OF AST.Node;
-   81  
-   82    (* Two-phase parse (milestone 2c): phase-1 skips a module-level proc
-   83       body (DeferSkip) and phase 2 re-parses it at unit end (RepassAll).
-   84       `deferredBody` reports the skip to ProcDecl's close choice;
-   85       `repassing` disables deferral during phase 2; `allowDefer` limits
-   86       deferral to plain ProcDecls (methods stay inline); `curProcNode` is
-   87       the NkProcDecl whose body is about to be parsed. *)
-   88    deferredBody: BOOLEAN;
-   89    repassing: BOOLEAN;
-   90    allowDefer: BOOLEAN;
-   91    curProcNode: AST.Node;
+   57    (* Two-phase parse (docs/plan-two-phase-parse.md), milestone 1.  When
+   58       TRUE each outermost procedure/method body is shadow-skipped at the
+   59       token level and the skip verified before the body parses normally.
+   60       Set by the driver (-notwophase turns it off); default on.
+   61       Blocks being parsed so only outermost bodies probe. *)
+   62    twoPhaseParse: BOOLEAN;
+   63  
+   64    (* Two-phase parse spans (milestone 2a): one entry per outermost body
+   65       shadow-skipped while twoPhaseParse is on — procedure name and the
+   66       buffer offset its body starts at (the lookahead token's nextPos).
+   67       Per-parse; nothing consumes the table yet. *)
+   68    nSpans: CARDINAL;
+   69    spanName: ARRAY [0 .. 1023] OF SymTab.Name;
+   70    spanStart: ARRAY [0 .. 1023] OF M2S.INT32;
+   71    spanIdx: ARRAY [0 .. 1023] OF CARDINAL;
+   72    spanTy: ARRAY [0 .. 1023] OF INTEGER;
+   73    spanNode: ARRAY [0 .. 1023] OF AST.Node;
+   74  
+   75    (* Two-phase parse (milestone 2c): phase-1 skips a module-level proc
+   76       body (DeferSkip) and phase 2 re-parses it at unit end (RepassAll).
+   77       `deferredBody` reports the skip to ProcDecl's close choice;
+   78       `repassing` disables deferral during phase 2; `allowDefer` limits
+   79       deferral to plain ProcDecls (methods stay inline); `curProcNode` is
+   80       the NkProcDecl whose body is about to be parsed. *)
+   81    deferredBody: BOOLEAN;
+   82    repassing: BOOLEAN;
+   83    allowDefer: BOOLEAN;
+   84    curProcNode: AST.Node;
+   85  
+   86    (* Result slot for the expression-AST builder (slice 2).  Every
+   87       Expr/SimExpr/Term/Fact leaves its node here; the combination
+   88       productions save it into locals before parsing the next operand.
+   89       `astIsLit` in Fact is per-invocation, so a nested Fact cannot make
+   90       an outer non-literal Fact look literal. *)
+   91    astCur: AST.Node;
    92  
    92  
-   93    (* Result slot for the expression-AST builder (slice 2).  Every
-   94       Expr/SimExpr/Term/Fact leaves its node here; the combination
-   95       productions save it into locals before parsing the next operand.
-   96       `astIsLit` in Fact is per-invocation, so a nested Fact cannot make
-   97       an outer non-literal Fact look literal. *)
-   98    astCur: AST.Node;
-   99  
-  100    (* Actual-argument nodes collected by ActParam for the call being
-  101       parsed by ArgList (slice 4).  Fact resets the count before the
-  102       optional ArgList and then folds the nodes into an NkCall. *)
-  103    astNArgs: CARDINAL;
-  104    astArgs: ARRAY [0 .. 31] OF AST.Node;
-  105  
-  106    (* Statement-AST result slot (slice 5): the most recently parsed
-  107       statement.  StatSeq folds these into an NkBlock. *)
-  108    astStmt: AST.Node;
-  109  
-  110    (* Declaration-AST result slot (slice 6): the most recently built
-  111       declaration; DeclSeq folds these into an NkDeclSeq. *)
-  112    astDecl: AST.Node;
+   93    (* Actual-argument nodes collected by ActParam for the call being
+   94       parsed by ArgList (slice 4).  Fact resets the count before the
+   95       optional ArgList and then folds the nodes into an NkCall. *)
+   96    astNArgs: CARDINAL;
+   97    astArgs: ARRAY [0 .. 31] OF AST.Node;
+   98  
+   99    (* Statement-AST result slot (slice 5): the most recently parsed
+  100       statement.  StatSeq folds these into an NkBlock. *)
+  101    astStmt: AST.Node;
+  102  
+  103    (* Declaration-AST result slot (slice 6): the most recently built
+  104       declaration; DeclSeq folds these into an NkDeclSeq. *)
+  105    astDecl: AST.Node;
+  106  
+  107    (* The local declarations of the most recent Block (a procedure body);
+  108       ProcDecl stores them as the proc node's child 2. *)
+  109    astBlkDecls: AST.Node;
+  110  
+  111    (* Unit-AST root (slice 7): NkUnit(name, decls, body). *)
+  112    astUnit: AST.Node;
   113  
   113  
-  114    (* The local declarations of the most recent Block (a procedure body);
-  115       ProcDecl stores them as the proc node's child 2. *)
-  116    astBlkDecls: AST.Node;
+  114    (* Import accumulator (slice 11): `{ Import }` appends NkImport
+  115       nodes here; each unit stores them as NkUnit child[3]. *)
+  116    astImp, astImpTail: AST.Node;
   117  
   117  
-  118    (* Unit-AST root (slice 7): NkUnit(name, decls, body). *)
-  119    astUnit: AST.Node;
-  120  
-  121    (* Import accumulator (slice 11): `{ Import }` appends NkImport
-  122       nodes here; each unit stores them as NkUnit child[3]. *)
-  123    astImp, astImpTail: AST.Node;
-  124  
-  125    (* Class-AST accumulators (slice 13): the class node currently being
-  126       parsed and its parent/field/method lists.  Classes are not nested
-  127       inside one another, so module-level state is safe. *)
-  128    astCls, astClsP, astClsPTail, astClsF, astClsFTail,
-  129    astClsM, astClsMTail, astMethod: AST.Node;
-  130  
-  131    (* Class of the method named by the last `obj.Method` designator
-  132       (InvalidType when the callee is an ordinary procedure). Set by
-  133       Design, consumed by the following ArgList. *)
-  134    methCls: SymTab.TypeIndex;
-  135    (* Class of the type of the innermost `TypeName{...}` brace
-  136       constructor (ClSet or ClArray); dispatches BraceElem. *)
-  137    braceCls: INTEGER;
-  138    (* Module-level VAR declarations whose type was still an unresolved
-  139       forward alias at declaration time; emitted once the TYPE block
-  140       completes (module scope only). *)
-  141    nPendVar: CARDINAL;
-  142    pendVarName: ARRAY [0 .. 255] OF SymTab.Name;
-  143    pendVarT: ARRAY [0 .. 255] OF SymTab.TypeIndex;
-  144    (* Forward module-level variables referenced from a procedure body. *)
-  145    (* GOTO/labels: the label and goto names of the procedure being parsed,
-  146       reset per procedure and checked at its END. *)
-  147    nLab, nGot: CARDINAL;
-  148    labNm, gotNm: ARRAY [0 .. 255] OF SymTab.Name;
+  118    (* Class-AST accumulators (slice 13): the class node currently being
+  119       parsed and its parent/field/method lists.  Classes are not nested
+  120       inside one another, so module-level state is safe. *)
+  121    astCls, astClsP, astClsPTail, astClsF, astClsFTail,
+  122    astClsM, astClsMTail, astMethod: AST.Node;
+  123  
+  124    (* Class of the method named by the last `obj.Method` designator
+  125       (InvalidType when the callee is an ordinary procedure). Set by
+  126       Design, consumed by the following ArgList. *)
+  127    methCls: SymTab.TypeIndex;
+  128    (* Class of the type of the innermost `TypeName{...}` brace
+  129       constructor (ClSet or ClArray); dispatches BraceElem. *)
+  130    braceCls: INTEGER;
+  131    (* Module-level VAR declarations whose type was still an unresolved
+  132       forward alias at declaration time; emitted once the TYPE block
+  133       completes (module scope only). *)
+  134    nPendVar: CARDINAL;
+  135    pendVarName: ARRAY [0 .. 255] OF SymTab.Name;
+  136    pendVarT: ARRAY [0 .. 255] OF SymTab.TypeIndex;
+  137    (* Forward module-level variables referenced from a procedure body. *)
+  138    (* GOTO/labels: the label and goto names of the procedure being parsed,
+  139       reset per procedure and checked at its END. *)
+  140    nLab, nGot: CARDINAL;
+  141    labNm, gotNm: ARRAY [0 .. 255] OF SymTab.Name;
+  142  
+  143    (* Generics (Increment 1): the last refining module seen — instance
+  144       name, generic name, and the actual type parameters. *)
+  145    refInst, refGen: SymTab.Name;
+  146    refN: CARDINAL;
+  147    refActual: ARRAY [0 .. 15] OF SymTab.TypeIndex;
+  148    isGen: BOOLEAN;
   149  
   149  
-  150    (* Generics (Increment 1): the last refining module seen — instance
-  151       name, generic name, and the actual type parameters. *)
-  152    refInst, refGen: SymTab.Name;
-  153    refN: CARDINAL;
-  154    refActual: ARRAY [0 .. 15] OF SymTab.TypeIndex;
-  155    isGen: BOOLEAN;
-  156  
-  157    (* Generics (Increment 2): instantiation re-parse context.  When the
-  158       driver re-parses a generic's source to instantiate it as `instName`,
-  159       instActive is TRUE, the module is renamed, and each type formal is
-  160       bound to the corresponding instActual entry. *)
-  161    instActive: BOOLEAN;
-  162    instName: SymTab.Name;
-  163    instActual: ARRAY [0 .. 15] OF SymTab.TypeIndex;
-  164    instN: CARDINAL;
-  165    instFk: CARDINAL;   (* formal cursor while binding during re-parse *)
-  166  
-  167    (* Identity of the last-parsed unit and refinement, for the driver's
-  168       generic registry and its re-parse decision. *)
-  169    unitName: SymTab.Name;
-  170    unitWasGen: BOOLEAN;
-  171    unitWasDef: BOOLEAN;
-  172    refSeen: BOOLEAN;
-  173    refIsDef: BOOLEAN;
-  174  
-  175  
-  176  PROCEDURE CopyNm (src: ARRAY OF CHAR; VAR dst: SymTab.Name);
-  177    VAR i: CARDINAL;
-  178    BEGIN
-  179      i := 0;
-  180      WHILE (i <= HIGH(dst)) AND (i <= HIGH(src)) AND (src[i] # CHR(0)) DO
-  181        dst[i] := src[i]; INC(i)
-  182      END;
-  183      IF i <= HIGH(dst) THEN dst[i] := CHR(0) END
-  184    END CopyNm;
-  185  
-  186  PROCEDURE InInst () : BOOLEAN;
-  187    BEGIN RETURN instActive END InInst;
-  188  
-  189  PROCEDURE InstNameGet (VAR nm: SymTab.Name);
-  190    BEGIN CopyNm(instName, nm) END InstNameGet;
-  191  
-  192  PROCEDURE InstActualGet (i: CARDINAL) : SymTab.TypeIndex;
-  193    BEGIN
-  194      IF i >= instN THEN RETURN SymTab.InvalidType END;
-  195      RETURN instActual[i]
-  196    END InstActualGet;
-  197  
-  198  PROCEDURE InstBegin (name: ARRAY OF CHAR);
-  199    BEGIN instActive := TRUE; CopyNm(name, instName); instN := 0;
-  200      instFk := 0 END InstBegin;
-  201  
-  202  PROCEDURE InstAddActual (t: SymTab.TypeIndex);
-  203    BEGIN
-  204      IF instN <= HIGH(instActual) THEN instActual[instN] := t; INC(instN) END
-  205    END InstAddActual;
-  206  
-  207  PROCEDURE InstEnd;
-  208    BEGIN instActive := FALSE; instN := 0 END InstEnd;
-  209  
-  210  PROCEDURE UnitNameGet (VAR nm: SymTab.Name);
-  211    BEGIN CopyNm(unitName, nm) END UnitNameGet;
-  212  
-  213  PROCEDURE UnitIsGeneric () : BOOLEAN;
-  214    BEGIN RETURN unitWasGen END UnitIsGeneric;
-  215  
-  216  PROCEDURE UnitIsDefModule () : BOOLEAN;
-  217    BEGIN RETURN unitWasDef END UnitIsDefModule;
-  218  
-  219  PROCEDURE RefineSeen () : BOOLEAN;
-  220    BEGIN RETURN refSeen END RefineSeen;
-  221  
-  222  PROCEDURE RefineIsDef () : BOOLEAN;
-  223    BEGIN RETURN refIsDef END RefineIsDef;
-  224  
-  225  PROCEDURE RefineInst (VAR nm: SymTab.Name);
-  226    BEGIN CopyNm(refInst, nm) END RefineInst;
-  227  
-  228  PROCEDURE RefineGen (VAR nm: SymTab.Name);
-  229    BEGIN CopyNm(refGen, nm) END RefineGen;
-  230  
-  231  PROCEDURE RefineActualCount () : CARDINAL;
-  232    BEGIN RETURN refN END RefineActualCount;
-  233  
-  234  PROCEDURE RefineActualGet (i: CARDINAL) : SymTab.TypeIndex;
-  235    BEGIN
-  236      IF i >= refN THEN RETURN SymTab.InvalidType END;
-  237      RETURN refActual[i]
-  238    END RefineActualGet;
-  239  
-  240  PROCEDURE NoteLabel (nm: ARRAY OF CHAR);
-  241  (* Record a statement label; duplicate is 200. *)
-  242    VAR i: CARDINAL;
-  243    BEGIN
-  244      i := 0;
-  245      WHILE i < nLab DO
-  246        IF SymTab.Equal(labNm[i], nm) THEN SemError(200); RETURN END;
-  247        INC(i)
-  248      END;
-  249      IF nLab <= HIGH(labNm) THEN
-  250        CopyNm(nm, labNm[nLab]); INC(nLab)
-  251      END
-  252    END NoteLabel;
-  253  
-  254  PROCEDURE NoteGoto (nm: ARRAY OF CHAR);
-  255    VAR i: CARDINAL;
-  256    BEGIN
-  257      i := 0;
-  258      WHILE i < nGot DO
-  259        IF SymTab.Equal(gotNm[i], nm) THEN RETURN END;
-  260        INC(i)
-  261      END;
-  262      IF nGot <= HIGH(gotNm) THEN
-  263        CopyNm(nm, gotNm[nGot]); INC(nGot)
-  264      END
-  265    END NoteGoto;
-  266  
-  267  PROCEDURE CheckGotos;
-  268  (* At a procedure's END: every GOTO must name a label in that procedure. *)
-  269    VAR i, j: CARDINAL; found: BOOLEAN;
-  270    BEGIN
-  271      i := 0;
-  272      WHILE i < nGot DO
-  273        found := FALSE; j := 0;
-  274        WHILE (j < nLab) AND NOT found DO
-  275          IF SymTab.Equal(labNm[j], gotNm[i]) THEN found := TRUE END;
-  276          INC(j)
-  277        END;
-  278        IF NOT found THEN SemError(201) END;
-  279        INC(i)
-  280      END
-  281    END CheckGotos;
-  282  
-  283  PROCEDURE FlushPend;
-  284  (* Emit module-level globals whose forward type is now resolved. *)
-  285    VAR k: CARDINAL;
-  286    BEGIN
-  287      k := 0;
-  288      WHILE k < nPendVar DO
-  289        INC(k)
-  290      END;
-  291      nPendVar := 0
-  292    END FlushPend;
-  293  
-  294  PROCEDURE AstAppend (kind: INTEGER; VAR head, tail: AST.Node;
-  295                       item: AST.Node);
-  296  (* Appends `item` to a chunked sequence: each node holds up to
-  297     AST.MaxChild-1 items; child[MaxChild-1] continues into the next
-  298     chunk.  Unbounded, so blocks/decl sequences are not capped at 8. *)
-  299    VAR n: AST.Node;
-  300    BEGIN
-  301      IF item = AST.NoNode THEN RETURN END;
-  302      IF head = AST.NoNode THEN
-  303        head := AST.MakeNode(kind); tail := head
-  304      END;
-  305      IF AST.NChild(tail) >= AST.MaxChild - 1 THEN
-  306        n := AST.MakeNode(kind);
-  307        AST.SetChild(tail, AST.MaxChild - 1, n);
-  308        tail := n
-  309      END;
-  310      AST.SetChild(tail, AST.NChild(tail), item)
-  311    END AstAppend;
-  312  
-  313  PROCEDURE AstCallNode (callee: AST.Node) : AST.Node;
-  314  (* Builds NkCall(callee, actuals...) from astArgs/astNArgs.  The actuals
-  315     are a chunked sequence (AstAppend): a call can have more than
-  316     MaxChild-1 arguments (the generic ArgList has 9), and SetChild would
-  317     silently drop the tail.  NkBlock marks the continuation chunks. *)
-  318    VAR n, tail: AST.Node; j: CARDINAL;
-  319    BEGIN
-  320      n := AST.MakeNode(AST.NkCall);
-  321      AST.SetChild(n, 0, callee);
-  322      tail := n;
-  323      j := 0;
-  324      WHILE j < astNArgs DO
-  325        AstAppend(AST.NkBlock, n, tail, astArgs[j]);
-  326        INC(j)
-  327      END;
-  328      RETURN n
-  329    END AstCallNode;
-  330  
+  150    (* Generics (Increment 2): instantiation re-parse context.  When the
+  151       driver re-parses a generic's source to instantiate it as `instName`,
+  152       instActive is TRUE, the module is renamed, and each type formal is
+  153       bound to the corresponding instActual entry. *)
+  154    instActive: BOOLEAN;
+  155    instName: SymTab.Name;
+  156    instActual: ARRAY [0 .. 15] OF SymTab.TypeIndex;
+  157    instN: CARDINAL;
+  158    instFk: CARDINAL;   (* formal cursor while binding during re-parse *)
+  159  
+  160    (* Identity of the last-parsed unit and refinement, for the driver's
+  161       generic registry and its re-parse decision. *)
+  162    unitName: SymTab.Name;
+  163    unitWasGen: BOOLEAN;
+  164    unitWasDef: BOOLEAN;
+  165    refSeen: BOOLEAN;
+  166    refIsDef: BOOLEAN;
+  167  
+  168  
+  169  PROCEDURE CopyNm (src: ARRAY OF CHAR; VAR dst: SymTab.Name);
+  170    VAR i: CARDINAL;
+  171    BEGIN
+  172      i := 0;
+  173      WHILE (i <= HIGH(dst)) AND (i <= HIGH(src)) AND (src[i] # CHR(0)) DO
+  174        dst[i] := src[i]; INC(i)
+  175      END;
+  176      IF i <= HIGH(dst) THEN dst[i] := CHR(0) END
+  177    END CopyNm;
+  178  
+  179  PROCEDURE InInst () : BOOLEAN;
+  180    BEGIN RETURN instActive END InInst;
+  181  
+  182  PROCEDURE InstNameGet (VAR nm: SymTab.Name);
+  183    BEGIN CopyNm(instName, nm) END InstNameGet;
+  184  
+  185  PROCEDURE InstActualGet (i: CARDINAL) : SymTab.TypeIndex;
+  186    BEGIN
+  187      IF i >= instN THEN RETURN SymTab.InvalidType END;
+  188      RETURN instActual[i]
+  189    END InstActualGet;
+  190  
+  191  PROCEDURE InstBegin (name: ARRAY OF CHAR);
+  192    BEGIN instActive := TRUE; CopyNm(name, instName); instN := 0;
+  193      instFk := 0 END InstBegin;
+  194  
+  195  PROCEDURE InstAddActual (t: SymTab.TypeIndex);
+  196    BEGIN
+  197      IF instN <= HIGH(instActual) THEN instActual[instN] := t; INC(instN) END
+  198    END InstAddActual;
+  199  
+  200  PROCEDURE InstEnd;
+  201    BEGIN instActive := FALSE; instN := 0 END InstEnd;
+  202  
+  203  PROCEDURE UnitNameGet (VAR nm: SymTab.Name);
+  204    BEGIN CopyNm(unitName, nm) END UnitNameGet;
+  205  
+  206  PROCEDURE UnitIsGeneric () : BOOLEAN;
+  207    BEGIN RETURN unitWasGen END UnitIsGeneric;
+  208  
+  209  PROCEDURE UnitIsDefModule () : BOOLEAN;
+  210    BEGIN RETURN unitWasDef END UnitIsDefModule;
+  211  
+  212  PROCEDURE RefineSeen () : BOOLEAN;
+  213    BEGIN RETURN refSeen END RefineSeen;
+  214  
+  215  PROCEDURE RefineIsDef () : BOOLEAN;
+  216    BEGIN RETURN refIsDef END RefineIsDef;
+  217  
+  218  PROCEDURE RefineInst (VAR nm: SymTab.Name);
+  219    BEGIN CopyNm(refInst, nm) END RefineInst;
+  220  
+  221  PROCEDURE RefineGen (VAR nm: SymTab.Name);
+  222    BEGIN CopyNm(refGen, nm) END RefineGen;
+  223  
+  224  PROCEDURE RefineActualCount () : CARDINAL;
+  225    BEGIN RETURN refN END RefineActualCount;
+  226  
+  227  PROCEDURE RefineActualGet (i: CARDINAL) : SymTab.TypeIndex;
+  228    BEGIN
+  229      IF i >= refN THEN RETURN SymTab.InvalidType END;
+  230      RETURN refActual[i]
+  231    END RefineActualGet;
+  232  
+  233  PROCEDURE NoteLabel (nm: ARRAY OF CHAR);
+  234  (* Record a statement label; duplicate is 200. *)
+  235    VAR i: CARDINAL;
+  236    BEGIN
+  237      i := 0;
+  238      WHILE i < nLab DO
+  239        IF SymTab.Equal(labNm[i], nm) THEN SemError(200); RETURN END;
+  240        INC(i)
+  241      END;
+  242      IF nLab <= HIGH(labNm) THEN
+  243        CopyNm(nm, labNm[nLab]); INC(nLab)
+  244      END
+  245    END NoteLabel;
+  246  
+  247  PROCEDURE NoteGoto (nm: ARRAY OF CHAR);
+  248    VAR i: CARDINAL;
+  249    BEGIN
+  250      i := 0;
+  251      WHILE i < nGot DO
+  252        IF SymTab.Equal(gotNm[i], nm) THEN RETURN END;
+  253        INC(i)
+  254      END;
+  255      IF nGot <= HIGH(gotNm) THEN
+  256        CopyNm(nm, gotNm[nGot]); INC(nGot)
+  257      END
+  258    END NoteGoto;
+  259  
+  260  PROCEDURE CheckGotos;
+  261  (* At a procedure's END: every GOTO must name a label in that procedure. *)
+  262    VAR i, j: CARDINAL; found: BOOLEAN;
+  263    BEGIN
+  264      i := 0;
+  265      WHILE i < nGot DO
+  266        found := FALSE; j := 0;
+  267        WHILE (j < nLab) AND NOT found DO
+  268          IF SymTab.Equal(labNm[j], gotNm[i]) THEN found := TRUE END;
+  269          INC(j)
+  270        END;
+  271        IF NOT found THEN SemError(201) END;
+  272        INC(i)
+  273      END
+  274    END CheckGotos;
+  275  
+  276  PROCEDURE FlushPend;
+  277  (* Emit module-level globals whose forward type is now resolved. *)
+  278    VAR k: CARDINAL;
+  279    BEGIN
+  280      k := 0;
+  281      WHILE k < nPendVar DO
+  282        INC(k)
+  283      END;
+  284      nPendVar := 0
+  285    END FlushPend;
+  286  
+  287  PROCEDURE AstAppend (kind: INTEGER; VAR head, tail: AST.Node;
+  288                       item: AST.Node);
+  289  (* Appends `item` to a chunked sequence: each node holds up to
+  290     AST.MaxChild-1 items; child[MaxChild-1] continues into the next
+  291     chunk.  Unbounded, so blocks/decl sequences are not capped at 8. *)
+  292    VAR n: AST.Node;
+  293    BEGIN
+  294      IF item = AST.NoNode THEN RETURN END;
+  295      IF head = AST.NoNode THEN
+  296        head := AST.MakeNode(kind); tail := head
+  297      END;
+  298      IF AST.NChild(tail) >= AST.MaxChild - 1 THEN
+  299        n := AST.MakeNode(kind);
+  300        AST.SetChild(tail, AST.MaxChild - 1, n);
+  301        tail := n
+  302      END;
+  303      AST.SetChild(tail, AST.NChild(tail), item)
+  304    END AstAppend;
+  305  
+  306  PROCEDURE AstCallNode (callee: AST.Node) : AST.Node;
+  307  (* Builds NkCall(callee, actuals...) from astArgs/astNArgs.  The actuals
+  308     are a chunked sequence (AstAppend): a call can have more than
+  309     MaxChild-1 arguments (the generic ArgList has 9), and SetChild would
+  310     silently drop the tail.  NkBlock marks the continuation chunks. *)
+  311    VAR n, tail: AST.Node; j: CARDINAL;
+  312    BEGIN
+  313      n := AST.MakeNode(AST.NkCall);
+  314      AST.SetChild(n, 0, callee);
+  315      tail := n;
+  316      j := 0;
+  317      WHILE j < astNArgs DO
+  318        AstAppend(AST.NkBlock, n, tail, astArgs[j]);
+  319        INC(j)
+  320      END;
+  321      RETURN n
+  322    END AstCallNode;
+  323  
+  324  
+  325  
+  326  PROCEDURE GetUnit (): AST.Node;
+  327  (* The most recently parsed unit's AST root (for the Lower comparison). *)
+  328    BEGIN
+  329      RETURN astUnit
+  330    END GetUnit;
   331  
   331  
-  332  
-  333  PROCEDURE GetUnit (): AST.Node;
-  334  (* The most recently parsed unit's AST root (for the Lower comparison). *)
-  335    BEGIN
-  336      RETURN astUnit
-  337    END GetUnit;
-  338  
-  339  PROCEDURE SetTwoPhase (b: BOOLEAN);
-  340  (* Driver switch for the two-phase parse probe (milestone 1). *)
-  341    BEGIN
-  342      twoPhaseParse := b
-  343    END SetTwoPhase;
-  344  
-  345  PROCEDURE TokIs (kw: ARRAY OF CHAR): BOOLEAN;
-  346  (* The current lookahead token's source text equals kw.  Compares text,
-  347     not token codes, so grammar renumbering cannot desync the skipper. *)
-  348    VAR tok: ARRAY [0 .. 63] OF CHAR;
-  349    BEGIN
-  350      M2S.GetName(M2S.nextPos, M2S.nextLen, tok);
-  351      RETURN SymTab.Equal(tok, kw)
-  352    END TokIs;
-  353  
-  354  PROCEDURE Adv;
-  355  (* Advance one token: exactly the parser frame's Get for a grammar
-  356     without pragmas (its pragma branch is empty and the scanner never
-  357     returns a token above maxT, so the repeat loop runs once).  A
-  358     separate name because the frame's Get is declared later in this
-  359     module: a bare Get here would bind the imported M2S.Get (which takes
-  360     a parameter) under single-pass compilers. *)
-  361    BEGIN
-  362      M2S.Get(sym);
-  363      INC(errDist)
-  364    END Adv;
-  365  
-  366  PROCEDURE NoteSpan (pn: SymTab.Name; start: M2S.INT32);
-  367  (* Records an outermost body span for the re-parse pass (milestone 2).
-  368     Diagnostic only for now: nothing consumes the table yet.  Declared
-  369     before its caller: V3 resolves single-pass (declaration before use),
-  370     with no forward tolerance for procedure calls. *)
-  371    BEGIN
-  372      IF nSpans > HIGH(spanName) THEN RETURN END;
-  373      CopyNm(pn, spanName[nSpans]);
-  374      spanStart[nSpans] := start;
-  375      spanIdx[nSpans] := SymTab.DeferBody();
-  376      INC(nSpans)
-  377    END NoteSpan;
-  378  
-  379  PROCEDURE Openers (): BOOLEAN;
-  380  (* TRUE when the current token opens a block that must be closed by an
-  381     END (BEGIN is excluded: a block's BEGIN shares the declaration END;
-  382     REPEAT..UNTIL and EXIT/RETURN need no END). *)
-  383    BEGIN
-  384      RETURN TokIs("MODULE") OR TokIs("PROCEDURE") OR TokIs("CLASS")
-  385         OR TokIs("RECORD") OR TokIs("IF") OR TokIs("CASE")
-  386         OR TokIs("WHILE") OR TokIs("FOR") OR TokIs("LOOP")
-  387         OR TokIs("WITH")
-  388    END Openers;
-  389  
-  390  PROCEDURE DeferSkip (pn: SymTab.Name): BOOLEAN;
-  391  (* Phase 1 of the deferral: skip the body starting at the current token
-  392     (the first token after the heading's ';') up to the matching END,
-  393     verify the END's name, and LEAVE the scanner positioned exactly at
-  394     that END (so Block's trailing "END" ident consumes it for real), with
-  395     the span recorded for the re-parse pass.  On any inconsistency,
-  396     restore the scanner and return FALSE so the caller parses normally. *)
-  397    VAR depth, guard: CARDINAL;
-  398      nm: SymTab.Name;
-  399      ok: BOOLEAN;
-  400      start, endPos: M2S.INT32;
-  401    BEGIN
-  402      deferredBody := FALSE;
-  403      start := M2S.nextPos;
-  404      M2S.PushPos;
-  405      depth := 0; guard := 0; ok := TRUE;
-  406      LOOP
-  407        IF sym = 0 THEN ok := FALSE; EXIT END;
-  408        IF TokIs("END") THEN
-  409          IF depth = 0 THEN EXIT END;
-  410          DEC(depth)
-  411        ELSIF Openers() THEN
-  412          INC(depth)
-  413        END;
-  414        Adv;
-  415        INC(guard);
-  416        IF guard > 1000000 THEN ok := FALSE; EXIT END
-  417      END;
-  418      IF ok THEN
-  419        (* sym is the matching END; check the name after it, then seek back
-  420           so Block sees END (its "END" ident then consumes it for real). *)
-  421        endPos := M2S.nextPos;
-  422        Adv;
-  423        M2S.GetName(M2S.nextPos, M2S.nextLen, nm);
-  424        IF (sym = 0) OR NOT SymTab.Equal(nm, pn) THEN ok := FALSE END;
-  425        IF ok THEN
-  426          M2S.SeekTo(endPos); Adv
-  427        END
-  428      END;
-  429      IF ok THEN
-  430        NoteSpan(pn, start);
-  431        spanTy[nSpans - 1] := Lower.CurScopeProc();
-  432        spanNode[nSpans - 1] := curProcNode;
-  433        M2S.DropPos;   (* keep the scanner at END; discard the snapshot *)
-  434        deferredBody := TRUE;
-  435        RETURN TRUE
-  436      ELSE
-  437        M2S.PopPos;
-  438        FileIO.WriteString(FileIO.StdOut, "twophase defer mismatch in ");
-  439        FileIO.WriteString(FileIO.StdOut, pn);
-  440        FileIO.WriteLn(FileIO.StdOut);
-  441        RETURN FALSE
-  442      END
-  443    END DeferSkip;
-  444  
-  445  CHARACTERS
-  446    eol      = CHR(13) .
-  447    lf       = CHR(10) .
-  448    letter   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
-  449    digit    = "0123456789" .
-  450    hexDigit = digit + "ABCDEFabcdef" .
-  451    noQuote1 = ANY - "'" - eol .
-  452    noQuote2 = ANY - '"' - eol .
-  453  
-  454  IGNORE CHR(9) .. CHR(13)
-  455  
-  456  COMMENTS FROM "(*" TO "*)" NESTED
-  457  COMMENTS FROM "//" TO lf
-  458  
-  459  TOKENS
-  460    ident   = letter { letter | digit | "_" } .
-  461    integer = digit { digit }
-  462            | digit { digit } CONTEXT("..")
-  463            | "0x" hexDigit { hexDigit }
-  464            | "0X" hexDigit { hexDigit } .
-  465    real    = digit { digit } "." { digit }
-  466              [ ( "E" | "e" ) [ "+" | "-" ] digit { digit } ] .
-  467    string  = "'" { noQuote1 } "'"
-  468            | '"' { noQuote2 } '"' .
-  469    charConst = digit { digit } ( "C" | "c" ) .
-  470    ustring = ( "U" | "u" ) ( "'" { noQuote1 } "'" | '"' { noQuote2 } '"' ) .
-  471  
-  472  PRODUCTIONS
-  473    M2
-  474      = (. twoPhase := TRUE; astCur := AST.NoNode; astStmt := AST.NoNode; astDecl := AST.NoNode; astImp := AST.NoNode; astImpTail := AST.NoNode;
-  475                                             astImp := AST.NoNode;
-  476                                             astImpTail := AST.NoNode;
-  477                                             procNest := 0; nSpans := 0;
-  478                                             SymTab.DeferReset; .)
-  479        Unit "." .
-  480    (* Units: program modules compile fully; DEFINITION and
-  481       IMPLEMENTATION modules parse + check now but lower in step 4
-  482       (each ends with one 230); same for nested local modules. *)
-  483    (* Generics (Increment 1): formal and actual parameters.  Formals are
-  484       TYPE parameters only; actuals are type identifiers. *)
-  485    GenericFormals
-  486      = "(" GenericFormal { ";" GenericFormal } ")" .
-  487    GenericFormal                         (. VAR nm: SymTab.Name; .)
-  488      = GetIdent<nm>                      (. IF instActive THEN
+  332  PROCEDURE SetTwoPhase (b: BOOLEAN);
+  333  (* Driver switch for the two-phase parse probe (milestone 1). *)
+  334    BEGIN
+  335      twoPhaseParse := b
+  336    END SetTwoPhase;
+  337  
+  338  PROCEDURE TokIs (kw: ARRAY OF CHAR): BOOLEAN;
+  339  (* The current lookahead token's source text equals kw.  Compares text,
+  340     not token codes, so grammar renumbering cannot desync the skipper. *)
+  341    VAR tok: ARRAY [0 .. 63] OF CHAR;
+  342    BEGIN
+  343      M2S.GetName(M2S.nextPos, M2S.nextLen, tok);
+  344      RETURN SymTab.Equal(tok, kw)
+  345    END TokIs;
+  346  
+  347  PROCEDURE Adv;
+  348  (* Advance one token: exactly the parser frame's Get for a grammar
+  349     without pragmas (its pragma branch is empty and the scanner never
+  350     returns a token above maxT, so the repeat loop runs once).  A
+  351     separate name because the frame's Get is declared later in this
+  352     module: a bare Get here would bind the imported M2S.Get (which takes
+  353     a parameter) under single-pass compilers. *)
+  354    BEGIN
+  355      M2S.Get(sym);
+  356      INC(errDist)
+  357    END Adv;
+  358  
+  359  PROCEDURE NoteSpan (pn: SymTab.Name; start: M2S.INT32);
+  360  (* Records an outermost body span for the re-parse pass (milestone 2).
+  361     Diagnostic only for now: nothing consumes the table yet.  Declared
+  362     before its caller: V3 resolves single-pass (declaration before use),
+  363     with no forward tolerance for procedure calls. *)
+  364    BEGIN
+  365      IF nSpans > HIGH(spanName) THEN RETURN END;
+  366      CopyNm(pn, spanName[nSpans]);
+  367      spanStart[nSpans] := start;
+  368      spanIdx[nSpans] := SymTab.DeferBody();
+  369      INC(nSpans)
+  370    END NoteSpan;
+  371  
+  372  PROCEDURE Openers (): BOOLEAN;
+  373  (* TRUE when the current token opens a block that must be closed by an
+  374     END (BEGIN is excluded: a block's BEGIN shares the declaration END;
+  375     REPEAT..UNTIL and EXIT/RETURN need no END). *)
+  376    BEGIN
+  377      RETURN TokIs("MODULE") OR TokIs("PROCEDURE") OR TokIs("CLASS")
+  378         OR TokIs("RECORD") OR TokIs("IF") OR TokIs("CASE")
+  379         OR TokIs("WHILE") OR TokIs("FOR") OR TokIs("LOOP")
+  380         OR TokIs("WITH")
+  381    END Openers;
+  382  
+  383  PROCEDURE DeferSkip (pn: SymTab.Name): BOOLEAN;
+  384  (* Phase 1 of the deferral: skip the body starting at the current token
+  385     (the first token after the heading's ';') up to the matching END,
+  386     verify the END's name, and LEAVE the scanner positioned exactly at
+  387     that END (so Block's trailing "END" ident consumes it for real), with
+  388     the span recorded for the re-parse pass.  On any inconsistency,
+  389     restore the scanner and return FALSE so the caller parses normally. *)
+  390    VAR depth, guard: CARDINAL;
+  391      nm: SymTab.Name;
+  392      ok: BOOLEAN;
+  393      start, endPos: M2S.INT32;
+  394    BEGIN
+  395      deferredBody := FALSE;
+  396      start := M2S.nextPos;
+  397      M2S.PushPos;
+  398      depth := 0; guard := 0; ok := TRUE;
+  399      LOOP
+  400        IF sym = 0 THEN ok := FALSE; EXIT END;
+  401        IF TokIs("END") THEN
+  402          IF depth = 0 THEN EXIT END;
+  403          DEC(depth)
+  404        ELSIF Openers() THEN
+  405          INC(depth)
+  406        END;
+  407        Adv;
+  408        INC(guard);
+  409        IF guard > 1000000 THEN ok := FALSE; EXIT END
+  410      END;
+  411      IF ok THEN
+  412        (* sym is the matching END; check the name after it, then seek back
+  413           so Block sees END (its "END" ident then consumes it for real). *)
+  414        endPos := M2S.nextPos;
+  415        Adv;
+  416        M2S.GetName(M2S.nextPos, M2S.nextLen, nm);
+  417        IF (sym = 0) OR NOT SymTab.Equal(nm, pn) THEN ok := FALSE END;
+  418        IF ok THEN
+  419          M2S.SeekTo(endPos); Adv
+  420        END
+  421      END;
+  422      IF ok THEN
+  423        NoteSpan(pn, start);
+  424        spanTy[nSpans - 1] := Lower.CurScopeProc();
+  425        spanNode[nSpans - 1] := curProcNode;
+  426        M2S.DropPos;   (* keep the scanner at END; discard the snapshot *)
+  427        deferredBody := TRUE;
+  428        RETURN TRUE
+  429      ELSE
+  430        M2S.PopPos;
+  431        FileIO.WriteString(FileIO.StdOut, "twophase defer mismatch in ");
+  432        FileIO.WriteString(FileIO.StdOut, pn);
+  433        FileIO.WriteLn(FileIO.StdOut);
+  434        RETURN FALSE
+  435      END
+  436    END DeferSkip;
+  437  
+  438  CHARACTERS
+  439    eol      = CHR(13) .
+  440    lf       = CHR(10) .
+  441    letter   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
+  442    digit    = "0123456789" .
+  443    hexDigit = digit + "ABCDEFabcdef" .
+  444    noQuote1 = ANY - "'" - eol .
+  445    noQuote2 = ANY - '"' - eol .
+  446  
+  447  IGNORE CHR(9) .. CHR(13)
+  448  
+  449  COMMENTS FROM "(*" TO "*)" NESTED
+  450  COMMENTS FROM "//" TO lf
+  451  
+  452  TOKENS
+  453    ident   = letter { letter | digit | "_" } .
+  454    integer = digit { digit }
+  455            | digit { digit } CONTEXT("..")
+  456            | "0x" hexDigit { hexDigit }
+  457            | "0X" hexDigit { hexDigit } .
+  458    real    = digit { digit } "." { digit }
+  459              [ ( "E" | "e" ) [ "+" | "-" ] digit { digit } ] .
+  460    string  = "'" { noQuote1 } "'"
+  461            | '"' { noQuote2 } '"' .
+  462    charConst = digit { digit } ( "C" | "c" ) .
+  463    ustring = ( "U" | "u" ) ( "'" { noQuote1 } "'" | '"' { noQuote2 } '"' ) .
+  464  
+  465  PRODUCTIONS
+  466    M2
+  467      = (. astCur := AST.NoNode; astStmt := AST.NoNode; astDecl := AST.NoNode; astImp := AST.NoNode; astImpTail := AST.NoNode;
+  468                                             astImp := AST.NoNode;
+  469                                             astImpTail := AST.NoNode;
+  470                                             nSpans := 0;
+  471                                             SymTab.DeferReset; .)
+  472        Unit "." .
+  473    (* Units: program modules compile fully; DEFINITION and
+  474       IMPLEMENTATION modules parse + check now but lower in step 4
+  475       (each ends with one 230); same for nested local modules. *)
+  476    (* Generics (Increment 1): formal and actual parameters.  Formals are
+  477       TYPE parameters only; actuals are type identifiers. *)
+  478    GenericFormals
+  479      = "(" GenericFormal { ";" GenericFormal } ")" .
+  480    GenericFormal                         (. VAR nm: SymTab.Name; .)
+  481      = GetIdent<nm>                      (. IF instActive THEN
+  482                                               IF NOT SymTab.EnterTypeParamBound(nm,
+  483                                                  InstActualGet(instFk)) THEN
+  484                                                 SemError(200) END
+  485                                             ELSIF NOT SymTab.EnterTypeParam(nm) THEN
+  486                                               SemError(200) END;
+  487                                             INC(instFk); .)
+  488        { "," GetIdent<nm>                (. IF instActive THEN
   489                                               IF NOT SymTab.EnterTypeParamBound(nm,
   489                                               IF NOT SymTab.EnterTypeParamBound(nm,
   490                                                  InstActualGet(instFk)) THEN
   490                                                  InstActualGet(instFk)) THEN
   491                                                 SemError(200) END
   491                                                 SemError(200) END
   492                                             ELSIF NOT SymTab.EnterTypeParam(nm) THEN
   492                                             ELSIF NOT SymTab.EnterTypeParam(nm) THEN
   493                                               SemError(200) END;
   493                                               SemError(200) END;
-  494                                             INC(instFk); .)
-  495        { "," GetIdent<nm>                (. IF instActive THEN
-  496                                               IF NOT SymTab.EnterTypeParamBound(nm,
-  497                                                  InstActualGet(instFk)) THEN
-  498                                                 SemError(200) END
-  499                                             ELSIF NOT SymTab.EnterTypeParam(nm) THEN
-  500                                               SemError(200) END;
-  501                                             INC(instFk); .) }
-  502        ":" "TYPE" .
-  503    Actuals
-  504      = Actual { "," Actual } .
-  505    Actual                                (. VAR at: SymTab.TypeIndex; .)
-  506      = TypeIdent<at>                     (. IF refN <= HIGH(refActual) THEN
-  507                                               refActual[refN] := at; INC(refN)
-  508                                             END; .) .
-  509    Unit
-  510      =                                   (. isGen := FALSE;
-  511                                             allowDefer := FALSE;
-  512                                             repassing := FALSE; .)
-  513        [ "GENERIC"                       (. isGen := TRUE; .) ]
-  514        ( DefUnit | ImplUnit | ProgModule ) .
-  515    (* Step 4.3: one session compiles DEFINITION, its IMPLEMENTATION
-  516       and one program (last) into one image. Units share the symbol
-  517       table; imports materialize exported names. *)
-  518    DefUnit                               (. VAR m1, m2, pn: SymTab.Name;
-  519                                               g: SymTab.Name;
-  520                                               astSeq, astTail, astProc: AST.Node; .)
-  521      =                                   (. refN := 0; refSeen := FALSE; .)
-  522        "DEFINITION" "MODULE"
-  523        GetIdent<m1>                      (. IF instActive THEN InstNameGet(m1) END;
-  524                                             IF instActive THEN
-  525                                               IF NOT SymTab.Reenter(m1,
-  526                                                      SymTab.UnitDef) THEN
-  527                                                 SemError(200) END
-  528                                             ELSIF NOT SymTab.BeginDef(m1) THEN
-  529                                               SemError(200) END;
-  530                                             QbeGen.SetModule(m1);
-  531                                             CopyNm(m1, unitName);
-  532                                             unitWasGen := isGen
-  533                                               AND NOT instActive;
-  534                                             unitWasDef := TRUE; .)
-  535        [ GenericFormals ]
-  536        ( ";"
-  537        { Import                        (. AstAppend(AST.NkDeclSeq,
-  538                                               astImp, astImpTail, astDecl); .) }
-  539        [ "EXPORT" [ "QUALIFIED" ]        (. (* definition-module export
-  540                                                list: parsed, and the
-  541                                                names are already exported
-  542                                                by the module scope *) .)
-  543          GetIdent<pn> { "," GetIdent<pn> } ";" ]
-  544                                          (. astSeq := AST.NoNode;
-  545                                             astTail := AST.NoNode; .)
-  546        { ConstBlock                      (. AstAppend(AST.NkDeclSeq,
-  547                                               astSeq, astTail, astDecl); .)
-  548        | TypeBlock<TRUE>                 (. AstAppend(AST.NkDeclSeq,
-  549                                               astSeq, astTail, astDecl); .)
-  550        | VarBlock                        (. AstAppend(AST.NkDeclSeq,
-  551                                               astSeq, astTail, astDecl); .)
-  552        | ProcHeading<pn, SymTab.InvalidType> ";"
-  553                                          (. (* a heading only: record it so
-  554                                                Lower can replay it *)
-  555                                             astProc := AST.MakeNode(AST.NkProcDecl);
-  556                                             AST.SetOp(astProc, 0);
-  557                                             AST.SetChild(astProc, 0,
-  558                                               AST.MakeLeaf(AST.NkIdent, pn));
-  559                                             AstAppend(AST.NkDeclSeq,
-  560                                               astSeq, astTail, astProc);
-  561                                             Lower.NoteProcNode(astProc);
-  562                                             Lower.ScopeLeave;
-  563                                             SymTab.CloseProc;
-  564                                             QbeGen.AbortFunc; .) }
-  565                                          (. astUnit := AST.MakeNode(AST.NkUnit);
-  566                                             AST.SetChild(astUnit, 0,
-  567                                               AST.MakeLeaf(AST.NkIdent, m1));
-  568                                             AST.SetChild(astUnit, 1, astSeq);
-  569                                             AST.SetChild(astUnit, 3, astImp);
-  570                                             astDecl := AST.NoNode;
-  571                                             astStmt := AST.NoNode; .)
-  572        "END"
-  573        GetIdent<m2>                      (. IF instActive THEN InstNameGet(m2) END;
-  574                                             IF NOT SymTab.Equal(m1, m2) THEN
-  575                                               SemError(202) END;
-  576                                             SymTab.EndUnit; .)
-  577        | "=" GetIdent<g> [ "(" Actuals ")" ] ";"
-  578                                          (. CopyNm(m1, refInst);
-  579                                             CopyNm(g, refGen);
-  580                                             refSeen := TRUE; refIsDef := TRUE;
-  581                                             astUnit := AST.MakeNode(AST.NkUnit);
-  582                                             AST.SetChild(astUnit, 0,
-  583                                               AST.MakeLeaf(AST.NkIdent, m1));
-  584                                             astDecl := AST.NoNode;
-  585                                             astStmt := AST.NoNode; .)
-  586          "END"
-  587          GetIdent<m2>                    (. IF NOT SymTab.Equal(m1, m2) THEN
-  588                                               SemError(202) END;
-  589                                             SymTab.EndUnit; .) ) .
-  590    ImplUnit                              (. VAR m1, m2: SymTab.Name;
-  591                                               g: SymTab.Name;
-  592                                               k: CARDINAL;
-  593                                               rp: CARDINAL;
-  594                                               rpOk: BOOLEAN;
-  595                                               rErrs: INTEGER;
-  596                                               rDecl, rStmt: AST.Node;
-  597                                               rnm: SymTab.Name;
-  598                                               rSym, rErr: CARDINAL;
-  599                                               fname: SymTab.Name;
-  600                                               unres: BOOLEAN;
-  601                                               astNode: AST.Node; .)
-  602      =                                   (. refN := 0; refSeen := FALSE; .)
-  603        "IMPLEMENTATION" "MODULE"
-  604        GetIdent<m1> (. IF instActive THEN InstNameGet(m1) END;
-  605                       IF instActive THEN
-  606                         IF NOT SymTab.Reenter(m1,
-  607                                SymTab.UnitImpl) THEN
-  608                           SemError(201) END
-  609                       ELSIF NOT SymTab.BeginImpl(m1) THEN
-  610                         SemError(201) END;
-  611                       astStmt := AST.NoNode;
-  612                       astDecl := AST.NoNode;
-  613                       astImp := AST.NoNode;
-  614                       astImpTail := AST.NoNode;
-  615                       nPendVar := 0;
-  616                       CopyNm(m1, unitName);
-  617                       unitWasGen := isGen AND NOT instActive;
-  618                       unitWasDef := FALSE;
-  619                       QbeGen.SetModule(m1); .)
-  620        [ GenericFormals ]
-  621        ( ";"
-  622        { Import                        (. AstAppend(AST.NkDeclSeq,
-  623                                               astImp, astImpTail, astDecl); .) }
-  624        DeclSeq                           (. astStmt := AST.NoNode; .)
-  625        [ "BEGIN"                         (. FlushPend;
-  626                                             k := 0;
-  627                                             WHILE k < SymTab.FwdPending() DO
-  628                                               SymTab.FwdInfo(k, fname, unres);
-  629                                               IF unres THEN SemError(201) END;
-  630                                               INC(k)
-  631                                             END;
-  632                                             SymTab.FwdClear;
-  633  
-  634                                             nLab := 0; nGot := 0; .)
-  635          [ StatSeq ] ]
-  636                                          (. IF twoPhaseParse THEN
-  637                                               rSym := sym; rErr := errDist;
-  638                                               rDecl := astDecl; rStmt := astStmt;
-  639                                               M2S.PushPos;
-  640                                               repassing := TRUE;
-  641                                               rp := 0;
-  642                                               WHILE rp < nSpans DO
-  643                                                 k := 0;
-  644                                                 WHILE (k <= HIGH(rnm))
-  645                                                   AND (spanName[rp][k] # CHR(0)) DO
-  646                                                   rnm[k] := spanName[rp][k]; INC(k)
-  647                                                 END;
-  648                                                 rnm[k] := CHR(0);
-  649                                                 M2S.SeekTo(spanStart[rp]);
-  650                                                 Adv;
-  651                                                 rpOk := SymTab.ReenterDeferred(spanIdx[rp]);
-  652                                                 IF NOT rpOk THEN
-  653                                                   FileIO.WriteString(FileIO.StdOut,
-  654                                                     "twophase reenter failed");
-  655                                                   FileIO.WriteLn(FileIO.StdOut)
-  656                                                 END;
-  657                                                 Lower.ReenterScopeProc(spanTy[rp]);
-  658                                                 QbeGen.BeginFunc("");
-  659                                                 Block(rnm);
-  660                                                 AST.SetChild(spanNode[rp], 1, astStmt);
-  661                                                 AST.SetChild(spanNode[rp], 2, astBlkDecls);
-  662                                                 Lower.ScopeLeave;
-  663                                                 SymTab.CloseProc;
-  664                                                 QbeGen.EndFunc(SymTab.ProcRes(rnm));
-  665                                                 INC(rp)
-  666                                               END;
-  667                                               rErrs := M2S.errors;
-  668                                               repassing := FALSE;
-  669                                               M2S.PopPos;
-  670                                               sym := rSym; errDist := rErr;
-  671                                               M2S.errors := rErrs;
-  672  
-  673                                               astDecl := rDecl; astStmt := rStmt
-  674                                             END; .)
-  675        "END"
-  676        GetIdent<m2>                      (. IF instActive THEN InstNameGet(m2) END;
-  677                                             FlushPend;
-  678                                             k := 0;
-  679                                             WHILE k < SymTab.FwdPending() DO
-  680                                               SymTab.FwdInfo(k, fname, unres);
-  681                                               IF unres THEN SemError(201) END;
-  682                                               INC(k)
-  683                                             END;
-  684                                             SymTab.FwdClear;
-  685  
-  686                                             astNode := AST.MakeNode(AST.NkUnit);
-  687                                             AST.SetChild(astNode, 0,
-  688                                               AST.MakeLeaf(AST.NkIdent, m1));
-  689                                             AST.SetChild(astNode, 1, astDecl);
-  690                                             AST.SetChild(astNode, 2, astStmt);
-  691                                             AST.SetChild(astNode, 3, astImp);
-  692                                             astUnit := astNode;
-  693                                             IF NOT SymTab.Equal(m1, m2) THEN
-  694                                               SemError(202) END;
-  695                                             CheckGotos;
-  696                                             SymTab.EndUnit; .)
-  697        | "=" GetIdent<g> [ "(" Actuals ")" ] ";"
-  698                                          (. CopyNm(m1, refInst);
-  699                                             CopyNm(g, refGen);
-  700                                             refSeen := TRUE; refIsDef := FALSE;
-  701                                             astNode := AST.MakeNode(AST.NkUnit);
-  702                                             AST.SetChild(astNode, 0,
-  703                                               AST.MakeLeaf(AST.NkIdent, m1));
-  704                                             astDecl := AST.NoNode;
-  705                                             astStmt := AST.NoNode; .)
-  706          "END"
-  707          GetIdent<m2>                    (. IF NOT SymTab.Equal(m1, m2) THEN
-  708                                               SemError(202) END;
-  709                                             SymTab.EndUnit; .) ) .
-  710    ProgModule                            (. VAR m1, m2: SymTab.Name;
-  711                                               k: CARDINAL;
-  712                                               rp: CARDINAL;
-  713                                               rpOk: BOOLEAN;
-  714                                               rErrs: INTEGER;
-  715                                               rDecl, rStmt: AST.Node;
-  716                                               rnm: SymTab.Name;
-  717                                               rSym, rErr: CARDINAL;
-  718                                               fname: SymTab.Name;
-  719                                               unres: BOOLEAN;
-  720                                               astNode: AST.Node; .)
-  721      = "MODULE"
-  722        GetIdent<m1> (. IF NOT SymTab.BeginProg(m1) THEN
-  723                                               SemError(200) END;
-  724                                             astStmt := AST.NoNode;
-  725                                             astDecl := AST.NoNode;
-  726                                             astImp := AST.NoNode;
-  727                                             astImpTail := AST.NoNode;
-  728                                             nPendVar := 0;
-  729                                             QbeGen.SetModule(m1); .)
-  730        [ Priority ]
-  731        ";"
-  732        { Import                        (. AstAppend(AST.NkDeclSeq,
-  733                                               astImp, astImpTail, astDecl); .) }
-  734        DeclSeq                           (. astStmt := AST.NoNode; .)
-  735        [ "BEGIN"                         (. FlushPend;
-  736                                             k := 0;
-  737                                             WHILE k < SymTab.FwdPending() DO
-  738                                               SymTab.FwdInfo(k, fname, unres);
-  739                                               IF unres THEN SemError(201) END;
-  740                                               INC(k)
-  741                                             END;
-  742                                             SymTab.FwdClear;
-  743  
-  744                                             nLab := 0; nGot := 0; .)
-  745          [ StatSeq ] ]
-  746                                          (. IF twoPhaseParse THEN
-  747                                               rSym := sym; rErr := errDist;
-  748                                               rDecl := astDecl; rStmt := astStmt;
-  749                                               M2S.PushPos;
-  750                                               repassing := TRUE;
-  751                                               rp := 0;
-  752                                               WHILE rp < nSpans DO
-  753                                                 k := 0;
-  754                                                 WHILE (k <= HIGH(rnm))
-  755                                                   AND (spanName[rp][k] # CHR(0)) DO
-  756                                                   rnm[k] := spanName[rp][k]; INC(k)
-  757                                                 END;
-  758                                                 rnm[k] := CHR(0);
-  759                                                 M2S.SeekTo(spanStart[rp]);
-  760                                                 Adv;
-  761                                                 rpOk := SymTab.ReenterDeferred(spanIdx[rp]);
-  762                                                 IF NOT rpOk THEN
-  763                                                   FileIO.WriteString(FileIO.StdOut,
-  764                                                     "twophase reenter failed");
-  765                                                   FileIO.WriteLn(FileIO.StdOut)
-  766                                                 END;
-  767                                                 Lower.ReenterScopeProc(spanTy[rp]);
-  768                                                 QbeGen.BeginFunc("");
-  769                                                 Block(rnm);
-  770                                                 AST.SetChild(spanNode[rp], 1, astStmt);
-  771                                                 AST.SetChild(spanNode[rp], 2, astBlkDecls);
-  772                                                 Lower.ScopeLeave;
-  773                                                 SymTab.CloseProc;
-  774                                                 QbeGen.EndFunc(SymTab.ProcRes(rnm));
-  775                                                 INC(rp)
-  776                                               END;
-  777                                               rErrs := M2S.errors;
-  778                                               repassing := FALSE;
-  779                                               M2S.PopPos;
-  780                                               sym := rSym; errDist := rErr;
-  781                                               M2S.errors := rErrs;
-  782  
-  783                                               astDecl := rDecl; astStmt := rStmt
-  784                                             END; .)
-  785        "END"
-  786        GetIdent<m2>                      (. IF instActive THEN InstNameGet(m2) END;
-  787                                             FlushPend;
-  788                                             k := 0;
-  789                                             WHILE k < SymTab.FwdPending() DO
-  790                                               SymTab.FwdInfo(k, fname, unres);
-  791                                               IF unres THEN SemError(201) END;
-  792                                               INC(k)
-  793                                             END;
-  794                                             SymTab.FwdClear;
-  795  
-  796                                             IF NOT SymTab.Equal(m1, m2) THEN
-  797                                               SemError(202) END;
-  798                                             astNode := AST.MakeNode(AST.NkUnit);
-  799                                             AST.SetChild(astNode, 0,
-  800                                               AST.MakeLeaf(AST.NkIdent, m1));
-  801                                             AST.SetChild(astNode, 1, astDecl);
-  802                                             AST.SetChild(astNode, 2, astStmt);
-  803                                             AST.SetChild(astNode, 3, astImp);
-  804                                             astUnit := astNode;
-  805                                             CheckGotos;
-  806                                             SymTab.EndUnit; .) .
-  807    DeclSeq                               (. VAR astSeq, astTail: AST.Node; .)
-  808      =                                   (. astSeq := AST.NoNode;
-  809                                             astTail := AST.NoNode; .)
-  810        { (. astDecl := AST.NoNode; .)
-  811          ( ConstBlock | TypeBlock<FALSE> | VarBlock | ProcDecl ";"
-  812          | NestedModule ";" | ClassItem ";" )
-  813                                          (. AstAppend(AST.NkDeclSeq,
-  814                                               astSeq, astTail, astDecl); .) }
-  815                                          (. astDecl := astSeq; .) .
-  816    (* Local module, Wirth form. Declarations lower like top-level ones
-  817       (same QBE module prefix); a BEGIN body becomes an init function
-  818       that main calls; the EXPORT list is hoisted into the enclosing
-  819       scope at END. *)
-  820    NestedModule                          (. VAR m1, m2: SymTab.Name;
-  821                                               expNames: ARRAY [0 .. 63] OF SymTab.Name;
-  822                                               expCount, k: CARDINAL;
-  823                                               astNode, nImp, nImpTail:
-  824                                                 AST.Node; .)
-  825      = "MODULE"
-  826        GetIdent<m1>                      (. IF NOT SymTab.Enter(m1,
-  827                                               SymTab.KindModule) THEN
-  828                                               SemError(200) END;
-  829                                             SymTab.PushScope;
-  830                                             expCount := 0;
-  831                                             astNode := AST.MakeNode(AST.NkUnit);
-  832                                             AST.SetChild(astNode, 0,
-  833                                               AST.MakeLeaf(AST.NkIdent, m1));
-  834                                             astStmt := AST.NoNode;
-  835                                             astDecl := AST.NoNode;
-  836                                             nImp := AST.NoNode;
-  837                                             nImpTail := AST.NoNode; .)
-  838        [ Priority ]
-  839        ";"
-  840        { Import                        (. AstAppend(AST.NkDeclSeq,
-  841                                               nImp, nImpTail, astDecl); .) }
-  842        [ "EXPORT" [ "QUALIFIED" ]
-  843          GetIdent<expNames[expCount]>    (. INC(expCount); .)
-  844          { "," GetIdent<expNames[expCount]>
-  845                                          (. INC(expCount); .) }
-  846          ";" ]
-  847        DeclSeq                           (. astStmt := AST.NoNode; .)
-  848        [ "BEGIN"                         (. astStmt := AST.NoNode;
-  849                                             .)
-  850          [ StatSeq ] ]
-  851        "END"
-  852        GetIdent<m2>                      (. AST.SetChild(astNode, 1, astDecl);
-  853                                             AST.SetChild(astNode, 2, astStmt);
-  854                                             AST.SetChild(astNode, 3, nImp);
-  855                                             astDecl := astNode;
-  856                                             IF NOT SymTab.Equal(m1, m2) THEN
-  857                                               SemError(202) END;
-  858                                             k := 0;
-  859                                             WHILE k < expCount DO
-  860                                               SymTab.ExportUp(expNames[k]);
-  861                                               INC(k)
-  862                                             END;
-  863                                             SymTab.PopScope; .) .
-  864    Priority
-  865      = "[" integer "]"                   (. SemError(230); .) .
-  866    (* Imports (4.3): FROM materializes the names (unqualified use);
-  867       plain IMPORT only demands the module exists — qualified `L.x`
-  868       materializes on first use (Design). *)
-  869    (* Unknown modules stay unchecked stubs (legacy, so hand-written
-  870       import lines don't fail); a known module's missing export is
-  871       201. *)
-  872    Import                                (. VAR n: SymTab.Name;
-  873                                               astImport: AST.Node; .)
-  874      = "FROM"
-  875        GetIdent<n>                       (. astImport := AST.MakeNode(AST.NkImport);
-  876                                             AST.SetChild(astImport, 0,
-  877                                               AST.MakeLeaf(AST.NkIdent, n)); .)
-  878        "IMPORT"
-  879        ImpList<n, astImport> ";"         (. astDecl := astImport; .)
-  880      | "IMPORT"                          (. astImport := AST.MakeNode(AST.NkImport); .)
-  881        ImpModList<astImport> ";"         (. astDecl := astImport; .) .
-  882    ImpList<mod: SymTab.Name; node: AST.Node>
-  883                                          (. VAR n: SymTab.Name; .)
-  884      = ImpName<mod, node>
-  885        { "," ImpName<mod, node> } .
-  886    (* Pervasive built-ins imported from SYSTEM (e.g. TSIZE) are
-  887       accepted and ignored: the built-in applies regardless. *)
-  888    ImpName<mod: SymTab.Name; node: AST.Node>
-  889                                          (. VAR n: SymTab.Name; .)
-  890      = GetIdent<n> (. AST.SetChild(node, AST.NChild(node),
-  891                                               AST.MakeLeaf(AST.NkIdent, n));
-  892                                             IF SymTab.Equal(mod, "libc") THEN
-  893                                               (* intrinsic C library:
-  894                                                  permissive external *)
-  895                                               IF NOT SymTab.DeclareCProc(n) THEN
-  896                                                 SemError(201) END;
-  897                                               Lower.NoteCProc(n)
-  898                                             ELSIF SymTab.ModKnown(mod) THEN
-  899                                               IF NOT SymTab.ImportFrom(mod, n) THEN
-  900                                                 SemError(201)
-  901                                               ELSE Lower.NoteImportedProc(n)
-  902                                               END
-  903                                             END; .)
-  904      | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN"
-  905        | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP"
-  906        | "UCHR" | "CHR8" | "UORD"
-  907        | "INC" | "DEC" ) .
-  908    ImpModList<node: AST.Node>            (. VAR n: SymTab.Name; .)
-  909      = GetIdent<n>                       (. AST.SetChild(node, AST.NChild(node),
-  910                                               AST.MakeLeaf(AST.NkIdent, n)); .)
-  911        { "," GetIdent<n>                 (. AST.SetChild(node, AST.NChild(node),
-  912                                               AST.MakeLeaf(AST.NkIdent, n)); .) } .
-  913    (* Opaque TYPE declarations (definition modules). The targetless
-  914       alias resolves to InvalidType until step 4 completes it. *)
-  915    (* Scalar-phase TYPEs: named types, integer subranges, enumerations.
-  916       Opaque "TYPE T;" needs isDef (definition units); elsewhere 231.
-  917       Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *)
-  918    TypeBlock<isDef: BOOLEAN>             (. VAR astSeq, astTail: AST.Node; .)
-  919      = "TYPE"                            (. SymTab.BeginTypeBlock;
-  920                                             astSeq := AST.NoNode;
-  921                                             astTail := AST.NoNode; .)
-  922        { (. astDecl := AST.NoNode; .)
-  923          ( TypeItem<isDef> ";" | ClassItem ";" )
-  924                                          (. AstAppend(AST.NkDeclSeq,
-  925                                               astSeq, astTail, astDecl); .) }
-  926                                          (. SymTab.EndTypeBlock;
-  927                                             astDecl := astSeq; .) .
-  928    TypeItem<isDef: BOOLEAN>              (. VAR n: SymTab.Name;
-  929                                               t, op: SymTab.TypeIndex;
-  930                                               astNode: AST.Node; .)
-  931      = GetIdent<n>                       (. op := SymTab.OpaqueBase(n);
-  932                                             IF op = SymTab.InvalidType THEN
-  933                                               IF NOT SymTab.Enter(n,
-  934                                                  SymTab.KindType) THEN
-  935                                                 SemError(200) END
-  936                                             END; .)
-  937        ( "=" Type<t, FALSE> (. astNode := AST.MakeNode(AST.NkTypeDecl);
-  938                                               AST.SetChild(astNode, 0,
-  939                                                 AST.MakeLeaf(AST.NkIdent, n));
-  940                                               AST.SetTy(astNode, t);
-  941                                               astDecl := astNode;
-  942                                               IF op # SymTab.InvalidType THEN
-  943                                               SymTab.SetTarget(op, t)
-  944                                             ELSE SymTab.SetSymType(n, t)
-  945                                             END; .)
-  946        |                                 (. IF op # SymTab.InvalidType THEN
-  947                                               (* stays opaque *)
-  948                                             ELSIF NOT isDef THEN
-  949                                               SemError(231)
-  950                                             ELSE SymTab.SetSymType(n,
-  951                                               SymTab.NewAlias()) END; .) ) .
-  952    Type<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
-  953      = TypeIdent<t> [ Subrange<t> ]     (* anchored subrange: T[lo..hi] *)
-  954      | Subrange<t>
-  955      | Enum<t>
-  956      | ArrayType<t, allowOpen>
-  957      | SetType<t>
-  958      | RecordType<t>
-  959      | PointerType<t>
-  960      | ProcType<t> .
-  961    PointerType<VAR t: SymTab.TypeIndex>  (. VAR base: SymTab.TypeIndex; .)
-  962      = "POINTER" "TO" Type<base, FALSE>(. t := SymTab.NewPtr(base); .) .
-  963    (* Procedure types (step 8.5): PROCEDURE (params): result. Values
-  964       are code pointers; params are collected into the descriptor. *)
-  965    ProcType<VAR t: SymTab.TypeIndex>     (. VAR res, pt: SymTab.TypeIndex;
-  966                                               isV: BOOLEAN; .)
-  967      = "PROCEDURE"                       (. res := SymTab.InvalidType;
-  968                                             t := SymTab.NewProcType(res); .)
-  969        [ "(" [ ProcTypeSection<t> { ";" ProcTypeSection<t> } ] ")" ]
-  970        [ ":" TypeIdent<res>              (. SymTab.SetProcTypeRes(t, res); .) ] .
-  971    ProcTypeSection<t: SymTab.TypeIndex>  (. VAR pt: SymTab.TypeIndex;
-  972                                               isV: BOOLEAN;
-  973                                               cnt, k: CARDINAL;
-  974                                               names: ARRAY [0 .. 15] OF SymTab.Name; .)
-  975      =                                   (. isV := FALSE; cnt := 0; .)
-  976        [ "VAR"                           (. isV := TRUE; .) ]
-  977        ( GetIdent<names[cnt]>            (. INC(cnt); .)
-  978          { "," GetIdent<names[cnt]>      (. INC(cnt); .) }
-  979          ( ":" Type<pt, TRUE>           (. k := 0;
-  980                                             WHILE k < cnt DO
-  981                                               SymTab.ProcTypeAdd(t, isV, pt);
-  982                                               INC(k)
-  983                                             END; .)
-  984          |                               (. (* type-only parameter list:
-  985                                                each name is a type (GNU
-  986                                                shorthand used by the
-  987                                                Coco/R scanner frame) *)
-  988                                             k := 0;
-  989                                             WHILE k < cnt DO
-  990                                               IF SymTab.Lookup(names[k])
-  991                                                  AND ((SymTab.SymKind(names[k]) = SymTab.KindType)
-  992    OR (SymTab.SymKind(names[k]) = SymTab.KindPredef)) THEN
-  993                                                 pt := SymTab.SymType(names[k])
-  994                                               ELSE SemError(201);
-  995                                                 pt := SymTab.InvalidType
-  996                                               END;
-  997                                               SymTab.ProcTypeAdd(t, isV, pt);
-  998                                               INC(k)
-  999                                             END; .) )
- 1000        | Type<pt, TRUE>                 (. (* unnamed parameter (PIM):
- 1001                                                e.g. PROCEDURE (VAR ARRAY OF REAL) *)
- 1002                                             SymTab.ProcTypeAdd(t, isV, pt); .) ) .
- 1003    (* Arrays: "OF" without bounds is an open formal (allowed only
- 1004       where allowOpen); "[lo..hi, ...]" nests bounded levels inside
- 1005       out. Bounds are folded literals (int/char); anything else 230.
- 1006       Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *)
- 1007    ArrayType<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
- 1008                                          (. VAR elem: SymTab.TypeIndex;
- 1009                                               ok: BOOLEAN;
- 1010                                               bnds, bndh: ARRAY [0 .. 7] OF INTEGER;
- 1011                                               nb, k: CARDINAL;
- 1012                                               idx: SymTab.TypeIndex;
- 1013                                               ilo, ihi: INTEGER; .)
- 1014      = "ARRAY"
- 1015        ( "OF" Type<elem, FALSE>          (. IF NOT allowOpen THEN
- 1016                                               SemError(230) END;
- 1017                                             t := SymTab.NewOpenArray(elem); .)
- 1018        | TypeIdent<idx> [ Subrange<idx> ]
- 1019          "OF" Type<elem, FALSE>          (. (* index-type array: the index
- 1020                                                type's ordinal bounds give the
- 1021                                                [lo..hi] pair *)
- 1022                                             IF SymTab.TypeBounds(idx, ilo,
- 1023                                                ihi)
- 1024                                             THEN t := SymTab.NewArrayB(elem,
- 1025                                                    ilo, ihi)
- 1026                                             ELSE SemError(230);
- 1027                                               t := SymTab.InvalidType
- 1028                                             END; .)
- 1029        | "["                             (. SymTab.BoundBegin; ok := TRUE; .)
- 1030          BoundPair<ok>
- 1031          { "," BoundPair<ok> }
- 1032          "]"                             (. (* snapshot before the element
- 1033                                                type, which reuses the bound
- 1034                                                buffer for a nested ARRAY *)
- 1035                                             nb := SymTab.BoundCount();
- 1036                                             k := 0;
- 1037                                             WHILE k < nb DO
- 1038                                               bnds[k] := SymTab.BoundLo(k);
- 1039                                               bndh[k] := SymTab.BoundHi(k);
- 1040                                               INC(k)
- 1041                                             END; .)
- 1042          "OF" Type<elem, FALSE>
- 1043                                          (. IF ok THEN
- 1044                                               k := nb;
- 1045                                               WHILE k > 0 DO
- 1046                                                 DEC(k);
- 1047                                                 elem := SymTab.NewArrayB(
- 1048                                                   elem, bnds[k], bndh[k])
- 1049                                               END;
- 1050                                               t := elem
- 1051                                             ELSE t := SymTab.InvalidType
- 1052                                             END; .) ) .
- 1053    BoundPair<VAR ok: BOOLEAN>            (. VAR tlo, thi: SymTab.TypeIndex;
- 1054                                               qlo, qhi: QbeGen.QVal;
- 1055                                               lo, hi: INTEGER;
- 1056                                               cl, cl2: INTEGER; .)
- 1057      = Expr<tlo, qlo> ".." Expr<thi, qhi>
- 1058                                          (. IF (tlo = SymTab.InvalidType)
- 1059                                              OR (thi = SymTab.InvalidType) THEN
- 1060                                             ok := FALSE
- 1061                                           ELSE cl := SymTab.ClassOf(tlo);
- 1062                                             cl2 := SymTab.ClassOf(thi);
- 1063                                             IF ((cl # SymTab.ClInt)
- 1064   AND (cl # SymTab.ClChar))
- 1065                                                OR ((cl2 # SymTab.ClInt)
- 1066   AND (cl2 # SymTab.ClChar)) THEN
- 1067                                               SemError(230); ok := FALSE
- 1068                                             ELSIF NOT SymTab.ConstInt(qlo, lo)
- 1069                                                OR NOT SymTab.ConstInt(qhi, hi)
- 1070                                                OR (lo > hi) THEN
- 1071                                               SemError(230); ok := FALSE
- 1072                                              ELSIF NOT SymTab.BoundAdd(lo, hi) THEN
- 1073                                                SemError(230); ok := FALSE
- 1074                                              END;
- 1075                                            END; .) .
- 1076    (* Sets: multi-word masks over bases ≤ 256 values (bool, char,
- 1077       bounded subranges; enums wait for ordinals, INTEGER is
- 1078       unbounded). Literals are SET OF [0..255]; assignment and
- 1079       comparison across suitable bases are lenient (masks over min
- 1080       words + zero-check extras), out-of-span literals are 222. *)
- 1081    SetType<VAR t: SymTab.TypeIndex>      (. VAR base: SymTab.TypeIndex;
- 1082                                               blo, bhi, bspan: INTEGER;
- 1083                                               bcls: INTEGER; .)
- 1084      = "SET" "OF" Type<base, FALSE>
- 1085                                          (. IF base = SymTab.InvalidType THEN
- 1086                                               t := SymTab.InvalidType
- 1087                                             ELSE bcls :=
- 1088                                                    SymTab.ClassOf(base);
- 1089                                               IF bcls = SymTab.ClBool THEN
- 1090                                                 blo := 0; bspan := 2
- 1091                                               ELSIF bcls = SymTab.ClChar THEN
- 1092                                                 blo := 0; bspan := 256
- 1093                                               ELSIF bcls = SymTab.ClEnum THEN
- 1094                                                 blo := 0;
- 1095                                                 bspan := VAL(INTEGER,
- 1096                                                   SymTab.EnumCount(base))
- 1097                                               ELSIF SymTab.SubBounds(base,
- 1098                                                       blo, bhi) THEN
- 1099                                                 bspan := bhi - blo + 1
- 1100                                               ELSE bspan := 0 END;
- 1101                                               IF (bspan <= 0)
- 1102                                                  OR (bspan > 65536) THEN
- 1103                                                 SemError(230);
- 1104                                                 t := SymTab.InvalidType
- 1105                                               ELSE t := SymTab.NewSet(base)
- 1106                                               END
- 1107                                             END; .) .
- 1108    (* Records: flat blobs; array fields are pointers to static
- 1109       descriptors (locked amendment), nested records inline. Field
- 1110       offsets static and declaration-ordered. *)
- 1111    (* Field list: plain fields and (optionally) one variant part.  The
- 1112       variant part is a `CASE ... END` item; because it starts with the
- 1113       CASE keyword it is unambiguously distinguishable from a field
- 1114       (which starts with an identifier). *)
- 1115    RecordType<VAR t: SymTab.TypeIndex>   (. VAR t2: SymTab.TypeIndex;
- 1116                                               tagOk: BOOLEAN; .)
- 1117      = "RECORD"                          (. t := SymTab.NewRecord(); .)
- 1118        [ RecItem<t> { ";" [ RecItem<t> ] } ]
- 1119        "END"                             (. SymTab.LayoutRecord(t); .) .
- 1120    RecItem<rec: SymTab.TypeIndex>        (. VAR tt: SymTab.TypeIndex; .)
- 1121      = RecField<rec>
- 1122      | CaseField<rec>                    (. SymTab.MarkVariant(rec); .) .
- 1123    (* A variant part: CASE tag : Type OF variants.  The layout overlays
- 1124       every branch from the tag slot (see SymTab.ComputeOffsets). *)
- 1125    CaseField<rec: SymTab.TypeIndex>      (. VAR tagT: SymTab.TypeIndex;
- 1126                                               tagN: SymTab.Name; .)
- 1127      = "CASE"                            (. SymTab.ResetFields(rec); .)
- 1128        GetIdent<tagN>                    (. IF NOT SymTab.FieldPending(rec,
- 1129                                               tagN) THEN
- 1130                                               SemError(200) END; .)
- 1131        ":" Type<tagT, FALSE>             (. IF (tagT # SymTab.InvalidType)
- 1132    AND NOT SymTab.IsOrdinal(tagT) THEN
- 1133                                               SemError(224)
- 1134                                             END;
- 1135                                             SymTab.FixPendingF(rec, tagT);
- 1136                                             SymTab.SetVariantTag(rec, tagN); .)
- 1137        "OF"
- 1138        RecFieldList<rec>
- 1139        { "|"                             (. SymTab.ResetFields(rec); .)
- 1140          RecFieldList<rec> }
- 1141        "END" .
- 1142    RecFieldList<rec: SymTab.TypeIndex>   (. VAR lt, lq: SymTab.TypeIndex;
- 1143                                               lv1, lv2: QbeGen.QVal; .)
- 1144      = VarLabel<lt, lv1> [ ".." VarLabel<lq, lv2> ] ":"
- 1145        RecField<rec> { ";" [ RecField<rec> ] } .
- 1146    (* Variant case label: a constant (or a constant range).  Values are
- 1147       not interpreted (the layout overlays regardless). *)
- 1148    VarLabel<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1149                                          (. VAR lname: SymTab.Name; .)
- 1150      = ( ident                         (. LexName(lname);
- 1151                                             QbeGen.CopyOp("0", q);
- 1152                                             t := SymTab.IntType(); .)
- 1153        | integer                       (. LexString(lname);
- 1154                                             QbeGen.CopyOp("0", q);
- 1155                                             t := SymTab.IntType(); .)
- 1156        | charConst                     (. LexString(lname);
- 1157                                             QbeGen.CopyOp("0", q);
- 1158                                             t := SymTab.CharType(); .) ) .
- 1159    RecField<rec: SymTab.TypeIndex>       (. VAR n: SymTab.Name;
- 1160                                               t2: SymTab.TypeIndex; .)
- 1161      = RecIdents<rec> ":" Type<t2, FALSE>(. SymTab.FixPendingF(rec, t2); .) .
- 1162    RecIdents<rec: SymTab.TypeIndex>      (. VAR n: SymTab.Name; .)
- 1163      = GetIdent<n>                       (. IF NOT SymTab.FieldPending(rec,
- 1164                                               n) THEN
- 1165                                               SemError(200) END; .)
- 1166        { "," GetIdent<n>                 (. IF NOT SymTab.FieldPending(rec,
- 1167                                               n) THEN
- 1168                                               SemError(200) END; .) } .
- 1169    TypeIdent<VAR t: SymTab.TypeIndex>    (. VAR n, qid: SymTab.Name;
- 1170                                               k: INTEGER;
- 1171                                               dotted: BOOLEAN; .)
- 1172      = GetIdent<n>                       (. dotted := FALSE;
- 1173                                             IF NOT SymTab.Lookup(n) THEN
- 1174                                               k := -1;
- 1175                                               t := SymTab.ForwardType(n);
- 1176                                               IF t = SymTab.InvalidType THEN
- 1177                                                 SemError(201)
- 1178                                               END
- 1179                                             ELSE k := SymTab.SymKind(n);
- 1180                                               IF (k = SymTab.KindType)
- 1181                                                  OR (k = SymTab.KindPredef) THEN
- 1182                                                 t := SymTab.SymType(n)
- 1183                                               ELSE t := SymTab.InvalidType
+  494                                             INC(instFk); .) }
+  495        ":" "TYPE" .
+  496    Actuals
+  497      = Actual { "," Actual } .
+  498    Actual                                (. VAR at: SymTab.TypeIndex; .)
+  499      = TypeIdent<at>                     (. IF refN <= HIGH(refActual) THEN
+  500                                               refActual[refN] := at; INC(refN)
+  501                                             END; .) .
+  502    Unit
+  503      =                                   (. isGen := FALSE;
+  504                                             allowDefer := FALSE;
+  505                                             repassing := FALSE; .)
+  506        [ "GENERIC"                       (. isGen := TRUE; .) ]
+  507        ( DefUnit | ImplUnit | ProgModule ) .
+  508    (* Step 4.3: one session compiles DEFINITION, its IMPLEMENTATION
+  509       and one program (last) into one image. Units share the symbol
+  510       table; imports materialize exported names. *)
+  511    DefUnit                               (. VAR m1, m2, pn: SymTab.Name;
+  512                                               g: SymTab.Name;
+  513                                               astSeq, astTail, astProc: AST.Node; .)
+  514      =                                   (. refN := 0; refSeen := FALSE; .)
+  515        "DEFINITION" "MODULE"
+  516        GetIdent<m1>                      (. IF instActive THEN InstNameGet(m1) END;
+  517                                             IF instActive THEN
+  518                                               IF NOT SymTab.Reenter(m1,
+  519                                                      SymTab.UnitDef) THEN
+  520                                                 SemError(200) END
+  521                                             ELSIF NOT SymTab.BeginDef(m1) THEN
+  522                                               SemError(200) END;
+  523                                             QbeGen.SetModule(m1);
+  524                                             CopyNm(m1, unitName);
+  525                                             unitWasGen := isGen
+  526                                               AND NOT instActive;
+  527                                             unitWasDef := TRUE; .)
+  528        [ GenericFormals ]
+  529        ( ";"
+  530        { Import                        (. AstAppend(AST.NkDeclSeq,
+  531                                               astImp, astImpTail, astDecl); .) }
+  532        [ "EXPORT" [ "QUALIFIED" ]        (. (* definition-module export
+  533                                                list: parsed, and the
+  534                                                names are already exported
+  535                                                by the module scope *) .)
+  536          GetIdent<pn> { "," GetIdent<pn> } ";" ]
+  537                                          (. astSeq := AST.NoNode;
+  538                                             astTail := AST.NoNode; .)
+  539        { ConstBlock                      (. AstAppend(AST.NkDeclSeq,
+  540                                               astSeq, astTail, astDecl); .)
+  541        | TypeBlock<TRUE>                 (. AstAppend(AST.NkDeclSeq,
+  542                                               astSeq, astTail, astDecl); .)
+  543        | VarBlock                        (. AstAppend(AST.NkDeclSeq,
+  544                                               astSeq, astTail, astDecl); .)
+  545        | ProcHeading<pn, SymTab.InvalidType> ";"
+  546                                          (. (* a heading only: record it so
+  547                                                Lower can replay it *)
+  548                                             astProc := AST.MakeNode(AST.NkProcDecl);
+  549                                             AST.SetOp(astProc, 0);
+  550                                             AST.SetChild(astProc, 0,
+  551                                               AST.MakeLeaf(AST.NkIdent, pn));
+  552                                             AstAppend(AST.NkDeclSeq,
+  553                                               astSeq, astTail, astProc);
+  554                                             Lower.NoteProcNode(astProc);
+  555                                             Lower.ScopeLeave;
+  556                                             SymTab.CloseProc;
+  557                                             QbeGen.AbortFunc; .) }
+  558                                          (. astUnit := AST.MakeNode(AST.NkUnit);
+  559                                             AST.SetChild(astUnit, 0,
+  560                                               AST.MakeLeaf(AST.NkIdent, m1));
+  561                                             AST.SetChild(astUnit, 1, astSeq);
+  562                                             AST.SetChild(astUnit, 3, astImp);
+  563                                             astDecl := AST.NoNode;
+  564                                             astStmt := AST.NoNode; .)
+  565        "END"
+  566        GetIdent<m2>                      (. IF instActive THEN InstNameGet(m2) END;
+  567                                             IF NOT SymTab.Equal(m1, m2) THEN
+  568                                               SemError(202) END;
+  569                                             SymTab.EndUnit; .)
+  570        | "=" GetIdent<g> [ "(" Actuals ")" ] ";"
+  571                                          (. CopyNm(m1, refInst);
+  572                                             CopyNm(g, refGen);
+  573                                             refSeen := TRUE; refIsDef := TRUE;
+  574                                             astUnit := AST.MakeNode(AST.NkUnit);
+  575                                             AST.SetChild(astUnit, 0,
+  576                                               AST.MakeLeaf(AST.NkIdent, m1));
+  577                                             astDecl := AST.NoNode;
+  578                                             astStmt := AST.NoNode; .)
+  579          "END"
+  580          GetIdent<m2>                    (. IF NOT SymTab.Equal(m1, m2) THEN
+  581                                               SemError(202) END;
+  582                                             SymTab.EndUnit; .) ) .
+  583    ImplUnit                              (. VAR m1, m2: SymTab.Name;
+  584                                               g: SymTab.Name;
+  585                                               k: CARDINAL;
+  586                                               rp: CARDINAL;
+  587                                               rpOk: BOOLEAN;
+  588                                               rErrs: INTEGER;
+  589                                               rDecl, rStmt: AST.Node;
+  590                                               rnm: SymTab.Name;
+  591                                               rSym, rErr: CARDINAL;
+  592                                               fname: SymTab.Name;
+  593                                               unres: BOOLEAN;
+  594                                               astNode: AST.Node; .)
+  595      =                                   (. refN := 0; refSeen := FALSE; .)
+  596        "IMPLEMENTATION" "MODULE"
+  597        GetIdent<m1> (. IF instActive THEN InstNameGet(m1) END;
+  598                       IF instActive THEN
+  599                         IF NOT SymTab.Reenter(m1,
+  600                                SymTab.UnitImpl) THEN
+  601                           SemError(201) END
+  602                       ELSIF NOT SymTab.BeginImpl(m1) THEN
+  603                         SemError(201) END;
+  604                       astStmt := AST.NoNode;
+  605                       astDecl := AST.NoNode;
+  606                       astImp := AST.NoNode;
+  607                       astImpTail := AST.NoNode;
+  608                       nPendVar := 0;
+  609                       CopyNm(m1, unitName);
+  610                       unitWasGen := isGen AND NOT instActive;
+  611                       unitWasDef := FALSE;
+  612                       QbeGen.SetModule(m1); .)
+  613        [ GenericFormals ]
+  614        ( ";"
+  615        { Import                        (. AstAppend(AST.NkDeclSeq,
+  616                                               astImp, astImpTail, astDecl); .) }
+  617        DeclSeq                           (. astStmt := AST.NoNode; .)
+  618        [ "BEGIN"                         (. FlushPend;
+  619                                             k := 0;
+  620                                             WHILE k < SymTab.FwdPending() DO
+  621                                               SymTab.FwdInfo(k, fname, unres);
+  622                                               IF unres THEN SemError(201) END;
+  623                                               INC(k)
+  624                                             END;
+  625                                             SymTab.FwdClear;
+  626  
+  627                                             nLab := 0; nGot := 0; .)
+  628          [ StatSeq ] ]
+  629                                          (. IF twoPhaseParse THEN
+  630                                               rSym := sym; rErr := errDist;
+  631                                               rDecl := astDecl; rStmt := astStmt;
+  632                                               M2S.PushPos;
+  633                                               repassing := TRUE;
+  634                                               rp := 0;
+  635                                               WHILE rp < nSpans DO
+  636                                                 k := 0;
+  637                                                 WHILE (k <= HIGH(rnm))
+  638                                                   AND (spanName[rp][k] # CHR(0)) DO
+  639                                                   rnm[k] := spanName[rp][k]; INC(k)
+  640                                                 END;
+  641                                                 rnm[k] := CHR(0);
+  642                                                 M2S.SeekTo(spanStart[rp]);
+  643                                                 Adv;
+  644                                                 rpOk := SymTab.ReenterDeferred(spanIdx[rp]);
+  645                                                 IF NOT rpOk THEN
+  646                                                   FileIO.WriteString(FileIO.StdOut,
+  647                                                     "twophase reenter failed");
+  648                                                   FileIO.WriteLn(FileIO.StdOut)
+  649                                                 END;
+  650                                                 Lower.ReenterScopeProc(spanTy[rp]);
+  651                                                 QbeGen.BeginFunc("");
+  652                                                 Block(rnm);
+  653                                                 AST.SetChild(spanNode[rp], 1, astStmt);
+  654                                                 AST.SetChild(spanNode[rp], 2, astBlkDecls);
+  655                                                 Lower.ScopeLeave;
+  656                                                 SymTab.CloseProc;
+  657                                                 QbeGen.EndFunc(SymTab.ProcRes(rnm));
+  658                                                 INC(rp)
+  659                                               END;
+  660                                               rErrs := M2S.errors;
+  661                                               repassing := FALSE;
+  662                                               M2S.PopPos;
+  663                                               sym := rSym; errDist := rErr;
+  664                                               M2S.errors := rErrs;
+  665  
+  666                                               astDecl := rDecl; astStmt := rStmt
+  667                                             END; .)
+  668        "END"
+  669        GetIdent<m2>                      (. IF instActive THEN InstNameGet(m2) END;
+  670                                             FlushPend;
+  671                                             k := 0;
+  672                                             WHILE k < SymTab.FwdPending() DO
+  673                                               SymTab.FwdInfo(k, fname, unres);
+  674                                               IF unres THEN SemError(201) END;
+  675                                               INC(k)
+  676                                             END;
+  677                                             SymTab.FwdClear;
+  678  
+  679                                             astNode := AST.MakeNode(AST.NkUnit);
+  680                                             AST.SetChild(astNode, 0,
+  681                                               AST.MakeLeaf(AST.NkIdent, m1));
+  682                                             AST.SetChild(astNode, 1, astDecl);
+  683                                             AST.SetChild(astNode, 2, astStmt);
+  684                                             AST.SetChild(astNode, 3, astImp);
+  685                                             astUnit := astNode;
+  686                                             IF NOT SymTab.Equal(m1, m2) THEN
+  687                                               SemError(202) END;
+  688                                             CheckGotos;
+  689                                             SymTab.EndUnit; .)
+  690        | "=" GetIdent<g> [ "(" Actuals ")" ] ";"
+  691                                          (. CopyNm(m1, refInst);
+  692                                             CopyNm(g, refGen);
+  693                                             refSeen := TRUE; refIsDef := FALSE;
+  694                                             astNode := AST.MakeNode(AST.NkUnit);
+  695                                             AST.SetChild(astNode, 0,
+  696                                               AST.MakeLeaf(AST.NkIdent, m1));
+  697                                             astDecl := AST.NoNode;
+  698                                             astStmt := AST.NoNode; .)
+  699          "END"
+  700          GetIdent<m2>                    (. IF NOT SymTab.Equal(m1, m2) THEN
+  701                                               SemError(202) END;
+  702                                             SymTab.EndUnit; .) ) .
+  703    ProgModule                            (. VAR m1, m2: SymTab.Name;
+  704                                               k: CARDINAL;
+  705                                               rp: CARDINAL;
+  706                                               rpOk: BOOLEAN;
+  707                                               rErrs: INTEGER;
+  708                                               rDecl, rStmt: AST.Node;
+  709                                               rnm: SymTab.Name;
+  710                                               rSym, rErr: CARDINAL;
+  711                                               fname: SymTab.Name;
+  712                                               unres: BOOLEAN;
+  713                                               astNode: AST.Node; .)
+  714      = "MODULE"
+  715        GetIdent<m1> (. IF NOT SymTab.BeginProg(m1) THEN
+  716                                               SemError(200) END;
+  717                                             astStmt := AST.NoNode;
+  718                                             astDecl := AST.NoNode;
+  719                                             astImp := AST.NoNode;
+  720                                             astImpTail := AST.NoNode;
+  721                                             nPendVar := 0;
+  722                                             QbeGen.SetModule(m1); .)
+  723        [ Priority ]
+  724        ";"
+  725        { Import                        (. AstAppend(AST.NkDeclSeq,
+  726                                               astImp, astImpTail, astDecl); .) }
+  727        DeclSeq                           (. astStmt := AST.NoNode; .)
+  728        [ "BEGIN"                         (. FlushPend;
+  729                                             k := 0;
+  730                                             WHILE k < SymTab.FwdPending() DO
+  731                                               SymTab.FwdInfo(k, fname, unres);
+  732                                               IF unres THEN SemError(201) END;
+  733                                               INC(k)
+  734                                             END;
+  735                                             SymTab.FwdClear;
+  736  
+  737                                             nLab := 0; nGot := 0; .)
+  738          [ StatSeq ] ]
+  739                                          (. IF twoPhaseParse THEN
+  740                                               rSym := sym; rErr := errDist;
+  741                                               rDecl := astDecl; rStmt := astStmt;
+  742                                               M2S.PushPos;
+  743                                               repassing := TRUE;
+  744                                               rp := 0;
+  745                                               WHILE rp < nSpans DO
+  746                                                 k := 0;
+  747                                                 WHILE (k <= HIGH(rnm))
+  748                                                   AND (spanName[rp][k] # CHR(0)) DO
+  749                                                   rnm[k] := spanName[rp][k]; INC(k)
+  750                                                 END;
+  751                                                 rnm[k] := CHR(0);
+  752                                                 M2S.SeekTo(spanStart[rp]);
+  753                                                 Adv;
+  754                                                 rpOk := SymTab.ReenterDeferred(spanIdx[rp]);
+  755                                                 IF NOT rpOk THEN
+  756                                                   FileIO.WriteString(FileIO.StdOut,
+  757                                                     "twophase reenter failed");
+  758                                                   FileIO.WriteLn(FileIO.StdOut)
+  759                                                 END;
+  760                                                 Lower.ReenterScopeProc(spanTy[rp]);
+  761                                                 QbeGen.BeginFunc("");
+  762                                                 Block(rnm);
+  763                                                 AST.SetChild(spanNode[rp], 1, astStmt);
+  764                                                 AST.SetChild(spanNode[rp], 2, astBlkDecls);
+  765                                                 Lower.ScopeLeave;
+  766                                                 SymTab.CloseProc;
+  767                                                 QbeGen.EndFunc(SymTab.ProcRes(rnm));
+  768                                                 INC(rp)
+  769                                               END;
+  770                                               rErrs := M2S.errors;
+  771                                               repassing := FALSE;
+  772                                               M2S.PopPos;
+  773                                               sym := rSym; errDist := rErr;
+  774                                               M2S.errors := rErrs;
+  775  
+  776                                               astDecl := rDecl; astStmt := rStmt
+  777                                             END; .)
+  778        "END"
+  779        GetIdent<m2>                      (. IF instActive THEN InstNameGet(m2) END;
+  780                                             FlushPend;
+  781                                             k := 0;
+  782                                             WHILE k < SymTab.FwdPending() DO
+  783                                               SymTab.FwdInfo(k, fname, unres);
+  784                                               IF unres THEN SemError(201) END;
+  785                                               INC(k)
+  786                                             END;
+  787                                             SymTab.FwdClear;
+  788  
+  789                                             IF NOT SymTab.Equal(m1, m2) THEN
+  790                                               SemError(202) END;
+  791                                             astNode := AST.MakeNode(AST.NkUnit);
+  792                                             AST.SetChild(astNode, 0,
+  793                                               AST.MakeLeaf(AST.NkIdent, m1));
+  794                                             AST.SetChild(astNode, 1, astDecl);
+  795                                             AST.SetChild(astNode, 2, astStmt);
+  796                                             AST.SetChild(astNode, 3, astImp);
+  797                                             astUnit := astNode;
+  798                                             CheckGotos;
+  799                                             SymTab.EndUnit; .) .
+  800    DeclSeq                               (. VAR astSeq, astTail: AST.Node; .)
+  801      =                                   (. astSeq := AST.NoNode;
+  802                                             astTail := AST.NoNode; .)
+  803        { (. astDecl := AST.NoNode; .)
+  804          ( ConstBlock | TypeBlock<FALSE> | VarBlock | ProcDecl ";"
+  805          | NestedModule ";" | ClassItem ";" )
+  806                                          (. AstAppend(AST.NkDeclSeq,
+  807                                               astSeq, astTail, astDecl); .) }
+  808                                          (. astDecl := astSeq; .) .
+  809    (* Local module, Wirth form. Declarations lower like top-level ones
+  810       (same QBE module prefix); a BEGIN body becomes an init function
+  811       that main calls; the EXPORT list is hoisted into the enclosing
+  812       scope at END. *)
+  813    NestedModule                          (. VAR m1, m2: SymTab.Name;
+  814                                               expNames: ARRAY [0 .. 63] OF SymTab.Name;
+  815                                               expCount, k: CARDINAL;
+  816                                               astNode, nImp, nImpTail:
+  817                                                 AST.Node; .)
+  818      = "MODULE"
+  819        GetIdent<m1>                      (. IF NOT SymTab.Enter(m1,
+  820                                               SymTab.KindModule) THEN
+  821                                               SemError(200) END;
+  822                                             SymTab.PushScope;
+  823                                             expCount := 0;
+  824                                             astNode := AST.MakeNode(AST.NkUnit);
+  825                                             AST.SetChild(astNode, 0,
+  826                                               AST.MakeLeaf(AST.NkIdent, m1));
+  827                                             astStmt := AST.NoNode;
+  828                                             astDecl := AST.NoNode;
+  829                                             nImp := AST.NoNode;
+  830                                             nImpTail := AST.NoNode; .)
+  831        [ Priority ]
+  832        ";"
+  833        { Import                        (. AstAppend(AST.NkDeclSeq,
+  834                                               nImp, nImpTail, astDecl); .) }
+  835        [ "EXPORT" [ "QUALIFIED" ]
+  836          GetIdent<expNames[expCount]>    (. INC(expCount); .)
+  837          { "," GetIdent<expNames[expCount]>
+  838                                          (. INC(expCount); .) }
+  839          ";" ]
+  840        DeclSeq                           (. astStmt := AST.NoNode; .)
+  841        [ "BEGIN"                         (. astStmt := AST.NoNode;
+  842                                             .)
+  843          [ StatSeq ] ]
+  844        "END"
+  845        GetIdent<m2>                      (. AST.SetChild(astNode, 1, astDecl);
+  846                                             AST.SetChild(astNode, 2, astStmt);
+  847                                             AST.SetChild(astNode, 3, nImp);
+  848                                             astDecl := astNode;
+  849                                             IF NOT SymTab.Equal(m1, m2) THEN
+  850                                               SemError(202) END;
+  851                                             k := 0;
+  852                                             WHILE k < expCount DO
+  853                                               SymTab.ExportUp(expNames[k]);
+  854                                               INC(k)
+  855                                             END;
+  856                                             SymTab.PopScope; .) .
+  857    Priority
+  858      = "[" integer "]"                   (. SemError(230); .) .
+  859    (* Imports (4.3): FROM materializes the names (unqualified use);
+  860       plain IMPORT only demands the module exists — qualified `L.x`
+  861       materializes on first use (Design). *)
+  862    (* Unknown modules stay unchecked stubs (legacy, so hand-written
+  863       import lines don't fail); a known module's missing export is
+  864       201. *)
+  865    Import                                (. VAR n: SymTab.Name;
+  866                                               astImport: AST.Node; .)
+  867      = "FROM"
+  868        GetIdent<n>                       (. astImport := AST.MakeNode(AST.NkImport);
+  869                                             AST.SetChild(astImport, 0,
+  870                                               AST.MakeLeaf(AST.NkIdent, n)); .)
+  871        "IMPORT"
+  872        ImpList<n, astImport> ";"         (. astDecl := astImport; .)
+  873      | "IMPORT"                          (. astImport := AST.MakeNode(AST.NkImport); .)
+  874        ImpModList<astImport> ";"         (. astDecl := astImport; .) .
+  875    ImpList<mod: SymTab.Name; node: AST.Node>
+  876                                          (. VAR n: SymTab.Name; .)
+  877      = ImpName<mod, node>
+  878        { "," ImpName<mod, node> } .
+  879    (* Pervasive built-ins imported from SYSTEM (e.g. TSIZE) are
+  880       accepted and ignored: the built-in applies regardless. *)
+  881    ImpName<mod: SymTab.Name; node: AST.Node>
+  882                                          (. VAR n: SymTab.Name; .)
+  883      = GetIdent<n> (. AST.SetChild(node, AST.NChild(node),
+  884                                               AST.MakeLeaf(AST.NkIdent, n));
+  885                                             IF SymTab.Equal(mod, "libc") THEN
+  886                                               (* intrinsic C library:
+  887                                                  permissive external *)
+  888                                               IF NOT SymTab.DeclareCProc(n) THEN
+  889                                                 SemError(201) END;
+  890                                               Lower.NoteCProc(n)
+  891                                             ELSIF SymTab.ModKnown(mod) THEN
+  892                                               IF NOT SymTab.ImportFrom(mod, n) THEN
+  893                                                 SemError(201)
+  894                                               ELSE Lower.NoteImportedProc(n)
+  895                                               END
+  896                                             END; .)
+  897      | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN"
+  898        | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP"
+  899        | "UCHR" | "CHR8" | "UORD"
+  900        | "INC" | "DEC" ) .
+  901    ImpModList<node: AST.Node>            (. VAR n: SymTab.Name; .)
+  902      = GetIdent<n>                       (. AST.SetChild(node, AST.NChild(node),
+  903                                               AST.MakeLeaf(AST.NkIdent, n)); .)
+  904        { "," GetIdent<n>                 (. AST.SetChild(node, AST.NChild(node),
+  905                                               AST.MakeLeaf(AST.NkIdent, n)); .) } .
+  906    (* Opaque TYPE declarations (definition modules). The targetless
+  907       alias resolves to InvalidType until step 4 completes it. *)
+  908    (* Scalar-phase TYPEs: named types, integer subranges, enumerations.
+  909       Opaque "TYPE T;" needs isDef (definition units); elsewhere 231.
+  910       Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *)
+  911    TypeBlock<isDef: BOOLEAN>             (. VAR astSeq, astTail: AST.Node; .)
+  912      = "TYPE"                            (. SymTab.BeginTypeBlock;
+  913                                             astSeq := AST.NoNode;
+  914                                             astTail := AST.NoNode; .)
+  915        { (. astDecl := AST.NoNode; .)
+  916          ( TypeItem<isDef> ";" | ClassItem ";" )
+  917                                          (. AstAppend(AST.NkDeclSeq,
+  918                                               astSeq, astTail, astDecl); .) }
+  919                                          (. SymTab.EndTypeBlock;
+  920                                             astDecl := astSeq; .) .
+  921    TypeItem<isDef: BOOLEAN>              (. VAR n: SymTab.Name;
+  922                                               t, op: SymTab.TypeIndex;
+  923                                               astNode: AST.Node; .)
+  924      = GetIdent<n>                       (. op := SymTab.OpaqueBase(n);
+  925                                             IF op = SymTab.InvalidType THEN
+  926                                               IF NOT SymTab.Enter(n,
+  927                                                  SymTab.KindType) THEN
+  928                                                 SemError(200) END
+  929                                             END; .)
+  930        ( "=" Type<t, FALSE> (. astNode := AST.MakeNode(AST.NkTypeDecl);
+  931                                               AST.SetChild(astNode, 0,
+  932                                                 AST.MakeLeaf(AST.NkIdent, n));
+  933                                               AST.SetTy(astNode, t);
+  934                                               astDecl := astNode;
+  935                                               IF op # SymTab.InvalidType THEN
+  936                                               SymTab.SetTarget(op, t)
+  937                                             ELSE SymTab.SetSymType(n, t)
+  938                                             END; .)
+  939        |                                 (. IF op # SymTab.InvalidType THEN
+  940                                               (* stays opaque *)
+  941                                             ELSIF NOT isDef THEN
+  942                                               SemError(231)
+  943                                             ELSE SymTab.SetSymType(n,
+  944                                               SymTab.NewAlias()) END; .) ) .
+  945    Type<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
+  946      = TypeIdent<t> [ Subrange<t> ]     (* anchored subrange: T[lo..hi] *)
+  947      | Subrange<t>
+  948      | Enum<t>
+  949      | ArrayType<t, allowOpen>
+  950      | SetType<t>
+  951      | RecordType<t>
+  952      | PointerType<t>
+  953      | ProcType<t> .
+  954    PointerType<VAR t: SymTab.TypeIndex>  (. VAR base: SymTab.TypeIndex; .)
+  955      = "POINTER" "TO" Type<base, FALSE>(. t := SymTab.NewPtr(base); .) .
+  956    (* Procedure types (step 8.5): PROCEDURE (params): result. Values
+  957       are code pointers; params are collected into the descriptor. *)
+  958    ProcType<VAR t: SymTab.TypeIndex>     (. VAR res, pt: SymTab.TypeIndex;
+  959                                               isV: BOOLEAN; .)
+  960      = "PROCEDURE"                       (. res := SymTab.InvalidType;
+  961                                             t := SymTab.NewProcType(res); .)
+  962        [ "(" [ ProcTypeSection<t> { ";" ProcTypeSection<t> } ] ")" ]
+  963        [ ":" TypeIdent<res>              (. SymTab.SetProcTypeRes(t, res); .) ] .
+  964    ProcTypeSection<t: SymTab.TypeIndex>  (. VAR pt: SymTab.TypeIndex;
+  965                                               isV: BOOLEAN;
+  966                                               cnt, k: CARDINAL;
+  967                                               names: ARRAY [0 .. 15] OF SymTab.Name; .)
+  968      =                                   (. isV := FALSE; cnt := 0; .)
+  969        [ "VAR"                           (. isV := TRUE; .) ]
+  970        ( GetIdent<names[cnt]>            (. INC(cnt); .)
+  971          { "," GetIdent<names[cnt]>      (. INC(cnt); .) }
+  972          ( ":" Type<pt, TRUE>           (. k := 0;
+  973                                             WHILE k < cnt DO
+  974                                               SymTab.ProcTypeAdd(t, isV, pt);
+  975                                               INC(k)
+  976                                             END; .)
+  977          |                               (. (* type-only parameter list:
+  978                                                each name is a type (GNU
+  979                                                shorthand used by the
+  980                                                Coco/R scanner frame) *)
+  981                                             k := 0;
+  982                                             WHILE k < cnt DO
+  983                                               IF SymTab.Lookup(names[k])
+  984                                                  AND ((SymTab.SymKind(names[k]) = SymTab.KindType)
+  985    OR (SymTab.SymKind(names[k]) = SymTab.KindPredef)) THEN
+  986                                                 pt := SymTab.SymType(names[k])
+  987                                               ELSE SemError(201);
+  988                                                 pt := SymTab.InvalidType
+  989                                               END;
+  990                                               SymTab.ProcTypeAdd(t, isV, pt);
+  991                                               INC(k)
+  992                                             END; .) )
+  993        | Type<pt, TRUE>                 (. (* unnamed parameter (PIM):
+  994                                                e.g. PROCEDURE (VAR ARRAY OF REAL) *)
+  995                                             SymTab.ProcTypeAdd(t, isV, pt); .) ) .
+  996    (* Arrays: "OF" without bounds is an open formal (allowed only
+  997       where allowOpen); "[lo..hi, ...]" nests bounded levels inside
+  998       out. Bounds are folded literals (int/char); anything else 230.
+  999       Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *)
+ 1000    ArrayType<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
+ 1001                                          (. VAR elem: SymTab.TypeIndex;
+ 1002                                               ok: BOOLEAN;
+ 1003                                               bnds, bndh: ARRAY [0 .. 7] OF INTEGER;
+ 1004                                               nb, k: CARDINAL;
+ 1005                                               idx: SymTab.TypeIndex;
+ 1006                                               ilo, ihi: INTEGER; .)
+ 1007      = "ARRAY"
+ 1008        ( "OF" Type<elem, FALSE>          (. IF NOT allowOpen THEN
+ 1009                                               SemError(230) END;
+ 1010                                             t := SymTab.NewOpenArray(elem); .)
+ 1011        | TypeIdent<idx> [ Subrange<idx> ]
+ 1012          "OF" Type<elem, FALSE>          (. (* index-type array: the index
+ 1013                                                type's ordinal bounds give the
+ 1014                                                [lo..hi] pair *)
+ 1015                                             IF SymTab.TypeBounds(idx, ilo,
+ 1016                                                ihi)
+ 1017                                             THEN t := SymTab.NewArrayB(elem,
+ 1018                                                    ilo, ihi)
+ 1019                                             ELSE SemError(230);
+ 1020                                               t := SymTab.InvalidType
+ 1021                                             END; .)
+ 1022        | "["                             (. SymTab.BoundBegin; ok := TRUE; .)
+ 1023          BoundPair<ok>
+ 1024          { "," BoundPair<ok> }
+ 1025          "]"                             (. (* snapshot before the element
+ 1026                                                type, which reuses the bound
+ 1027                                                buffer for a nested ARRAY *)
+ 1028                                             nb := SymTab.BoundCount();
+ 1029                                             k := 0;
+ 1030                                             WHILE k < nb DO
+ 1031                                               bnds[k] := SymTab.BoundLo(k);
+ 1032                                               bndh[k] := SymTab.BoundHi(k);
+ 1033                                               INC(k)
+ 1034                                             END; .)
+ 1035          "OF" Type<elem, FALSE>
+ 1036                                          (. IF ok THEN
+ 1037                                               k := nb;
+ 1038                                               WHILE k > 0 DO
+ 1039                                                 DEC(k);
+ 1040                                                 elem := SymTab.NewArrayB(
+ 1041                                                   elem, bnds[k], bndh[k])
+ 1042                                               END;
+ 1043                                               t := elem
+ 1044                                             ELSE t := SymTab.InvalidType
+ 1045                                             END; .) ) .
+ 1046    BoundPair<VAR ok: BOOLEAN>            (. VAR tlo, thi: SymTab.TypeIndex;
+ 1047                                               qlo, qhi: QbeGen.QVal;
+ 1048                                               lo, hi: INTEGER;
+ 1049                                               cl, cl2: INTEGER; .)
+ 1050      = Expr<tlo, qlo> ".." Expr<thi, qhi>
+ 1051                                          (. IF (tlo = SymTab.InvalidType)
+ 1052                                              OR (thi = SymTab.InvalidType) THEN
+ 1053                                             ok := FALSE
+ 1054                                           ELSE cl := SymTab.ClassOf(tlo);
+ 1055                                             cl2 := SymTab.ClassOf(thi);
+ 1056                                             IF ((cl # SymTab.ClInt)
+ 1057   AND (cl # SymTab.ClChar))
+ 1058                                                OR ((cl2 # SymTab.ClInt)
+ 1059   AND (cl2 # SymTab.ClChar)) THEN
+ 1060                                               SemError(230); ok := FALSE
+ 1061                                             ELSIF NOT SymTab.ConstInt(qlo, lo)
+ 1062                                                OR NOT SymTab.ConstInt(qhi, hi)
+ 1063                                                OR (lo > hi) THEN
+ 1064                                               SemError(230); ok := FALSE
+ 1065                                              ELSIF NOT SymTab.BoundAdd(lo, hi) THEN
+ 1066                                                SemError(230); ok := FALSE
+ 1067                                              END;
+ 1068                                            END; .) .
+ 1069    (* Sets: multi-word masks over bases ≤ 256 values (bool, char,
+ 1070       bounded subranges; enums wait for ordinals, INTEGER is
+ 1071       unbounded). Literals are SET OF [0..255]; assignment and
+ 1072       comparison across suitable bases are lenient (masks over min
+ 1073       words + zero-check extras), out-of-span literals are 222. *)
+ 1074    SetType<VAR t: SymTab.TypeIndex>      (. VAR base: SymTab.TypeIndex;
+ 1075                                               blo, bhi, bspan: INTEGER;
+ 1076                                               bcls: INTEGER; .)
+ 1077      = "SET" "OF" Type<base, FALSE>
+ 1078                                          (. IF base = SymTab.InvalidType THEN
+ 1079                                               t := SymTab.InvalidType
+ 1080                                             ELSE bcls :=
+ 1081                                                    SymTab.ClassOf(base);
+ 1082                                               IF bcls = SymTab.ClBool THEN
+ 1083                                                 blo := 0; bspan := 2
+ 1084                                               ELSIF bcls = SymTab.ClChar THEN
+ 1085                                                 blo := 0; bspan := 256
+ 1086                                               ELSIF bcls = SymTab.ClEnum THEN
+ 1087                                                 blo := 0;
+ 1088                                                 bspan := VAL(INTEGER,
+ 1089                                                   SymTab.EnumCount(base))
+ 1090                                               ELSIF SymTab.SubBounds(base,
+ 1091                                                       blo, bhi) THEN
+ 1092                                                 bspan := bhi - blo + 1
+ 1093                                               ELSE bspan := 0 END;
+ 1094                                               IF (bspan <= 0)
+ 1095                                                  OR (bspan > 65536) THEN
+ 1096                                                 SemError(230);
+ 1097                                                 t := SymTab.InvalidType
+ 1098                                               ELSE t := SymTab.NewSet(base)
+ 1099                                               END
+ 1100                                             END; .) .
+ 1101    (* Records: flat blobs; array fields are pointers to static
+ 1102       descriptors (locked amendment), nested records inline. Field
+ 1103       offsets static and declaration-ordered. *)
+ 1104    (* Field list: plain fields and (optionally) one variant part.  The
+ 1105       variant part is a `CASE ... END` item; because it starts with the
+ 1106       CASE keyword it is unambiguously distinguishable from a field
+ 1107       (which starts with an identifier). *)
+ 1108    RecordType<VAR t: SymTab.TypeIndex>   (. VAR t2: SymTab.TypeIndex;
+ 1109                                               tagOk: BOOLEAN; .)
+ 1110      = "RECORD"                          (. t := SymTab.NewRecord(); .)
+ 1111        [ RecItem<t> { ";" [ RecItem<t> ] } ]
+ 1112        "END"                             (. SymTab.LayoutRecord(t); .) .
+ 1113    RecItem<rec: SymTab.TypeIndex>        (. VAR tt: SymTab.TypeIndex; .)
+ 1114      = RecField<rec>
+ 1115      | CaseField<rec>                    (. SymTab.MarkVariant(rec); .) .
+ 1116    (* A variant part: CASE tag : Type OF variants.  The layout overlays
+ 1117       every branch from the tag slot (see SymTab.ComputeOffsets). *)
+ 1118    CaseField<rec: SymTab.TypeIndex>      (. VAR tagT: SymTab.TypeIndex;
+ 1119                                               tagN: SymTab.Name; .)
+ 1120      = "CASE"                            (. SymTab.ResetFields(rec); .)
+ 1121        GetIdent<tagN>                    (. IF NOT SymTab.FieldPending(rec,
+ 1122                                               tagN) THEN
+ 1123                                               SemError(200) END; .)
+ 1124        ":" Type<tagT, FALSE>             (. IF (tagT # SymTab.InvalidType)
+ 1125    AND NOT SymTab.IsOrdinal(tagT) THEN
+ 1126                                               SemError(224)
+ 1127                                             END;
+ 1128                                             SymTab.FixPendingF(rec, tagT);
+ 1129                                             SymTab.SetVariantTag(rec, tagN); .)
+ 1130        "OF"
+ 1131        RecFieldList<rec>
+ 1132        { "|"                             (. SymTab.ResetFields(rec); .)
+ 1133          RecFieldList<rec> }
+ 1134        "END" .
+ 1135    RecFieldList<rec: SymTab.TypeIndex>   (. VAR lt, lq: SymTab.TypeIndex;
+ 1136                                               lv1, lv2: QbeGen.QVal; .)
+ 1137      = VarLabel<lt, lv1> [ ".." VarLabel<lq, lv2> ] ":"
+ 1138        RecField<rec> { ";" [ RecField<rec> ] } .
+ 1139    (* Variant case label: a constant (or a constant range).  Values are
+ 1140       not interpreted (the layout overlays regardless). *)
+ 1141    VarLabel<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1142                                          (. VAR lname: SymTab.Name; .)
+ 1143      = ( ident                         (. LexName(lname);
+ 1144                                             QbeGen.CopyOp("0", q);
+ 1145                                             t := SymTab.IntType(); .)
+ 1146        | integer                       (. LexString(lname);
+ 1147                                             QbeGen.CopyOp("0", q);
+ 1148                                             t := SymTab.IntType(); .)
+ 1149        | charConst                     (. LexString(lname);
+ 1150                                             QbeGen.CopyOp("0", q);
+ 1151                                             t := SymTab.CharType(); .) ) .
+ 1152    RecField<rec: SymTab.TypeIndex>       (. VAR n: SymTab.Name;
+ 1153                                               t2: SymTab.TypeIndex; .)
+ 1154      = RecIdents<rec> ":" Type<t2, FALSE>(. SymTab.FixPendingF(rec, t2); .) .
+ 1155    RecIdents<rec: SymTab.TypeIndex>      (. VAR n: SymTab.Name; .)
+ 1156      = GetIdent<n>                       (. IF NOT SymTab.FieldPending(rec,
+ 1157                                               n) THEN
+ 1158                                               SemError(200) END; .)
+ 1159        { "," GetIdent<n>                 (. IF NOT SymTab.FieldPending(rec,
+ 1160                                               n) THEN
+ 1161                                               SemError(200) END; .) } .
+ 1162    TypeIdent<VAR t: SymTab.TypeIndex>    (. VAR n, qid: SymTab.Name;
+ 1163                                               k: INTEGER;
+ 1164                                               dotted: BOOLEAN; .)
+ 1165      = GetIdent<n>                       (. dotted := FALSE;
+ 1166                                             IF NOT SymTab.Lookup(n) THEN
+ 1167                                               k := -1;
+ 1168                                               t := SymTab.ForwardType(n);
+ 1169                                               IF t = SymTab.InvalidType THEN
+ 1170                                                 SemError(201)
+ 1171                                               END
+ 1172                                             ELSE k := SymTab.SymKind(n);
+ 1173                                               IF (k = SymTab.KindType)
+ 1174                                                  OR (k = SymTab.KindPredef) THEN
+ 1175                                                 t := SymTab.SymType(n)
+ 1176                                               ELSE t := SymTab.InvalidType
+ 1177                                               END
+ 1178                                             END; .)
+ 1179        [ "." GetIdent<qid>               (. dotted := TRUE;
+ 1180                                             IF k = SymTab.KindModule THEN
+ 1181                                               t := SymTab.QualType(n, qid);
+ 1182                                               IF t = SymTab.InvalidType THEN
+ 1183                                                 SemError(201)
  1184                                               END
  1184                                               END
- 1185                                             END; .)
- 1186        [ "." GetIdent<qid>               (. dotted := TRUE;
- 1187                                             IF k = SymTab.KindModule THEN
- 1188                                               t := SymTab.QualType(n, qid);
- 1189                                               IF t = SymTab.InvalidType THEN
- 1190                                                 SemError(201)
- 1191                                               END
- 1192                                             ELSE SemError(221);
- 1193                                               t := SymTab.InvalidType
- 1194                                             END; .) ]
- 1195                                          (. IF NOT dotted THEN
- 1196                                               IF (k = SymTab.KindModule)
- 1197                                                  OR ((k # SymTab.KindType)
- 1198    AND (k # SymTab.KindPredef)
- 1199    AND (k # SymTab.KindImport)
- 1200    AND (k # -1)) THEN
- 1201                                                 SemError(221)
- 1202                                               END
- 1203                                             END; .) .
- 1204    Subrange<VAR t: SymTab.TypeIndex>     (. VAR tlo, thi: SymTab.TypeIndex;
- 1205                                               qlo, qhi: QbeGen.QVal;
- 1206                                               lo, hi: INTEGER; .)
- 1207      = "[" Expr<tlo, qlo> ".." Expr<thi, qhi>
- 1208                                          (. IF (tlo = SymTab.InvalidType)
- 1209                                              OR (thi = SymTab.InvalidType) THEN
- 1210                                             t := SymTab.InvalidType
- 1211                                           ELSIF NOT SymTab.IsOrdinal(tlo)
- 1212                                              OR NOT SymTab.IsOrdinal(thi) THEN
- 1213                                             SemError(230);
- 1214                                             t := SymTab.InvalidType
- 1215                                           ELSIF NOT SymTab.ConstInt(qlo, lo)
- 1216                                              OR NOT SymTab.ConstInt(qhi, hi)
- 1217                                              OR (lo > hi) THEN
- 1218                                             SemError(230);
- 1219                                             t := SymTab.InvalidType
- 1220                                           ELSE t := SymTab.NewSubR(lo, hi)
- 1221                                           END; .)
- 1222        "]" .
- 1223    Enum<VAR t: SymTab.TypeIndex>         (. VAR n: SymTab.Name;
- 1224                                               ord: INTEGER;
- 1225                                               qv: QbeGen.QVal; .)
- 1226      = "("                               (. t := SymTab.NewEnum();
- 1227                                             ord := 0; .)
- 1228        GetIdent<n>                       (. IF NOT SymTab.Enter(n,
- 1229                                               SymTab.KindConst) THEN
- 1230                                               SemError(200) END;
- 1231                                             SymTab.SetSymType(n, t);
- 1232                                             QbeGen.IntStr(ord, qv);
- 1233                                             SymTab.SetSymVal(n, qv);
- 1234                                             Lower.NoteVar(n,
- 1235                                               SymTab.KindConst, t);
- 1236                                             Lower.NoteConstVal(qv);
- 1237                                             INC(ord); .)
- 1238        { "," GetIdent<n>                 (. IF NOT SymTab.Enter(n,
- 1239                                               SymTab.KindConst) THEN
- 1240                                               SemError(200) END;
- 1241                                             SymTab.SetSymType(n, t);
- 1242                                             QbeGen.IntStr(ord, qv);
- 1243                                             SymTab.SetSymVal(n, qv);
- 1244                                             Lower.NoteVar(n,
- 1245                                               SymTab.KindConst, t);
- 1246                                             Lower.NoteConstVal(qv);
- 1247                                             INC(ord); .) }
- 1248        ")"                               (. SymTab.SetEnumCount(t,
- 1249                                               VAL(CARDINAL, ord)); .) .
- 1250    (* Clarion-form classes (docs/OOP.txt): declaration + single
- 1251       inheritance + IMPLEMENTATION blocks. Scopes and member checks
- 1252       now; lowering (vtable, dispatch, THIS) later — one 230 per
- 1253       class/impl block. Methods end with ";" per the Table example
- 1254       (not "," as in the sketch). No underscores in identifiers. *)
- 1255    (* Single CLASS item in both loops: separating declaration from
- 1256       IMPLEMENTATION at the loop level needs 2-token lookahead
- 1257       (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
- 1258       The second token decides after CLASS is consumed. A misplaced
- 1259       CLASS IMPLEMENTATION inside TYPE still parses (harmless: the
- 1260       whole unit ends 230 until lowering). *)
- 1261    ClassItem
- 1262      = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
- 1263    ClassRest                             (. VAR cn, m2, pn: SymTab.Name;
- 1264                                               ct: SymTab.TypeIndex; .)
- 1265      = GetIdent<cn>                      (. IF NOT SymTab.Enter(cn,
- 1266                                               SymTab.KindType) THEN
- 1267                                               SemError(200) END;
- 1268                                             ct := SymTab.NewClass();
- 1269                                             SymTab.SetSymType(cn, ct);
- 1270                                             SymTab.PushClassScope(ct);
- 1271                                             astCls := AST.MakeNode(AST.NkClassDecl);
- 1272                                             AST.SetChild(astCls, 0,
- 1273                                               AST.MakeLeaf(AST.NkIdent, cn));
- 1274                                             astClsP := AST.NoNode;
- 1275                                             astClsPTail := AST.NoNode;
- 1276                                             astClsF := AST.NoNode;
- 1277                                             astClsFTail := AST.NoNode;
- 1278                                             astClsM := AST.NoNode;
- 1279                                             astClsMTail := AST.NoNode; .)
- 1280        [ Parents<ct> ]
- 1281        ";"
- 1282        { ClassField<ct> ";" }
- 1283        { MethodHeading<pn, SymTab.InvalidType> ";"
- 1284                                          (. Lower.ScopeLeave;
- 1285                                             SymTab.CloseProc;
- 1286                                             QbeGen.AbortFunc; .) }
- 1287        "END"
- 1288        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
- 1289                                               SemError(202) END;
- 1290                                             SymTab.LayoutClass(ct);
- 1291                                             SymTab.PopScope;
- 1292                                             AST.SetChild(astCls, 1, astClsP);
- 1293                                             AST.SetChild(astCls, 2, astClsF);
- 1294                                             AST.SetChild(astCls, 3, astClsM);
- 1295                                             astDecl := astCls; .) .
- 1296    Parents<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name; .)
- 1297      = "(" Parent1<ct>
- 1298        { "," GetIdent<p>                 (. SemError(230); .) }
- 1299        ")" .
- 1300    Parent1<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name;
- 1301                                               pt: SymTab.TypeIndex; .)
- 1302      = GetIdent<p>                       (. IF NOT SymTab.Lookup(p) THEN
- 1303                                               SemError(201)
- 1304                                             ELSE pt := SymTab.SymType(p);
- 1305                                               IF SymTab.ClassOf(pt) #
- 1306                                                  SymTab.ClClass THEN
- 1307                                                 SemError(230)
- 1308                                               ELSE SymTab.SetParent(ct, pt)
- 1309                                               END
- 1310                                             END;
- 1311                                             AstAppend(AST.NkFieldDecl,
- 1312                                               astClsP, astClsPTail,
- 1313                                               AST.MakeLeaf(AST.NkIdent, p)); .) .
- 1314    ClassField<ct: SymTab.TypeIndex>      (. VAR n, rhs: SymTab.Name;
- 1315                                               t: SymTab.TypeIndex;
- 1316                                               astNode: AST.Node; .)
- 1317      = GetIdent<n>
- 1318        ( "=" GetIdent<rhs>               (. IF NOT SymTab.Enter(n,
- 1319                                               SymTab.KindConst) THEN
- 1320                                               SemError(200) END;
- 1321                                             astNode := AST.MakeNode(AST.NkConstDecl);
- 1322                                             AST.SetChild(astNode, 0,
- 1323                                               AST.MakeLeaf(AST.NkIdent, n));
- 1324                                             AST.SetChild(astNode, 1,
- 1325                                               AST.MakeLeaf(AST.NkIdent, rhs));
- 1326                                             AstAppend(AST.NkFieldDecl,
- 1327                                               astClsF, astClsFTail, astNode);
- 1328                                             IF SymTab.Lookup(rhs) THEN
- 1329                                               SymTab.SetSymType(n,
- 1330                                                 SymTab.SymType(rhs))
- 1331                                             END; .)
- 1332        |                                 (. IF NOT SymTab.FieldPending(ct,
- 1333                                               n) THEN
- 1334                                               SemError(200) END;
- 1335                                             astNode := AST.MakeNode(AST.NkVarDecl);
- 1336                                             AST.SetChild(astNode, 0,
- 1337                                               AST.MakeLeaf(AST.NkIdent, n)); .)
- 1338          { "," GetIdent<n>               (. IF NOT SymTab.FieldPending(ct,
- 1339                                               n) THEN
- 1340                                               SemError(200) END;
- 1341                                             AST.SetChild(astNode,
- 1342                                               AST.NChild(astNode),
- 1343                                               AST.MakeLeaf(AST.NkIdent, n)); .) }
- 1344          ":" Type<t, FALSE>              (. SymTab.FixPendingF(ct, t);
- 1345                                             AST.SetTy(astNode, t);
- 1346                                             AstAppend(AST.NkFieldDecl,
- 1347                                               astClsF, astClsFTail, astNode); .) ) .
- 1348    MethodHeading<VAR pn: SymTab.Name; ct: SymTab.TypeIndex>
- 1349                                          (. VAR wantVirt: BOOLEAN; .)
- 1350      =                                   (. wantVirt := FALSE; .)
- 1351        [ "VIRTUAL"                       (. wantVirt := TRUE; .) ]
- 1352        ProcHeading<pn, ct>               (. IF wantVirt THEN
- 1353                                               SymTab.MarkVirtual END;
- 1354                                             astMethod := AST.MakeNode(AST.NkProcDecl);
- 1355                                             AST.SetChild(astMethod, 0,
- 1356                                               AST.MakeLeaf(AST.NkIdent, pn));
- 1357                                             IF wantVirt THEN
- 1358                                               AST.SetOp(astMethod, 3)
- 1359                                             ELSE AST.SetOp(astMethod, 0)
- 1360                                             END;
- 1361                                             AstAppend(AST.NkFieldDecl,
- 1362                                               astClsM, astClsMTail, astMethod); .) .
- 1363    ClassImplRest                         (. VAR cn, m2: SymTab.Name;
- 1364                                               ct: SymTab.TypeIndex; .)
- 1365      = GetIdent<cn>                      (. IF NOT SymTab.Lookup(cn) THEN
- 1366                                               SemError(201);
- 1367                                               ct := SymTab.InvalidType
- 1368                                             ELSE ct := SymTab.SymType(cn);
- 1369                                               IF SymTab.ClassOf(ct) #
- 1370                                                  SymTab.ClClass THEN
- 1371                                                 SemError(230);
- 1372                                                 ct := SymTab.InvalidType
- 1373                                               END
- 1374                                             END;
- 1375                                             astCls := AST.MakeNode(AST.NkClassDecl);
- 1376                                             AST.SetOp(astCls, 1);
- 1377                                             AST.SetChild(astCls, 0,
- 1378                                               AST.MakeLeaf(AST.NkIdent, cn));
- 1379                                             astClsM := AST.NoNode;
- 1380                                             astClsMTail := AST.NoNode;
- 1381                                             astStmt := AST.NoNode;
- 1382                                             IF ct #
- 1383                                                SymTab.InvalidType THEN
- 1384                                               IF NOT SymTab.PushClassMembers(
- 1385                                                      ct) THEN
- 1386                                                 SemError(230) END;
- 1387                                               SymTab.PushImplClass(ct)
- 1388                                             END; .)
- 1389        ";" { MethodImpl<ct> ";" }
- 1390                                          (. astStmt := AST.NoNode; .)
- 1391        [ "BEGIN"                         (. astStmt := AST.MakeNode(AST.NkBlock);
- 1392                                             .)
- 1393          [ StatSeq ] ]
- 1394        "END"
- 1395        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
- 1396                                               SemError(202) END;
- 1397                                             SymTab.PopImplClass;
- 1398                                             SymTab.PopScope;
- 1399                                             AST.SetChild(astCls, 1, AST.NoNode);
- 1400                                             AST.SetChild(astCls, 2, astStmt);
- 1401                                             AST.SetChild(astCls, 3, astClsM);
- 1402                                             astDecl := astCls; .) .
- 1403    MethodImpl<ct: SymTab.TypeIndex>      (. VAR pn: SymTab.Name;
- 1404                                               thisQ: QbeGen.QVal;
- 1405                                               methRes: SymTab.TypeIndex; .)
- 1406      = MethodHeading<pn, ct> ";"
- 1407                                          (. IF (ct #
- 1408                                                SymTab.InvalidType)
- 1409   AND NOT SymTab.MethodExists(ct,
- 1410                                                    pn) THEN
- 1411                                               SemError(201) END; .)
- 1412        ( "FORWARD"                       (. AST.SetOp(astMethod, 1);
- 1413                                             SymTab.MarkFwd;
- 1414                                             QbeGen.AbortFunc;
- 1415                                             Lower.ScopeLeave;
- 1416                                             SymTab.CloseProc; .)
- 1417        |                                 (.
- 1418                                             (* bind the receiver: bare
- 1419                                                field names resolve
- 1420                                                against THIS *)
- 1421                                              QbeGen.CopyOp("@", thisQ);
- 1422                                             QbeGen.PushWith(thisQ); .)
- 1423          Block<pn>                       (. AST.SetChild(astMethod, 1, astStmt);
- 1424                                             AST.SetChild(astMethod, 2, astBlkDecls);
- 1425                                             QbeGen.PopWith;
- 1426                                             methRes := SymTab.CurRes();
- 1427                                             Lower.ScopeLeave;
- 1428                                             SymTab.CloseProc;
- 1429                                             QbeGen.EndFunc(methRes); .) ) .
- 1430    ConstBlock                            (. VAR astSeq, astTail: AST.Node; .)
- 1431      = "CONST"                           (. astSeq := AST.NoNode;
- 1432                                             astTail := AST.NoNode; .)
- 1433        { ConstDecl ";"                   (. AstAppend(AST.NkDeclSeq,
- 1434                                               astSeq, astTail, astDecl); .) }
- 1435                                          (. astDecl := astSeq; .) .
- 1436    ConstDecl                             (. VAR n: SymTab.Name;
- 1437                                               t: SymTab.TypeIndex;
- 1438                                               qv: QbeGen.QVal;
- 1439                                               cls: INTEGER;
- 1440                                               astNode: AST.Node; .)
- 1441      = GetIdent<n>                       (. IF NOT SymTab.Enter(n,
- 1442                                               SymTab.KindConst) THEN
- 1443                                               SemError(200) END; .)
- 1444        "="
- 1445        Expr<t, qv> (. astNode := AST.MakeNode(AST.NkConstDecl);
- 1446                                             AST.SetChild(astNode, 0,
- 1447                                               AST.MakeLeaf(AST.NkIdent, n));
- 1448                                             AST.SetChild(astNode, 1, astCur);
- 1449                                             AST.SetTy(astNode, t);
- 1450                                             astDecl := astNode;
- 1451                                             Lower.NoteVar(n, SymTab.KindConst, t);
- 1452                                             Lower.NoteConstVal(qv);
- 1453                                             SymTab.SetSymType(n, t);
- 1454                                             cls := SymTab.ClassOf(t);
- 1455                                             IF (cls = SymTab.ClArray)
- 1456                                                OR (cls = SymTab.ClRecord)
- 1457                                                OR (cls = SymTab.ClClass)
- 1458                                                OR (cls = SymTab.ClStr)
- 1459                                                OR (cls = SymTab.ClUStr) THEN
- 1460                                               (* an aggregate/string
- 1461                                                  constant: qv is its
- 1462                                                  descriptor address; no
- 1463                                                  scalar data *)
- 1464                                               SymTab.SetSymVal(n, qv)
- 1465                                             ELSIF NOT QbeGen.IsImm(qv) THEN
- 1466                                               SemError(230)
- 1467                                             ELSE
- 1468                                               SymTab.SetSymVal(n, qv);
- 1469                                             END; .) .
- 1470    VarBlock                              (. VAR astSeq, astTail: AST.Node; .)
- 1471      = "VAR"                             (. astSeq := AST.NoNode;
- 1472                                             astTail := AST.NoNode; .)
- 1473        { VarDecl ";"                     (. AstAppend(AST.NkDeclSeq,
- 1474                                               astSeq, astTail, astDecl); .) }
- 1475                                          (. astDecl := astSeq; .) .
- 1476    VarDecl                               (. VAR nm: SymTab.Name;
- 1477                                               t: SymTab.TypeIndex;
- 1478                                               i: CARDINAL;
- 1479                                               cls: INTEGER;
- 1480                                               astNode, astTail: AST.Node; .)
- 1481      = VarIdents ":"
- 1482        Type<t, FALSE> (. astNode := AST.MakeNode(AST.NkVarDecl);
- 1483                                             astTail := astNode;
- 1484                                             i := 0;
- 1485                                             WHILE i < SymTab.PendCount() DO
- 1486                                               SymTab.PendName(i, nm);
- 1487                                               Lower.NoteVar(nm, SymTab.KindVar, t);
- 1488                                               (* chunked: a VAR list can
- 1489                                                  exceed AST.MaxChild *)
- 1490                                               AstAppend(AST.NkBlock,
- 1491                                                 astNode, astTail,
- 1492                                                 AST.MakeLeaf(AST.NkIdent, nm));
- 1493                                               INC(i)
- 1494                                             END;
- 1495                                             AST.SetTy(astNode, t);
- 1496                                             astDecl := astNode;
- 1497                                             cls := SymTab.ClassOf(t);
- 1498                                             IF (t # SymTab.InvalidType)
- 1499   AND NOT SymTab.IsUnresolved(t)
- 1500   AND (cls # SymTab.ClInt)
- 1501   AND (cls # SymTab.ClBool)
- 1502   AND (cls # SymTab.ClChar)
- 1503   AND (cls # SymTab.ClReal)
- 1504   AND (cls # SymTab.ClArray)
- 1505   AND (cls # SymTab.ClSet)
- 1506   AND (cls # SymTab.ClRecord)
- 1507   AND (cls # SymTab.ClPtr)
- 1508   AND (cls # SymTab.ClLong)
- 1509   AND (cls # SymTab.ClProc)
- 1510   AND (cls # SymTab.ClUChar)
- 1511   AND (cls # SymTab.ClUStr)
- 1512   AND (cls # SymTab.ClEnum)
- 1513   AND (cls # SymTab.ClClass) THEN
- 1514                                               SemError(230) END;
- 1515                                             IF QbeGen.LocFull() THEN
- 1516                                               SemError(233) END;
- 1517                                             i := 0;
- 1518                                             IF SymTab.IsUnresolved(t)
- 1519                                                AND NOT SymTab.InProc() THEN
- 1520                                               (* a forward-typed global:
- 1521                                                  defer emission until the
- 1522                                                  TYPE block completes *)
- 1523                                               AST.SetOp(astNode, 1);
- 1524                                               WHILE i < SymTab.PendCount() DO
- 1525                                                 SymTab.PendName(i, nm);
- 1526                                                 IF nPendVar <=
- 1527                                                    HIGH(pendVarName) THEN
- 1528                                                   pendVarName[nPendVar] := nm;
- 1529                                                   pendVarT[nPendVar] := t;
- 1530                                                   INC(nPendVar)
- 1531                                                 END;
- 1532                                                 INC(i)
- 1533                                               END
- 1534                                             ELSE
- 1535                                               WHILE i < SymTab.PendCount() DO
- 1536                                                 SymTab.PendName(i, nm);
- 1537                                                 INC(i)
- 1538                                               END
- 1539                                             END;
- 1540                                             (* a plain VAR list, not a
- 1541                                                heading: the signature
- 1542                                                result is discarded *)
- 1543                                             IF NOT SymTab.FixPending(t) THEN
- 1544                                             END; .) .
- 1545    VarIdents                             (. VAR n: SymTab.Name; .)
- 1546      = GetIdent<n>                       (. IF NOT SymTab.EnterPending(n,
- 1547                                               SymTab.KindVar) THEN
+ 1185                                             ELSE SemError(221);
+ 1186                                               t := SymTab.InvalidType
+ 1187                                             END; .) ]
+ 1188                                          (. IF NOT dotted THEN
+ 1189                                               IF (k = SymTab.KindModule)
+ 1190                                                  OR ((k # SymTab.KindType)
+ 1191    AND (k # SymTab.KindPredef)
+ 1192    AND (k # SymTab.KindImport)
+ 1193    AND (k # -1)) THEN
+ 1194                                                 SemError(221)
+ 1195                                               END
+ 1196                                             END; .) .
+ 1197    Subrange<VAR t: SymTab.TypeIndex>     (. VAR tlo, thi: SymTab.TypeIndex;
+ 1198                                               qlo, qhi: QbeGen.QVal;
+ 1199                                               lo, hi: INTEGER; .)
+ 1200      = "[" Expr<tlo, qlo> ".." Expr<thi, qhi>
+ 1201                                          (. IF (tlo = SymTab.InvalidType)
+ 1202                                              OR (thi = SymTab.InvalidType) THEN
+ 1203                                             t := SymTab.InvalidType
+ 1204                                           ELSIF NOT SymTab.IsOrdinal(tlo)
+ 1205                                              OR NOT SymTab.IsOrdinal(thi) THEN
+ 1206                                             SemError(230);
+ 1207                                             t := SymTab.InvalidType
+ 1208                                           ELSIF NOT SymTab.ConstInt(qlo, lo)
+ 1209                                              OR NOT SymTab.ConstInt(qhi, hi)
+ 1210                                              OR (lo > hi) THEN
+ 1211                                             SemError(230);
+ 1212                                             t := SymTab.InvalidType
+ 1213                                           ELSE t := SymTab.NewSubR(lo, hi)
+ 1214                                           END; .)
+ 1215        "]" .
+ 1216    Enum<VAR t: SymTab.TypeIndex>         (. VAR n: SymTab.Name;
+ 1217                                               ord: INTEGER;
+ 1218                                               qv: QbeGen.QVal; .)
+ 1219      = "("                               (. t := SymTab.NewEnum();
+ 1220                                             ord := 0; .)
+ 1221        GetIdent<n>                       (. IF NOT SymTab.Enter(n,
+ 1222                                               SymTab.KindConst) THEN
+ 1223                                               SemError(200) END;
+ 1224                                             SymTab.SetSymType(n, t);
+ 1225                                             QbeGen.IntStr(ord, qv);
+ 1226                                             SymTab.SetSymVal(n, qv);
+ 1227                                             Lower.NoteVar(n,
+ 1228                                               SymTab.KindConst, t);
+ 1229                                             Lower.NoteConstVal(qv);
+ 1230                                             INC(ord); .)
+ 1231        { "," GetIdent<n>                 (. IF NOT SymTab.Enter(n,
+ 1232                                               SymTab.KindConst) THEN
+ 1233                                               SemError(200) END;
+ 1234                                             SymTab.SetSymType(n, t);
+ 1235                                             QbeGen.IntStr(ord, qv);
+ 1236                                             SymTab.SetSymVal(n, qv);
+ 1237                                             Lower.NoteVar(n,
+ 1238                                               SymTab.KindConst, t);
+ 1239                                             Lower.NoteConstVal(qv);
+ 1240                                             INC(ord); .) }
+ 1241        ")"                               (. SymTab.SetEnumCount(t,
+ 1242                                               VAL(CARDINAL, ord)); .) .
+ 1243    (* Clarion-form classes (docs/OOP.txt): declaration + single
+ 1244       inheritance + IMPLEMENTATION blocks. Scopes and member checks
+ 1245       now; lowering (vtable, dispatch, THIS) later — one 230 per
+ 1246       class/impl block. Methods end with ";" per the Table example
+ 1247       (not "," as in the sketch). No underscores in identifiers. *)
+ 1248    (* Single CLASS item in both loops: separating declaration from
+ 1249       IMPLEMENTATION at the loop level needs 2-token lookahead
+ 1250       (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
+ 1251       The second token decides after CLASS is consumed. A misplaced
+ 1252       CLASS IMPLEMENTATION inside TYPE still parses (harmless: the
+ 1253       whole unit ends 230 until lowering). *)
+ 1254    ClassItem
+ 1255      = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
+ 1256    ClassRest                             (. VAR cn, m2, pn: SymTab.Name;
+ 1257                                               ct: SymTab.TypeIndex; .)
+ 1258      = GetIdent<cn>                      (. IF NOT SymTab.Enter(cn,
+ 1259                                               SymTab.KindType) THEN
+ 1260                                               SemError(200) END;
+ 1261                                             ct := SymTab.NewClass();
+ 1262                                             SymTab.SetSymType(cn, ct);
+ 1263                                             SymTab.PushClassScope(ct);
+ 1264                                             astCls := AST.MakeNode(AST.NkClassDecl);
+ 1265                                             AST.SetChild(astCls, 0,
+ 1266                                               AST.MakeLeaf(AST.NkIdent, cn));
+ 1267                                             astClsP := AST.NoNode;
+ 1268                                             astClsPTail := AST.NoNode;
+ 1269                                             astClsF := AST.NoNode;
+ 1270                                             astClsFTail := AST.NoNode;
+ 1271                                             astClsM := AST.NoNode;
+ 1272                                             astClsMTail := AST.NoNode; .)
+ 1273        [ Parents<ct> ]
+ 1274        ";"
+ 1275        { ClassField<ct> ";" }
+ 1276        { MethodHeading<pn, SymTab.InvalidType> ";"
+ 1277                                          (. Lower.ScopeLeave;
+ 1278                                             SymTab.CloseProc;
+ 1279                                             QbeGen.AbortFunc; .) }
+ 1280        "END"
+ 1281        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
+ 1282                                               SemError(202) END;
+ 1283                                             SymTab.LayoutClass(ct);
+ 1284                                             SymTab.PopScope;
+ 1285                                             AST.SetChild(astCls, 1, astClsP);
+ 1286                                             AST.SetChild(astCls, 2, astClsF);
+ 1287                                             AST.SetChild(astCls, 3, astClsM);
+ 1288                                             astDecl := astCls; .) .
+ 1289    Parents<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name; .)
+ 1290      = "(" Parent1<ct>
+ 1291        { "," GetIdent<p>                 (. SemError(230); .) }
+ 1292        ")" .
+ 1293    Parent1<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name;
+ 1294                                               pt: SymTab.TypeIndex; .)
+ 1295      = GetIdent<p>                       (. IF NOT SymTab.Lookup(p) THEN
+ 1296                                               SemError(201)
+ 1297                                             ELSE pt := SymTab.SymType(p);
+ 1298                                               IF SymTab.ClassOf(pt) #
+ 1299                                                  SymTab.ClClass THEN
+ 1300                                                 SemError(230)
+ 1301                                               ELSE SymTab.SetParent(ct, pt)
+ 1302                                               END
+ 1303                                             END;
+ 1304                                             AstAppend(AST.NkFieldDecl,
+ 1305                                               astClsP, astClsPTail,
+ 1306                                               AST.MakeLeaf(AST.NkIdent, p)); .) .
+ 1307    ClassField<ct: SymTab.TypeIndex>      (. VAR n, rhs: SymTab.Name;
+ 1308                                               t: SymTab.TypeIndex;
+ 1309                                               astNode: AST.Node; .)
+ 1310      = GetIdent<n>
+ 1311        ( "=" GetIdent<rhs>               (. IF NOT SymTab.Enter(n,
+ 1312                                               SymTab.KindConst) THEN
+ 1313                                               SemError(200) END;
+ 1314                                             astNode := AST.MakeNode(AST.NkConstDecl);
+ 1315                                             AST.SetChild(astNode, 0,
+ 1316                                               AST.MakeLeaf(AST.NkIdent, n));
+ 1317                                             AST.SetChild(astNode, 1,
+ 1318                                               AST.MakeLeaf(AST.NkIdent, rhs));
+ 1319                                             AstAppend(AST.NkFieldDecl,
+ 1320                                               astClsF, astClsFTail, astNode);
+ 1321                                             IF SymTab.Lookup(rhs) THEN
+ 1322                                               SymTab.SetSymType(n,
+ 1323                                                 SymTab.SymType(rhs))
+ 1324                                             END; .)
+ 1325        |                                 (. IF NOT SymTab.FieldPending(ct,
+ 1326                                               n) THEN
+ 1327                                               SemError(200) END;
+ 1328                                             astNode := AST.MakeNode(AST.NkVarDecl);
+ 1329                                             AST.SetChild(astNode, 0,
+ 1330                                               AST.MakeLeaf(AST.NkIdent, n)); .)
+ 1331          { "," GetIdent<n>               (. IF NOT SymTab.FieldPending(ct,
+ 1332                                               n) THEN
+ 1333                                               SemError(200) END;
+ 1334                                             AST.SetChild(astNode,
+ 1335                                               AST.NChild(astNode),
+ 1336                                               AST.MakeLeaf(AST.NkIdent, n)); .) }
+ 1337          ":" Type<t, FALSE>              (. SymTab.FixPendingF(ct, t);
+ 1338                                             AST.SetTy(astNode, t);
+ 1339                                             AstAppend(AST.NkFieldDecl,
+ 1340                                               astClsF, astClsFTail, astNode); .) ) .
+ 1341    MethodHeading<VAR pn: SymTab.Name; ct: SymTab.TypeIndex>
+ 1342                                          (. VAR wantVirt: BOOLEAN; .)
+ 1343      =                                   (. wantVirt := FALSE; .)
+ 1344        [ "VIRTUAL"                       (. wantVirt := TRUE; .) ]
+ 1345        ProcHeading<pn, ct>               (. IF wantVirt THEN
+ 1346                                               SymTab.MarkVirtual END;
+ 1347                                             astMethod := AST.MakeNode(AST.NkProcDecl);
+ 1348                                             AST.SetChild(astMethod, 0,
+ 1349                                               AST.MakeLeaf(AST.NkIdent, pn));
+ 1350                                             IF wantVirt THEN
+ 1351                                               AST.SetOp(astMethod, 3)
+ 1352                                             ELSE AST.SetOp(astMethod, 0)
+ 1353                                             END;
+ 1354                                             AstAppend(AST.NkFieldDecl,
+ 1355                                               astClsM, astClsMTail, astMethod); .) .
+ 1356    ClassImplRest                         (. VAR cn, m2: SymTab.Name;
+ 1357                                               ct: SymTab.TypeIndex; .)
+ 1358      = GetIdent<cn>                      (. IF NOT SymTab.Lookup(cn) THEN
+ 1359                                               SemError(201);
+ 1360                                               ct := SymTab.InvalidType
+ 1361                                             ELSE ct := SymTab.SymType(cn);
+ 1362                                               IF SymTab.ClassOf(ct) #
+ 1363                                                  SymTab.ClClass THEN
+ 1364                                                 SemError(230);
+ 1365                                                 ct := SymTab.InvalidType
+ 1366                                               END
+ 1367                                             END;
+ 1368                                             astCls := AST.MakeNode(AST.NkClassDecl);
+ 1369                                             AST.SetOp(astCls, 1);
+ 1370                                             AST.SetChild(astCls, 0,
+ 1371                                               AST.MakeLeaf(AST.NkIdent, cn));
+ 1372                                             astClsM := AST.NoNode;
+ 1373                                             astClsMTail := AST.NoNode;
+ 1374                                             astStmt := AST.NoNode;
+ 1375                                             IF ct #
+ 1376                                                SymTab.InvalidType THEN
+ 1377                                               IF NOT SymTab.PushClassMembers(
+ 1378                                                      ct) THEN
+ 1379                                                 SemError(230) END;
+ 1380                                               SymTab.PushImplClass(ct)
+ 1381                                             END; .)
+ 1382        ";" { MethodImpl<ct> ";" }
+ 1383                                          (. astStmt := AST.NoNode; .)
+ 1384        [ "BEGIN"                         (. astStmt := AST.MakeNode(AST.NkBlock);
+ 1385                                             .)
+ 1386          [ StatSeq ] ]
+ 1387        "END"
+ 1388        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
+ 1389                                               SemError(202) END;
+ 1390                                             SymTab.PopImplClass;
+ 1391                                             SymTab.PopScope;
+ 1392                                             AST.SetChild(astCls, 1, AST.NoNode);
+ 1393                                             AST.SetChild(astCls, 2, astStmt);
+ 1394                                             AST.SetChild(astCls, 3, astClsM);
+ 1395                                             astDecl := astCls; .) .
+ 1396    MethodImpl<ct: SymTab.TypeIndex>      (. VAR pn: SymTab.Name;
+ 1397                                               thisQ: QbeGen.QVal;
+ 1398                                               methRes: SymTab.TypeIndex; .)
+ 1399      = MethodHeading<pn, ct> ";"
+ 1400                                          (. IF (ct #
+ 1401                                                SymTab.InvalidType)
+ 1402   AND NOT SymTab.MethodExists(ct,
+ 1403                                                    pn) THEN
+ 1404                                               SemError(201) END; .)
+ 1405        ( "FORWARD"                       (. AST.SetOp(astMethod, 1);
+ 1406                                             SymTab.MarkFwd;
+ 1407                                             QbeGen.AbortFunc;
+ 1408                                             Lower.ScopeLeave;
+ 1409                                             SymTab.CloseProc; .)
+ 1410        |                                 (.
+ 1411                                             (* bind the receiver: bare
+ 1412                                                field names resolve
+ 1413                                                against THIS *)
+ 1414                                              QbeGen.CopyOp("@", thisQ);
+ 1415                                             QbeGen.PushWith(thisQ); .)
+ 1416          Block<pn>                       (. AST.SetChild(astMethod, 1, astStmt);
+ 1417                                             AST.SetChild(astMethod, 2, astBlkDecls);
+ 1418                                             QbeGen.PopWith;
+ 1419                                             methRes := SymTab.CurRes();
+ 1420                                             Lower.ScopeLeave;
+ 1421                                             SymTab.CloseProc;
+ 1422                                             QbeGen.EndFunc(methRes); .) ) .
+ 1423    ConstBlock                            (. VAR astSeq, astTail: AST.Node; .)
+ 1424      = "CONST"                           (. astSeq := AST.NoNode;
+ 1425                                             astTail := AST.NoNode; .)
+ 1426        { ConstDecl ";"                   (. AstAppend(AST.NkDeclSeq,
+ 1427                                               astSeq, astTail, astDecl); .) }
+ 1428                                          (. astDecl := astSeq; .) .
+ 1429    ConstDecl                             (. VAR n: SymTab.Name;
+ 1430                                               t: SymTab.TypeIndex;
+ 1431                                               qv: QbeGen.QVal;
+ 1432                                               cls: INTEGER;
+ 1433                                               astNode: AST.Node; .)
+ 1434      = GetIdent<n>                       (. IF NOT SymTab.Enter(n,
+ 1435                                               SymTab.KindConst) THEN
+ 1436                                               SemError(200) END; .)
+ 1437        "="
+ 1438        Expr<t, qv> (. astNode := AST.MakeNode(AST.NkConstDecl);
+ 1439                                             AST.SetChild(astNode, 0,
+ 1440                                               AST.MakeLeaf(AST.NkIdent, n));
+ 1441                                             AST.SetChild(astNode, 1, astCur);
+ 1442                                             AST.SetTy(astNode, t);
+ 1443                                             astDecl := astNode;
+ 1444                                             Lower.NoteVar(n, SymTab.KindConst, t);
+ 1445                                             Lower.NoteConstVal(qv);
+ 1446                                             SymTab.SetSymType(n, t);
+ 1447                                             cls := SymTab.ClassOf(t);
+ 1448                                             IF (cls = SymTab.ClArray)
+ 1449                                                OR (cls = SymTab.ClRecord)
+ 1450                                                OR (cls = SymTab.ClClass)
+ 1451                                                OR (cls = SymTab.ClStr)
+ 1452                                                OR (cls = SymTab.ClUStr) THEN
+ 1453                                               (* an aggregate/string
+ 1454                                                  constant: qv is its
+ 1455                                                  descriptor address; no
+ 1456                                                  scalar data *)
+ 1457                                               SymTab.SetSymVal(n, qv)
+ 1458                                             ELSIF NOT QbeGen.IsImm(qv) THEN
+ 1459                                               SemError(230)
+ 1460                                             ELSE
+ 1461                                               SymTab.SetSymVal(n, qv);
+ 1462                                             END; .) .
+ 1463    VarBlock                              (. VAR astSeq, astTail: AST.Node; .)
+ 1464      = "VAR"                             (. astSeq := AST.NoNode;
+ 1465                                             astTail := AST.NoNode; .)
+ 1466        { VarDecl ";"                     (. AstAppend(AST.NkDeclSeq,
+ 1467                                               astSeq, astTail, astDecl); .) }
+ 1468                                          (. astDecl := astSeq; .) .
+ 1469    VarDecl                               (. VAR nm: SymTab.Name;
+ 1470                                               t: SymTab.TypeIndex;
+ 1471                                               i: CARDINAL;
+ 1472                                               cls: INTEGER;
+ 1473                                               astNode, astTail: AST.Node; .)
+ 1474      = VarIdents ":"
+ 1475        Type<t, FALSE> (. astNode := AST.MakeNode(AST.NkVarDecl);
+ 1476                                             astTail := astNode;
+ 1477                                             i := 0;
+ 1478                                             WHILE i < SymTab.PendCount() DO
+ 1479                                               SymTab.PendName(i, nm);
+ 1480                                               Lower.NoteVar(nm, SymTab.KindVar, t);
+ 1481                                               (* chunked: a VAR list can
+ 1482                                                  exceed AST.MaxChild *)
+ 1483                                               AstAppend(AST.NkBlock,
+ 1484                                                 astNode, astTail,
+ 1485                                                 AST.MakeLeaf(AST.NkIdent, nm));
+ 1486                                               INC(i)
+ 1487                                             END;
+ 1488                                             AST.SetTy(astNode, t);
+ 1489                                             astDecl := astNode;
+ 1490                                             cls := SymTab.ClassOf(t);
+ 1491                                             IF (t # SymTab.InvalidType)
+ 1492   AND NOT SymTab.IsUnresolved(t)
+ 1493   AND (cls # SymTab.ClInt)
+ 1494   AND (cls # SymTab.ClBool)
+ 1495   AND (cls # SymTab.ClChar)
+ 1496   AND (cls # SymTab.ClReal)
+ 1497   AND (cls # SymTab.ClArray)
+ 1498   AND (cls # SymTab.ClSet)
+ 1499   AND (cls # SymTab.ClRecord)
+ 1500   AND (cls # SymTab.ClPtr)
+ 1501   AND (cls # SymTab.ClLong)
+ 1502   AND (cls # SymTab.ClProc)
+ 1503   AND (cls # SymTab.ClUChar)
+ 1504   AND (cls # SymTab.ClUStr)
+ 1505   AND (cls # SymTab.ClEnum)
+ 1506   AND (cls # SymTab.ClClass) THEN
+ 1507                                               SemError(230) END;
+ 1508                                             IF QbeGen.LocFull() THEN
+ 1509                                               SemError(233) END;
+ 1510                                             i := 0;
+ 1511                                             IF SymTab.IsUnresolved(t)
+ 1512                                                AND NOT SymTab.InProc() THEN
+ 1513                                               (* a forward-typed global:
+ 1514                                                  defer emission until the
+ 1515                                                  TYPE block completes *)
+ 1516                                               AST.SetOp(astNode, 1);
+ 1517                                               WHILE i < SymTab.PendCount() DO
+ 1518                                                 SymTab.PendName(i, nm);
+ 1519                                                 IF nPendVar <=
+ 1520                                                    HIGH(pendVarName) THEN
+ 1521                                                   pendVarName[nPendVar] := nm;
+ 1522                                                   pendVarT[nPendVar] := t;
+ 1523                                                   INC(nPendVar)
+ 1524                                                 END;
+ 1525                                                 INC(i)
+ 1526                                               END
+ 1527                                             ELSE
+ 1528                                               WHILE i < SymTab.PendCount() DO
+ 1529                                                 SymTab.PendName(i, nm);
+ 1530                                                 INC(i)
+ 1531                                               END
+ 1532                                             END;
+ 1533                                             (* a plain VAR list, not a
+ 1534                                                heading: the signature
+ 1535                                                result is discarded *)
+ 1536                                             IF NOT SymTab.FixPending(t) THEN
+ 1537                                             END; .) .
+ 1538    VarIdents                             (. VAR n: SymTab.Name; .)
+ 1539      = GetIdent<n>                       (. IF NOT SymTab.EnterPending(n,
+ 1540                                               SymTab.KindVar) THEN
+ 1541                                               SemError(200) END; .)
+ 1542        { ","
+ 1543          GetIdent<n>                     (. IF NOT SymTab.EnterPending(n,
+ 1544                                               SymTab.KindVar) THEN
+ 1545                                               SemError(200) END; .) } .
+ 1546    ParIdents<isV: BOOLEAN>               (. VAR n: SymTab.Name; .)
+ 1547      = GetIdent<n>                       (. IF NOT SymTab.EnterParam(n, isV) THEN
  1548                                               SemError(200) END; .)
  1548                                               SemError(200) END; .)
- 1549        { ","
- 1550          GetIdent<n>                     (. IF NOT SymTab.EnterPending(n,
- 1551                                               SymTab.KindVar) THEN
- 1552                                               SemError(200) END; .) } .
- 1553    ParIdents<isV: BOOLEAN>               (. VAR n: SymTab.Name; .)
- 1554      = GetIdent<n>                       (. IF NOT SymTab.EnterParam(n, isV) THEN
- 1555                                               SemError(200) END; .)
- 1556        { "," GetIdent<n>                 (. IF NOT SymTab.EnterParam(n, isV) THEN
- 1557                                               SemError(200) END; .) } .
- 1558    (* Procedure headings enter scopes/params/result and buffer the
- 1559       QBE header; bodies lower to functions (4.1, module level only).
- 1560       FORWARD marks; the body heading re-enters (signature compare
- 1561       deferred). Nested procedures parse + check, lowering = 4.2. *)
- 1562    ProcHeading<VAR pn: SymTab.Name; methCls: SymTab.TypeIndex>
- 1563                                          (. VAR t: SymTab.TypeIndex;
- 1564                                               mg: QbeGen.QVal; .)
- 1565      = "PROCEDURE"
- 1566        GetIdent<pn>                      (. IF methCls #
- 1567                                                SymTab.InvalidType THEN
- 1568                                             (* a method: resume the
- 1569                                                declared symbol (reuse
- 1570                                                its uid) *)
- 1571                                             IF NOT SymTab.ResumeMethod(
- 1572                                                  methCls, pn) THEN
- 1573                                               SemError(200) END
- 1574                                             ELSIF NOT SymTab.EnterProc(pn) THEN
- 1575                                             IF NOT SymTab.ReenterProc(pn) THEN
- 1576                                               IF NOT SymTab.ResumeProc(pn) THEN
- 1577                                                 SemError(200) END
- 1578                                               END
- 1579                                             END;
- 1580                                             Lower.ScopeEnter;
- 1581                                             Lower.NoteProc(pn,
- 1582                                               SymTab.ProcUid(pn),
- 1583                                               SymTab.InvalidType,
- 1584                                               SymTab.ProcDepthOf(pn),
- 1585                                               FALSE);
- 1586                                             QbeGen.BeginFunc("");
- 1587                                             IF methCls #
- 1588                                                SymTab.InvalidType THEN
- 1589                                               (* hidden THIS receiver:
- 1590                                                  a VAR param of the
- 1591                                                  class type, pushed as
- 1592                                                  the WITH base *)
- 1593                                               IF NOT SymTab.EnterThisParam(
- 1594                                                    methCls) THEN
- 1595                                                 SemError(200) END;
- 1596                                               IF NOT QbeGen.FuncParam(
- 1597                                                    "THIS", TRUE,
- 1598                                                    methCls) THEN
- 1599                                                 SemError(233) END
- 1600                                             END; .)
- 1601        [ FormalParams ]
- 1602        [ ":" TypeIdent<t>                (. IF NOT SymTab.SetProcRes(t) THEN
- 1603                                               SemError(235) END;
- 1604                                             Lower.SetProcRes(t); .) ] .
- 1605    FormalParams
- 1606      = "(" [ ParamSection { ";" ParamSection } ] ")" .
- 1607    ParamSection                          (. VAR t: SymTab.TypeIndex;
- 1608                                               nm: SymTab.Name;
- 1609                                               i: CARDINAL;
- 1610                                               isV: BOOLEAN; .)
- 1611      =                                   (. isV := FALSE; .)
- 1612        [ "VAR"                           (. isV := TRUE; .) ]
- 1613        ParIdents<isV> ":" Type<t, TRUE>  (. i := 0;
- 1614                                             WHILE i < SymTab.PendCount() DO
- 1615                                               SymTab.PendName(i, nm);
- 1616                                               Lower.NoteParam(nm, t, isV);
- 1617                                               Lower.NoteVar(nm, SymTab.KindParam, t);
- 1618                                               (* value open arrays are
- 1619                                                  passed as descriptor
- 1620                                                  addresses (no copy):
- 1621                                                  same representation as
- 1622                                                  VAR formals *)
- 1623                                               IF NOT QbeGen.FuncParam(nm,
- 1624                                                    isV
- 1625                                                    OR SymTab.IsOpenArray(t),
- 1626                                                    t) THEN
- 1627                                                 SemError(233) END;
- 1628                                               INC(i)
- 1629                                             END;
- 1630                                             IF NOT SymTab.FixPending(t) THEN
- 1631                                               SemError(235) END; .) .
- 1632    (* Nested procedures lower like top-level ones (4.2): the
- 1633       static link gives them their parent's frame. Methods keep
- 1634       parse-now/230-later. *)
- 1635    ProcDecl                              (. VAR pn: SymTab.Name;
- 1636                                               astNode: AST.Node; .)
- 1637      = ProcHeading<pn, SymTab.InvalidType> ";"
- 1638                                          (. astNode := AST.MakeNode(AST.NkProcDecl);
- 1639                                             AST.SetOp(astNode, 0);
- 1640                                             AST.SetChild(astNode, 0,
- 1641                                               AST.MakeLeaf(AST.NkIdent, pn));
- 1642                                             Lower.NoteProcNode(astNode); .)
- 1643        ( "FORWARD"                       (. AST.SetOp(astNode, 1);
- 1644                                             astDecl := astNode;
+ 1549        { "," GetIdent<n>                 (. IF NOT SymTab.EnterParam(n, isV) THEN
+ 1550                                               SemError(200) END; .) } .
+ 1551    (* Procedure headings enter scopes/params/result and buffer the
+ 1552       QBE header; bodies lower to functions (4.1, module level only).
+ 1553       FORWARD marks; the body heading re-enters (signature compare
+ 1554       deferred). Nested procedures parse + check, lowering = 4.2. *)
+ 1555    ProcHeading<VAR pn: SymTab.Name; methCls: SymTab.TypeIndex>
+ 1556                                          (. VAR t: SymTab.TypeIndex;
+ 1557                                               mg: QbeGen.QVal; .)
+ 1558      = "PROCEDURE"
+ 1559        GetIdent<pn>                      (. IF methCls #
+ 1560                                                SymTab.InvalidType THEN
+ 1561                                             (* a method: resume the
+ 1562                                                declared symbol (reuse
+ 1563                                                its uid) *)
+ 1564                                             IF NOT SymTab.ResumeMethod(
+ 1565                                                  methCls, pn) THEN
+ 1566                                               SemError(200) END
+ 1567                                             ELSIF NOT SymTab.EnterProc(pn) THEN
+ 1568                                             IF NOT SymTab.ReenterProc(pn) THEN
+ 1569                                               IF NOT SymTab.ResumeProc(pn) THEN
+ 1570                                                 SemError(200) END
+ 1571                                               END
+ 1572                                             END;
+ 1573                                             Lower.ScopeEnter;
+ 1574                                             Lower.NoteProc(pn,
+ 1575                                               SymTab.ProcUid(pn),
+ 1576                                               SymTab.InvalidType,
+ 1577                                               SymTab.ProcDepthOf(pn),
+ 1578                                               FALSE);
+ 1579                                             QbeGen.BeginFunc("");
+ 1580                                             IF methCls #
+ 1581                                                SymTab.InvalidType THEN
+ 1582                                               (* hidden THIS receiver:
+ 1583                                                  a VAR param of the
+ 1584                                                  class type, pushed as
+ 1585                                                  the WITH base *)
+ 1586                                               IF NOT SymTab.EnterThisParam(
+ 1587                                                    methCls) THEN
+ 1588                                                 SemError(200) END;
+ 1589                                               IF NOT QbeGen.FuncParam(
+ 1590                                                    "THIS", TRUE,
+ 1591                                                    methCls) THEN
+ 1592                                                 SemError(233) END
+ 1593                                             END; .)
+ 1594        [ FormalParams ]
+ 1595        [ ":" TypeIdent<t>                (. IF NOT SymTab.SetProcRes(t) THEN
+ 1596                                               SemError(235) END;
+ 1597                                             Lower.SetProcRes(t); .) ] .
+ 1598    FormalParams
+ 1599      = "(" [ ParamSection { ";" ParamSection } ] ")" .
+ 1600    ParamSection                          (. VAR t: SymTab.TypeIndex;
+ 1601                                               nm: SymTab.Name;
+ 1602                                               i: CARDINAL;
+ 1603                                               isV: BOOLEAN; .)
+ 1604      =                                   (. isV := FALSE; .)
+ 1605        [ "VAR"                           (. isV := TRUE; .) ]
+ 1606        ParIdents<isV> ":" Type<t, TRUE>  (. i := 0;
+ 1607                                             WHILE i < SymTab.PendCount() DO
+ 1608                                               SymTab.PendName(i, nm);
+ 1609                                               Lower.NoteParam(nm, t, isV);
+ 1610                                               Lower.NoteVar(nm, SymTab.KindParam, t);
+ 1611                                               (* value open arrays are
+ 1612                                                  passed as descriptor
+ 1613                                                  addresses (no copy):
+ 1614                                                  same representation as
+ 1615                                                  VAR formals *)
+ 1616                                               IF NOT QbeGen.FuncParam(nm,
+ 1617                                                    isV
+ 1618                                                    OR SymTab.IsOpenArray(t),
+ 1619                                                    t) THEN
+ 1620                                                 SemError(233) END;
+ 1621                                               INC(i)
+ 1622                                             END;
+ 1623                                             IF NOT SymTab.FixPending(t) THEN
+ 1624                                               SemError(235) END; .) .
+ 1625    (* Nested procedures lower like top-level ones (4.2): the
+ 1626       static link gives them their parent's frame. Methods keep
+ 1627       parse-now/230-later. *)
+ 1628    ProcDecl                              (. VAR pn: SymTab.Name;
+ 1629                                               astNode: AST.Node; .)
+ 1630      = ProcHeading<pn, SymTab.InvalidType> ";"
+ 1631                                          (. astNode := AST.MakeNode(AST.NkProcDecl);
+ 1632                                             AST.SetOp(astNode, 0);
+ 1633                                             AST.SetChild(astNode, 0,
+ 1634                                               AST.MakeLeaf(AST.NkIdent, pn));
+ 1635                                             Lower.NoteProcNode(astNode); .)
+ 1636        ( "FORWARD"                       (. AST.SetOp(astNode, 1);
+ 1637                                             astDecl := astNode;
+ 1638                                             Lower.ScopeLeave;
+ 1639                                             SymTab.MarkFwd;
+ 1640                                             SymTab.CloseProc;
+ 1641                                             QbeGen.AbortFunc; .)
+ 1642        | "EXTERNAL"                      (. AST.SetOp(astNode, 2);
+ 1643                                             astDecl := astNode;
+ 1644                                             Lower.MarkProcExternal;
  1645                                             Lower.ScopeLeave;
  1645                                             Lower.ScopeLeave;
- 1646                                             SymTab.MarkFwd;
+ 1646                                             SymTab.MarkExternal("");
  1647                                             SymTab.CloseProc;
  1647                                             SymTab.CloseProc;
  1648                                             QbeGen.AbortFunc; .)
  1648                                             QbeGen.AbortFunc; .)
- 1649        | "EXTERNAL"                      (. AST.SetOp(astNode, 2);
- 1650                                             astDecl := astNode;
- 1651                                             Lower.MarkProcExternal;
- 1652                                             Lower.ScopeLeave;
- 1653                                             SymTab.MarkExternal("");
- 1654                                             SymTab.CloseProc;
- 1655                                             QbeGen.AbortFunc; .)
- 1656        |                                 
- 1657          (. allowDefer := TRUE; deferredBody := FALSE;
- 1658                                             curProcNode := astNode; .)
- 1659          Block<pn>                       (. IF deferredBody THEN
- 1660                                               (* body skipped: close like
- 1661                                                  FORWARD (no body node) *)
+ 1649        |                                 
+ 1650          (. allowDefer := TRUE; deferredBody := FALSE;
+ 1651                                             curProcNode := astNode; .)
+ 1652          Block<pn>                       (. IF deferredBody THEN
+ 1653                                               (* body skipped: close like
+ 1654                                                  FORWARD (no body node) *)
+ 1655                                               astDecl := astNode;
+ 1656                                               Lower.ScopeLeave;
+ 1657                                               SymTab.CloseProc;
+ 1658                                               QbeGen.AbortFunc
+ 1659                                             ELSE
+ 1660                                               AST.SetChild(astNode, 1, astStmt);
+ 1661                                               AST.SetChild(astNode, 2, astBlkDecls);
  1662                                               astDecl := astNode;
  1662                                               astDecl := astNode;
  1663                                               Lower.ScopeLeave;
  1663                                               Lower.ScopeLeave;
  1664                                               SymTab.CloseProc;
  1664                                               SymTab.CloseProc;
- 1665                                               QbeGen.AbortFunc
- 1666                                             ELSE
- 1667                                               AST.SetChild(astNode, 1, astStmt);
- 1668                                               AST.SetChild(astNode, 2, astBlkDecls);
- 1669                                               astDecl := astNode;
- 1670                                               Lower.ScopeLeave;
- 1671                                               SymTab.CloseProc;
- 1672                                               QbeGen.EndFunc(
- 1673                                                 SymTab.ProcRes(pn))
- 1674                                             END; .) ) .
- 1675    Block<pn: SymTab.Name>                (. VAR m2: SymTab.Name; dfr: BOOLEAN; .)
- 1676      =                                   (. dfr := FALSE;
- 1677                                             IF allowDefer AND twoPhaseParse
- 1678                                                AND NOT repassing THEN
- 1679                                               dfr := DeferSkip(pn)
- 1680                                             END;
- 1681                                             allowDefer := FALSE;
- 1682                                             IF NOT dfr THEN INC(procNest) END; .)
- 1683        DeclSeq                           (. astBlkDecls := astDecl;
- 1684                                             astStmt := AST.NoNode;
- 1685                                             nLab := 0; nGot := 0; .)
- 1686        [ "BEGIN"                         (. (* an empty body is still a
- 1687                                               body: mark it so Lower
- 1688                                               does not read it as a
- 1689                                               definition heading *)
- 1690                                             IF NOT dfr THEN
- 1691                                               IF astStmt = AST.NoNode THEN
- 1692                                                 astStmt :=
- 1693                                                   AST.MakeNode(AST.NkBlock)
- 1694                                               END
- 1695                                             END; .)
- 1696          [ StatSeq ] ]
- 1697        "END"
- 1698        GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
- 1699                                               SemError(202) END;
- 1700                                             IF NOT dfr THEN DEC(procNest) END;
- 1701                                             CheckGotos; .) .
- 1702    (* Two-phase, phase 2 (milestone 2c): re-parse every deferred module-
- 1703       level body once the unit's declarations are complete.  Inlined at
- 1704       both call sites because a stand-alone epsilon production is
- 1705       "unreachable" to Coco/R (referenced only from actions). *)
- 1706    StatSeq                               (. VAR astSeq, astTail: AST.Node; .)
- 1707      =                                   (. astSeq := AST.NoNode;
- 1708                                             astTail := AST.NoNode; .)
- 1709        Statement                         (. AstAppend(AST.NkBlock,
- 1710                                               astSeq, astTail, astStmt); .)
- 1711        { ";" [ Statement                 (. AstAppend(AST.NkBlock,
- 1712                                               astSeq, astTail, astStmt); .) ] }
- 1713                                          (. astStmt := astSeq; .) .
- 1714    (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
- 1715       are accepted: the statement after ';' is optional. *)
- 1716    Statement                             (. VAR lx: QbeGen.QVal; lxnm: SymTab.Name; .)
- 1717      = (. astStmt := AST.NoNode; .)
- 1718        ( AssOrCall
- 1719      | IfStat
- 1720      | WhileStat
- 1721      | RepeatStat
- 1722      | LoopStat
- 1723      | ForStat
- 1724      | CaseStat
- 1725      | WithStat
- 1726      | ReturnStat
- 1727      | HaltStat
- 1728      | NewStat
- 1729      | DisposeStat
- 1730      | IncDecStat
- 1731      | InclExclStat
- 1732      | "EXIT"                            (. IF NOT QbeGen.TopLoop(lx) THEN
- 1733                                               SemError(230) END;
- 1734                                             astStmt := AST.MakeNode(AST.NkExit); .)
- 1735      | "GOTO" GetIdent<lxnm>             (. NoteGoto(lxnm);
- 1736                                             astStmt := AST.MakeNode(AST.NkGoto);
- 1737                                             AST.SetChild(astStmt, 0,
- 1738                                               AST.MakeLeaf(AST.NkIdent, lxnm)); .) ) .
- 1739    (* INCL(set, elem) / EXCL(set, elem): PIM set-element builtins. *)
- 1740    InclExclStat                          (. VAR at, et2: SymTab.TypeIndex;
- 1741                                               dk: INTEGER;
- 1742                                               qd, qe: QbeGen.QVal;
- 1743                                               qn: SymTab.Name;
- 1744                                               sfx, isInc: BOOLEAN;
- 1745                                               astNode, astD: AST.Node; .)
- 1746      = ( "INCL"                          (. isInc := TRUE; .)
- 1747        | "EXCL"                          (. isInc := FALSE; .) )
- 1748        "(" Design<at, dk, qd, qn, sfx> (. astD := astCur; .) ","
- 1749        Expr<et2, qe> ")"
- 1750                                          (. astNode := AST.MakeNode(AST.NkCall);
- 1751                                             IF isInc THEN
- 1752                                               AST.SetChild(astNode, 0,
- 1753                                                 AST.MakeLeaf(AST.NkIdent, "INCL"))
- 1754                                             ELSE AST.SetChild(astNode, 0,
- 1755                                                 AST.MakeLeaf(AST.NkIdent, "EXCL"))
- 1756                                             END;
- 1757                                             IF astD # AST.NoNode THEN
- 1758                                               AST.SetChild(astNode, 1, astD) END;
- 1759                                             IF astCur # AST.NoNode THEN
- 1760                                               AST.SetChild(astNode, 2, astCur) END;
- 1761                                             astStmt := astNode; .)
- 1762                                          (. IF (at # SymTab.InvalidType)
- 1763    AND (SymTab.ClassOf(at) # SymTab.ClSet) THEN
- 1764                                               SemError(222)
- 1765                                             END; .) .
- 1766    (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an
- 1767       integer designator. *)
- 1768    IncDecStat                            (. VAR dt, et2: SymTab.TypeIndex;
- 1769                                               dk: INTEGER;
- 1770                                               qd, qv, qn2, qstep:
- 1771                                                 QbeGen.QVal;
- 1772                                               qn: SymTab.Name;
- 1773                                               sfx, isInc: BOOLEAN;
- 1774                                               astNode, astD, astStep:
- 1775                                                 AST.Node; .)
- 1776      =                                   (. isInc := TRUE; .)
- 1777        ( "INC"                           (. isInc := TRUE; .)
- 1778        | "DEC"                           (. isInc := FALSE; .) )
- 1779        "("                               (. astStep := AST.NoNode; .)
- 1780        Design<dt, dk, qd, qn, sfx> (. astD := astCur; .)
- 1781        [ "," Expr<et2, qstep> (. astStep := astCur; .) ]
- 1782        ")"                               (. astNode := AST.MakeNode(AST.NkCall);
- 1783                                             IF isInc THEN
- 1784                                               AST.SetChild(astNode, 0,
- 1785                                                 AST.MakeLeaf(AST.NkIdent, "INC"))
- 1786                                             ELSE AST.SetChild(astNode, 0,
- 1787                                                 AST.MakeLeaf(AST.NkIdent, "DEC"))
- 1788                                             END;
- 1789                                             IF astD # AST.NoNode THEN
- 1790                                               AST.SetChild(astNode, 1, astD) END;
- 1791                                             IF astStep # AST.NoNode THEN
- 1792                                               AST.SetChild(astNode, 2, astStep) END;
- 1793                                             astStmt := astNode; .)                               (. IF dt = SymTab.InvalidType THEN
- 1794                                             ELSIF (dk # SymTab.KindVar)
- 1795   AND (dk # SymTab.KindParam)
- 1796   AND (dk # SymTab.KindField) THEN
- 1797                                               SemError(210)
- 1798                                             ELSIF NOT SymTab.IsIntFamily(dt) THEN
- 1799                                               SemError(211)
- 1800                                             END; .) .
- 1801    (* NEW/DISPOSE as builtin statements (no call syntax until step 4).
- 1802       Targets are pointer designators; DISPOSE nils afterwards (safer
- 1803       than Wirth-undefined; documented). DISPOSE is shallow. *)
- 1804    NewStat                               (. VAR dt: SymTab.TypeIndex;
- 1805                                               dk: INTEGER;
- 1806                                               qd, qm: QbeGen.QVal;
- 1807                                               qn: SymTab.Name;
- 1808                                               sfx: BOOLEAN;
- 1809                                               bt: SymTab.TypeIndex;
- 1810                                               astNode, astD: AST.Node; .)
- 1811      = "NEW" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
- 1812                                          (. astNode := AST.MakeNode(AST.NkCall);
- 1813                                             AST.SetChild(astNode, 0,
- 1814                                               AST.MakeLeaf(AST.NkIdent, "NEW"));
- 1815                                             IF astD # AST.NoNode THEN
- 1816                                               AST.SetChild(astNode, 1, astD) END;
- 1817                                             astStmt := astNode; .)
- 1818                                           (. IF dt = SymTab.InvalidType THEN
- 1819                                              ELSIF (dk # SymTab.KindVar)
- 1820    AND (dk # SymTab.KindParam)
- 1821    AND (dk # SymTab.KindField) THEN
- 1822                                                SemError(210)
- 1823                                              ELSIF SymTab.ClassOf(dt) #
- 1824                                                    SymTab.ClPtr THEN
- 1825                                                SemError(219)
- 1826                                              END; .) .
- 1827    DisposeStat                           (. VAR dt: SymTab.TypeIndex;
- 1828                                               dk: INTEGER;
- 1829                                               qd, qv: QbeGen.QVal;
- 1830                                               qn: SymTab.Name;
- 1831                                               sfx: BOOLEAN;
- 1832                                               astNode, astD: AST.Node; .)
- 1833      = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
- 1834                                          (. astNode := AST.MakeNode(AST.NkCall);
- 1835                                             AST.SetChild(astNode, 0,
- 1836                                               AST.MakeLeaf(AST.NkIdent, "DISPOSE"));
- 1837                                             IF astD # AST.NoNode THEN
- 1838                                               AST.SetChild(astNode, 1, astD) END;
- 1839                                             astStmt := astNode; .)
- 1840                                           (. IF dt = SymTab.InvalidType THEN
- 1841                                              ELSIF (dk # SymTab.KindVar)
- 1842    AND (dk # SymTab.KindParam)
- 1843    AND (dk # SymTab.KindField) THEN
- 1844                                                SemError(210)
- 1845                                              ELSIF SymTab.ClassOf(dt) #
- 1846                                                    SymTab.ClPtr THEN
- 1847                                                SemError(219)
- 1848                                              END; .) .
- 1849    (* WITH pushes each record's fields (inner wins) plus its base
- 1850       address; field designators resolve through both stacks. *)
- 1851    WithStat                              (. VAR nW: CARDINAL;
- 1852                                               astNode: AST.Node; .)
- 1853      = "WITH"                            (. nW := 0;
- 1854                                             astNode := AST.MakeNode(AST.NkWith); .)
- 1855        WithItem<nW, astNode> { "," WithItem<nW, astNode> }
- 1856        "DO"                              (. astStmt := AST.NoNode; .)
- 1857        [ StatSeq ] "END"                 (. AST.SetChild(astNode,
- 1858                                             AST.NChild(astNode), astStmt);
- 1859                                             astStmt := astNode;
- 1860                                             WHILE nW > 0 DO
- 1861                                               SymTab.PopScope;
- 1862                                               QbeGen.PopWith;
- 1863                                               DEC(nW)
- 1864                                             END; .) .
- 1865    WithItem<VAR nW: CARDINAL; wnode: AST.Node>
- 1866                                          (. VAR dt: SymTab.TypeIndex;
- 1867                                               dk: INTEGER;
- 1868                                               qd, qe: QbeGen.QVal;
- 1869                                               qn: SymTab.Name;
- 1870                                               sfx: BOOLEAN; .)
- 1871      = Design<dt, dk, qd, qn, sfx>
- 1872                                          (. IF astCur # AST.NoNode THEN
- 1873                                               AST.SetChild(wnode,
- 1874                                                 AST.NChild(wnode), astCur) END;
- 1875                                             IF dt = SymTab.InvalidType THEN
- 1876                                             ELSIF (SymTab.ClassOf(dt) #
- 1877                                                    SymTab.ClRecord)
- 1878   AND (SymTab.ClassOf(dt) #
- 1879                                                   SymTab.ClClass) THEN
- 1880                                               SemError(215)
- 1881                                             ELSIF SymTab.PushRecord(dt) THEN
- 1882                                               QbeGen.PushWith(qd);
- 1883                                               INC(nW)
- 1884                                             END; .) .
- 1885    (* Assignment or procedure-statement call (4.1, module level).
- 1886       Bare `P;` is a syntax error; function-as-statement is 233. *)
- 1887    AssOrCall                             (. VAR dt, et: SymTab.TypeIndex;
- 1888                                               dk: INTEGER;
- 1889                                               qd, qe, qt, ql: QbeGen.QVal;
- 1890                                               qn: SymTab.Name;
- 1891                                               ct2, res0: SymTab.TypeIndex;
- 1892                                               q2, mg0: QbeGen.QVal;
- 1893                                               isR, conv, wconv: BOOLEAN;
- 1894                                               called, sfx: BOOLEAN;
- 1895                                               astLhs, astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN;
- 1896                                               n: SymTab.Name; astLab, astNode: AST.Node; .)
- 1897      = GetIdent<n>
- 1898        ( ":"                             (. NoteLabel(n);
- 1899                                             astNode := AST.MakeNode(AST.NkLabel);
- 1900                                             AST.SetChild(astNode, 0,
- 1901                                               AST.MakeLeaf(AST.NkIdent, n));
- 1902                                             astLab := AST.MakeNode(AST.NkBlock);
- 1903                                             AST.SetChild(astLab, 0, astNode); .)
- 1904          Statement                       (. IF astStmt # AST.NoNode THEN
- 1905                                               AST.SetChild(astLab, 1, astStmt) END;
- 1906                                             astStmt := astLab; .)
- 1907        | DesignTail<n, dt, dk, qd, qn, sfx>
- 1908        (. astLhs := astCur; astNArgs := 0; .)
- 1909        ( ":="
- 1910          Expr<et, qe>                    (. astStmt := AST.MakeBin(
- 1911                                               AST.NkAssign, 0, astLhs, astCur);
- 1912                                             IF (dt # SymTab.InvalidType)
- 1913   AND (dk # SymTab.KindVar)
- 1914   AND (dk # SymTab.KindParam)
- 1915   AND (dk # SymTab.KindField) THEN
- 1916                                             SemError(210)
- 1917                                           ELSIF NOT SymTab.Assignable(et,
- 1918                                                    dt) THEN
- 1919                                             SemError(210)
- 1920                                           ELSIF (dt # SymTab.InvalidType)
- 1921   AND (SymTab.ClassOf(dt) =
- 1922                                                 SymTab.ClClass) THEN
- 1923                                             SemError(230) END;
- 1924                                           isR := (dt #
- 1925                                                   SymTab.InvalidType)
- 1926   AND (SymTab.ClassOf(dt)
- 1927                                                     = SymTab.ClReal);
- 1928                                           conv := isR
- 1929   AND SymTab.IsIntFamily(et);
- 1930                                           wconv := (dt #
- 1931                                                     SymTab.InvalidType)
- 1932   AND SymTab.IsLongFamily(dt)
- 1933   AND SymTab.IsIntFamily(et);
- 1934                                           IF ((dk = SymTab.KindVar)
- 1935                                               OR (dk = SymTab.KindParam)
- 1936                                               OR (dk = SymTab.KindField))
- 1937   AND (dt # SymTab.InvalidType)
- 1938   AND (et # SymTab.InvalidType)
- 1939   AND (SymTab.ClassOf(dt) #
- 1940                                                 SymTab.ClClass) THEN
- 1941                                           END; .)
- 1942        | ArgList<qn, dt, qd, TRUE, TRUE, methCls, ct2, q2, called>
- 1943                                          (. astRes := AstCallNode(astLhs);
- 1944                                             sfx := FALSE; .)
- 1945          ( { ResultComp<ct2, q2, sfx, astRes, mname, methCls, isM> }
- 1946            ":=" Expr<et, qe>             (. astStmt := AST.MakeBin(
- 1947                                               AST.NkAssign, 0, astRes, astCur);
- 1948                                             IF NOT sfx THEN
- 1949                                               SemError(233)
- 1950                                             ELSIF (ct2 # SymTab.InvalidType)
- 1951    AND NOT SymTab.Assignable(et, ct2) THEN
- 1952                                               SemError(210)
- 1953                                             END; .)
- 1954          |                               (. IF ct2 #
- 1955                                               SymTab.InvalidType THEN
- 1956                                               SemError(233) END;
- 1957                                             astStmt := astRes; .) )
- 1958        |                                 (* bare `P;`: proper parameterless
- 1959                                              procedure call; anything else
- 1960                                              here is 233 (was a bare syntax
- 1961                                              error before 4.2) *)
- 1962                                          (. astStmt := AstCallNode(astLhs);
- 1963                                              IF (dk = SymTab.KindProc)
- 1964   AND NOT sfx THEN
- 1965                                               res0 := SymTab.ProcRes(qn);
- 1966                                               IF res0 #
- 1967                                                  SymTab.InvalidType THEN
- 1968                                                 SemError(233)
- 1969                                               ELSIF SymTab.ProcNPar(qn) #
- 1970                                                       0 THEN
- 1971                                                 SemError(233)
- 1972                                               END
- 1973                                             ELSE SemError(233)
- 1974                                              END; .) ) ) .
- 1975    (* Actual-parameter list shared by statement and expression calls.
- 1976       want selects CallEnd's result handling; t/q carry the call
- 1977       value (statement calls discard). Arity/type failures are 233;
- 1978       evaluation code still emits so the .ssa stays assembleable. *)
- 1979    ArgList<pn: SymTab.Name; pt: SymTab.TypeIndex; callee: QbeGen.QVal;
- 1980            want: BOOLEAN; soft: BOOLEAN; methCls: SymTab.TypeIndex;
- 1981            VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
- 1982            VAR called: BOOLEAN>          (. VAR i, np: CARDINAL;
- 1983                                               vs: INTEGER;
- 1984                                               res: SymTab.TypeIndex;
- 1985                                               mg: QbeGen.QVal;
- 1986                                               ok, ind, isMeth, va: BOOLEAN; .)
- 1987      = "("                               (. called := TRUE;
- 1988                                             ok := TRUE;
- 1989                                             ind := FALSE;
- 1990                                             isMeth := methCls #
- 1991                                               SymTab.InvalidType;
- 1992                                             IF isMeth THEN
- 1993                                               res := SymTab.ClassMethodRes(methCls, pn)
- 1994                                             ELSIF SymTab.SymKind(pn) = SymTab.KindProc THEN
- 1995                                               res := SymTab.ProcRes(pn)
- 1996                                             ELSIF (pt # SymTab.InvalidType)
- 1997    AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN
- 1998                                               ind := TRUE;
- 1999                                               res := SymTab.ProcTypeRes(pt)
- 2000                                             ELSE SemError(233);
- 2001                                               ok := FALSE;
- 2002                                               res := SymTab.InvalidType
- 2003                                             END;
- 2004                                             i := 0; .)
- 2005        [ ActParam<pn, pt, ind, methCls, i>        (. INC(i); .)
- 2006          { "," ActParam<pn, pt, ind, methCls, i>  (. INC(i); .) } ]
- 2007        ")"                               (. IF ok THEN
- 2008                                               IF isMeth THEN
- 2009                                                 np := SymTab.ClassMethodNPar(
- 2010                                                   methCls, pn)
- 2011                                               ELSIF ind THEN
- 2012                                                 np := SymTab.ProcTypeNPar(pt)
- 2013                                               ELSE np := SymTab.ProcNPar(pn)
- 2014                                               END;
- 2015                                               va := (NOT isMeth) AND (NOT ind)
- 2016                                                 AND (SymTab.SymKind(pn) =
- 2017                                                      SymTab.KindProc)
- 2018                                                 AND SymTab.Varargs(pn);
- 2019                                               IF (i # np) AND NOT va THEN
- 2020                                                 SemError(233); ok := FALSE
- 2021                                               END
- 2022                                             END;
- 2023                                             IF NOT ok THEN
- 2024                                               t := SymTab.InvalidType;
- 2025                                               QbeGen.CopyOp("0", q)
- 2026                                             ELSIF want THEN
- 2027                                               IF res =
- 2028                                                  SymTab.InvalidType THEN
- 2029                                                 IF NOT soft THEN SemError(233) END;
- 2030                                                 t := SymTab.InvalidType;
- 2031                                                 QbeGen.CopyOp("0", q)
- 2032                                               ELSE t := res;
- 2033                                                  QbeGen.CopyOp("@", q)
- 2034                                               END
- 2035                                             ELSE
- 2036                                               IF res #
- 2037                                                  SymTab.InvalidType THEN
- 2038                                                 SemError(233)
- 2039                                               END;
- 2040                                               t := SymTab.InvalidType;
- 2041                                               QbeGen.CopyOp("0", q);
- 2042                                             END; .) .
- 2043    (* One actual: VAR formals take recorded designator addresses
- 2044       (233 otherwise); value formals take converted expressions. *)
- 2045    ActParam<pn: SymTab.Name; pt: SymTab.TypeIndex; ind: BOOLEAN;
- 2046             methCls: SymTab.TypeIndex; i: CARDINAL>
- 2047                                          (. VAR at, ft: SymTab.TypeIndex;
- 2048                                               qe, qa, qt: QbeGen.QVal;
- 2049                                               isV, conv, va: BOOLEAN;
- 2050                                               cl: CHAR;
- 2051                                               savedN, aj: CARDINAL;
- 2052                                               savedArgs: ARRAY [0 .. 31]
- 2053                                                 OF AST.Node;
- 2054                                               astActual: AST.Node; .)
- 2055      =                                   (. (* Parsing the actual can clobber
- 2056                                               the enclosing call's argument
- 2057                                               list (Factor resets astNArgs),
- 2058                                               so save/restore it. *)
- 2059                                             savedN := astNArgs; aj := 0;
- 2060                                             WHILE aj <= HIGH(astArgs) DO
- 2061                                               savedArgs[aj] := astArgs[aj];
- 2062                                               INC(aj)
- 2063                                             END; .)
- 2064        Expr<at, qe>                      (. astActual := astCur;
- 2065                                             astNArgs := savedN; aj := 0;
- 2066                                             WHILE aj <= HIGH(astArgs) DO
- 2067                                               astArgs[aj] := savedArgs[aj];
- 2068                                               INC(aj)
- 2069                                             END;
- 2070                                             IF astNArgs <= HIGH(astArgs) THEN
- 2071                                               astArgs[astNArgs] := astCur;
- 2072                                               INC(astNArgs)
- 2073                                             END;
- 2074                                             va := (NOT ind)
- 2075                                               AND (methCls =
- 2076                                                  SymTab.InvalidType)
- 2077                                               AND (SymTab.SymKind(pn) =
- 2078                                                  SymTab.KindProc)
- 2079                                               AND SymTab.Varargs(pn);
- 2080                                             IF ind THEN
+ 1665                                               QbeGen.EndFunc(
+ 1666                                                 SymTab.ProcRes(pn))
+ 1667                                             END; .) ) .
+ 1668    Block<pn: SymTab.Name>                (. VAR m2: SymTab.Name; dfr: BOOLEAN; .)
+ 1669      =                                   (. dfr := FALSE;
+ 1670                                             IF allowDefer AND twoPhaseParse
+ 1671                                                AND NOT repassing THEN
+ 1672                                               dfr := DeferSkip(pn)
+ 1673                                             END;
+ 1674                                             allowDefer := FALSE;
+ 1675                                             .)
+ 1676        DeclSeq                           (. astBlkDecls := astDecl;
+ 1677                                             astStmt := AST.NoNode;
+ 1678                                             nLab := 0; nGot := 0; .)
+ 1679        [ "BEGIN"                         (. (* an empty body is still a
+ 1680                                               body: mark it so Lower
+ 1681                                               does not read it as a
+ 1682                                               definition heading *)
+ 1683                                             IF NOT dfr THEN
+ 1684                                               IF astStmt = AST.NoNode THEN
+ 1685                                                 astStmt :=
+ 1686                                                   AST.MakeNode(AST.NkBlock)
+ 1687                                               END
+ 1688                                             END; .)
+ 1689          [ StatSeq ] ]
+ 1690        "END"
+ 1691        GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
+ 1692                                               SemError(202) END;
+ 1693                                             CheckGotos; .) .
+ 1694    (* Two-phase, phase 2 (milestone 2c): re-parse every deferred module-
+ 1695       level body once the unit's declarations are complete.  Inlined at
+ 1696       both call sites because a stand-alone epsilon production is
+ 1697       "unreachable" to Coco/R (referenced only from actions). *)
+ 1698    StatSeq                               (. VAR astSeq, astTail: AST.Node; .)
+ 1699      =                                   (. astSeq := AST.NoNode;
+ 1700                                             astTail := AST.NoNode; .)
+ 1701        Statement                         (. AstAppend(AST.NkBlock,
+ 1702                                               astSeq, astTail, astStmt); .)
+ 1703        { ";" [ Statement                 (. AstAppend(AST.NkBlock,
+ 1704                                               astSeq, astTail, astStmt); .) ] }
+ 1705                                          (. astStmt := astSeq; .) .
+ 1706    (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
+ 1707       are accepted: the statement after ';' is optional. *)
+ 1708    Statement                             (. VAR lx: QbeGen.QVal; lxnm: SymTab.Name; .)
+ 1709      = (. astStmt := AST.NoNode; .)
+ 1710        ( AssOrCall
+ 1711      | IfStat
+ 1712      | WhileStat
+ 1713      | RepeatStat
+ 1714      | LoopStat
+ 1715      | ForStat
+ 1716      | CaseStat
+ 1717      | WithStat
+ 1718      | ReturnStat
+ 1719      | HaltStat
+ 1720      | NewStat
+ 1721      | DisposeStat
+ 1722      | IncDecStat
+ 1723      | InclExclStat
+ 1724      | "EXIT"                            (. IF NOT QbeGen.TopLoop(lx) THEN
+ 1725                                               SemError(230) END;
+ 1726                                             astStmt := AST.MakeNode(AST.NkExit); .)
+ 1727      | "GOTO" GetIdent<lxnm>             (. NoteGoto(lxnm);
+ 1728                                             astStmt := AST.MakeNode(AST.NkGoto);
+ 1729                                             AST.SetChild(astStmt, 0,
+ 1730                                               AST.MakeLeaf(AST.NkIdent, lxnm)); .) ) .
+ 1731    (* INCL(set, elem) / EXCL(set, elem): PIM set-element builtins. *)
+ 1732    InclExclStat                          (. VAR at, et2: SymTab.TypeIndex;
+ 1733                                               dk: INTEGER;
+ 1734                                               qd, qe: QbeGen.QVal;
+ 1735                                               qn: SymTab.Name;
+ 1736                                               sfx, isInc: BOOLEAN;
+ 1737                                               astNode, astD: AST.Node; .)
+ 1738      = ( "INCL"                          (. isInc := TRUE; .)
+ 1739        | "EXCL"                          (. isInc := FALSE; .) )
+ 1740        "(" Design<at, dk, qd, qn, sfx> (. astD := astCur; .) ","
+ 1741        Expr<et2, qe> ")"
+ 1742                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 1743                                             IF isInc THEN
+ 1744                                               AST.SetChild(astNode, 0,
+ 1745                                                 AST.MakeLeaf(AST.NkIdent, "INCL"))
+ 1746                                             ELSE AST.SetChild(astNode, 0,
+ 1747                                                 AST.MakeLeaf(AST.NkIdent, "EXCL"))
+ 1748                                             END;
+ 1749                                             IF astD # AST.NoNode THEN
+ 1750                                               AST.SetChild(astNode, 1, astD) END;
+ 1751                                             IF astCur # AST.NoNode THEN
+ 1752                                               AST.SetChild(astNode, 2, astCur) END;
+ 1753                                             astStmt := astNode; .)
+ 1754                                          (. IF (at # SymTab.InvalidType)
+ 1755    AND (SymTab.ClassOf(at) # SymTab.ClSet) THEN
+ 1756                                               SemError(222)
+ 1757                                             END; .) .
+ 1758    (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an
+ 1759       integer designator. *)
+ 1760    IncDecStat                            (. VAR dt, et2: SymTab.TypeIndex;
+ 1761                                               dk: INTEGER;
+ 1762                                               qd, qv, qn2, qstep:
+ 1763                                                 QbeGen.QVal;
+ 1764                                               qn: SymTab.Name;
+ 1765                                               sfx, isInc: BOOLEAN;
+ 1766                                               astNode, astD, astStep:
+ 1767                                                 AST.Node; .)
+ 1768      =                                   (. isInc := TRUE; .)
+ 1769        ( "INC"                           (. isInc := TRUE; .)
+ 1770        | "DEC"                           (. isInc := FALSE; .) )
+ 1771        "("                               (. astStep := AST.NoNode; .)
+ 1772        Design<dt, dk, qd, qn, sfx> (. astD := astCur; .)
+ 1773        [ "," Expr<et2, qstep> (. astStep := astCur; .) ]
+ 1774        ")"                               (. astNode := AST.MakeNode(AST.NkCall);
+ 1775                                             IF isInc THEN
+ 1776                                               AST.SetChild(astNode, 0,
+ 1777                                                 AST.MakeLeaf(AST.NkIdent, "INC"))
+ 1778                                             ELSE AST.SetChild(astNode, 0,
+ 1779                                                 AST.MakeLeaf(AST.NkIdent, "DEC"))
+ 1780                                             END;
+ 1781                                             IF astD # AST.NoNode THEN
+ 1782                                               AST.SetChild(astNode, 1, astD) END;
+ 1783                                             IF astStep # AST.NoNode THEN
+ 1784                                               AST.SetChild(astNode, 2, astStep) END;
+ 1785                                             astStmt := astNode; .)                               (. IF dt = SymTab.InvalidType THEN
+ 1786                                             ELSIF (dk # SymTab.KindVar)
+ 1787   AND (dk # SymTab.KindParam)
+ 1788   AND (dk # SymTab.KindField) THEN
+ 1789                                               SemError(210)
+ 1790                                             ELSIF NOT SymTab.IsIntFamily(dt) THEN
+ 1791                                               SemError(211)
+ 1792                                             END; .) .
+ 1793    (* NEW/DISPOSE as builtin statements (no call syntax until step 4).
+ 1794       Targets are pointer designators; DISPOSE nils afterwards (safer
+ 1795       than Wirth-undefined; documented). DISPOSE is shallow. *)
+ 1796    NewStat                               (. VAR dt: SymTab.TypeIndex;
+ 1797                                               dk: INTEGER;
+ 1798                                               qd, qm: QbeGen.QVal;
+ 1799                                               qn: SymTab.Name;
+ 1800                                               sfx: BOOLEAN;
+ 1801                                               bt: SymTab.TypeIndex;
+ 1802                                               astNode, astD: AST.Node; .)
+ 1803      = "NEW" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
+ 1804                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 1805                                             AST.SetChild(astNode, 0,
+ 1806                                               AST.MakeLeaf(AST.NkIdent, "NEW"));
+ 1807                                             IF astD # AST.NoNode THEN
+ 1808                                               AST.SetChild(astNode, 1, astD) END;
+ 1809                                             astStmt := astNode; .)
+ 1810                                           (. IF dt = SymTab.InvalidType THEN
+ 1811                                              ELSIF (dk # SymTab.KindVar)
+ 1812    AND (dk # SymTab.KindParam)
+ 1813    AND (dk # SymTab.KindField) THEN
+ 1814                                                SemError(210)
+ 1815                                              ELSIF SymTab.ClassOf(dt) #
+ 1816                                                    SymTab.ClPtr THEN
+ 1817                                                SemError(219)
+ 1818                                              END; .) .
+ 1819    DisposeStat                           (. VAR dt: SymTab.TypeIndex;
+ 1820                                               dk: INTEGER;
+ 1821                                               qd, qv: QbeGen.QVal;
+ 1822                                               qn: SymTab.Name;
+ 1823                                               sfx: BOOLEAN;
+ 1824                                               astNode, astD: AST.Node; .)
+ 1825      = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
+ 1826                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 1827                                             AST.SetChild(astNode, 0,
+ 1828                                               AST.MakeLeaf(AST.NkIdent, "DISPOSE"));
+ 1829                                             IF astD # AST.NoNode THEN
+ 1830                                               AST.SetChild(astNode, 1, astD) END;
+ 1831                                             astStmt := astNode; .)
+ 1832                                           (. IF dt = SymTab.InvalidType THEN
+ 1833                                              ELSIF (dk # SymTab.KindVar)
+ 1834    AND (dk # SymTab.KindParam)
+ 1835    AND (dk # SymTab.KindField) THEN
+ 1836                                                SemError(210)
+ 1837                                              ELSIF SymTab.ClassOf(dt) #
+ 1838                                                    SymTab.ClPtr THEN
+ 1839                                                SemError(219)
+ 1840                                              END; .) .
+ 1841    (* WITH pushes each record's fields (inner wins) plus its base
+ 1842       address; field designators resolve through both stacks. *)
+ 1843    WithStat                              (. VAR nW: CARDINAL;
+ 1844                                               astNode: AST.Node; .)
+ 1845      = "WITH"                            (. nW := 0;
+ 1846                                             astNode := AST.MakeNode(AST.NkWith); .)
+ 1847        WithItem<nW, astNode> { "," WithItem<nW, astNode> }
+ 1848        "DO"                              (. astStmt := AST.NoNode; .)
+ 1849        [ StatSeq ] "END"                 (. AST.SetChild(astNode,
+ 1850                                             AST.NChild(astNode), astStmt);
+ 1851                                             astStmt := astNode;
+ 1852                                             WHILE nW > 0 DO
+ 1853                                               SymTab.PopScope;
+ 1854                                               QbeGen.PopWith;
+ 1855                                               DEC(nW)
+ 1856                                             END; .) .
+ 1857    WithItem<VAR nW: CARDINAL; wnode: AST.Node>
+ 1858                                          (. VAR dt: SymTab.TypeIndex;
+ 1859                                               dk: INTEGER;
+ 1860                                               qd, qe: QbeGen.QVal;
+ 1861                                               qn: SymTab.Name;
+ 1862                                               sfx: BOOLEAN; .)
+ 1863      = Design<dt, dk, qd, qn, sfx>
+ 1864                                          (. IF astCur # AST.NoNode THEN
+ 1865                                               AST.SetChild(wnode,
+ 1866                                                 AST.NChild(wnode), astCur) END;
+ 1867                                             IF dt = SymTab.InvalidType THEN
+ 1868                                             ELSIF (SymTab.ClassOf(dt) #
+ 1869                                                    SymTab.ClRecord)
+ 1870   AND (SymTab.ClassOf(dt) #
+ 1871                                                   SymTab.ClClass) THEN
+ 1872                                               SemError(215)
+ 1873                                             ELSIF SymTab.PushRecord(dt) THEN
+ 1874                                               QbeGen.PushWith(qd);
+ 1875                                               INC(nW)
+ 1876                                             END; .) .
+ 1877    (* Assignment or procedure-statement call (4.1, module level).
+ 1878       Bare `P;` is a syntax error; function-as-statement is 233. *)
+ 1879    AssOrCall                             (. VAR dt, et: SymTab.TypeIndex;
+ 1880                                               dk: INTEGER;
+ 1881                                               qd, qe, qt, ql: QbeGen.QVal;
+ 1882                                               qn: SymTab.Name;
+ 1883                                               ct2, res0: SymTab.TypeIndex;
+ 1884                                               q2, mg0: QbeGen.QVal;
+ 1885                                               isR, conv, wconv: BOOLEAN;
+ 1886                                               called, sfx: BOOLEAN;
+ 1887                                               astLhs, astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN;
+ 1888                                               n: SymTab.Name; astLab, astNode: AST.Node; .)
+ 1889      = GetIdent<n>
+ 1890        ( ":"                             (. NoteLabel(n);
+ 1891                                             astNode := AST.MakeNode(AST.NkLabel);
+ 1892                                             AST.SetChild(astNode, 0,
+ 1893                                               AST.MakeLeaf(AST.NkIdent, n));
+ 1894                                             astLab := AST.MakeNode(AST.NkBlock);
+ 1895                                             AST.SetChild(astLab, 0, astNode); .)
+ 1896          Statement                       (. IF astStmt # AST.NoNode THEN
+ 1897                                               AST.SetChild(astLab, 1, astStmt) END;
+ 1898                                             astStmt := astLab; .)
+ 1899        | DesignTail<n, dt, dk, qd, qn, sfx>
+ 1900        (. astLhs := astCur; astNArgs := 0; .)
+ 1901        ( ":="
+ 1902          Expr<et, qe>                    (. astStmt := AST.MakeBin(
+ 1903                                               AST.NkAssign, 0, astLhs, astCur);
+ 1904                                             IF (dt # SymTab.InvalidType)
+ 1905   AND (dk # SymTab.KindVar)
+ 1906   AND (dk # SymTab.KindParam)
+ 1907   AND (dk # SymTab.KindField) THEN
+ 1908                                             SemError(210)
+ 1909                                           ELSIF NOT SymTab.Assignable(et,
+ 1910                                                    dt) THEN
+ 1911                                             SemError(210)
+ 1912                                           ELSIF (dt # SymTab.InvalidType)
+ 1913   AND (SymTab.ClassOf(dt) =
+ 1914                                                 SymTab.ClClass) THEN
+ 1915                                             SemError(230) END;
+ 1916                                           isR := (dt #
+ 1917                                                   SymTab.InvalidType)
+ 1918   AND (SymTab.ClassOf(dt)
+ 1919                                                     = SymTab.ClReal);
+ 1920                                           conv := isR
+ 1921   AND SymTab.IsIntFamily(et);
+ 1922                                           wconv := (dt #
+ 1923                                                     SymTab.InvalidType)
+ 1924   AND SymTab.IsLongFamily(dt)
+ 1925   AND SymTab.IsIntFamily(et);
+ 1926                                           IF ((dk = SymTab.KindVar)
+ 1927                                               OR (dk = SymTab.KindParam)
+ 1928                                               OR (dk = SymTab.KindField))
+ 1929   AND (dt # SymTab.InvalidType)
+ 1930   AND (et # SymTab.InvalidType)
+ 1931   AND (SymTab.ClassOf(dt) #
+ 1932                                                 SymTab.ClClass) THEN
+ 1933                                           END; .)
+ 1934        | ArgList<qn, dt, qd, TRUE, TRUE, methCls, ct2, q2, called>
+ 1935                                          (. astRes := AstCallNode(astLhs);
+ 1936                                             sfx := FALSE; .)
+ 1937          ( { ResultComp<ct2, q2, sfx, astRes, mname, methCls, isM> }
+ 1938            ":=" Expr<et, qe>             (. astStmt := AST.MakeBin(
+ 1939                                               AST.NkAssign, 0, astRes, astCur);
+ 1940                                             IF NOT sfx THEN
+ 1941                                               SemError(233)
+ 1942                                             ELSIF (ct2 # SymTab.InvalidType)
+ 1943    AND NOT SymTab.Assignable(et, ct2) THEN
+ 1944                                               SemError(210)
+ 1945                                             END; .)
+ 1946          |                               (. IF ct2 #
+ 1947                                               SymTab.InvalidType THEN
+ 1948                                               SemError(233) END;
+ 1949                                             astStmt := astRes; .) )
+ 1950        |                                 (* bare `P;`: proper parameterless
+ 1951                                              procedure call; anything else
+ 1952                                              here is 233 (was a bare syntax
+ 1953                                              error before 4.2) *)
+ 1954                                          (. astStmt := AstCallNode(astLhs);
+ 1955                                              IF (dk = SymTab.KindProc)
+ 1956   AND NOT sfx THEN
+ 1957                                               res0 := SymTab.ProcRes(qn);
+ 1958                                               IF res0 #
+ 1959                                                  SymTab.InvalidType THEN
+ 1960                                                 SemError(233)
+ 1961                                               ELSIF SymTab.ProcNPar(qn) #
+ 1962                                                       0 THEN
+ 1963                                                 SemError(233)
+ 1964                                               END
+ 1965                                             ELSE SemError(233)
+ 1966                                              END; .) ) ) .
+ 1967    (* Actual-parameter list shared by statement and expression calls.
+ 1968       want selects CallEnd's result handling; t/q carry the call
+ 1969       value (statement calls discard). Arity/type failures are 233;
+ 1970       evaluation code still emits so the .ssa stays assembleable. *)
+ 1971    ArgList<pn: SymTab.Name; pt: SymTab.TypeIndex; callee: QbeGen.QVal;
+ 1972            want: BOOLEAN; soft: BOOLEAN; methCls: SymTab.TypeIndex;
+ 1973            VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
+ 1974            VAR called: BOOLEAN>          (. VAR i, np: CARDINAL;
+ 1975                                               vs: INTEGER;
+ 1976                                               res: SymTab.TypeIndex;
+ 1977                                               mg: QbeGen.QVal;
+ 1978                                               ok, ind, isMeth, va: BOOLEAN; .)
+ 1979      = "("                               (. called := TRUE;
+ 1980                                             ok := TRUE;
+ 1981                                             ind := FALSE;
+ 1982                                             isMeth := methCls #
+ 1983                                               SymTab.InvalidType;
+ 1984                                             IF isMeth THEN
+ 1985                                               res := SymTab.ClassMethodRes(methCls, pn)
+ 1986                                             ELSIF SymTab.SymKind(pn) = SymTab.KindProc THEN
+ 1987                                               res := SymTab.ProcRes(pn)
+ 1988                                             ELSIF (pt # SymTab.InvalidType)
+ 1989    AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN
+ 1990                                               ind := TRUE;
+ 1991                                               res := SymTab.ProcTypeRes(pt)
+ 1992                                             ELSE SemError(233);
+ 1993                                               ok := FALSE;
+ 1994                                               res := SymTab.InvalidType
+ 1995                                             END;
+ 1996                                             i := 0; .)
+ 1997        [ ActParam<pn, pt, ind, methCls, i>        (. INC(i); .)
+ 1998          { "," ActParam<pn, pt, ind, methCls, i>  (. INC(i); .) } ]
+ 1999        ")"                               (. IF ok THEN
+ 2000                                               IF isMeth THEN
+ 2001                                                 np := SymTab.ClassMethodNPar(
+ 2002                                                   methCls, pn)
+ 2003                                               ELSIF ind THEN
+ 2004                                                 np := SymTab.ProcTypeNPar(pt)
+ 2005                                               ELSE np := SymTab.ProcNPar(pn)
+ 2006                                               END;
+ 2007                                               va := (NOT isMeth) AND (NOT ind)
+ 2008                                                 AND (SymTab.SymKind(pn) =
+ 2009                                                      SymTab.KindProc)
+ 2010                                                 AND SymTab.Varargs(pn);
+ 2011                                               IF (i # np) AND NOT va THEN
+ 2012                                                 SemError(233); ok := FALSE
+ 2013                                               END
+ 2014                                             END;
+ 2015                                             IF NOT ok THEN
+ 2016                                               t := SymTab.InvalidType;
+ 2017                                               QbeGen.CopyOp("0", q)
+ 2018                                             ELSIF want THEN
+ 2019                                               IF res =
+ 2020                                                  SymTab.InvalidType THEN
+ 2021                                                 IF NOT soft THEN SemError(233) END;
+ 2022                                                 t := SymTab.InvalidType;
+ 2023                                                 QbeGen.CopyOp("0", q)
+ 2024                                               ELSE t := res;
+ 2025                                                  QbeGen.CopyOp("@", q)
+ 2026                                               END
+ 2027                                             ELSE
+ 2028                                               IF res #
+ 2029                                                  SymTab.InvalidType THEN
+ 2030                                                 SemError(233)
+ 2031                                               END;
+ 2032                                               t := SymTab.InvalidType;
+ 2033                                               QbeGen.CopyOp("0", q);
+ 2034                                             END; .) .
+ 2035    (* One actual: VAR formals take recorded designator addresses
+ 2036       (233 otherwise); value formals take converted expressions. *)
+ 2037    ActParam<pn: SymTab.Name; pt: SymTab.TypeIndex; ind: BOOLEAN;
+ 2038             methCls: SymTab.TypeIndex; i: CARDINAL>
+ 2039                                          (. VAR at, ft: SymTab.TypeIndex;
+ 2040                                               qe, qa, qt: QbeGen.QVal;
+ 2041                                               isV, conv, va: BOOLEAN;
+ 2042                                               cl: CHAR;
+ 2043                                               savedN, aj: CARDINAL;
+ 2044                                               savedArgs: ARRAY [0 .. 31]
+ 2045                                                 OF AST.Node;
+ 2046                                               astActual: AST.Node; .)
+ 2047      =                                   (. (* Parsing the actual can clobber
+ 2048                                               the enclosing call's argument
+ 2049                                               list (Factor resets astNArgs),
+ 2050                                               so save/restore it. *)
+ 2051                                             savedN := astNArgs; aj := 0;
+ 2052                                             WHILE aj <= HIGH(astArgs) DO
+ 2053                                               savedArgs[aj] := astArgs[aj];
+ 2054                                               INC(aj)
+ 2055                                             END; .)
+ 2056        Expr<at, qe>                      (. astActual := astCur;
+ 2057                                             astNArgs := savedN; aj := 0;
+ 2058                                             WHILE aj <= HIGH(astArgs) DO
+ 2059                                               astArgs[aj] := savedArgs[aj];
+ 2060                                               INC(aj)
+ 2061                                             END;
+ 2062                                             IF astNArgs <= HIGH(astArgs) THEN
+ 2063                                               astArgs[astNArgs] := astCur;
+ 2064                                               INC(astNArgs)
+ 2065                                             END;
+ 2066                                             va := (NOT ind)
+ 2067                                               AND (methCls =
+ 2068                                                  SymTab.InvalidType)
+ 2069                                               AND (SymTab.SymKind(pn) =
+ 2070                                                  SymTab.KindProc)
+ 2071                                               AND SymTab.Varargs(pn);
+ 2072                                             IF ind THEN
+ 2073                                               ft :=
+ 2074                                                 SymTab.ProcTypeParamType(pt,
+ 2075                                                   i);
+ 2076                                               isV :=
+ 2077                                                 SymTab.ProcTypeParamIsVar(pt,
+ 2078                                                   i)
+ 2079                                             ELSIF methCls #
+ 2080                                                SymTab.InvalidType THEN
  2081                                               ft :=
  2081                                               ft :=
- 2082                                                 SymTab.ProcTypeParamType(pt,
- 2083                                                   i);
+ 2082                                                 SymTab.ClassMethodParamType(
+ 2083                                                 methCls, pn, i);
  2084                                               isV :=
  2084                                               isV :=
- 2085                                                 SymTab.ProcTypeParamIsVar(pt,
- 2086                                                   i)
- 2087                                             ELSIF methCls #
- 2088                                                SymTab.InvalidType THEN
- 2089                                               ft :=
- 2090                                                 SymTab.ClassMethodParamType(
- 2091                                                 methCls, pn, i);
- 2092                                               isV :=
- 2093                                                 SymTab.ClassMethodParamIsVar(
- 2094                                                 methCls, pn, i)
- 2095                                             ELSE
- 2096                                               ft := SymTab.ParamType(pn, i);
- 2097                                               isV := SymTab.ParamIsVar(pn, i)
- 2098                                             END;
- 2099                                             IF (at = SymTab.InvalidType) THEN
- 2100                                             ELSIF ft = SymTab.InvalidType THEN
- 2101                                             ELSIF isV THEN
- 2102                                               IF (SymTab.ClassOf(at) = SymTab.ClChar)
- 2103    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
- 2104    AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar)
- 2105    AND QbeGen.IsImm(qe) THEN
- 2106                                               ELSIF (AST.Kind(astActual) #
- 2107                                                      AST.NkDesignator)
- 2108    AND (AST.Kind(astActual) # AST.NkStrLit) THEN
- 2109                                                 SemError(233)
- 2110                                               ELSIF NOT SymTab.VarParamOk(at, ft) THEN
+ 2085                                                 SymTab.ClassMethodParamIsVar(
+ 2086                                                 methCls, pn, i)
+ 2087                                             ELSE
+ 2088                                               ft := SymTab.ParamType(pn, i);
+ 2089                                               isV := SymTab.ParamIsVar(pn, i)
+ 2090                                             END;
+ 2091                                             IF (at = SymTab.InvalidType) THEN
+ 2092                                             ELSIF ft = SymTab.InvalidType THEN
+ 2093                                             ELSIF isV THEN
+ 2094                                               IF (SymTab.ClassOf(at) = SymTab.ClChar)
+ 2095    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
+ 2096    AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar)
+ 2097    AND QbeGen.IsImm(qe) THEN
+ 2098                                               ELSIF (AST.Kind(astActual) #
+ 2099                                                      AST.NkDesignator)
+ 2100    AND (AST.Kind(astActual) # AST.NkStrLit) THEN
+ 2101                                                 SemError(233)
+ 2102                                               ELSIF NOT SymTab.VarParamOk(at, ft) THEN
+ 2103                                                 SemError(233)
+ 2104                                               END
+ 2105                                             ELSE
+ 2106                                               IF (SymTab.ClassOf(at) = SymTab.ClChar)
+ 2107    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
+ 2108    AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar)
+ 2109    AND QbeGen.IsImm(qe) THEN
+ 2110                                               ELSIF NOT SymTab.Assignable(at, ft) THEN
  2111                                                 SemError(233)
  2111                                                 SemError(233)
  2112                                               END
  2112                                               END
- 2113                                             ELSE
- 2114                                               IF (SymTab.ClassOf(at) = SymTab.ClChar)
- 2115    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
- 2116    AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar)
- 2117    AND QbeGen.IsImm(qe) THEN
- 2118                                               ELSIF NOT SymTab.Assignable(at, ft) THEN
- 2119                                                 SemError(233)
- 2120                                               END
- 2121                                             END; .) .
- 2122    IfStat                                (. VAR t: SymTab.TypeIndex;
- 2123                                               q: QbeGen.QVal;
- 2124                                               hasElse: BOOLEAN;
- 2125                                               astCond, astIf, astLast,
- 2126                                               astNode: AST.Node; .)
- 2127      = "IF" (. hasElse := FALSE; .)
- 2128        Expr<t, q> (. astCond := astCur; astStmt := AST.NoNode;
- 2129                                             IF NOT SymTab.BoolCheck(t) THEN
- 2130                                               SemError(214) END; .)
- 2131        "THEN" [ StatSeq ]                (. astNode := AST.MakeNode(AST.NkIf);
- 2132                                             AST.SetChild(astNode, 0, astCond);
- 2133                                             AST.SetChild(astNode, 1, astStmt);
- 2134                                             astIf := astNode;
- 2135                                             astLast := astNode; .)
- 2136        { "ELSIF"
- 2137          Expr<t, q> (. astCond := astCur; astStmt := AST.NoNode;
- 2138                                             IF NOT SymTab.BoolCheck(t) THEN
- 2139                                               SemError(214) END; .)
- 2140          "THEN" [ StatSeq ]              (. astNode := AST.MakeNode(AST.NkIf);
- 2141                                             AST.SetChild(astNode, 0, astCond);
- 2142                                             AST.SetChild(astNode, 1, astStmt);
- 2143                                             AST.SetChild(astLast, 2, astNode);
- 2144                                             astLast := astNode; .) }
- 2145        [ "ELSE"                          (. hasElse := TRUE;
- 2146                                             astStmt := AST.NoNode; .)
- 2147          [ StatSeq ] (. AST.SetChild(astLast, 2, astStmt); .) ]
- 2148        "END" (. astStmt := astIf; .) .
- 2149    WhileStat                             (. VAR t: SymTab.TypeIndex;
- 2150                                               q: QbeGen.QVal;
- 2151                                               astCond, astNode: AST.Node; .)
- 2152      = "WHILE" (. astStmt := AST.NoNode; .)
- 2153        Expr<t, q> (. astCond := astCur;
- 2154                                             IF NOT SymTab.BoolCheck(t) THEN
- 2155                                               SemError(214) END; .)
- 2156        "DO" [ StatSeq ]                  (. astNode := AST.MakeNode(AST.NkWhile);
- 2157                                             AST.SetChild(astNode, 0, astCond);
- 2158                                             AST.SetChild(astNode, 1, astStmt);
- 2159                                             astStmt := astNode; .)
- 2160        "END" .
- 2161    RepeatStat                            (. VAR t: SymTab.TypeIndex;
- 2162                                               q: QbeGen.QVal;
- 2163                                               astCond, astBody, astNode:
- 2164                                                 AST.Node; .)
- 2165      = "REPEAT" (. astStmt := AST.NoNode; .)
- 2166        [ StatSeq ] (. astBody := astStmt; .)
- 2167        "UNTIL" Expr<t, q> (. astCond := astCur;
- 2168                                             astNode := AST.MakeNode(AST.NkRepeat);
- 2169                                             AST.SetChild(astNode, 0, astBody);
- 2170                                             AST.SetChild(astNode, 1, astCond);
- 2171                                             astStmt := astNode;
- 2172                                             IF NOT SymTab.BoolCheck(t) THEN
- 2173                                               SemError(214) END; .) .
- 2174    LoopStat                              (. VAR lEnd: QbeGen.QVal; astNode: AST.Node; .)
- 2175      = "LOOP"                            (. astStmt := AST.NoNode;
- 2176                                             QbeGen.NewLabel(lEnd);
- 2177                                             QbeGen.PushLoop(lEnd); .)
- 2178        [ StatSeq ]
- 2179        "END"                             (. astNode := AST.MakeNode(AST.NkLoop);
- 2180                                             AST.SetChild(astNode, 0, astStmt);
- 2181                                             astStmt := astNode;
- 2182                                             QbeGen.PopLoop; .) .
- 2183    (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
- 2184       Runtime direction would need a compare-select; the literal
- 2185       sign picks cslew/csegew at "DO" time. *)
- 2186    ForStat                               (. VAR lv: SymTab.Name;
- 2187                                               tlo, thi, tby:
- 2188                                                 SymTab.TypeIndex;
- 2189                                               qlo, qhi, qby, qt, qk, qb:
- 2190                                                 QbeGen.QVal;
- 2191                                               lTop, lBody, lEnd:
- 2192                                                 QbeGen.QVal;
- 2193                                               by: INTEGER;
- 2194                                               ok: BOOLEAN;
- 2195                                               astVar, astLo, astHi, astBy,
- 2196                                               astNode: AST.Node; .)
- 2197      = "FOR"                             (. by := 1; .)
- 2198        GetIdent<lv> (. astVar := AST.MakeLeaf(AST.NkIdent, lv);
- 2199                                             astStmt := AST.NoNode;
- 2200                                             astBy := AST.NoNode;
- 2201                                             ok := SymTab.Lookup(lv);
- 2202                                             IF NOT ok THEN
- 2203                                               SemError(201)
- 2204                                             ELSIF (SymTab.SymKind(lv) #
- 2205                                                    SymTab.KindVar)
- 2206   AND (SymTab.SymKind(lv) #
- 2207                                                   SymTab.KindParam) THEN
- 2208                                               SemError(220); ok := FALSE
- 2209                                             ELSIF NOT SymTab.IsIntFamily(
- 2210                                                     SymTab.SymType(lv)) THEN
+ 2113                                             END; .) .
+ 2114    IfStat                                (. VAR t: SymTab.TypeIndex;
+ 2115                                               q: QbeGen.QVal;
+ 2116                                               hasElse: BOOLEAN;
+ 2117                                               astCond, astIf, astLast,
+ 2118                                               astNode: AST.Node; .)
+ 2119      = "IF" (. hasElse := FALSE; .)
+ 2120        Expr<t, q> (. astCond := astCur; astStmt := AST.NoNode;
+ 2121                                             IF NOT SymTab.BoolCheck(t) THEN
+ 2122                                               SemError(214) END; .)
+ 2123        "THEN" [ StatSeq ]                (. astNode := AST.MakeNode(AST.NkIf);
+ 2124                                             AST.SetChild(astNode, 0, astCond);
+ 2125                                             AST.SetChild(astNode, 1, astStmt);
+ 2126                                             astIf := astNode;
+ 2127                                             astLast := astNode; .)
+ 2128        { "ELSIF"
+ 2129          Expr<t, q> (. astCond := astCur; astStmt := AST.NoNode;
+ 2130                                             IF NOT SymTab.BoolCheck(t) THEN
+ 2131                                               SemError(214) END; .)
+ 2132          "THEN" [ StatSeq ]              (. astNode := AST.MakeNode(AST.NkIf);
+ 2133                                             AST.SetChild(astNode, 0, astCond);
+ 2134                                             AST.SetChild(astNode, 1, astStmt);
+ 2135                                             AST.SetChild(astLast, 2, astNode);
+ 2136                                             astLast := astNode; .) }
+ 2137        [ "ELSE"                          (. hasElse := TRUE;
+ 2138                                             astStmt := AST.NoNode; .)
+ 2139          [ StatSeq ] (. AST.SetChild(astLast, 2, astStmt); .) ]
+ 2140        "END" (. astStmt := astIf; .) .
+ 2141    WhileStat                             (. VAR t: SymTab.TypeIndex;
+ 2142                                               q: QbeGen.QVal;
+ 2143                                               astCond, astNode: AST.Node; .)
+ 2144      = "WHILE" (. astStmt := AST.NoNode; .)
+ 2145        Expr<t, q> (. astCond := astCur;
+ 2146                                             IF NOT SymTab.BoolCheck(t) THEN
+ 2147                                               SemError(214) END; .)
+ 2148        "DO" [ StatSeq ]                  (. astNode := AST.MakeNode(AST.NkWhile);
+ 2149                                             AST.SetChild(astNode, 0, astCond);
+ 2150                                             AST.SetChild(astNode, 1, astStmt);
+ 2151                                             astStmt := astNode; .)
+ 2152        "END" .
+ 2153    RepeatStat                            (. VAR t: SymTab.TypeIndex;
+ 2154                                               q: QbeGen.QVal;
+ 2155                                               astCond, astBody, astNode:
+ 2156                                                 AST.Node; .)
+ 2157      = "REPEAT" (. astStmt := AST.NoNode; .)
+ 2158        [ StatSeq ] (. astBody := astStmt; .)
+ 2159        "UNTIL" Expr<t, q> (. astCond := astCur;
+ 2160                                             astNode := AST.MakeNode(AST.NkRepeat);
+ 2161                                             AST.SetChild(astNode, 0, astBody);
+ 2162                                             AST.SetChild(astNode, 1, astCond);
+ 2163                                             astStmt := astNode;
+ 2164                                             IF NOT SymTab.BoolCheck(t) THEN
+ 2165                                               SemError(214) END; .) .
+ 2166    LoopStat                              (. VAR lEnd: QbeGen.QVal; astNode: AST.Node; .)
+ 2167      = "LOOP"                            (. astStmt := AST.NoNode;
+ 2168                                             QbeGen.NewLabel(lEnd);
+ 2169                                             QbeGen.PushLoop(lEnd); .)
+ 2170        [ StatSeq ]
+ 2171        "END"                             (. astNode := AST.MakeNode(AST.NkLoop);
+ 2172                                             AST.SetChild(astNode, 0, astStmt);
+ 2173                                             astStmt := astNode;
+ 2174                                             QbeGen.PopLoop; .) .
+ 2175    (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
+ 2176       Runtime direction would need a compare-select; the literal
+ 2177       sign picks cslew/csegew at "DO" time. *)
+ 2178    ForStat                               (. VAR lv: SymTab.Name;
+ 2179                                               tlo, thi, tby:
+ 2180                                                 SymTab.TypeIndex;
+ 2181                                               qlo, qhi, qby, qt, qk, qb:
+ 2182                                                 QbeGen.QVal;
+ 2183                                               lTop, lBody, lEnd:
+ 2184                                                 QbeGen.QVal;
+ 2185                                               by: INTEGER;
+ 2186                                               ok: BOOLEAN;
+ 2187                                               astVar, astLo, astHi, astBy,
+ 2188                                               astNode: AST.Node; .)
+ 2189      = "FOR"                             (. by := 1; .)
+ 2190        GetIdent<lv> (. astVar := AST.MakeLeaf(AST.NkIdent, lv);
+ 2191                                             astStmt := AST.NoNode;
+ 2192                                             astBy := AST.NoNode;
+ 2193                                             ok := SymTab.Lookup(lv);
+ 2194                                             IF NOT ok THEN
+ 2195                                               SemError(201)
+ 2196                                             ELSIF (SymTab.SymKind(lv) #
+ 2197                                                    SymTab.KindVar)
+ 2198   AND (SymTab.SymKind(lv) #
+ 2199                                                   SymTab.KindParam) THEN
+ 2200                                               SemError(220); ok := FALSE
+ 2201                                             ELSIF NOT SymTab.IsIntFamily(
+ 2202                                                     SymTab.SymType(lv)) THEN
+ 2203                                               SemError(220); ok := FALSE
+ 2204                                             END; .)
+ 2205        ":=" Expr<tlo, qlo> (. astLo := astCur;
+ 2206                                             IF NOT SymTab.IsIntFamily(tlo) THEN
+ 2207                                               SemError(220); ok := FALSE
+ 2208                                             END; .)
+ 2209        "TO" Expr<thi, qhi> (. astHi := astCur;
+ 2210                                             IF NOT SymTab.IsIntFamily(thi) THEN
  2211                                               SemError(220); ok := FALSE
  2211                                               SemError(220); ok := FALSE
  2212                                             END; .)
  2212                                             END; .)
- 2213        ":=" Expr<tlo, qlo> (. astLo := astCur;
- 2214                                             IF NOT SymTab.IsIntFamily(tlo) THEN
- 2215                                               SemError(220); ok := FALSE
- 2216                                             END; .)
- 2217        "TO" Expr<thi, qhi> (. astHi := astCur;
- 2218                                             IF NOT SymTab.IsIntFamily(thi) THEN
- 2219                                               SemError(220); ok := FALSE
- 2220                                             END; .)
- 2221        [ "BY" Expr<tby, qby> (. astBy := astCur;
- 2222                                             IF (tby #
- 2223                                               SymTab.InvalidType)
- 2224   AND NOT SymTab.IsIntFamily(tby) THEN
- 2225                                               SemError(220); ok := FALSE
- 2226                                             END;
- 2227                                             IF NOT SymTab.ConstInt(qby, by) THEN
- 2228                                               SemError(230); by := 1
- 2229                                             ELSIF by = 0 THEN
- 2230                                               SemError(220); by := 1
- 2231                                             END; .) ]
- 2232        "DO"
- 2233        [ StatSeq ]
- 2234        "END" (. astNode := AST.MakeNode(AST.NkFor);
- 2235                                             AST.SetChild(astNode, 0, astVar);
- 2236                                             AST.SetChild(astNode, 1, astLo);
- 2237                                             AST.SetChild(astNode, 2, astHi);
- 2238                                             AST.SetChild(astNode, 3, astBy);
- 2239                                             AST.SetChild(astNode, 4, astStmt);
- 2240                                             astStmt := astNode;
- 2241                                             .) .
- 2242    CaseStat                              (. VAR tsel: SymTab.TypeIndex;
- 2243                                               qsel, lEnd: QbeGen.QVal;
- 2244                                               arm, astNode, astArms,
- 2245                                               astArmsTail: AST.Node; .)
- 2246      = "CASE" Expr<tsel, qsel>           (. astNode := AST.MakeNode(AST.NkCase);
- 2247                                             AST.SetChild(astNode, 0, astCur);
- 2248                                             astArms := AST.NoNode;
- 2249                                             astArmsTail := AST.NoNode;
- 2250                                             .)
- 2251        "OF" CaseAlt<tsel, qsel, lEnd, astArms, astArmsTail>
- 2252        { "|" CaseAlt<tsel, qsel, lEnd, astArms, astArmsTail> }
- 2253        [ "ELSE"                          (. astStmt := AST.NoNode; .)
- 2254          [ StatSeq ]                     (. arm := AST.MakeNode(AST.NkCaseArm);
- 2255                                             AST.SetOp(arm, 1);
- 2256                                             AST.SetChild(arm, 0, astStmt);
- 2257                                             AstAppend(AST.NkBlock,
- 2258                                               astArms, astArmsTail, arm); .) ]
- 2259        "END"                             (. AST.SetChild(astNode, 1, astArms);
- 2260                                             astStmt := astNode;
- 2261                                             .) .
- 2262    (* Compare-chain lowering: each alternative ends its match-tests
- 2263       with "jmp lAfter", so the no-match fallthrough skips the body:
- 2264       "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
- 2265       lAfter:". Falls into the next alternative, ELSE, or END. *)
- 2266    CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
- 2267            lEnd: QbeGen.QVal; VAR arms, armsTail: AST.Node>
- 2268                                          (. VAR arm: AST.Node; .)
- 2269      =                                   (. arm := AST.MakeNode(AST.NkCaseArm); .)
- 2270        CaseLabel<tsel, qsel, arm>
- 2271        { "," CaseLabel<tsel, qsel, arm> }
- 2272        ":"                               (. astStmt := AST.NoNode; .)
- 2273        [ StatSeq ]                       (. AST.SetChild(arm, AST.NChild(arm),
- 2274                                             astStmt);
- 2275                                             AstAppend(AST.NkBlock,
- 2276                                               arms, armsTail, arm);
- 2277                                             .) .
- 2278    CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
- 2279              arm: AST.Node>
- 2280                                          (. VAR t2, t3: SymTab.TypeIndex;
- 2281                                               q2, q3, qc, qd, qe:
- 2282                                                 QbeGen.QVal;
- 2283                                               astLab: AST.Node;
- 2284                                               lNext: QbeGen.QVal; .)
- 2285      = Expr<t2, q2> (. astLab := astCur;
- 2286                                             IF (t2 #
- 2287                                               SymTab.InvalidType)
- 2288   AND (tsel #
- 2289                                                 SymTab.InvalidType)
- 2290   AND ((SymTab.ClassOf(t2) =
- 2291                                                  SymTab.ClSet)
- 2292                                                 OR (SymTab.ClassOf(tsel) =
- 2293                                                     SymTab.ClSet)) THEN
- 2294                                               SemError(230)
- 2295                                             ELSIF (t2 #
- 2296                                               SymTab.InvalidType)
- 2297   AND (tsel #
- 2298                                                 SymTab.InvalidType)
- 2299   AND NOT SymTab.EqCheck(t2,
- 2300                                                   tsel) THEN
- 2301                                               SemError(213) END;
- 2302                                                 IF NOT QbeGen.IsImm(q2) THEN
- 2303                                                   SemError(230)
- 2304                                                 END; .)
- 2305        [ ".." Expr<t3, q3>               (. astLab := AST.MakeBin(
- 2306                                               AST.NkSubrange, 0, astLab, astCur);
- 2307                                             IF (t3 #
- 2308                                               SymTab.InvalidType)
- 2309   AND (tsel #
- 2310                                                 SymTab.InvalidType)
- 2311   AND NOT SymTab.EqCheck(t3,
- 2312                                                   tsel) THEN
- 2313                                               SemError(213) END;
- 2314                                                 IF NOT QbeGen.IsImm(q3) THEN
- 2315                                                   SemError(230)
- 2316                                                 END; .) ]
- 2317                                          (. AST.SetChild(arm,
- 2318                                               AST.NChild(arm), astLab); .) .
- 2319    ReturnStat                            (. VAR t: SymTab.TypeIndex;
- 2320                                               q, qt: QbeGen.QVal;
- 2321                                               res: SymTab.TypeIndex;
- 2322                                               hadE, conv: BOOLEAN;
- 2323                                               astVal, astNode: AST.Node; .)
- 2324      = "RETURN"                          (. hadE := FALSE; astStmt := AST.NoNode; .)
- 2325        [ Expr<t, q> (. hadE := TRUE; astVal := astCur; .) ]
- 2326                                          (. astNode := AST.MakeNode(AST.NkReturn);
- 2327                                             IF hadE THEN
- 2328                                               AST.SetChild(astNode, 0, astVal)
- 2329                                             END;
- 2330                                             astStmt := astNode;
- 2331                                             conv := FALSE;
- 2332                                             IF NOT SymTab.InProc() THEN
- 2333                                               SemError(232)
- 2334                                             ELSE res := SymTab.CurRes();
- 2335                                               IF NOT hadE THEN
- 2336                                                 IF res #
- 2337                                                    SymTab.InvalidType THEN
- 2338                                                   SemError(232)
- 2339                                                 END
- 2340                                               ELSIF (res =
- 2341                                                      SymTab.InvalidType)
- 2342                                                  OR (t #
- 2343                                                      SymTab.InvalidType)
- 2344   AND NOT SymTab.Assignable(t,
- 2345                                                       res) THEN
- 2346                                                 SemError(232)
- 2347                                             END
- 2348                                             END; .) .
- 2349    HaltStat                              (. VAR t: SymTab.TypeIndex;
- 2350                                               q: QbeGen.QVal;
- 2351                                               astVal, astNode: AST.Node; .)
- 2352      = "HALT" (. astVal := AST.NoNode; .)
- 2353        [ "(" Expr<t, q> (. astVal := astCur; .) ")" ]
- 2354                                          (. astNode := AST.MakeNode(AST.NkHalt);
- 2355                                             IF astVal # AST.NoNode THEN
- 2356                                               AST.SetChild(astNode, 0, astVal)
- 2357                                             END;
- 2358                                             astStmt := astNode;
- 2359                                             .) .
- 2360    (* Designator: scalar loads, array addresses, and index suffixes.
- 2361       Each index descends one level (bounds-checked, trap on breach);
- 2362       nested levels reload the inner descriptor address. q ends as the
- 2363       value (scalars), the descriptor address (plain arrays), or the
- 2364       element address (indexed); sfx marks the indexed form. *)
- 2365    Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
- 2366           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
- 2367                                          (. VAR n: SymTab.Name; .)
- 2368      = GetIdent<n> DesignTail<n, t, k, q, qn, sfx> .
- 2369    (* The part of Design after the identifier: resolve it and walk the
- 2370       selectors.  Split out so a statement can decide between a label
- 2371       (`ident :`) and a designator (`ident := ...`) with one token. *)
- 2372    DesignTail<VAR n: SymTab.Name; VAR t: SymTab.TypeIndex; VAR k: INTEGER;
- 2373           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
- 2374                                          (. VAR fn, mal: SymTab.Name;
- 2375                                               cls: INTEGER;
- 2376                                               ic: SymTab.TypeIndex;
- 2377                                               curT, it, eT, bt:
- 2378                                                 SymTab.TypeIndex;
- 2379                                               iq, ql, qlo, qhi, qe:
- 2380                                                 QbeGen.QVal;
- 2381                                               lo, hi: INTEGER;
- 2382                                               fo: INTEGER;
- 2383                                               isOpen: BOOLEAN;
- 2384                                               qb, cv: QbeGen.QVal;
- 2385                                               r: BOOLEAN;
- 2386                                                astDes, astSel: AST.Node; .)
- 2387      =                                   (. methCls := SymTab.InvalidType;
- 2388                                             QbeGen.CopyOp(n, qn);
- 2389                                             sfx := FALSE;
- 2390                                             IF NOT SymTab.Lookup(n) THEN
- 2391                                               (* a bare method name inside
- 2392                                                  a CLASS IMPLEMENTATION
- 2393                                                  is a sibling call on
- 2394                                                  THIS *)
- 2395                                               ic := SymTab.CurImplClass();
- 2396                                               IF (ic #
- 2397                                                  SymTab.InvalidType)
- 2398    AND SymTab.MethodExists(ic, n) THEN
- 2399                                                 sfx := FALSE;
- 2400                                                  QbeGen.CopyOp("@", q);
- 2401                                                 methCls := ic;
- 2402                                                 k := SymTab.KindProc;
- 2403                                                 t := SymTab.InvalidType
- 2404                                               ELSIF SymTab.InProc() THEN
- 2405                                                 (* not declared anywhere
- 2406                                                    in scope: with bodies
- 2407                                                    parsed at unit end this
- 2408                                                    is a genuine 201 (a
- 2409                                                    nested-local forward is
- 2410                                                    no longer tolerated). *)
- 2411                                                 SemError(201);
- 2412                                                 t := SymTab.InvalidType;
- 2413                                                 k := -1;
- 2414                                                 QbeGen.CopyOp("0", q)
- 2415                                               ELSE
- 2416                                                 SemError(201);
- 2417                                                 t :=
- 2418                                                   SymTab.InvalidType;
- 2419                                                 k := -1;
- 2420                                                 QbeGen.CopyOp("0", q)
- 2421                                               END
- 2422                                             ELSE
- 2423                                               t := SymTab.SymType(n);
- 2424                                               k := SymTab.SymKind(n);
- 2425                                               IF k = SymTab.KindConst THEN
- 2426                                                 IF SymTab.Equal(n,
- 2427                                                    "TRUE") THEN
- 2428                                                   t := SymTab.BoolType();
- 2429                                                   QbeGen.CopyOp("1", q)
- 2430                                                 ELSIF SymTab.Equal(n,
- 2431                                                    "FALSE") THEN
- 2432                                                   t := SymTab.BoolType();
- 2433                                                   QbeGen.CopyOp("0", q)
- 2434                                                 ELSIF SymTab.Equal(n,
- 2435                                                    "NIL") THEN
- 2436                                                   QbeGen.CopyOp("0", q)
- 2437                                                 ELSE
- 2438                                                   cls :=
- 2439                                                     SymTab.ClassOf(t);
- 2440                                                   IF (t #
- 2441                                                       SymTab.InvalidType)
- 2442   AND ((cls = SymTab.ClInt)
+ 2213        [ "BY" Expr<tby, qby> (. astBy := astCur;
+ 2214                                             IF (tby #
+ 2215                                               SymTab.InvalidType)
+ 2216   AND NOT SymTab.IsIntFamily(tby) THEN
+ 2217                                               SemError(220); ok := FALSE
+ 2218                                             END;
+ 2219                                             IF NOT SymTab.ConstInt(qby, by) THEN
+ 2220                                               SemError(230); by := 1
+ 2221                                             ELSIF by = 0 THEN
+ 2222                                               SemError(220); by := 1
+ 2223                                             END; .) ]
+ 2224        "DO"
+ 2225        [ StatSeq ]
+ 2226        "END" (. astNode := AST.MakeNode(AST.NkFor);
+ 2227                                             AST.SetChild(astNode, 0, astVar);
+ 2228                                             AST.SetChild(astNode, 1, astLo);
+ 2229                                             AST.SetChild(astNode, 2, astHi);
+ 2230                                             AST.SetChild(astNode, 3, astBy);
+ 2231                                             AST.SetChild(astNode, 4, astStmt);
+ 2232                                             astStmt := astNode;
+ 2233                                             .) .
+ 2234    CaseStat                              (. VAR tsel: SymTab.TypeIndex;
+ 2235                                               qsel, lEnd: QbeGen.QVal;
+ 2236                                               arm, astNode, astArms,
+ 2237                                               astArmsTail: AST.Node; .)
+ 2238      = "CASE" Expr<tsel, qsel>           (. astNode := AST.MakeNode(AST.NkCase);
+ 2239                                             AST.SetChild(astNode, 0, astCur);
+ 2240                                             astArms := AST.NoNode;
+ 2241                                             astArmsTail := AST.NoNode;
+ 2242                                             .)
+ 2243        "OF" CaseAlt<tsel, qsel, lEnd, astArms, astArmsTail>
+ 2244        { "|" CaseAlt<tsel, qsel, lEnd, astArms, astArmsTail> }
+ 2245        [ "ELSE"                          (. astStmt := AST.NoNode; .)
+ 2246          [ StatSeq ]                     (. arm := AST.MakeNode(AST.NkCaseArm);
+ 2247                                             AST.SetOp(arm, 1);
+ 2248                                             AST.SetChild(arm, 0, astStmt);
+ 2249                                             AstAppend(AST.NkBlock,
+ 2250                                               astArms, astArmsTail, arm); .) ]
+ 2251        "END"                             (. AST.SetChild(astNode, 1, astArms);
+ 2252                                             astStmt := astNode;
+ 2253                                             .) .
+ 2254    (* Compare-chain lowering: each alternative ends its match-tests
+ 2255       with "jmp lAfter", so the no-match fallthrough skips the body:
+ 2256       "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
+ 2257       lAfter:". Falls into the next alternative, ELSE, or END. *)
+ 2258    CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
+ 2259            lEnd: QbeGen.QVal; VAR arms, armsTail: AST.Node>
+ 2260                                          (. VAR arm: AST.Node; .)
+ 2261      =                                   (. arm := AST.MakeNode(AST.NkCaseArm); .)
+ 2262        CaseLabel<tsel, qsel, arm>
+ 2263        { "," CaseLabel<tsel, qsel, arm> }
+ 2264        ":"                               (. astStmt := AST.NoNode; .)
+ 2265        [ StatSeq ]                       (. AST.SetChild(arm, AST.NChild(arm),
+ 2266                                             astStmt);
+ 2267                                             AstAppend(AST.NkBlock,
+ 2268                                               arms, armsTail, arm);
+ 2269                                             .) .
+ 2270    CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
+ 2271              arm: AST.Node>
+ 2272                                          (. VAR t2, t3: SymTab.TypeIndex;
+ 2273                                               q2, q3, qc, qd, qe:
+ 2274                                                 QbeGen.QVal;
+ 2275                                               astLab: AST.Node;
+ 2276                                               lNext: QbeGen.QVal; .)
+ 2277      = Expr<t2, q2> (. astLab := astCur;
+ 2278                                             IF (t2 #
+ 2279                                               SymTab.InvalidType)
+ 2280   AND (tsel #
+ 2281                                                 SymTab.InvalidType)
+ 2282   AND ((SymTab.ClassOf(t2) =
+ 2283                                                  SymTab.ClSet)
+ 2284                                                 OR (SymTab.ClassOf(tsel) =
+ 2285                                                     SymTab.ClSet)) THEN
+ 2286                                               SemError(230)
+ 2287                                             ELSIF (t2 #
+ 2288                                               SymTab.InvalidType)
+ 2289   AND (tsel #
+ 2290                                                 SymTab.InvalidType)
+ 2291   AND NOT SymTab.EqCheck(t2,
+ 2292                                                   tsel) THEN
+ 2293                                               SemError(213) END;
+ 2294                                                 IF NOT QbeGen.IsImm(q2) THEN
+ 2295                                                   SemError(230)
+ 2296                                                 END; .)
+ 2297        [ ".." Expr<t3, q3>               (. astLab := AST.MakeBin(
+ 2298                                               AST.NkSubrange, 0, astLab, astCur);
+ 2299                                             IF (t3 #
+ 2300                                               SymTab.InvalidType)
+ 2301   AND (tsel #
+ 2302                                                 SymTab.InvalidType)
+ 2303   AND NOT SymTab.EqCheck(t3,
+ 2304                                                   tsel) THEN
+ 2305                                               SemError(213) END;
+ 2306                                                 IF NOT QbeGen.IsImm(q3) THEN
+ 2307                                                   SemError(230)
+ 2308                                                 END; .) ]
+ 2309                                          (. AST.SetChild(arm,
+ 2310                                               AST.NChild(arm), astLab); .) .
+ 2311    ReturnStat                            (. VAR t: SymTab.TypeIndex;
+ 2312                                               q, qt: QbeGen.QVal;
+ 2313                                               res: SymTab.TypeIndex;
+ 2314                                               hadE, conv: BOOLEAN;
+ 2315                                               astVal, astNode: AST.Node; .)
+ 2316      = "RETURN"                          (. hadE := FALSE; astStmt := AST.NoNode; .)
+ 2317        [ Expr<t, q> (. hadE := TRUE; astVal := astCur; .) ]
+ 2318                                          (. astNode := AST.MakeNode(AST.NkReturn);
+ 2319                                             IF hadE THEN
+ 2320                                               AST.SetChild(astNode, 0, astVal)
+ 2321                                             END;
+ 2322                                             astStmt := astNode;
+ 2323                                             conv := FALSE;
+ 2324                                             IF NOT SymTab.InProc() THEN
+ 2325                                               SemError(232)
+ 2326                                             ELSE res := SymTab.CurRes();
+ 2327                                               IF NOT hadE THEN
+ 2328                                                 IF res #
+ 2329                                                    SymTab.InvalidType THEN
+ 2330                                                   SemError(232)
+ 2331                                                 END
+ 2332                                               ELSIF (res =
+ 2333                                                      SymTab.InvalidType)
+ 2334                                                  OR (t #
+ 2335                                                      SymTab.InvalidType)
+ 2336   AND NOT SymTab.Assignable(t,
+ 2337                                                       res) THEN
+ 2338                                                 SemError(232)
+ 2339                                             END
+ 2340                                             END; .) .
+ 2341    HaltStat                              (. VAR t: SymTab.TypeIndex;
+ 2342                                               q: QbeGen.QVal;
+ 2343                                               astVal, astNode: AST.Node; .)
+ 2344      = "HALT" (. astVal := AST.NoNode; .)
+ 2345        [ "(" Expr<t, q> (. astVal := astCur; .) ")" ]
+ 2346                                          (. astNode := AST.MakeNode(AST.NkHalt);
+ 2347                                             IF astVal # AST.NoNode THEN
+ 2348                                               AST.SetChild(astNode, 0, astVal)
+ 2349                                             END;
+ 2350                                             astStmt := astNode;
+ 2351                                             .) .
+ 2352    (* Designator: scalar loads, array addresses, and index suffixes.
+ 2353       Each index descends one level (bounds-checked, trap on breach);
+ 2354       nested levels reload the inner descriptor address. q ends as the
+ 2355       value (scalars), the descriptor address (plain arrays), or the
+ 2356       element address (indexed); sfx marks the indexed form. *)
+ 2357    Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
+ 2358           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
+ 2359                                          (. VAR n: SymTab.Name; .)
+ 2360      = GetIdent<n> DesignTail<n, t, k, q, qn, sfx> .
+ 2361    (* The part of Design after the identifier: resolve it and walk the
+ 2362       selectors.  Split out so a statement can decide between a label
+ 2363       (`ident :`) and a designator (`ident := ...`) with one token. *)
+ 2364    DesignTail<VAR n: SymTab.Name; VAR t: SymTab.TypeIndex; VAR k: INTEGER;
+ 2365           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
+ 2366                                          (. VAR fn, mal: SymTab.Name;
+ 2367                                               cls: INTEGER;
+ 2368                                               ic: SymTab.TypeIndex;
+ 2369                                               curT, it, eT, bt:
+ 2370                                                 SymTab.TypeIndex;
+ 2371                                               iq, ql, qlo, qhi, qe:
+ 2372                                                 QbeGen.QVal;
+ 2373                                               lo, hi: INTEGER;
+ 2374                                               fo: INTEGER;
+ 2375                                               isOpen: BOOLEAN;
+ 2376                                               qb, cv: QbeGen.QVal;
+ 2377                                               r: BOOLEAN;
+ 2378                                                astDes, astSel: AST.Node; .)
+ 2379      =                                   (. methCls := SymTab.InvalidType;
+ 2380                                             QbeGen.CopyOp(n, qn);
+ 2381                                             sfx := FALSE;
+ 2382                                             IF NOT SymTab.Lookup(n) THEN
+ 2383                                               (* a bare method name inside
+ 2384                                                  a CLASS IMPLEMENTATION
+ 2385                                                  is a sibling call on
+ 2386                                                  THIS *)
+ 2387                                               ic := SymTab.CurImplClass();
+ 2388                                               IF (ic #
+ 2389                                                  SymTab.InvalidType)
+ 2390    AND SymTab.MethodExists(ic, n) THEN
+ 2391                                                 sfx := FALSE;
+ 2392                                                  QbeGen.CopyOp("@", q);
+ 2393                                                 methCls := ic;
+ 2394                                                 k := SymTab.KindProc;
+ 2395                                                 t := SymTab.InvalidType
+ 2396                                               ELSIF SymTab.InProc() THEN
+ 2397                                                 (* not declared anywhere
+ 2398                                                    in scope: with bodies
+ 2399                                                    parsed at unit end this
+ 2400                                                    is a genuine 201 (a
+ 2401                                                    nested-local forward is
+ 2402                                                    no longer tolerated). *)
+ 2403                                                 SemError(201);
+ 2404                                                 t := SymTab.InvalidType;
+ 2405                                                 k := -1;
+ 2406                                                 QbeGen.CopyOp("0", q)
+ 2407                                               ELSE
+ 2408                                                 SemError(201);
+ 2409                                                 t :=
+ 2410                                                   SymTab.InvalidType;
+ 2411                                                 k := -1;
+ 2412                                                 QbeGen.CopyOp("0", q)
+ 2413                                               END
+ 2414                                             ELSE
+ 2415                                               t := SymTab.SymType(n);
+ 2416                                               k := SymTab.SymKind(n);
+ 2417                                               IF k = SymTab.KindConst THEN
+ 2418                                                 IF SymTab.Equal(n,
+ 2419                                                    "TRUE") THEN
+ 2420                                                   t := SymTab.BoolType();
+ 2421                                                   QbeGen.CopyOp("1", q)
+ 2422                                                 ELSIF SymTab.Equal(n,
+ 2423                                                    "FALSE") THEN
+ 2424                                                   t := SymTab.BoolType();
+ 2425                                                   QbeGen.CopyOp("0", q)
+ 2426                                                 ELSIF SymTab.Equal(n,
+ 2427                                                    "NIL") THEN
+ 2428                                                   QbeGen.CopyOp("0", q)
+ 2429                                                 ELSE
+ 2430                                                   cls :=
+ 2431                                                     SymTab.ClassOf(t);
+ 2432                                                   IF (t #
+ 2433                                                       SymTab.InvalidType)
+ 2434   AND ((cls = SymTab.ClInt)
+ 2435                                                      OR (cls
+ 2436                                                          = SymTab.ClChar)
+ 2437                                                      OR (cls
+ 2438                                                          = SymTab.ClEnum)
+ 2439                                                      OR (cls
+ 2440                                                          = SymTab.ClReal)
+ 2441                                                      OR (cls
+ 2442                                                          = SymTab.ClLong)
  2443                                                      OR (cls
  2443                                                      OR (cls
- 2444                                                          = SymTab.ClChar)
- 2445                                                      OR (cls
- 2446                                                          = SymTab.ClEnum)
- 2447                                                      OR (cls
- 2448                                                          = SymTab.ClReal)
- 2449                                                      OR (cls
- 2450                                                          = SymTab.ClLong)
- 2451                                                      OR (cls
- 2452                                                          = SymTab.ClNil)) THEN
- 2453                                                     IF cls = SymTab.ClNil THEN
- 2454                                                       QbeGen.CopyOp("0", q)
- 2455                                                     ELSIF ((cls
- 2456                                                         = SymTab.ClInt)
- 2457                                                       OR (cls
- 2458                                                         = SymTab.ClChar)
- 2459                                                       OR (cls
- 2460                                                         = SymTab.ClEnum)
- 2461                                                       OR (cls
- 2462                                                         = SymTab.ClLong))
- 2463    AND SymTab.GetSymVal(n, cv)
- 2464    AND QbeGen.IsImm(cv) THEN
- 2465                                                       QbeGen.CopyOp(cv, q)
- 2466                                                     ELSE
- 2467                                                       QbeGen.LoadVar(n,
- 2468                                                         cls = SymTab.ClReal,
- 2469                                                         q)
- 2470                                                     END
- 2471                                                   ELSIF (cls = SymTab.ClArray)
- 2472                                                      OR (cls = SymTab.ClRecord)
- 2473                                                      OR (cls = SymTab.ClClass)
- 2474                                                      OR (cls = SymTab.ClStr)
- 2475                                                      OR (cls = SymTab.ClUStr) THEN
- 2476                                                     (* aggregate constant:
- 2477                                                        its value IS the
- 2478                                                        descriptor address *)
- 2479                                                     IF SymTab.GetSymVal(n, cv) THEN
- 2480                                                       QbeGen.CopyOp(cv, q)
- 2481                                                     ELSE
- 2482                                                       QbeGen.CopyOp("0", q)
- 2483                                                     END
- 2484                                                   ELSE
- 2485                                                     IF t #
- 2486                                                        SymTab.InvalidType THEN
- 2487                                                       SemError(230)
- 2488                                                     END;
- 2489                                                     QbeGen.CopyOp("0", q)
- 2490                                                   END
- 2491                                                 END
- 2492                                               ELSIF (k = SymTab.KindVar)
- 2493                                                  OR (k = SymTab.KindParam) THEN
- 2494                                                 cls := SymTab.ClassOf(t);
- 2495                                                 IF (cls # SymTab.ClInt)
- 2496                                                    AND (cls # SymTab.ClBool)
- 2497                                                    AND (cls # SymTab.ClChar)
- 2498                                                    AND (cls # SymTab.ClUChar)
- 2499                                                    AND (cls # SymTab.ClEnum)
- 2500                                                    AND (cls # SymTab.ClReal)
- 2501                                                    AND (cls # SymTab.ClPtr)
- 2502                                                    AND (cls # SymTab.ClProc)
- 2503                                                    AND (cls # SymTab.ClLong)
- 2504                                                    AND (cls # SymTab.ClArray)
- 2505                                                    AND (cls # SymTab.ClSet)
- 2506                                                    AND (cls # SymTab.ClRecord)
- 2507                                                    AND (cls # SymTab.ClUStr)
- 2508                                                    AND (cls # SymTab.ClClass) THEN
- 2509                                                   SemError(230);
- 2510                                                   QbeGen.CopyOp("0", q)
- 2511                                                 ELSE QbeGen.CopyOp("@", q)
- 2512                                                 END
- 2513                                               ELSE QbeGen.CopyOp("0", q);
- 2514                                                 IF k = SymTab.KindImport THEN
- 2515                                                   SemError(230)
- 2516                                                 ELSIF k =
- 2517                                                    SymTab.KindProc THEN
- 2518                                                   (* bare procedure name:
- 2519                                                      a following ArgList
- 2520                                                      makes it a call;
- 2521                                                      otherwise Fact
- 2522                                                      reports 230 *)
- 2523                                                 ELSE
- 2524                                                    IF k = SymTab.KindField THEN
- 2525                                                      IF QbeGen.TopWith(qb) THEN
- 2526                                                        sfx := TRUE
- 2527                                                      ELSE SemError(230);
- 2528                                                        QbeGen.CopyOp("0", q)
- 2529                                                      END
- 2530                                                    END
- 2531                                                 END
- 2532                                               END
- 2533                                             END; .)
- 2534        (. astDes := AST.MakeNode(AST.NkDesignator);
- 2535           AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .)
- 2536        { "[" Expr<it, iq>
- 2537                                          (. AST.SetChild(astDes, AST.NChild(astDes),
- 2538               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
- 2539                                             ELSIF SymTab.ClassOf(t) #
- 2540                                                   SymTab.ClArray THEN
- 2541                                               SemError(217);
- 2542                                               t := SymTab.InvalidType
- 2543                                             ELSIF NOT SymTab.IsIntFamily(it)
- 2544   AND (SymTab.ClassOf(it) #
- 2545                                                   SymTab.ClChar)
- 2546   AND (SymTab.ClassOf(it) #
- 2547                                                   SymTab.ClEnum) THEN
- 2548                                               SemError(218);
- 2549                                               t := SymTab.InvalidType
- 2550                                              ELSE
- 2551                                                eT := SymTab.ArrayElem(t);
- 2552                                                t := eT; sfx := TRUE
- 2553                                              END; .)
- 2554          { "," Expr<it, iq>
- 2555                                          (. AST.SetChild(astDes, AST.NChild(astDes),
- 2556               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
- 2557                                             ELSIF SymTab.ClassOf(t) #
- 2558                                                   SymTab.ClArray THEN
- 2559                                               SemError(217);
- 2560                                               t := SymTab.InvalidType
- 2561                                             ELSIF NOT SymTab.IsIntFamily(it)
- 2562   AND (SymTab.ClassOf(it) #
- 2563                                                   SymTab.ClChar)
- 2564   AND (SymTab.ClassOf(it) #
- 2565                                                   SymTab.ClEnum) THEN
- 2566                                               SemError(218);
- 2567                                               t := SymTab.InvalidType
- 2568                                              ELSE
- 2569                                                eT := SymTab.ArrayElem(t);
- 2570                                                t := eT; sfx := TRUE
- 2571                                              END; .) }
- 2572          "]"
- 2573        | "." GetIdent<fn>
- 2574                                          (. astSel := AST.MakeNode(AST.NkSelector);
- 2575               AST.SetOp(astSel, AST.SelField);
- 2576               AST.SetChild(astSel, 0, AST.MakeLeaf(AST.NkIdent, fn));
- 2577               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF k = SymTab.KindModule THEN
- 2578                                               (* qualified L.x: materialize
- 2579                                                  the export, then load it *)
- 2580                                               IF NOT SymTab.MaterializeAlias(n,
- 2581                                                    fn, mal) THEN
- 2582                                                 SemError(201);
- 2583                                                 t := SymTab.InvalidType;
- 2584                                                 QbeGen.CopyOp("0", q)
- 2585                                               ELSE
- 2586                                                 QbeGen.CopyOp(mal, qn);
- 2587                                                 t := SymTab.SymType(mal);
- 2588                                                 k := SymTab.SymKind(mal);
- 2589                                                 sfx := FALSE;
- 2590                                                 IF k = SymTab.KindProc THEN
- 2591                                                   (* call: ArgList supplies
- 2592                                                      the value *)
- 2593                                                   QbeGen.CopyOp("0", q)
- 2594                                                  END
- 2595                                               END
- 2596                                             ELSIF t = SymTab.InvalidType THEN
- 2597                                             ELSIF (SymTab.ClassOf(t) #
- 2598                                                    SymTab.ClRecord)
- 2599   AND (SymTab.ClassOf(t) #
- 2600                                                   SymTab.ClClass) THEN
- 2601                                               SemError(215);
- 2602                                               t := SymTab.InvalidType
- 2603                                             ELSIF (SymTab.ClassOf(t) =
- 2604                                                    SymTab.ClClass)
- 2605    AND SymTab.MethodExists(t, fn) THEN
- 2606                                               (* obj.Method: bind the
- 2607                                                  method and pass obj as
- 2608                                                  the hidden receiver; q
- 2609                                                  already holds the
- 2610                                                  object's address *)
- 2611                                               QbeGen.CopyOp(fn, n);
- 2612                                               QbeGen.CopyOp(fn, qn);
- 2613                                               methCls := t;
- 2614                                               k := SymTab.KindProc;
- 2615                                               t := SymTab.InvalidType
- 2616                                             ELSIF NOT SymTab.FieldExists(t,
- 2617                                                      fn) THEN
- 2618                                               SemError(216);
- 2619                                               t := SymTab.InvalidType
- 2620                                              ELSE
- 2621                                                t := SymTab.FieldType(t, fn);
- 2622                                                sfx := TRUE
- 2623                                              END; .)
- 2624        | "^"
- 2625                                          (. astSel := AST.MakeNode(AST.NkSelector);
- 2626               AST.SetOp(astSel, AST.SelDeref);
- 2627               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF t = SymTab.InvalidType THEN
- 2628                                             ELSIF SymTab.ClassOf(t) #
- 2629                                                   SymTab.ClPtr THEN
- 2630                                               SemError(219);
- 2631                                               t := SymTab.InvalidType
- 2632                                             ELSE
- 2633                                               bt := SymTab.PtrBase(t);
- 2634                                               IF bt = SymTab.InvalidType THEN
- 2635                                               ELSE
- 2636                                                  t := bt;
- 2637                                                  sfx := TRUE
- 2638                                                END
- 2639                                             END; .) } (. astCur := astDes; .) .
- 2640    (* Result suffix (ISO component after a function call): `F()^`,
- 2641       `F()[i]`, `F().field`.  The call result is in t/q with sfx FALSE
- 2642       (a value, or a descriptor address for aggregates); each component
- 2643       descends one level exactly like the Design components. *)
- 2644    ResultComp<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
- 2645               VAR sfx: BOOLEAN; VAR node: AST.Node;
- 2646               VAR mname: SymTab.Name; VAR methCls: SymTab.TypeIndex;
- 2647               VAR isM: BOOLEAN>          (. VAR it, eT, bt: SymTab.TypeIndex;
- 2648                                               iq, ql, qlo, qhi, qe, qb:
- 2649                                                 QbeGen.QVal;
- 2650                                               lo, hi, fo: INTEGER;
- 2651                                               isOpen: BOOLEAN;
- 2652                                               fname: SymTab.Name;
- 2653                                               astWrap, astSel: AST.Node; .)
- 2654      = "[" Expr<it, iq>
- 2655                                          (. isM := FALSE;
- 2656                                             IF AST.Kind(node) # AST.NkDesignator THEN
- 2657                                               astWrap := AST.MakeNode(
- 2658                                                 AST.NkDesignator);
- 2659                                               AST.SetChild(astWrap, 0, node);
- 2660                                               node := astWrap
- 2661                                             END;
- 2662                                             AST.SetChild(node, AST.NChild(node),
- 2663                                               AST.MakeUn(AST.NkSelector,
- 2664                                                 AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
- 2665                                             ELSIF SymTab.ClassOf(t) #
- 2666                                                   SymTab.ClArray THEN
- 2667                                               SemError(217);
- 2668                                               t := SymTab.InvalidType
- 2669                                             ELSIF NOT SymTab.IsIntFamily(it)
- 2670    AND (SymTab.ClassOf(it) # SymTab.ClChar)
- 2671    AND (SymTab.ClassOf(it) # SymTab.ClEnum) THEN
- 2672                                               SemError(218);
- 2673                                               t := SymTab.InvalidType
- 2674                                              ELSE
- 2675                                                eT := SymTab.ArrayElem(t);
- 2676                                                t := eT; sfx := TRUE
- 2677                                              END; .)
- 2678        "]"
- 2679      | "." GetIdent<fname>
- 2680                                          (. isM := FALSE;
- 2681                                             IF AST.Kind(node) # AST.NkDesignator THEN
- 2682                                               astWrap := AST.MakeNode(
- 2683                                                 AST.NkDesignator);
- 2684                                               AST.SetChild(astWrap, 0, node);
- 2685                                               node := astWrap
- 2686                                             END;
- 2687                                             AST.SetChild(node, AST.NChild(node),
- 2688                                               AST.MakeUn(AST.NkSelector,
- 2689                                                 AST.SelField,
- 2690                                                 AST.MakeLeaf(AST.NkIdent,
- 2691                                                   fname))); IF t = SymTab.InvalidType THEN
- 2692                                             ELSIF (SymTab.ClassOf(t) #
- 2693                                                    SymTab.ClRecord)
- 2694    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
- 2695                                               SemError(215);
- 2696                                               t := SymTab.InvalidType
- 2697                                              ELSIF (SymTab.ClassOf(t) =
- 2698                                                     SymTab.ClClass)
- 2699    AND SymTab.MethodExists(t, fname) THEN
- 2700                                                (* a method on the call result:
- 2701                                                   a following ArgList makes
- 2702                                                   the call *)
- 2703                                                mname := fname;
- 2704                                                methCls := t; isM := TRUE;
- 2705                                                t := SymTab.InvalidType
- 2706                                             ELSIF NOT SymTab.FieldExists(t,
- 2707                                                      fname) THEN
- 2708                                               SemError(216);
- 2709                                               t := SymTab.InvalidType
- 2710                                              ELSE
- 2711                                                t := SymTab.FieldType(t, fname);
- 2712                                                sfx := TRUE
- 2713                                              END; .)
- 2714      | "^"                               (. isM := FALSE;
- 2715                                             IF AST.Kind(node) # AST.NkDesignator THEN
- 2716                                               astWrap := AST.MakeNode(
- 2717                                                 AST.NkDesignator);
- 2718                                               AST.SetChild(astWrap, 0, node);
- 2719                                               node := astWrap
- 2720                                             END;
- 2721                                             astSel := AST.MakeNode(AST.NkSelector);
- 2722                                             AST.SetOp(astSel, AST.SelDeref);
- 2723                                             AST.SetChild(node,
- 2724                                               AST.NChild(node), astSel); IF t = SymTab.InvalidType THEN
- 2725                                             ELSIF SymTab.ClassOf(t) #
- 2726                                                   SymTab.ClPtr THEN
- 2727                                               SemError(219);
- 2728                                               t := SymTab.InvalidType
- 2729                                             ELSE
- 2730                                               bt := SymTab.PtrBase(t);
- 2731                                               IF bt # SymTab.InvalidType THEN
- 2732                                                  t := bt; sfx := TRUE
- 2733                                               END
- 2734                                             END; .) .
- 2735    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2736                                          (. VAR t2: SymTab.TypeIndex;
- 2737                                               op: INTEGER;
- 2738                                               q2, qt, wl: QbeGen.QVal;
- 2739                                                astA, astB: AST.Node;
- 2740                                                astOp: INTEGER;
- 2741                                                astMade: BOOLEAN;
- 2742                                               isR: BOOLEAN; .)
- 2743      = SimExpr<t, q>                     (. astA := astCur; astMade := FALSE; .)
- 2744        [ Rel<op> SimExpr<t2, q2>
- 2745          (. astB := astCur; astMade := TRUE;
- 2746              astOp := AST.OpEq;
- 2747              IF op = SymTab.OpNeq1 THEN astOp := AST.OpNe
- 2748              ELSIF op = SymTab.OpNeq2 THEN astOp := AST.OpNe
- 2749              ELSIF op = SymTab.OpLt THEN astOp := AST.OpLt
- 2750              ELSIF op = SymTab.OpLe THEN astOp := AST.OpLe
- 2751              ELSIF op = SymTab.OpGt THEN astOp := AST.OpGt
- 2752              ELSIF op = SymTab.OpGe THEN astOp := AST.OpGe
- 2753              ELSIF op = SymTab.OpIn THEN astOp := AST.OpIn
- 2754              END;
- 2755              IF op = SymTab.OpIn THEN
- 2756               IF SymTab.InCheck(t, t2) THEN
- 2757                 IF (t = SymTab.InvalidType)
- 2758                    OR (t2 = SymTab.InvalidType) THEN
- 2759                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 2760                 ELSE
- 2761                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 2762                 END
- 2763               ELSE SemError(222); t := SymTab.InvalidType;
- 2764                 QbeGen.CopyOp("0", q)
- 2765               END
- 2766             ELSIF SymTab.RelCheck(t, t2, op) THEN
- 2767               IF (t = SymTab.InvalidType)
- 2768                  OR (t2 = SymTab.InvalidType) THEN
- 2769                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 2770               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
- 2771                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
- 2772                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
- 2773   AND (op # SymTab.OpNeq2) THEN
- 2774                   SemError(213); t := SymTab.InvalidType;
- 2775                   QbeGen.CopyOp("0", q)
- 2776                  ELSE
- 2777                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 2778                  END
- 2779                ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
- 2780                   OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 2781                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 2782               ELSIF SymTab.StrCompat(t, t2) THEN
- 2783                 QbeGen.StrEq(op, q, q2, qt);
- 2784                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 2785               ELSIF SymTab.IsLongFamily(t)
- 2786                  OR SymTab.IsLongFamily(t2) THEN
- 2787                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 2788                ELSE
- 2789                  t := SymTab.BoolType();
- 2790                  QbeGen.CopyOp("@", q)
- 2791                END
- 2792             ELSE SemError(213); t := SymTab.InvalidType;
- 2793                QbeGen.CopyOp("0", q)
- 2794              END;
- 2795              astCur := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); .) ]
- 2796         (. IF NOT astMade THEN astCur := astA END; .)
- 2797             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 2798    Rel<VAR op: INTEGER>
- 2799      = "="                               (. op := SymTab.OpEq; .)
- 2800      | "#"                               (. op := SymTab.OpNeq1; .)
- 2801      | "<"                               (. op := SymTab.OpLt; .)
- 2802      | "<="                              (. op := SymTab.OpLe; .)
- 2803      | ">"                               (. op := SymTab.OpGt; .)
- 2804      | ">="                              (. op := SymTab.OpGe; .)
- 2805      | "IN"                              (. op := SymTab.OpIn; .) .
- 2806    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2807                                          (. VAR t2, res2, lt, rt:
- 2808                                                 SymTab.TypeIndex;
- 2809                                               op: INTEGER;
- 2810                                               q2, qt, wq, qf, q2a, q2b:
- 2811                                                 QbeGen.QVal;
- 2812                                               neg, isR, isL, folded:
- 2813                                                 BOOLEAN;
- 2814                                               fok: BOOLEAN;
- 2815                                               lw, rw, mw: CARDINAL;
- 2816                                               lTrue, lNext, lDone, qr, qs: QbeGen.QVal;
- 2817                                                astA, astB: AST.Node;
- 2818                                                astSign, astOp: INTEGER; .)
- 2819      =                                   (. neg := FALSE; astSign := 0; .)
- 2820        [ "+"                         (. neg := TRUE; astSign := 1; .)
- 2821        | "-"                         (. neg := TRUE; astSign := -1; .) ]
- 2822        Term<t, q> (. astA := astCur;
- 2823                                            IF neg AND QbeGen.IsImm(q) THEN
- 2824                                              QbeGen.NegFold(q, q)
- 2825                                            END;
- 2826                                           IF astSign < 0 THEN
- 2827                                             astCur := AST.MakeUn(
- 2828                                               AST.NkUnary, AST.OpSub, astA);
- 2829                                             astA := astCur
- 2830                                           END; .)
- 2831         { AddOp<op>
- 2832           Term<t2, q2> (. astB := astCur; .)
- 2833          (. astOp := AST.OpAdd;
- 2834             IF op = SymTab.OpSub THEN astOp := AST.OpSub
- 2835             ELSIF op = SymTab.OpOr THEN astOp := AST.OpOr END;
- 2836             astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
- 2837             astCur := astA;
- 2838             IF op = SymTab.OpOr THEN
- 2839               (* short-circuit: if q is true the RHS is skipped *)
- 2840               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 2841                 t := SymTab.BoolType()
- 2842               ELSE SemError(212); t := SymTab.InvalidType END;
- 2843                IF t # SymTab.InvalidType THEN
- 2844                  QbeGen.CopyOp("@", q)
- 2845                ELSE QbeGen.CopyOp("0", q)
- 2846                END
- 2847             ELSIF (op = SymTab.OpAdd)
- 2848               AND (SymTab.UStrCompat(t, t2)
- 2849                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
- 2850                   AND (SymTab.ClassOf(t2) = SymTab.ClUStr))
- 2851                 OR ((SymTab.ClassOf(t) = SymTab.ClUStr)
- 2852                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))
- 2853                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
- 2854                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN
- 2855               (* UString concatenation: a UCHAR operand becomes a
- 2856                  1-codepoint UString; the result is a descriptor in the
- 2857                  shim's concat buffer.  Work on copies so neither
- 2858                  operand is clobbered. *)
- 2859                t := SymTab.NewUStr();
- 2860                QbeGen.CopyOp("@", q)
- 2861             ELSIF (op = SymTab.OpAdd)
- 2862               AND (SymTab.StrCompat(t, t2)
- 2863                 OR (SymTab.IsStrType(t)
- 2864                   AND (SymTab.ClassOf(t2) = SymTab.ClChar))
- 2865                 OR ((SymTab.ClassOf(t) = SymTab.ClChar)
- 2866                   AND SymTab.IsStrType(t2))) THEN
- 2867               (* string concatenation; a CHAR operand becomes a
- 2868                  1-character string literal.  When both operands are
- 2869                  constants, fold to a single string literal so a
- 2870                  constructor element stays compile-time. *)
- 2871                QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2),
- 2872                  qt, fok);
- 2873                IF fok THEN QbeGen.CopyOp(qt, q)
- 2874                ELSE QbeGen.CopyOp("@", q)
- 2875                END;
- 2876                t := SymTab.NewStr()
- 2877             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 2878   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 2879   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 2880                lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 2881                mw := lw;
- 2882                IF rw > mw THEN mw := rw END;
- 2883                t := SymTab.NewSet(
- 2884                       SymTab.NewSubR(0,
- 2885                         VAL(INTEGER, mw) * 32 - 1));
- 2886                QbeGen.CopyOp("@", q)
- 2887             ELSE
- 2888               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
- 2889                 lt := t; rt := t2; t := res2
- 2890               ELSE SemError(211); t := SymTab.InvalidType END;
- 2891               IF t # SymTab.InvalidType THEN
- 2892                 isL := SymTab.IsLongFamily(t);
- 2893                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 2894                 folded := FALSE;
- 2895                 IF (NOT isL) AND (NOT isR)
- 2896    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 2897                   IF op = SymTab.OpAdd THEN
- 2898                     folded := QbeGen.Fold2(0, q, q2, qf)
- 2899                   ELSE
- 2900                     folded := QbeGen.Fold2(1, q, q2, qf)
- 2901                   END
- 2902                 END;
- 2903                 IF folded THEN QbeGen.CopyOp(qf, q)
- 2904                  ELSE
- 2905                  QbeGen.CopyOp("@", q)
- 2906                  END
- 2907               ELSE QbeGen.CopyOp("0", q)
- 2908               END
- 2909             END; .) }
- 2910             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 2911    AddOp<VAR op: INTEGER>
- 2912      = "+"                               (. op := SymTab.OpAdd; .)
- 2913      | "-"                               (. op := SymTab.OpSub; .)
- 2914      | "OR"                              (. op := SymTab.OpOr; .) .
- 2915    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2916                                          (. VAR t2, res2, lt, rt:
- 2917                                                 SymTab.TypeIndex;
- 2918                                               op: INTEGER;
- 2919                                               q2, qt, wq, qf:
- 2920                                                 QbeGen.QVal;
- 2921                                               isR, isL, folded: BOOLEAN;
- 2922                                               lw, rw, mw: CARDINAL;
- 2923                                               lNext, lFalse, lDone, qr, qs: QbeGen.QVal;
- 2924                                                astA, astB: AST.Node;
- 2925                                                astOp: INTEGER; .)
- 2926      = Fact<t, q> (. astA := astCur; .) { MulOp<op>
- 2927          Fact<t2, q2> (. astB := astCur; .)
- 2928        (. astOp := AST.OpMul;
- 2929           IF op = SymTab.OpSlash THEN astOp := AST.OpDiv
- 2930           ELSIF op = SymTab.OpDiv THEN astOp := AST.OpDiv
- 2931           ELSIF op = SymTab.OpMod THEN astOp := AST.OpMod
- 2932           ELSIF op = SymTab.OpAnd THEN astOp := AST.OpAnd END;
- 2933           astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
- 2934           astCur := astA;
- 2935           IF op = SymTab.OpAnd THEN
- 2936             (* short-circuit: if q is false the RHS is skipped *)
- 2937             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 2938               t := SymTab.BoolType()
- 2939             ELSE SemError(212); t := SymTab.InvalidType END;
- 2940              IF t # SymTab.InvalidType THEN QbeGen.CopyOp("@", q)
- 2941              ELSE QbeGen.CopyOp("0", q)
- 2942              END
- 2943           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 2944   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 2945   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 2946              lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 2947              mw := lw;
- 2948              IF rw > mw THEN mw := rw END;
- 2949              t := SymTab.NewSet(
- 2950                     SymTab.NewSubR(0,
- 2951                       VAL(INTEGER, mw) * 32 - 1));
- 2952              QbeGen.CopyOp("@", q)
- 2953           ELSE
- 2954             IF SymTab.ArithCheck(t, t2,
- 2955                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
- 2956                  res2) THEN
- 2957               lt := t; rt := t2; t := res2
- 2958             ELSE SemError(211); t := SymTab.InvalidType END;
- 2959             IF t # SymTab.InvalidType THEN
- 2960               isL := SymTab.IsLongFamily(t);
- 2961               isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 2962               folded := FALSE;
- 2963               IF (NOT isL) AND (NOT isR)
- 2964    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 2965                 IF op = SymTab.OpTimes THEN
- 2966                   folded := QbeGen.Fold2(2, q, q2, qf)
- 2967                 ELSIF op = SymTab.OpDiv THEN
- 2968                   folded := QbeGen.Fold2(3, q, q2, qf)
- 2969                 ELSIF op = SymTab.OpMod THEN
- 2970                   folded := QbeGen.Fold2(4, q, q2, qf)
- 2971                 END
- 2972               END;
- 2973               IF folded THEN QbeGen.CopyOp(qf, q)
- 2974                ELSE
- 2975                QbeGen.CopyOp("@", q)
- 2976                END
- 2977             ELSE QbeGen.CopyOp("0", q)
- 2978             END
- 2979           END; .) }
- 2980             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 2981    MulOp<VAR op: INTEGER>
- 2982      = "*"                               (. op := SymTab.OpTimes; .)
- 2983      | "/"                               (. op := SymTab.OpSlash; .)
- 2984      | "DIV"                             (. op := SymTab.OpDiv; .)
- 2985      | "MOD"                             (. op := SymTab.OpMod; .)
- 2986      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
- 2987    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2988                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
- 2989                                               et, dt, t2, st, ct2, et2:
- 2990                                                 SymTab.TypeIndex;
- 2991                                               dk: INTEGER;
- 2992                                               qd, q2, sq, qa, qm0, qr, qt:
- 2993                                                 QbeGen.QVal;
- 2994                                               qn, vn: SymTab.Name;
- 2995                                               vt: SymTab.TypeIndex;
- 2996                                               c1, c2: INTEGER;
- 2997                                               lo, hi: INTEGER;
- 2998                                               isMax: BOOLEAN;
- 2999                                               called, isHigh, sfx, isCh,
- 3000                                               isU, uok, isStr: BOOLEAN;
- 3001                                               ucp: INTEGER; astIsLit: BOOLEAN;
- 3002                                                astD: AST.Node;
- 3003                                                astCall: BOOLEAN;
- 3004                                                astNode, astNot: AST.Node;
- 3005                                                j: CARDINAL;
- 3006                                                astArg2: AST.Node;
- 3007                                                astBrace: AST.Node;
- 3008                                                astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN; .)
- 3009      = (. astIsLit := FALSE; .)
- 3010      ( integer                           (. LexString(s);
- 3011                                             QbeGen.NormInt(s, q); IF twoPhase THEN astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s) END;
- 3012                                             t := SymTab.IntType(); .)
- 3013      | charConst                         (. LexString(s);
- 3014                                             QbeGen.NormLit(s, q, isCh);
- 3015                                             IF twoPhase THEN
- 3016                                               astIsLit := TRUE;
- 3017                                               astCur := AST.MakeLeaf(
- 3018                                                 AST.NkCharLit, s)
- 3019                                             END;
- 3020                                             t := SymTab.CharType(); .)
- 3021      | real                              (. LexString(s);
- 3022                                             QbeGen.NormReal(s, q);
- 3023                                             IF twoPhase THEN
- 3024                                               astIsLit := TRUE;
- 3025                                               astCur := AST.MakeLeaf(
- 3026                                                 AST.NkRealLit, s)
- 3027                                             END;
- 3028                                             t := SymTab.RealType(); .)
- 3029      | string                            (. LexString(s);
- 3030                                             IF twoPhase THEN
- 3031                                               astIsLit := TRUE;
- 3032                                               astCur := AST.MakeLeaf(
- 3033                                                 AST.NkStrLit, s)
- 3034                                             END;
- 3035                                             IF SymTab.StrLen(s) = 3 THEN
- 3036                                               t := SymTab.CharType();
- 3037                                               QbeGen.IntStr(
- 3038                                                 QbeGen.CharVal(s), q)
- 3039                                             ELSE t := SymTab.NewStr();
- 3040                                               QbeGen.DeclStr(s, q);
- 3041                                               (* a literal's value IS its
- 3042                                                  static descriptor address *)
- 3043                                             END; .)
- 3044      | ustring                           (. LexString(s);
- 3045                                             IF twoPhase THEN
- 3046                                               astIsLit := TRUE;
- 3047                                               astCur := AST.MakeLeaf(
- 3048                                                 AST.NkStrLit, s)
- 3049                                             END;
- 3050                                             QbeGen.DeclUStr(s, q, isU, ucp,
- 3051                                               uok);
- 3052                                             IF NOT uok THEN
- 3053                                               SemError(234);
- 3054                                               t := SymTab.InvalidType
- 3055                                             ELSIF isU THEN
- 3056                                               t := SymTab.UCharType();
- 3057                                               QbeGen.IntStr(ucp, q)
- 3058                                             ELSE
- 3059                                               t := SymTab.NewUStr();
- 3060                                             END; .)
- 3061      | Design<dt, dk, qd, qn, sfx>       (. astD := astCur; astCall := FALSE; astBrace := AST.NoNode;
- 3062                                             astNArgs := 0; called := FALSE;
- 3063                                             t := dt;
- 3064                                             IF dk = SymTab.KindConst THEN
- 3065                                               QbeGen.CopyOp(qd, q)
- 3066                                             ELSE QbeGen.CopyOp("@", q)
- 3067                                             END; .)
- 3068        [ TypedBraceLit<dt, q>            (. t := dt; astCall := TRUE;
- 3069                                               astBrace := astCur; .) ]
- 3070        [ ArgList<qn, dt, qd, TRUE, FALSE, methCls, ct2, q2, called>
- 3071                                          (. astCall := TRUE;
- 3072                                             astNode := AstCallNode(astD);
- 3073                                             astRes := astNode;
- 3074                                             t := ct2;
- 3075                                             QbeGen.CopyOp(q2, q);
- 3076                                             sfx := FALSE; .)
- 3077          { ResultComp<t, q, sfx, astRes, mname, methCls, isM>
- 3078            [ (. astNArgs := 0; .)
- 3079              ArgList<mname, t, q, TRUE, FALSE, methCls, ct2, q2, called>
- 3080                                          (. astNode := AstCallNode(astRes);
- 3081                                             astRes := astNode;
- 3082                                             t := ct2;
- 3083                                             QbeGen.CopyOp(q2, q);
- 3084                                             sfx := FALSE; .) ] }
- 3085                                          (. IF sfx THEN
- 3086                                               IF t = SymTab.InvalidType THEN
- 3087                                                 QbeGen.CopyOp("0", q)
- 3088                                               ELSIF (SymTab.ClassOf(t) #
- 3089                                                      SymTab.ClRecord)
- 3090    AND (SymTab.ClassOf(t) # SymTab.ClSet)
- 3091    AND (SymTab.ClassOf(t) # SymTab.ClArray)
- 3092    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
- 3093                                                  QbeGen.CopyOp("@", q)
- 3094                                               END
- 3095                                             END; .) ]
- 3096                                          (. IF called THEN
- 3097                                               astCur := astRes
- 3098                                             ELSIF astCall THEN
- 3099                                               astCur := astBrace
- 3100                                             ELSE astCur := astD
- 3101                                             END;
- 3102                                              astIsLit := TRUE;
- 3103                                              IF NOT called
- 3104   AND (dk = SymTab.KindProc) THEN
- 3105                                               (* bare zero-arg function
- 3106                                                  call (parentheses may be
- 3107                                                  omitted); a proper or
- 3108                                                  parameterised proc here
- 3109                                                  is 230 *)
- 3110                                                IF (SymTab.ProcNPar(qn) = 0)
- 3111   AND (SymTab.ProcRes(qn) # SymTab.InvalidType) THEN
- 3112                                                  t := SymTab.ProcRes(qn);
- 3113                                                  QbeGen.CopyOp("@", q);
- 3114                                                  astCur := AST.MakeNode(AST.NkCall);
- 3115                                                  AST.SetChild(astCur, 0, astD)
- 3116                                                ELSE
- 3117                                                  t := SymTab.ProcTypeOf(qn);
- 3118                                                  QbeGen.CopyOp("@", q)
- 3119                                                END
- 3120                                             END; .)
- 3121      | ( "HIGH"                          (. isHigh := TRUE; .)
- 3122        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
- 3123        "(" ( Design<dt, dk, qd, qn, sfx> (. isStr := FALSE;
- 3124                                              isU := FALSE; .)
- 3125            | string                       (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
- 3126                                              isStr := TRUE;
- 3127                                              isU := FALSE;
- 3128                                              IF SymTab.StrLen(s) = 3 THEN
- 3129                                                dt := SymTab.CharType();
- 3130                                                QbeGen.IntStr(QbeGen.CharVal(s),
- 3131                                                  qd)
- 3132                                              ELSE
- 3133                                                dt := SymTab.NewStr();
- 3134                                                QbeGen.DeclStr(s, qd);
- 3135                                              END;
- 3136                                              dk := -1;
- 3137                                              qn[0] := CHR(0); .)
- 3138            | ustring                      (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
- 3139                                              QbeGen.DeclUStr(s, qd, isU, ucp,
- 3140                                                uok);
- 3141                                              isStr := FALSE;
- 3142                                              IF NOT uok THEN
- 3143                                                SemError(234);
- 3144                                                dt := SymTab.InvalidType
- 3145                                              ELSIF isU THEN
- 3146                                                (* one codepoint: a UCHAR;
- 3147                                                   LEN is 1, HIGH is 0 *)
- 3148                                                dt := SymTab.UCharType();
- 3149                                                QbeGen.IntStr(ucp, qd)
- 3150                                              ELSE
- 3151                                                dt := SymTab.NewUStr();
- 3152                                              END;
- 3153                                              dk := -1;
- 3154                                              qn[0] := CHR(0); .) )
- 3155        ")"
- 3156                                          (. astNode := AST.MakeNode(AST.NkCall);
- 3157     IF isHigh THEN AST.SetChild(astNode, 0,
- 3158       AST.MakeLeaf(AST.NkIdent, "HIGH"))
- 3159     ELSE AST.SetChild(astNode, 0,
- 3160       AST.MakeLeaf(AST.NkIdent, "LEN")) END;
- 3161     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3162     astCur := astNode; astIsLit := TRUE;
- 3163                                             IF (dt # SymTab.InvalidType)
- 3164    AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN
- 3165                                               (* UString: the count is
- 3166                                                  the descriptor header *)
- 3167                                                t := SymTab.IntType();
- 3168                                                QbeGen.CopyOp("@", q)
- 3169                                             ELSIF (dt # SymTab.InvalidType)
- 3170    AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN
- 3171                                               (* single UCHAR codepoint *)
+ 2444                                                          = SymTab.ClNil)) THEN
+ 2445                                                     IF cls = SymTab.ClNil THEN
+ 2446                                                       QbeGen.CopyOp("0", q)
+ 2447                                                     ELSIF ((cls
+ 2448                                                         = SymTab.ClInt)
+ 2449                                                       OR (cls
+ 2450                                                         = SymTab.ClChar)
+ 2451                                                       OR (cls
+ 2452                                                         = SymTab.ClEnum)
+ 2453                                                       OR (cls
+ 2454                                                         = SymTab.ClLong))
+ 2455    AND SymTab.GetSymVal(n, cv)
+ 2456    AND QbeGen.IsImm(cv) THEN
+ 2457                                                       QbeGen.CopyOp(cv, q)
+ 2458                                                     ELSE
+ 2459                                                       QbeGen.LoadVar(n,
+ 2460                                                         cls = SymTab.ClReal,
+ 2461                                                         q)
+ 2462                                                     END
+ 2463                                                   ELSIF (cls = SymTab.ClArray)
+ 2464                                                      OR (cls = SymTab.ClRecord)
+ 2465                                                      OR (cls = SymTab.ClClass)
+ 2466                                                      OR (cls = SymTab.ClStr)
+ 2467                                                      OR (cls = SymTab.ClUStr) THEN
+ 2468                                                     (* aggregate constant:
+ 2469                                                        its value IS the
+ 2470                                                        descriptor address *)
+ 2471                                                     IF SymTab.GetSymVal(n, cv) THEN
+ 2472                                                       QbeGen.CopyOp(cv, q)
+ 2473                                                     ELSE
+ 2474                                                       QbeGen.CopyOp("0", q)
+ 2475                                                     END
+ 2476                                                   ELSE
+ 2477                                                     IF t #
+ 2478                                                        SymTab.InvalidType THEN
+ 2479                                                       SemError(230)
+ 2480                                                     END;
+ 2481                                                     QbeGen.CopyOp("0", q)
+ 2482                                                   END
+ 2483                                                 END
+ 2484                                               ELSIF (k = SymTab.KindVar)
+ 2485                                                  OR (k = SymTab.KindParam) THEN
+ 2486                                                 cls := SymTab.ClassOf(t);
+ 2487                                                 IF (cls # SymTab.ClInt)
+ 2488                                                    AND (cls # SymTab.ClBool)
+ 2489                                                    AND (cls # SymTab.ClChar)
+ 2490                                                    AND (cls # SymTab.ClUChar)
+ 2491                                                    AND (cls # SymTab.ClEnum)
+ 2492                                                    AND (cls # SymTab.ClReal)
+ 2493                                                    AND (cls # SymTab.ClPtr)
+ 2494                                                    AND (cls # SymTab.ClProc)
+ 2495                                                    AND (cls # SymTab.ClLong)
+ 2496                                                    AND (cls # SymTab.ClArray)
+ 2497                                                    AND (cls # SymTab.ClSet)
+ 2498                                                    AND (cls # SymTab.ClRecord)
+ 2499                                                    AND (cls # SymTab.ClUStr)
+ 2500                                                    AND (cls # SymTab.ClClass) THEN
+ 2501                                                   SemError(230);
+ 2502                                                   QbeGen.CopyOp("0", q)
+ 2503                                                 ELSE QbeGen.CopyOp("@", q)
+ 2504                                                 END
+ 2505                                               ELSE QbeGen.CopyOp("0", q);
+ 2506                                                 IF k = SymTab.KindImport THEN
+ 2507                                                   SemError(230)
+ 2508                                                 ELSIF k =
+ 2509                                                    SymTab.KindProc THEN
+ 2510                                                   (* bare procedure name:
+ 2511                                                      a following ArgList
+ 2512                                                      makes it a call;
+ 2513                                                      otherwise Fact
+ 2514                                                      reports 230 *)
+ 2515                                                 ELSE
+ 2516                                                    IF k = SymTab.KindField THEN
+ 2517                                                      IF QbeGen.TopWith(qb) THEN
+ 2518                                                        sfx := TRUE
+ 2519                                                      ELSE SemError(230);
+ 2520                                                        QbeGen.CopyOp("0", q)
+ 2521                                                      END
+ 2522                                                    END
+ 2523                                                 END
+ 2524                                               END
+ 2525                                             END; .)
+ 2526        (. astDes := AST.MakeNode(AST.NkDesignator);
+ 2527           AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .)
+ 2528        { "[" Expr<it, iq>
+ 2529                                          (. AST.SetChild(astDes, AST.NChild(astDes),
+ 2530               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
+ 2531                                             ELSIF SymTab.ClassOf(t) #
+ 2532                                                   SymTab.ClArray THEN
+ 2533                                               SemError(217);
+ 2534                                               t := SymTab.InvalidType
+ 2535                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 2536   AND (SymTab.ClassOf(it) #
+ 2537                                                   SymTab.ClChar)
+ 2538   AND (SymTab.ClassOf(it) #
+ 2539                                                   SymTab.ClEnum) THEN
+ 2540                                               SemError(218);
+ 2541                                               t := SymTab.InvalidType
+ 2542                                              ELSE
+ 2543                                                eT := SymTab.ArrayElem(t);
+ 2544                                                t := eT; sfx := TRUE
+ 2545                                              END; .)
+ 2546          { "," Expr<it, iq>
+ 2547                                          (. AST.SetChild(astDes, AST.NChild(astDes),
+ 2548               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
+ 2549                                             ELSIF SymTab.ClassOf(t) #
+ 2550                                                   SymTab.ClArray THEN
+ 2551                                               SemError(217);
+ 2552                                               t := SymTab.InvalidType
+ 2553                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 2554   AND (SymTab.ClassOf(it) #
+ 2555                                                   SymTab.ClChar)
+ 2556   AND (SymTab.ClassOf(it) #
+ 2557                                                   SymTab.ClEnum) THEN
+ 2558                                               SemError(218);
+ 2559                                               t := SymTab.InvalidType
+ 2560                                              ELSE
+ 2561                                                eT := SymTab.ArrayElem(t);
+ 2562                                                t := eT; sfx := TRUE
+ 2563                                              END; .) }
+ 2564          "]"
+ 2565        | "." GetIdent<fn>
+ 2566                                          (. astSel := AST.MakeNode(AST.NkSelector);
+ 2567               AST.SetOp(astSel, AST.SelField);
+ 2568               AST.SetChild(astSel, 0, AST.MakeLeaf(AST.NkIdent, fn));
+ 2569               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF k = SymTab.KindModule THEN
+ 2570                                               (* qualified L.x: materialize
+ 2571                                                  the export, then load it *)
+ 2572                                               IF NOT SymTab.MaterializeAlias(n,
+ 2573                                                    fn, mal) THEN
+ 2574                                                 SemError(201);
+ 2575                                                 t := SymTab.InvalidType;
+ 2576                                                 QbeGen.CopyOp("0", q)
+ 2577                                               ELSE
+ 2578                                                 QbeGen.CopyOp(mal, qn);
+ 2579                                                 t := SymTab.SymType(mal);
+ 2580                                                 k := SymTab.SymKind(mal);
+ 2581                                                 sfx := FALSE;
+ 2582                                                 IF k = SymTab.KindProc THEN
+ 2583                                                   (* call: ArgList supplies
+ 2584                                                      the value *)
+ 2585                                                   QbeGen.CopyOp("0", q)
+ 2586                                                  END
+ 2587                                               END
+ 2588                                             ELSIF t = SymTab.InvalidType THEN
+ 2589                                             ELSIF (SymTab.ClassOf(t) #
+ 2590                                                    SymTab.ClRecord)
+ 2591   AND (SymTab.ClassOf(t) #
+ 2592                                                   SymTab.ClClass) THEN
+ 2593                                               SemError(215);
+ 2594                                               t := SymTab.InvalidType
+ 2595                                             ELSIF (SymTab.ClassOf(t) =
+ 2596                                                    SymTab.ClClass)
+ 2597    AND SymTab.MethodExists(t, fn) THEN
+ 2598                                               (* obj.Method: bind the
+ 2599                                                  method and pass obj as
+ 2600                                                  the hidden receiver; q
+ 2601                                                  already holds the
+ 2602                                                  object's address *)
+ 2603                                               QbeGen.CopyOp(fn, n);
+ 2604                                               QbeGen.CopyOp(fn, qn);
+ 2605                                               methCls := t;
+ 2606                                               k := SymTab.KindProc;
+ 2607                                               t := SymTab.InvalidType
+ 2608                                             ELSIF NOT SymTab.FieldExists(t,
+ 2609                                                      fn) THEN
+ 2610                                               SemError(216);
+ 2611                                               t := SymTab.InvalidType
+ 2612                                              ELSE
+ 2613                                                t := SymTab.FieldType(t, fn);
+ 2614                                                sfx := TRUE
+ 2615                                              END; .)
+ 2616        | "^"
+ 2617                                          (. astSel := AST.MakeNode(AST.NkSelector);
+ 2618               AST.SetOp(astSel, AST.SelDeref);
+ 2619               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF t = SymTab.InvalidType THEN
+ 2620                                             ELSIF SymTab.ClassOf(t) #
+ 2621                                                   SymTab.ClPtr THEN
+ 2622                                               SemError(219);
+ 2623                                               t := SymTab.InvalidType
+ 2624                                             ELSE
+ 2625                                               bt := SymTab.PtrBase(t);
+ 2626                                               IF bt = SymTab.InvalidType THEN
+ 2627                                               ELSE
+ 2628                                                  t := bt;
+ 2629                                                  sfx := TRUE
+ 2630                                                END
+ 2631                                             END; .) } (. astCur := astDes; .) .
+ 2632    (* Result suffix (ISO component after a function call): `F()^`,
+ 2633       `F()[i]`, `F().field`.  The call result is in t/q with sfx FALSE
+ 2634       (a value, or a descriptor address for aggregates); each component
+ 2635       descends one level exactly like the Design components. *)
+ 2636    ResultComp<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
+ 2637               VAR sfx: BOOLEAN; VAR node: AST.Node;
+ 2638               VAR mname: SymTab.Name; VAR methCls: SymTab.TypeIndex;
+ 2639               VAR isM: BOOLEAN>          (. VAR it, eT, bt: SymTab.TypeIndex;
+ 2640                                               iq, ql, qlo, qhi, qe, qb:
+ 2641                                                 QbeGen.QVal;
+ 2642                                               lo, hi, fo: INTEGER;
+ 2643                                               isOpen: BOOLEAN;
+ 2644                                               fname: SymTab.Name;
+ 2645                                               astWrap, astSel: AST.Node; .)
+ 2646      = "[" Expr<it, iq>
+ 2647                                          (. isM := FALSE;
+ 2648                                             IF AST.Kind(node) # AST.NkDesignator THEN
+ 2649                                               astWrap := AST.MakeNode(
+ 2650                                                 AST.NkDesignator);
+ 2651                                               AST.SetChild(astWrap, 0, node);
+ 2652                                               node := astWrap
+ 2653                                             END;
+ 2654                                             AST.SetChild(node, AST.NChild(node),
+ 2655                                               AST.MakeUn(AST.NkSelector,
+ 2656                                                 AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
+ 2657                                             ELSIF SymTab.ClassOf(t) #
+ 2658                                                   SymTab.ClArray THEN
+ 2659                                               SemError(217);
+ 2660                                               t := SymTab.InvalidType
+ 2661                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 2662    AND (SymTab.ClassOf(it) # SymTab.ClChar)
+ 2663    AND (SymTab.ClassOf(it) # SymTab.ClEnum) THEN
+ 2664                                               SemError(218);
+ 2665                                               t := SymTab.InvalidType
+ 2666                                              ELSE
+ 2667                                                eT := SymTab.ArrayElem(t);
+ 2668                                                t := eT; sfx := TRUE
+ 2669                                              END; .)
+ 2670        "]"
+ 2671      | "." GetIdent<fname>
+ 2672                                          (. isM := FALSE;
+ 2673                                             IF AST.Kind(node) # AST.NkDesignator THEN
+ 2674                                               astWrap := AST.MakeNode(
+ 2675                                                 AST.NkDesignator);
+ 2676                                               AST.SetChild(astWrap, 0, node);
+ 2677                                               node := astWrap
+ 2678                                             END;
+ 2679                                             AST.SetChild(node, AST.NChild(node),
+ 2680                                               AST.MakeUn(AST.NkSelector,
+ 2681                                                 AST.SelField,
+ 2682                                                 AST.MakeLeaf(AST.NkIdent,
+ 2683                                                   fname))); IF t = SymTab.InvalidType THEN
+ 2684                                             ELSIF (SymTab.ClassOf(t) #
+ 2685                                                    SymTab.ClRecord)
+ 2686    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
+ 2687                                               SemError(215);
+ 2688                                               t := SymTab.InvalidType
+ 2689                                              ELSIF (SymTab.ClassOf(t) =
+ 2690                                                     SymTab.ClClass)
+ 2691    AND SymTab.MethodExists(t, fname) THEN
+ 2692                                                (* a method on the call result:
+ 2693                                                   a following ArgList makes
+ 2694                                                   the call *)
+ 2695                                                mname := fname;
+ 2696                                                methCls := t; isM := TRUE;
+ 2697                                                t := SymTab.InvalidType
+ 2698                                             ELSIF NOT SymTab.FieldExists(t,
+ 2699                                                      fname) THEN
+ 2700                                               SemError(216);
+ 2701                                               t := SymTab.InvalidType
+ 2702                                              ELSE
+ 2703                                                t := SymTab.FieldType(t, fname);
+ 2704                                                sfx := TRUE
+ 2705                                              END; .)
+ 2706      | "^"                               (. isM := FALSE;
+ 2707                                             IF AST.Kind(node) # AST.NkDesignator THEN
+ 2708                                               astWrap := AST.MakeNode(
+ 2709                                                 AST.NkDesignator);
+ 2710                                               AST.SetChild(astWrap, 0, node);
+ 2711                                               node := astWrap
+ 2712                                             END;
+ 2713                                             astSel := AST.MakeNode(AST.NkSelector);
+ 2714                                             AST.SetOp(astSel, AST.SelDeref);
+ 2715                                             AST.SetChild(node,
+ 2716                                               AST.NChild(node), astSel); IF t = SymTab.InvalidType THEN
+ 2717                                             ELSIF SymTab.ClassOf(t) #
+ 2718                                                   SymTab.ClPtr THEN
+ 2719                                               SemError(219);
+ 2720                                               t := SymTab.InvalidType
+ 2721                                             ELSE
+ 2722                                               bt := SymTab.PtrBase(t);
+ 2723                                               IF bt # SymTab.InvalidType THEN
+ 2724                                                  t := bt; sfx := TRUE
+ 2725                                               END
+ 2726                                             END; .) .
+ 2727    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2728                                          (. VAR t2: SymTab.TypeIndex;
+ 2729                                               op: INTEGER;
+ 2730                                               q2, qt, wl: QbeGen.QVal;
+ 2731                                                astA, astB: AST.Node;
+ 2732                                                astOp: INTEGER;
+ 2733                                                astMade: BOOLEAN;
+ 2734                                               isR: BOOLEAN; .)
+ 2735      = SimExpr<t, q>                     (. astA := astCur; astMade := FALSE; .)
+ 2736        [ Rel<op> SimExpr<t2, q2>
+ 2737          (. astB := astCur; astMade := TRUE;
+ 2738              astOp := AST.OpEq;
+ 2739              IF op = SymTab.OpNeq1 THEN astOp := AST.OpNe
+ 2740              ELSIF op = SymTab.OpNeq2 THEN astOp := AST.OpNe
+ 2741              ELSIF op = SymTab.OpLt THEN astOp := AST.OpLt
+ 2742              ELSIF op = SymTab.OpLe THEN astOp := AST.OpLe
+ 2743              ELSIF op = SymTab.OpGt THEN astOp := AST.OpGt
+ 2744              ELSIF op = SymTab.OpGe THEN astOp := AST.OpGe
+ 2745              ELSIF op = SymTab.OpIn THEN astOp := AST.OpIn
+ 2746              END;
+ 2747              IF op = SymTab.OpIn THEN
+ 2748               IF SymTab.InCheck(t, t2) THEN
+ 2749                 IF (t = SymTab.InvalidType)
+ 2750                    OR (t2 = SymTab.InvalidType) THEN
+ 2751                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 2752                 ELSE
+ 2753                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 2754                 END
+ 2755               ELSE SemError(222); t := SymTab.InvalidType;
+ 2756                 QbeGen.CopyOp("0", q)
+ 2757               END
+ 2758             ELSIF SymTab.RelCheck(t, t2, op) THEN
+ 2759               IF (t = SymTab.InvalidType)
+ 2760                  OR (t2 = SymTab.InvalidType) THEN
+ 2761                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 2762               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
+ 2763                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
+ 2764                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
+ 2765   AND (op # SymTab.OpNeq2) THEN
+ 2766                   SemError(213); t := SymTab.InvalidType;
+ 2767                   QbeGen.CopyOp("0", q)
+ 2768                  ELSE
+ 2769                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 2770                  END
+ 2771                ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
+ 2772                   OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 2773                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 2774               ELSIF SymTab.StrCompat(t, t2) THEN
+ 2775                 QbeGen.StrEq(op, q, q2, qt);
+ 2776                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 2777               ELSIF SymTab.IsLongFamily(t)
+ 2778                  OR SymTab.IsLongFamily(t2) THEN
+ 2779                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 2780                ELSE
+ 2781                  t := SymTab.BoolType();
+ 2782                  QbeGen.CopyOp("@", q)
+ 2783                END
+ 2784             ELSE SemError(213); t := SymTab.InvalidType;
+ 2785                QbeGen.CopyOp("0", q)
+ 2786              END;
+ 2787              astCur := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); .) ]
+ 2788         (. IF NOT astMade THEN astCur := astA END; .)
+ 2789             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 2790    Rel<VAR op: INTEGER>
+ 2791      = "="                               (. op := SymTab.OpEq; .)
+ 2792      | "#"                               (. op := SymTab.OpNeq1; .)
+ 2793      | "<"                               (. op := SymTab.OpLt; .)
+ 2794      | "<="                              (. op := SymTab.OpLe; .)
+ 2795      | ">"                               (. op := SymTab.OpGt; .)
+ 2796      | ">="                              (. op := SymTab.OpGe; .)
+ 2797      | "IN"                              (. op := SymTab.OpIn; .) .
+ 2798    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2799                                          (. VAR t2, res2, lt, rt:
+ 2800                                                 SymTab.TypeIndex;
+ 2801                                               op: INTEGER;
+ 2802                                               q2, qt, wq, qf, q2a, q2b:
+ 2803                                                 QbeGen.QVal;
+ 2804                                               neg, isR, isL, folded:
+ 2805                                                 BOOLEAN;
+ 2806                                               fok: BOOLEAN;
+ 2807                                               lw, rw, mw: CARDINAL;
+ 2808                                               lTrue, lNext, lDone, qr, qs: QbeGen.QVal;
+ 2809                                                astA, astB: AST.Node;
+ 2810                                                astSign, astOp: INTEGER; .)
+ 2811      =                                   (. neg := FALSE; astSign := 0; .)
+ 2812        [ "+"                         (. neg := TRUE; astSign := 1; .)
+ 2813        | "-"                         (. neg := TRUE; astSign := -1; .) ]
+ 2814        Term<t, q> (. astA := astCur;
+ 2815                                            IF neg AND QbeGen.IsImm(q) THEN
+ 2816                                              QbeGen.NegFold(q, q)
+ 2817                                            END;
+ 2818                                           IF astSign < 0 THEN
+ 2819                                             astCur := AST.MakeUn(
+ 2820                                               AST.NkUnary, AST.OpSub, astA);
+ 2821                                             astA := astCur
+ 2822                                           END; .)
+ 2823         { AddOp<op>
+ 2824           Term<t2, q2> (. astB := astCur; .)
+ 2825          (. astOp := AST.OpAdd;
+ 2826             IF op = SymTab.OpSub THEN astOp := AST.OpSub
+ 2827             ELSIF op = SymTab.OpOr THEN astOp := AST.OpOr END;
+ 2828             astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
+ 2829             astCur := astA;
+ 2830             IF op = SymTab.OpOr THEN
+ 2831               (* short-circuit: if q is true the RHS is skipped *)
+ 2832               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 2833                 t := SymTab.BoolType()
+ 2834               ELSE SemError(212); t := SymTab.InvalidType END;
+ 2835                IF t # SymTab.InvalidType THEN
+ 2836                  QbeGen.CopyOp("@", q)
+ 2837                ELSE QbeGen.CopyOp("0", q)
+ 2838                END
+ 2839             ELSIF (op = SymTab.OpAdd)
+ 2840               AND (SymTab.UStrCompat(t, t2)
+ 2841                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
+ 2842                   AND (SymTab.ClassOf(t2) = SymTab.ClUStr))
+ 2843                 OR ((SymTab.ClassOf(t) = SymTab.ClUStr)
+ 2844                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))
+ 2845                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
+ 2846                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN
+ 2847               (* UString concatenation: a UCHAR operand becomes a
+ 2848                  1-codepoint UString; the result is a descriptor in the
+ 2849                  shim's concat buffer.  Work on copies so neither
+ 2850                  operand is clobbered. *)
+ 2851                t := SymTab.NewUStr();
+ 2852                QbeGen.CopyOp("@", q)
+ 2853             ELSIF (op = SymTab.OpAdd)
+ 2854               AND (SymTab.StrCompat(t, t2)
+ 2855                 OR (SymTab.IsStrType(t)
+ 2856                   AND (SymTab.ClassOf(t2) = SymTab.ClChar))
+ 2857                 OR ((SymTab.ClassOf(t) = SymTab.ClChar)
+ 2858                   AND SymTab.IsStrType(t2))) THEN
+ 2859               (* string concatenation; a CHAR operand becomes a
+ 2860                  1-character string literal.  When both operands are
+ 2861                  constants, fold to a single string literal so a
+ 2862                  constructor element stays compile-time. *)
+ 2863                QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2),
+ 2864                  qt, fok);
+ 2865                IF fok THEN QbeGen.CopyOp(qt, q)
+ 2866                ELSE QbeGen.CopyOp("@", q)
+ 2867                END;
+ 2868                t := SymTab.NewStr()
+ 2869             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 2870   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 2871   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 2872                lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 2873                mw := lw;
+ 2874                IF rw > mw THEN mw := rw END;
+ 2875                t := SymTab.NewSet(
+ 2876                       SymTab.NewSubR(0,
+ 2877                         VAL(INTEGER, mw) * 32 - 1));
+ 2878                QbeGen.CopyOp("@", q)
+ 2879             ELSE
+ 2880               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
+ 2881                 lt := t; rt := t2; t := res2
+ 2882               ELSE SemError(211); t := SymTab.InvalidType END;
+ 2883               IF t # SymTab.InvalidType THEN
+ 2884                 isL := SymTab.IsLongFamily(t);
+ 2885                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 2886                 folded := FALSE;
+ 2887                 IF (NOT isL) AND (NOT isR)
+ 2888    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 2889                   IF op = SymTab.OpAdd THEN
+ 2890                     folded := QbeGen.Fold2(0, q, q2, qf)
+ 2891                   ELSE
+ 2892                     folded := QbeGen.Fold2(1, q, q2, qf)
+ 2893                   END
+ 2894                 END;
+ 2895                 IF folded THEN QbeGen.CopyOp(qf, q)
+ 2896                  ELSE
+ 2897                  QbeGen.CopyOp("@", q)
+ 2898                  END
+ 2899               ELSE QbeGen.CopyOp("0", q)
+ 2900               END
+ 2901             END; .) }
+ 2902             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 2903    AddOp<VAR op: INTEGER>
+ 2904      = "+"                               (. op := SymTab.OpAdd; .)
+ 2905      | "-"                               (. op := SymTab.OpSub; .)
+ 2906      | "OR"                              (. op := SymTab.OpOr; .) .
+ 2907    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2908                                          (. VAR t2, res2, lt, rt:
+ 2909                                                 SymTab.TypeIndex;
+ 2910                                               op: INTEGER;
+ 2911                                               q2, qt, wq, qf:
+ 2912                                                 QbeGen.QVal;
+ 2913                                               isR, isL, folded: BOOLEAN;
+ 2914                                               lw, rw, mw: CARDINAL;
+ 2915                                               lNext, lFalse, lDone, qr, qs: QbeGen.QVal;
+ 2916                                                astA, astB: AST.Node;
+ 2917                                                astOp: INTEGER; .)
+ 2918      = Fact<t, q> (. astA := astCur; .) { MulOp<op>
+ 2919          Fact<t2, q2> (. astB := astCur; .)
+ 2920        (. astOp := AST.OpMul;
+ 2921           IF op = SymTab.OpSlash THEN astOp := AST.OpDiv
+ 2922           ELSIF op = SymTab.OpDiv THEN astOp := AST.OpDiv
+ 2923           ELSIF op = SymTab.OpMod THEN astOp := AST.OpMod
+ 2924           ELSIF op = SymTab.OpAnd THEN astOp := AST.OpAnd END;
+ 2925           astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
+ 2926           astCur := astA;
+ 2927           IF op = SymTab.OpAnd THEN
+ 2928             (* short-circuit: if q is false the RHS is skipped *)
+ 2929             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 2930               t := SymTab.BoolType()
+ 2931             ELSE SemError(212); t := SymTab.InvalidType END;
+ 2932              IF t # SymTab.InvalidType THEN QbeGen.CopyOp("@", q)
+ 2933              ELSE QbeGen.CopyOp("0", q)
+ 2934              END
+ 2935           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 2936   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 2937   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 2938              lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 2939              mw := lw;
+ 2940              IF rw > mw THEN mw := rw END;
+ 2941              t := SymTab.NewSet(
+ 2942                     SymTab.NewSubR(0,
+ 2943                       VAL(INTEGER, mw) * 32 - 1));
+ 2944              QbeGen.CopyOp("@", q)
+ 2945           ELSE
+ 2946             IF SymTab.ArithCheck(t, t2,
+ 2947                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
+ 2948                  res2) THEN
+ 2949               lt := t; rt := t2; t := res2
+ 2950             ELSE SemError(211); t := SymTab.InvalidType END;
+ 2951             IF t # SymTab.InvalidType THEN
+ 2952               isL := SymTab.IsLongFamily(t);
+ 2953               isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 2954               folded := FALSE;
+ 2955               IF (NOT isL) AND (NOT isR)
+ 2956    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 2957                 IF op = SymTab.OpTimes THEN
+ 2958                   folded := QbeGen.Fold2(2, q, q2, qf)
+ 2959                 ELSIF op = SymTab.OpDiv THEN
+ 2960                   folded := QbeGen.Fold2(3, q, q2, qf)
+ 2961                 ELSIF op = SymTab.OpMod THEN
+ 2962                   folded := QbeGen.Fold2(4, q, q2, qf)
+ 2963                 END
+ 2964               END;
+ 2965               IF folded THEN QbeGen.CopyOp(qf, q)
+ 2966                ELSE
+ 2967                QbeGen.CopyOp("@", q)
+ 2968                END
+ 2969             ELSE QbeGen.CopyOp("0", q)
+ 2970             END
+ 2971           END; .) }
+ 2972             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 2973    MulOp<VAR op: INTEGER>
+ 2974      = "*"                               (. op := SymTab.OpTimes; .)
+ 2975      | "/"                               (. op := SymTab.OpSlash; .)
+ 2976      | "DIV"                             (. op := SymTab.OpDiv; .)
+ 2977      | "MOD"                             (. op := SymTab.OpMod; .)
+ 2978      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
+ 2979    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2980                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
+ 2981                                               et, dt, t2, st, ct2, et2:
+ 2982                                                 SymTab.TypeIndex;
+ 2983                                               dk: INTEGER;
+ 2984                                               qd, q2, sq, qa, qm0, qr, qt:
+ 2985                                                 QbeGen.QVal;
+ 2986                                               qn, vn: SymTab.Name;
+ 2987                                               vt: SymTab.TypeIndex;
+ 2988                                               c1, c2: INTEGER;
+ 2989                                               lo, hi: INTEGER;
+ 2990                                               isMax: BOOLEAN;
+ 2991                                               called, isHigh, sfx, isCh,
+ 2992                                               isU, uok, isStr: BOOLEAN;
+ 2993                                               ucp: INTEGER; astIsLit: BOOLEAN;
+ 2994                                                astD: AST.Node;
+ 2995                                                astCall: BOOLEAN;
+ 2996                                                astNode, astNot: AST.Node;
+ 2997                                                j: CARDINAL;
+ 2998                                                astArg2: AST.Node;
+ 2999                                                astBrace: AST.Node;
+ 3000                                                astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN; .)
+ 3001      = (. astIsLit := FALSE; .)
+ 3002      ( integer                           (. LexString(s);
+ 3003                                             QbeGen.NormInt(s, q); astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s);
+ 3004                                             t := SymTab.IntType(); .)
+ 3005      | charConst                         (. LexString(s);
+ 3006                                             QbeGen.NormLit(s, q, isCh);
+ 3007                                             astIsLit := TRUE;
+ 3008                                             astCur := AST.MakeLeaf(
+ 3009                                               AST.NkCharLit, s);
+ 3010                                             t := SymTab.CharType(); .)
+ 3011      | real                              (. LexString(s);
+ 3012                                             QbeGen.NormReal(s, q);
+ 3013                                             astIsLit := TRUE;
+ 3014                                             astCur := AST.MakeLeaf(
+ 3015                                               AST.NkRealLit, s);
+ 3016                                             t := SymTab.RealType(); .)
+ 3017      | string                            (. LexString(s);
+ 3018                                             astIsLit := TRUE;
+ 3019                                             astCur := AST.MakeLeaf(
+ 3020                                               AST.NkStrLit, s);
+ 3021                                             IF SymTab.StrLen(s) = 3 THEN
+ 3022                                               t := SymTab.CharType();
+ 3023                                               QbeGen.IntStr(
+ 3024                                                 QbeGen.CharVal(s), q)
+ 3025                                             ELSE t := SymTab.NewStr();
+ 3026                                               QbeGen.DeclStr(s, q);
+ 3027                                               (* a literal's value IS its
+ 3028                                                  static descriptor address *)
+ 3029                                             END; .)
+ 3030      | ustring                           (. LexString(s);
+ 3031                                             astIsLit := TRUE;
+ 3032                                             astCur := AST.MakeLeaf(
+ 3033                                               AST.NkStrLit, s);
+ 3034                                             QbeGen.DeclUStr(s, q, isU, ucp,
+ 3035                                               uok);
+ 3036                                             IF NOT uok THEN
+ 3037                                               SemError(234);
+ 3038                                               t := SymTab.InvalidType
+ 3039                                             ELSIF isU THEN
+ 3040                                               t := SymTab.UCharType();
+ 3041                                               QbeGen.IntStr(ucp, q)
+ 3042                                             ELSE
+ 3043                                               t := SymTab.NewUStr();
+ 3044                                             END; .)
+ 3045      | Design<dt, dk, qd, qn, sfx>       (. astD := astCur; astCall := FALSE; astBrace := AST.NoNode;
+ 3046                                             astNArgs := 0; called := FALSE;
+ 3047                                             t := dt;
+ 3048                                             IF dk = SymTab.KindConst THEN
+ 3049                                               QbeGen.CopyOp(qd, q)
+ 3050                                             ELSE QbeGen.CopyOp("@", q)
+ 3051                                             END; .)
+ 3052        [ TypedBraceLit<dt, q>            (. t := dt; astCall := TRUE;
+ 3053                                               astBrace := astCur; .) ]
+ 3054        [ ArgList<qn, dt, qd, TRUE, FALSE, methCls, ct2, q2, called>
+ 3055                                          (. astCall := TRUE;
+ 3056                                             astNode := AstCallNode(astD);
+ 3057                                             astRes := astNode;
+ 3058                                             t := ct2;
+ 3059                                             QbeGen.CopyOp(q2, q);
+ 3060                                             sfx := FALSE; .)
+ 3061          { ResultComp<t, q, sfx, astRes, mname, methCls, isM>
+ 3062            [ (. astNArgs := 0; .)
+ 3063              ArgList<mname, t, q, TRUE, FALSE, methCls, ct2, q2, called>
+ 3064                                          (. astNode := AstCallNode(astRes);
+ 3065                                             astRes := astNode;
+ 3066                                             t := ct2;
+ 3067                                             QbeGen.CopyOp(q2, q);
+ 3068                                             sfx := FALSE; .) ] }
+ 3069                                          (. IF sfx THEN
+ 3070                                               IF t = SymTab.InvalidType THEN
+ 3071                                                 QbeGen.CopyOp("0", q)
+ 3072                                               ELSIF (SymTab.ClassOf(t) #
+ 3073                                                      SymTab.ClRecord)
+ 3074    AND (SymTab.ClassOf(t) # SymTab.ClSet)
+ 3075    AND (SymTab.ClassOf(t) # SymTab.ClArray)
+ 3076    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
+ 3077                                                  QbeGen.CopyOp("@", q)
+ 3078                                               END
+ 3079                                             END; .) ]
+ 3080                                          (. IF called THEN
+ 3081                                               astCur := astRes
+ 3082                                             ELSIF astCall THEN
+ 3083                                               astCur := astBrace
+ 3084                                             ELSE astCur := astD
+ 3085                                             END;
+ 3086                                              astIsLit := TRUE;
+ 3087                                              IF NOT called
+ 3088   AND (dk = SymTab.KindProc) THEN
+ 3089                                               (* bare zero-arg function
+ 3090                                                  call (parentheses may be
+ 3091                                                  omitted); a proper or
+ 3092                                                  parameterised proc here
+ 3093                                                  is 230 *)
+ 3094                                                IF (SymTab.ProcNPar(qn) = 0)
+ 3095   AND (SymTab.ProcRes(qn) # SymTab.InvalidType) THEN
+ 3096                                                  t := SymTab.ProcRes(qn);
+ 3097                                                  QbeGen.CopyOp("@", q);
+ 3098                                                  astCur := AST.MakeNode(AST.NkCall);
+ 3099                                                  AST.SetChild(astCur, 0, astD)
+ 3100                                                ELSE
+ 3101                                                  t := SymTab.ProcTypeOf(qn);
+ 3102                                                  QbeGen.CopyOp("@", q)
+ 3103                                                END
+ 3104                                             END; .)
+ 3105      | ( "HIGH"                          (. isHigh := TRUE; .)
+ 3106        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
+ 3107        "(" ( Design<dt, dk, qd, qn, sfx> (. isStr := FALSE;
+ 3108                                              isU := FALSE; .)
+ 3109            | string                       (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
+ 3110                                              isStr := TRUE;
+ 3111                                              isU := FALSE;
+ 3112                                              IF SymTab.StrLen(s) = 3 THEN
+ 3113                                                dt := SymTab.CharType();
+ 3114                                                QbeGen.IntStr(QbeGen.CharVal(s),
+ 3115                                                  qd)
+ 3116                                              ELSE
+ 3117                                                dt := SymTab.NewStr();
+ 3118                                                QbeGen.DeclStr(s, qd);
+ 3119                                              END;
+ 3120                                              dk := -1;
+ 3121                                              qn[0] := CHR(0); .)
+ 3122            | ustring                      (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
+ 3123                                              QbeGen.DeclUStr(s, qd, isU, ucp,
+ 3124                                                uok);
+ 3125                                              isStr := FALSE;
+ 3126                                              IF NOT uok THEN
+ 3127                                                SemError(234);
+ 3128                                                dt := SymTab.InvalidType
+ 3129                                              ELSIF isU THEN
+ 3130                                                (* one codepoint: a UCHAR;
+ 3131                                                   LEN is 1, HIGH is 0 *)
+ 3132                                                dt := SymTab.UCharType();
+ 3133                                                QbeGen.IntStr(ucp, qd)
+ 3134                                              ELSE
+ 3135                                                dt := SymTab.NewUStr();
+ 3136                                              END;
+ 3137                                              dk := -1;
+ 3138                                              qn[0] := CHR(0); .) )
+ 3139        ")"
+ 3140                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 3141     IF isHigh THEN AST.SetChild(astNode, 0,
+ 3142       AST.MakeLeaf(AST.NkIdent, "HIGH"))
+ 3143     ELSE AST.SetChild(astNode, 0,
+ 3144       AST.MakeLeaf(AST.NkIdent, "LEN")) END;
+ 3145     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3146     astCur := astNode; astIsLit := TRUE;
+ 3147                                             IF (dt # SymTab.InvalidType)
+ 3148    AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN
+ 3149                                               (* UString: the count is
+ 3150                                                  the descriptor header *)
+ 3151                                                t := SymTab.IntType();
+ 3152                                                QbeGen.CopyOp("@", q)
+ 3153                                             ELSIF (dt # SymTab.InvalidType)
+ 3154    AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN
+ 3155                                               (* single UCHAR codepoint *)
+ 3156                                               IF isHigh THEN
+ 3157                                                 QbeGen.CopyOp("0", qr)
+ 3158                                               ELSE
+ 3159                                                 QbeGen.CopyOp("1", qr)
+ 3160                                               END;
+ 3161                                               t := SymTab.IntType();
+ 3162                                               QbeGen.CopyOp(qr, q)
+ 3163                                             ELSIF isStr THEN
+ 3164                                               (* fold: content length at
+ 3165                                                  compile time *)
+ 3166                                               IF SymTab.StrLen(s) = 3 THEN
+ 3167                                                 c1 := 1
+ 3168                                               ELSE
+ 3169                                                 c1 :=
+ 3170                                                   SymTab.StrLen(s) - 2
+ 3171                                               END;
  3172                                               IF isHigh THEN
  3172                                               IF isHigh THEN
- 3173                                                 QbeGen.CopyOp("0", qr)
- 3174                                               ELSE
- 3175                                                 QbeGen.CopyOp("1", qr)
- 3176                                               END;
- 3177                                               t := SymTab.IntType();
- 3178                                               QbeGen.CopyOp(qr, q)
- 3179                                             ELSIF isStr THEN
- 3180                                               (* fold: content length at
- 3181                                                  compile time *)
- 3182                                               IF SymTab.StrLen(s) = 3 THEN
- 3183                                                 c1 := 1
- 3184                                               ELSE
- 3185                                                 c1 :=
- 3186                                                   SymTab.StrLen(s) - 2
- 3187                                               END;
- 3188                                               IF isHigh THEN
- 3189                                                 DEC(c1)
- 3190                                               END;
- 3191                                               QbeGen.IntStr(c1, qr);
- 3192                                               t := SymTab.IntType();
- 3193                                               QbeGen.CopyOp(qr, q)
- 3194                                             ELSIF dt = SymTab.InvalidType THEN
- 3195                                               t := SymTab.InvalidType;
- 3196                                               QbeGen.CopyOp("0", q)
- 3197                                             ELSIF SymTab.ClassOf(dt) #
- 3198                                                   SymTab.ClArray THEN
- 3199                                               SemError(217);
- 3200                                               t := SymTab.InvalidType;
- 3201                                               QbeGen.CopyOp("0", q)
- 3202                                             ELSE
- 3203                                                IF SymTab.IsOpenArray(dt) THEN
- 3204                                                  t := SymTab.IntType();
- 3205                                                  QbeGen.CopyOp("@", q)
- 3206                                                ELSE
- 3207                                                  IF isHigh THEN
- 3208                                                    QbeGen.IntStr(
- 3209                                                      SymTab.ArrayHi(dt), qr)
- 3210                                                  ELSE
- 3211                                                    QbeGen.IntStr(VAL(
- 3212                                                      INTEGER,
- 3213                                                      SymTab.ArrayLen(dt)),
- 3214                                                      qr)
- 3215                                                  END;
- 3216                                                  t := SymTab.IntType();
- 3217                                                  QbeGen.CopyOp(qr, q)
- 3218                                                END
- 3219                                              END; .)
- 3220      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
- 3221      (. astNode := AST.MakeNode(AST.NkCall);
- 3222     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "SIZE"));
- 3223     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3224     astCur := astNode; astIsLit := TRUE; .)
- 3225                                          (. IF dt = SymTab.InvalidType THEN
- 3226                                               t := SymTab.InvalidType;
- 3227                                               QbeGen.CopyOp("0", q)
- 3228                                             ELSE
- 3229                                               QbeGen.IntStr(VAL(INTEGER,
- 3230                                                 SymTab.ObjectSize(dt)), q);
- 3231                                               t := SymTab.IntType()
- 3232                                             END; .)
- 3233      | ( "SHIFT"                         (. isMax := FALSE; .)
- 3234        | "ROTATE"                        (. isMax := TRUE; .) )
- 3235        "(" Expr<et, q> (. astArg2 := astCur; .) "," Expr<et2, q2> ")"
- 3236                                          (. astNode := AST.MakeNode(AST.NkCall);
- 3237     IF isMax THEN AST.SetChild(astNode, 0,
- 3238       AST.MakeLeaf(AST.NkIdent, "ROTATE"))
- 3239     ELSE AST.SetChild(astNode, 0,
- 3240       AST.MakeLeaf(AST.NkIdent, "SHIFT")) END;
- 3241     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
- 3242     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
- 3243     astCur := astNode; astIsLit := TRUE;
- 3244                                             (* set shift/rotate: isMax
- 3245                                                doubles as "rotate" *)
- 3246                                             IF (et # SymTab.InvalidType)
- 3247                                                AND (SymTab.ClassOf(et) =
- 3248                                                   SymTab.ClSet) THEN
- 3249                                                t := et;
- 3250                                                QbeGen.CopyOp("@", q)
- 3251                                             ELSE SemError(230);
- 3252                                               t := SymTab.InvalidType;
- 3253                                               QbeGen.CopyOp("0", q)
- 3254                                             END; .)
- 3255      | ( "MIN"                           (. isMax := FALSE; .)
- 3256        | "MAX"                           (. isMax := TRUE; .) )
- 3257        "(" Design<dt, dk, qd, qn, sfx> ")"
- 3258                                          (. astNode := AST.MakeNode(AST.NkCall);
- 3259     IF isMax THEN AST.SetChild(astNode, 0,
- 3260       AST.MakeLeaf(AST.NkIdent, "MAX"))
- 3261     ELSE AST.SetChild(astNode, 0,
- 3262       AST.MakeLeaf(AST.NkIdent, "MIN")) END;
- 3263     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3264     astCur := astNode; astIsLit := TRUE;
- 3265                                             IF (dt # SymTab.InvalidType)
- 3266   AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN
- 3267                                               (* REAL/LONGREAL: the
- 3268                                                  implementation bounds *)
- 3269                                               IF isMax THEN
- 3270                                                 QbeGen.NormReal(
- 3271                                                   "3.402823e38", q)
- 3272                                               ELSE QbeGen.NormReal(
- 3273                                                   "-3.402823e38", q)
- 3274                                               END;
- 3275                                               t := SymTab.RealType()
- 3276                                             ELSIF (dt #
- 3277                                                SymTab.InvalidType)
- 3278   AND (SymTab.ClassOf(dt) =
- 3279                                                   SymTab.ClLong) THEN
- 3280                                               IF isMax THEN
- 3281                                                 QbeGen.CopyOp(
- 3282                                                   "9223372036854775807", q)
- 3283                                               ELSE QbeGen.CopyOp(
- 3284                                                   "-9223372036854775808", q)
- 3285                                               END;
- 3286                                               t := SymTab.LongType()
- 3287                                             ELSIF SymTab.TypeBounds(dt, lo,
- 3288                                                      hi) THEN
- 3289                                               IF isMax THEN
- 3290                                                 QbeGen.IntStr(hi, q)
- 3291                                               ELSE QbeGen.IntStr(lo, q)
- 3292                                               END;
- 3293                                               t := SymTab.IntType()
- 3294                                             ELSE SemError(230);
- 3295                                               t := SymTab.InvalidType;
- 3296                                               QbeGen.CopyOp("0", q)
- 3297                                             END; .)
- 3298      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
- 3299      (. astNode := AST.MakeNode(AST.NkCall);
- 3300     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ADR"));
- 3301     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3302     astCur := astNode; astIsLit := TRUE; .)
- 3303                                          (. IF dt = SymTab.InvalidType THEN
- 3304                                               t := SymTab.InvalidType;
- 3305                                               QbeGen.CopyOp("0", q)
- 3306                                             ELSE
- 3307                                                IF sfx
- 3308                                                   OR (dk = SymTab.KindVar)
- 3309                                                   OR (dk = SymTab.KindParam) THEN
- 3310                                                  QbeGen.CopyOp("@", q)
- 3311                                                ELSE SemError(230);
- 3312                                                  QbeGen.CopyOp("0", q)
- 3313                                                END;
- 3314                                               t := SymTab.AddrType()
- 3315                                             END; .)
- 3316      | "CHR" "(" Expr<et, q> ")"
- 3317      (. astNode := AST.MakeNode(AST.NkCall);
- 3318     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR"));
- 3319     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3320     astCur := astNode; astIsLit := TRUE; .)
- 3321                                          (. IF (et # SymTab.InvalidType)
- 3322   AND NOT SymTab.IsIntFamily(et) THEN
- 3323                                               SemError(211) END;
- 3324                                             t := SymTab.CharType(); .)
- 3325      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
+ 3173                                                 DEC(c1)
+ 3174                                               END;
+ 3175                                               QbeGen.IntStr(c1, qr);
+ 3176                                               t := SymTab.IntType();
+ 3177                                               QbeGen.CopyOp(qr, q)
+ 3178                                             ELSIF dt = SymTab.InvalidType THEN
+ 3179                                               t := SymTab.InvalidType;
+ 3180                                               QbeGen.CopyOp("0", q)
+ 3181                                             ELSIF SymTab.ClassOf(dt) #
+ 3182                                                   SymTab.ClArray THEN
+ 3183                                               SemError(217);
+ 3184                                               t := SymTab.InvalidType;
+ 3185                                               QbeGen.CopyOp("0", q)
+ 3186                                             ELSE
+ 3187                                                IF SymTab.IsOpenArray(dt) THEN
+ 3188                                                  t := SymTab.IntType();
+ 3189                                                  QbeGen.CopyOp("@", q)
+ 3190                                                ELSE
+ 3191                                                  IF isHigh THEN
+ 3192                                                    QbeGen.IntStr(
+ 3193                                                      SymTab.ArrayHi(dt), qr)
+ 3194                                                  ELSE
+ 3195                                                    QbeGen.IntStr(VAL(
+ 3196                                                      INTEGER,
+ 3197                                                      SymTab.ArrayLen(dt)),
+ 3198                                                      qr)
+ 3199                                                  END;
+ 3200                                                  t := SymTab.IntType();
+ 3201                                                  QbeGen.CopyOp(qr, q)
+ 3202                                                END
+ 3203                                              END; .)
+ 3204      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
+ 3205      (. astNode := AST.MakeNode(AST.NkCall);
+ 3206     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "SIZE"));
+ 3207     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3208     astCur := astNode; astIsLit := TRUE; .)
+ 3209                                          (. IF dt = SymTab.InvalidType THEN
+ 3210                                               t := SymTab.InvalidType;
+ 3211                                               QbeGen.CopyOp("0", q)
+ 3212                                             ELSE
+ 3213                                               QbeGen.IntStr(VAL(INTEGER,
+ 3214                                                 SymTab.ObjectSize(dt)), q);
+ 3215                                               t := SymTab.IntType()
+ 3216                                             END; .)
+ 3217      | ( "SHIFT"                         (. isMax := FALSE; .)
+ 3218        | "ROTATE"                        (. isMax := TRUE; .) )
+ 3219        "(" Expr<et, q> (. astArg2 := astCur; .) "," Expr<et2, q2> ")"
+ 3220                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 3221     IF isMax THEN AST.SetChild(astNode, 0,
+ 3222       AST.MakeLeaf(AST.NkIdent, "ROTATE"))
+ 3223     ELSE AST.SetChild(astNode, 0,
+ 3224       AST.MakeLeaf(AST.NkIdent, "SHIFT")) END;
+ 3225     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
+ 3226     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
+ 3227     astCur := astNode; astIsLit := TRUE;
+ 3228                                             (* set shift/rotate: isMax
+ 3229                                                doubles as "rotate" *)
+ 3230                                             IF (et # SymTab.InvalidType)
+ 3231                                                AND (SymTab.ClassOf(et) =
+ 3232                                                   SymTab.ClSet) THEN
+ 3233                                                t := et;
+ 3234                                                QbeGen.CopyOp("@", q)
+ 3235                                             ELSE SemError(230);
+ 3236                                               t := SymTab.InvalidType;
+ 3237                                               QbeGen.CopyOp("0", q)
+ 3238                                             END; .)
+ 3239      | ( "MIN"                           (. isMax := FALSE; .)
+ 3240        | "MAX"                           (. isMax := TRUE; .) )
+ 3241        "(" Design<dt, dk, qd, qn, sfx> ")"
+ 3242                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 3243     IF isMax THEN AST.SetChild(astNode, 0,
+ 3244       AST.MakeLeaf(AST.NkIdent, "MAX"))
+ 3245     ELSE AST.SetChild(astNode, 0,
+ 3246       AST.MakeLeaf(AST.NkIdent, "MIN")) END;
+ 3247     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3248     astCur := astNode; astIsLit := TRUE;
+ 3249                                             IF (dt # SymTab.InvalidType)
+ 3250   AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN
+ 3251                                               (* REAL/LONGREAL: the
+ 3252                                                  implementation bounds *)
+ 3253                                               IF isMax THEN
+ 3254                                                 QbeGen.NormReal(
+ 3255                                                   "3.402823e38", q)
+ 3256                                               ELSE QbeGen.NormReal(
+ 3257                                                   "-3.402823e38", q)
+ 3258                                               END;
+ 3259                                               t := SymTab.RealType()
+ 3260                                             ELSIF (dt #
+ 3261                                                SymTab.InvalidType)
+ 3262   AND (SymTab.ClassOf(dt) =
+ 3263                                                   SymTab.ClLong) THEN
+ 3264                                               IF isMax THEN
+ 3265                                                 QbeGen.CopyOp(
+ 3266                                                   "9223372036854775807", q)
+ 3267                                               ELSE QbeGen.CopyOp(
+ 3268                                                   "-9223372036854775808", q)
+ 3269                                               END;
+ 3270                                               t := SymTab.LongType()
+ 3271                                             ELSIF SymTab.TypeBounds(dt, lo,
+ 3272                                                      hi) THEN
+ 3273                                               IF isMax THEN
+ 3274                                                 QbeGen.IntStr(hi, q)
+ 3275                                               ELSE QbeGen.IntStr(lo, q)
+ 3276                                               END;
+ 3277                                               t := SymTab.IntType()
+ 3278                                             ELSE SemError(230);
+ 3279                                               t := SymTab.InvalidType;
+ 3280                                               QbeGen.CopyOp("0", q)
+ 3281                                             END; .)
+ 3282      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 3283      (. astNode := AST.MakeNode(AST.NkCall);
+ 3284     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ADR"));
+ 3285     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3286     astCur := astNode; astIsLit := TRUE; .)
+ 3287                                          (. IF dt = SymTab.InvalidType THEN
+ 3288                                               t := SymTab.InvalidType;
+ 3289                                               QbeGen.CopyOp("0", q)
+ 3290                                             ELSE
+ 3291                                                IF sfx
+ 3292                                                   OR (dk = SymTab.KindVar)
+ 3293                                                   OR (dk = SymTab.KindParam) THEN
+ 3294                                                  QbeGen.CopyOp("@", q)
+ 3295                                                ELSE SemError(230);
+ 3296                                                  QbeGen.CopyOp("0", q)
+ 3297                                                END;
+ 3298                                               t := SymTab.AddrType()
+ 3299                                             END; .)
+ 3300      | "CHR" "(" Expr<et, q> ")"
+ 3301      (. astNode := AST.MakeNode(AST.NkCall);
+ 3302     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR"));
+ 3303     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3304     astCur := astNode; astIsLit := TRUE; .)
+ 3305                                          (. IF (et # SymTab.InvalidType)
+ 3306   AND NOT SymTab.IsIntFamily(et) THEN
+ 3307                                               SemError(211) END;
+ 3308                                             t := SymTab.CharType(); .)
+ 3309      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
+ 3310      (. astNode := AST.MakeNode(AST.NkCall);
+ 3311     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ORD"));
+ 3312     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3313     astCur := astNode; astIsLit := TRUE; .)
+ 3314                                          (. IF et # SymTab.InvalidType THEN
+ 3315                                               IF (SymTab.ClassOf(et) #
+ 3316                                                   SymTab.ClChar)
+ 3317   AND (SymTab.ClassOf(et) #
+ 3318                                                     SymTab.ClBool)
+ 3319   AND (SymTab.ClassOf(et) #
+ 3320                                                     SymTab.ClEnum)
+ 3321   AND NOT SymTab.IsIntFamily(et) THEN
+ 3322                                                 SemError(211) END
+ 3323                                             END;
+ 3324                                             t := SymTab.IntType(); .)
+ 3325      | "CAP" "(" Expr<et, q> ")"
  3326      (. astNode := AST.MakeNode(AST.NkCall);
  3326      (. astNode := AST.MakeNode(AST.NkCall);
- 3327     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ORD"));
+ 3327     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CAP"));
  3328     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3328     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  3329     astCur := astNode; astIsLit := TRUE; .)
  3329     astCur := astNode; astIsLit := TRUE; .)
- 3330                                          (. IF et # SymTab.InvalidType THEN
- 3331                                               IF (SymTab.ClassOf(et) #
- 3332                                                   SymTab.ClChar)
- 3333   AND (SymTab.ClassOf(et) #
- 3334                                                     SymTab.ClBool)
- 3335   AND (SymTab.ClassOf(et) #
- 3336                                                     SymTab.ClEnum)
- 3337   AND NOT SymTab.IsIntFamily(et) THEN
- 3338                                                 SemError(211) END
- 3339                                             END;
- 3340                                             t := SymTab.IntType(); .)
- 3341      | "CAP" "(" Expr<et, q> ")"
- 3342      (. astNode := AST.MakeNode(AST.NkCall);
- 3343     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CAP"));
- 3344     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3345     astCur := astNode; astIsLit := TRUE; .)
- 3346                                           (. QbeGen.CopyOp("@", q);
- 3347                                             t := SymTab.CharType(); .)
- 3348      | "UCHR" "(" Expr<et, q> ")"
- 3349      (. astNode := AST.MakeNode(AST.NkCall);
- 3350     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UCHR"));
- 3351     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3352     astCur := astNode; astIsLit := TRUE; .)
- 3353                                          (. (* UCHR: the UCHAR constructor.
- 3354                                                CHAR -> UCHAR (identity);
- 3355                                                INTEGER familly -> UCHAR
- 3356                                                (codepoint value). *)
- 3357                                             IF (et # SymTab.InvalidType)
- 3358    AND (SymTab.ClassOf(et) # SymTab.ClChar)
- 3359    AND NOT SymTab.IsIntFamily(et) THEN
- 3360                                               SemError(211) END;
- 3361                                             t := SymTab.UCharType(); .)
- 3362      | "CHR8" "(" Expr<et, q> ")"
- 3363      (. astNode := AST.MakeNode(AST.NkCall);
- 3364     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR8"));
- 3365     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3366     astCur := astNode; astIsLit := TRUE; .)
- 3367                                          (. IF (et # SymTab.InvalidType)
- 3368    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
- 3369                                               SemError(211) END;
- 3370                                             t := SymTab.CharType(); .)
- 3371      | "UORD" "(" Expr<et, q> ")"
- 3372      (. astNode := AST.MakeNode(AST.NkCall);
- 3373     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UORD"));
- 3374     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3375     astCur := astNode; astIsLit := TRUE; .)
- 3376                                          (. (* UORD(u): the codepoint as a
- 3377                                                32-bit ordinal (INTEGER),
- 3378                                                cf. ORD for CHAR. *)
- 3379                                             IF (et # SymTab.InvalidType)
- 3380    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
- 3381                                               SemError(211) END;
- 3382                                             t := SymTab.IntType(); .)
- 3383      | "ABS" "(" Expr<et, q> ")"
- 3384      (. astNode := AST.MakeNode(AST.NkCall);
- 3385     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ABS"));
- 3386     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3387     astCur := astNode; astIsLit := TRUE; .)
- 3388                                          (. IF (et # SymTab.InvalidType)
- 3389   AND NOT SymTab.IsIntFamily(et)
- 3390   AND (SymTab.ClassOf(et) #
- 3391                                                  SymTab.ClReal) THEN
- 3392                                               SemError(211)
- 3393                                              ELSE QbeGen.CopyOp("@", q)
- 3394                                             END;
- 3395                                             t := et; .)
- 3396      | "VAL" "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
- 3397      (. astNode := AST.MakeNode(AST.NkCall);
- 3398     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
- 3399     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
- 3400     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
- 3401     astCur := astNode; astIsLit := TRUE; .)
- 3402                                          (. IF NOT SymTab.Lookup(vn) THEN
- 3403                                               SemError(201);
- 3404                                               t := SymTab.InvalidType
- 3405                                             ELSE vt := SymTab.SymType(vn);
- 3406                                               IF vt = SymTab.InvalidType THEN
- 3407                                                 t := SymTab.InvalidType
- 3408                                               ELSIF et =
- 3409                                                  SymTab.InvalidType THEN
- 3410                                                 t := vt
- 3411                                               ELSE
- 3412                                                 c1 := SymTab.ClassOf(et);
- 3413                                                 c2 := SymTab.ClassOf(vt);
- 3414                                                 IF (c1 = SymTab.ClInt)
- 3415    AND (c2 = SymTab.ClLong) THEN
- 3416                                                   QbeGen.WidenLong(q, qa);
- 3417                                                   QbeGen.CopyOp(qa, q);
- 3418                                                   t := vt
- 3419                                                 ELSIF (c1 = SymTab.ClLong)
- 3420    AND (c2 = SymTab.ClInt) THEN
- 3421                                                   QbeGen.NarrowLong(q, qa);
- 3422                                                   QbeGen.CopyOp(qa, q);
- 3423                                                   t := vt
- 3424                                                 ELSIF (c1 = SymTab.ClInt)
- 3425    AND (c2 = SymTab.ClReal) THEN
- 3426                                                   QbeGen.ConvIR(q, qa);
- 3427                                                   QbeGen.CopyOp(qa, q);
- 3428                                                   t := vt
- 3429                                                 ELSIF (c1 = SymTab.ClLong)
- 3430    AND (c2 = SymTab.ClReal) THEN
- 3431                                                   QbeGen.ConvLR(q, qa);
- 3432                                                   QbeGen.CopyOp(qa, q);
- 3433                                                   t := vt
- 3434                                                 ELSIF (c1 = SymTab.ClReal)
- 3435    AND (c2 = SymTab.ClInt) THEN
- 3436                                                   QbeGen.ConvRI(q, qa);
- 3437                                                   QbeGen.CopyOp(qa, q);
- 3438                                                   t := vt
- 3439                                                 ELSIF (c1 = SymTab.ClReal)
- 3440    AND (c2 = SymTab.ClLong) THEN
- 3441                                                   QbeGen.ConvRL(q, qa);
- 3442                                                   QbeGen.CopyOp(qa, q);
- 3443                                                   t := vt
- 3444                                                 ELSIF ((c1 = SymTab.ClInt)
- 3445                                                     OR (c1 =
- 3446                                                        SymTab.ClChar)
- 3447                                                     OR (c1 =
- 3448                                                        SymTab.ClBool)
- 3449                                                     OR (c1 =
- 3450                                                        SymTab.ClEnum))
- 3451   AND ((c2 = SymTab.ClInt)
- 3452                                                     OR (c2 =
- 3453                                                        SymTab.ClChar)
- 3454                                                     OR (c2 =
- 3455                                                        SymTab.ClBool)
- 3456                                                     OR (c2 =
- 3457                                                        SymTab.ClEnum)) THEN
- 3458                                                   t := vt
- 3459                                                 ELSIF (c1 = SymTab.ClPtr)
- 3460   AND (c2 = SymTab.ClPtr) THEN
- 3461                                                   t := vt
- 3462                                                 ELSIF (c1 = SymTab.ClReal)
- 3463   AND (c2 = SymTab.ClReal) THEN
- 3464                                                   t := vt
- 3465                                                 ELSE SemError(230);
- 3466                                                   t := SymTab.InvalidType
- 3467                                                 END
- 3468                                               END
- 3469                                             END; .)
- 3470      | "(" Expr<et, q> ")"               (. t := et; astIsLit := TRUE; .)
- 3471      | SetLit<st, sq>                    (. astIsLit := TRUE; t := st;
- 3472                                             QbeGen.CopyOp(sq, q); .)
- 3473      | ( "NOT" | "~" ) Fact<t2, q2>      (. astNot := astCur;
- 3474                                             IF SymTab.BoolCheck(t2) THEN
- 3475                                               t := SymTab.BoolType()
- 3476                                             ELSE SemError(212);
- 3477                                               t := SymTab.InvalidType END;
- 3478                                             IF t # SymTab.InvalidType THEN
- 3479                                                QbeGen.CopyOp("@", q)
- 3480                                             ELSE QbeGen.CopyOp("0", q)
- 3481                                             END;
- 3482                                             astIsLit := TRUE;
- 3483                                             astCur := AST.MakeUn(
- 3484                                               AST.NkUnary, AST.OpNot, astNot); .)
- 3485      )
- 3486      (. IF NOT astIsLit THEN astCur := AST.NoNode END; .)
- 3487             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 3488    (* Set literals are SET OF [0..255] (8 words); elements validated
- 3489       0..255 statically when foldable (222 otherwise), runtime trap
- 3490       for computed elements. Ranges always lower via SetRange. *)
- 3491    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3492                                          (. VAR astNode: AST.Node; .)
- 3493      = "{"                               (. t := SymTab.NewSet(
- 3494                                               SymTab.NewSubR(0, 255));
- 3495                                             astNode := AST.MakeNode(AST.NkSetLit);
- 3496                                             QbeGen.NewSetTemp(8, q);
- 3497                                             QbeGen.SetZero(q, 8); .)
- 3498        [ SetElem<t, q, astNode> { "," SetElem<t, q, astNode> } ]
- 3499        "}"                               (. astCur := astNode; .) .
- 3500    (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set)
- 3501       or ArrayName{...} (an array constructor, GNU Modula-2).  The
- 3502       declared type sets the width (set) or element type (array). *)
- 3503    TypedBraceLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3504                                          (. VAR nw: CARDINAL;
- 3505                                               astNode, astTail: AST.Node;
- 3506                                               savedCls: INTEGER; .)
- 3507      = "{"                               (. savedCls := braceCls;
- 3508                                             astNode := AST.MakeNode(AST.NkBraceLit);
- 3509                                             AST.SetTy(astNode, vt);
- 3510                                             astTail := astNode;
- 3511                                             IF vt = SymTab.InvalidType THEN
- 3512                                               braceCls := -1
- 3513                                             ELSE braceCls :=
- 3514                                                    SymTab.ClassOf(vt)
- 3515                                             END;
- 3516                                             IF braceCls = SymTab.ClSet THEN
- 3517                                               IF vt = SymTab.InvalidType THEN
- 3518                                                 nw := 8
- 3519                                               ELSE nw := SymTab.SetWords(vt);
- 3520                                                 IF nw = 0 THEN nw := 8 END
- 3521                                               END;
- 3522                                               QbeGen.NewSetTemp(nw, q);
- 3523                                               QbeGen.SetZero(q, nw)
- 3524                                             ELSIF (braceCls =
- 3525                                                    SymTab.ClArray)
- 3526                                                OR (braceCls =
- 3527                                                    SymTab.ClRecord)
- 3528                                                OR (braceCls =
- 3529                                                    SymTab.ClClass) THEN
- 3530                                               QbeGen.CtorBegin(vt)
- 3531                                             ELSE
- 3532                                               IF vt # SymTab.InvalidType THEN
- 3533                                                 SemError(230) END;
- 3534                                               braceCls := -1
- 3535                                             END; .)
- 3536        [ BraceElem<vt, q, astNode, astTail>
- 3537          { "," BraceElem<vt, q, astNode, astTail> } ]
- 3538        "}"                               (. IF (braceCls = SymTab.ClArray)
- 3539                                                OR (braceCls =
- 3540                                                   SymTab.ClRecord)
- 3541                                                OR (braceCls =
- 3542                                                   SymTab.ClClass) THEN
- 3543                                               QbeGen.CtorEnd(q)
- 3544                                             ELSIF braceCls # SymTab.ClSet THEN
- 3545                                               QbeGen.CopyOp("0", q)
- 3546                                             END;
- 3547                                             braceCls := savedCls; .)
- 3548                                          (. astCur := astNode; .) .
- 3549    BraceElem<vt: SymTab.TypeIndex; VAR sq: QbeGen.QVal;
- 3550              VAR node, tail: AST.Node>
- 3551                                          (. VAR et, et2: SymTab.TypeIndex;
- 3552                                               qe, q2: QbeGen.QVal;
- 3553                                               v, v2, reps, k: INTEGER;
- 3554                                               elem: SymTab.TypeIndex;
- 3555                                               lo: INTEGER;
- 3556                                               span: CARDINAL;
- 3557                                               cl, cl2: INTEGER;
- 3558                                               hasR, hasB: BOOLEAN;
- 3559                                               astEl: AST.Node; .)
- 3560      =                                   (. hasR := FALSE; hasB := FALSE;
- 3561                                             reps := 1; .)
- 3562        Expr<et, qe> (. astEl := astCur; .)
- 3563        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
- 3564                                               AST.NkSubrange, 0, astEl, astCur);
- 3565                                             hasR := TRUE; .) ]
- 3566        [ "BY" Expr<et2, q2>              (. hasB := TRUE; .) ]
- 3567                                          (. IF braceCls = SymTab.ClSet THEN
- 3568                                               IF hasB THEN SemError(230) END;
- 3569                                               lo := SymTab.SetBaseLo(vt);
- 3570                                               span := SymTab.SetCount(vt);
- 3571                                               IF (et = SymTab.InvalidType)
- 3572                                                  OR (hasR AND (et2 =
- 3573                                                     SymTab.InvalidType)) THEN
- 3574                                               ELSE cl :=
- 3575                                                      SymTab.ClassOf(et);
- 3576                                                 IF hasR THEN
- 3577                                                   cl2 :=
- 3578                                                     SymTab.ClassOf(et2)
- 3579                                                 ELSE cl2 := SymTab.ClInt
- 3580                                                 END;
- 3581                                                 IF NOT SymTab.SetElemClassOk(cl)
- 3582                                                    OR (hasR AND NOT
- 3583                                                       SymTab.SetElemClassOk(cl2))
- 3584                                                 THEN
- 3585                                                   SemError(222)
- 3586                                                 ELSIF hasR
- 3587   AND SymTab.ConstInt(qe, v)
- 3588   AND SymTab.ConstInt(q2,
- 3589                                                       v2)
- 3590   AND ((v < lo)
- 3591                                                       OR (v2 < lo)
- 3592                                                       OR (v >= lo +
- 3593                                                          VAL(INTEGER, span))
- 3594                                                       OR (v2 >= lo +
- 3595                                                          VAL(INTEGER, span))
- 3596                                                       OR (v > v2)) THEN
- 3597                                                   SemError(222)
- 3598                                                  ELSIF hasR THEN
- 3599                                                    QbeGen.SetRange(sq, qe, q2,
- 3600                                                      lo, span)
- 3601                                                  ELSIF SymTab.ConstInt(qe,
- 3602                                                          v)
- 3603   AND ((v < lo)
- 3604                                                        OR (v >= lo +
- 3605                                                           VAL(INTEGER,
- 3606                                                             span))) THEN
- 3607                                                    SemError(222)
- 3608                                                  ELSE QbeGen.SetBit(sq, qe,
- 3609                                                    lo, span)
- 3610                                                 END
- 3611                                               END
- 3612                                             ELSIF (braceCls = SymTab.ClArray)
- 3613                                                OR (braceCls =
- 3614                                                   SymTab.ClRecord)
- 3615                                                OR (braceCls =
- 3616                                                   SymTab.ClClass) THEN
- 3617                                               IF hasR THEN SemError(230) END;
- 3618                                               reps := 1;
- 3619                                               IF hasB THEN
- 3620                                                 IF SymTab.ConstInt(q2, v2)
- 3621   AND (v2 >= 1) THEN
- 3622                                                   reps := v2
- 3623                                                 ELSE SemError(230)
- 3624                                                 END
- 3625                                               END;
- 3626                                               k := 0;
- 3627                                               WHILE k < reps DO
- 3628                                                 QbeGen.CtorElem(qe);
- 3629                                                 INC(k)
- 3630                                               END
- 3631                                             END; .)
- 3632                                          (. (* the BY form repeats the
- 3633                                               element; keep the AST in
- 3634                                               step with CtorElem *)
- 3635                                             k := 0;
- 3636                                             WHILE k < reps DO
- 3637                                               AstAppend(AST.NkBlock,
- 3638                                                 node, tail, astEl);
- 3639                                               INC(k)
- 3640                                             END; .) .
- 3641    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal; node: AST.Node>         (. VAR et, et2: SymTab.TypeIndex;
- 3642                                               qe, q2: QbeGen.QVal;
- 3643                                               v, v2: INTEGER;
- 3644                                               lo: INTEGER;
- 3645                                               span: CARDINAL;
- 3646                                               cl, cl2: INTEGER;
- 3647                                               hasR: BOOLEAN;
- 3648                                               astEl: AST.Node; .)
- 3649      =                                   (. hasR := FALSE; .)
- 3650        Expr<et, qe> (. astEl := astCur; .)
- 3651        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
- 3652                                               AST.NkSubrange, 0, astEl, astCur);
- 3653                                             hasR := TRUE; .) ]
- 3654                                          (. lo := SymTab.SetBaseLo(st);
- 3655                                             span := SymTab.SetCount(st);
- 3656                                             IF (et = SymTab.InvalidType)
- 3657                                                OR (hasR AND (et2 =
- 3658                                                   SymTab.InvalidType)) THEN
- 3659                                             ELSE cl :=
- 3660                                                    SymTab.ClassOf(et);
- 3661                                               IF hasR THEN
- 3662                                                 cl2 :=
- 3663                                                   SymTab.ClassOf(et2)
- 3664                                               ELSE cl2 := SymTab.ClInt
- 3665                                               END;
- 3666                                               IF NOT SymTab.SetElemClassOk(cl)
- 3667                                                  OR (hasR AND NOT
- 3668                                                     SymTab.SetElemClassOk(cl2))
- 3669                                               THEN
- 3670                                                 SemError(222)
- 3671                                               ELSIF hasR
- 3672   AND SymTab.ConstInt(qe, v)
- 3673   AND SymTab.ConstInt(q2,
- 3674                                                     v2)
- 3675   AND ((v < lo)
- 3676                                                     OR (v2 < lo)
- 3677                                                     OR (v >= lo +
- 3678                                                        VAL(INTEGER, span))
- 3679                                                     OR (v2 >= lo +
- 3680                                                        VAL(INTEGER, span))
- 3681                                                     OR (v > v2)) THEN
- 3682                                                 SemError(222)
- 3683                                                ELSIF hasR THEN
- 3684                                                  QbeGen.SetRange(sq, qe, q2,
- 3685                                                    lo, span)
- 3686                                                ELSIF SymTab.ConstInt(qe,
- 3687                                                        v)
- 3688   AND ((v < lo)
- 3689                                                      OR (v >= lo +
- 3690                                                         VAL(INTEGER,
- 3691                                                           span))) THEN
- 3692                                                  SemError(222)
- 3693                                                ELSE QbeGen.SetBit(sq, qe,
- 3694                                                  lo, span)
- 3695                                               END
- 3696                                             END; .)
- 3697                                          (. AST.SetChild(node,
- 3698                                               AST.NChild(node), astEl); .) .
- 3699    GetIdent<VAR n: SymTab.Name>
- 3700      = ident                             (. LexName(n); .) .
- 3701  
- 3702  END M2.
+ 3330                                           (. QbeGen.CopyOp("@", q);
+ 3331                                             t := SymTab.CharType(); .)
+ 3332      | "UCHR" "(" Expr<et, q> ")"
+ 3333      (. astNode := AST.MakeNode(AST.NkCall);
+ 3334     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UCHR"));
+ 3335     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3336     astCur := astNode; astIsLit := TRUE; .)
+ 3337                                          (. (* UCHR: the UCHAR constructor.
+ 3338                                                CHAR -> UCHAR (identity);
+ 3339                                                INTEGER familly -> UCHAR
+ 3340                                                (codepoint value). *)
+ 3341                                             IF (et # SymTab.InvalidType)
+ 3342    AND (SymTab.ClassOf(et) # SymTab.ClChar)
+ 3343    AND NOT SymTab.IsIntFamily(et) THEN
+ 3344                                               SemError(211) END;
+ 3345                                             t := SymTab.UCharType(); .)
+ 3346      | "CHR8" "(" Expr<et, q> ")"
+ 3347      (. astNode := AST.MakeNode(AST.NkCall);
+ 3348     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR8"));
+ 3349     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3350     astCur := astNode; astIsLit := TRUE; .)
+ 3351                                          (. IF (et # SymTab.InvalidType)
+ 3352    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
+ 3353                                               SemError(211) END;
+ 3354                                             t := SymTab.CharType(); .)
+ 3355      | "UORD" "(" Expr<et, q> ")"
+ 3356      (. astNode := AST.MakeNode(AST.NkCall);
+ 3357     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UORD"));
+ 3358     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3359     astCur := astNode; astIsLit := TRUE; .)
+ 3360                                          (. (* UORD(u): the codepoint as a
+ 3361                                                32-bit ordinal (INTEGER),
+ 3362                                                cf. ORD for CHAR. *)
+ 3363                                             IF (et # SymTab.InvalidType)
+ 3364    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
+ 3365                                               SemError(211) END;
+ 3366                                             t := SymTab.IntType(); .)
+ 3367      | "ABS" "(" Expr<et, q> ")"
+ 3368      (. astNode := AST.MakeNode(AST.NkCall);
+ 3369     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ABS"));
+ 3370     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3371     astCur := astNode; astIsLit := TRUE; .)
+ 3372                                          (. IF (et # SymTab.InvalidType)
+ 3373   AND NOT SymTab.IsIntFamily(et)
+ 3374   AND (SymTab.ClassOf(et) #
+ 3375                                                  SymTab.ClReal) THEN
+ 3376                                               SemError(211)
+ 3377                                              ELSE QbeGen.CopyOp("@", q)
+ 3378                                             END;
+ 3379                                             t := et; .)
+ 3380      | "VAL" "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
+ 3381      (. astNode := AST.MakeNode(AST.NkCall);
+ 3382     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
+ 3383     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
+ 3384     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
+ 3385     astCur := astNode; astIsLit := TRUE; .)
+ 3386                                          (. IF NOT SymTab.Lookup(vn) THEN
+ 3387                                               SemError(201);
+ 3388                                               t := SymTab.InvalidType
+ 3389                                             ELSE vt := SymTab.SymType(vn);
+ 3390                                               IF vt = SymTab.InvalidType THEN
+ 3391                                                 t := SymTab.InvalidType
+ 3392                                               ELSIF et =
+ 3393                                                  SymTab.InvalidType THEN
+ 3394                                                 t := vt
+ 3395                                               ELSE
+ 3396                                                 c1 := SymTab.ClassOf(et);
+ 3397                                                 c2 := SymTab.ClassOf(vt);
+ 3398                                                 IF (c1 = SymTab.ClInt)
+ 3399    AND (c2 = SymTab.ClLong) THEN
+ 3400                                                   QbeGen.WidenLong(q, qa);
+ 3401                                                   QbeGen.CopyOp(qa, q);
+ 3402                                                   t := vt
+ 3403                                                 ELSIF (c1 = SymTab.ClLong)
+ 3404    AND (c2 = SymTab.ClInt) THEN
+ 3405                                                   QbeGen.NarrowLong(q, qa);
+ 3406                                                   QbeGen.CopyOp(qa, q);
+ 3407                                                   t := vt
+ 3408                                                 ELSIF (c1 = SymTab.ClInt)
+ 3409    AND (c2 = SymTab.ClReal) THEN
+ 3410                                                   QbeGen.ConvIR(q, qa);
+ 3411                                                   QbeGen.CopyOp(qa, q);
+ 3412                                                   t := vt
+ 3413                                                 ELSIF (c1 = SymTab.ClLong)
+ 3414    AND (c2 = SymTab.ClReal) THEN
+ 3415                                                   QbeGen.ConvLR(q, qa);
+ 3416                                                   QbeGen.CopyOp(qa, q);
+ 3417                                                   t := vt
+ 3418                                                 ELSIF (c1 = SymTab.ClReal)
+ 3419    AND (c2 = SymTab.ClInt) THEN
+ 3420                                                   QbeGen.ConvRI(q, qa);
+ 3421                                                   QbeGen.CopyOp(qa, q);
+ 3422                                                   t := vt
+ 3423                                                 ELSIF (c1 = SymTab.ClReal)
+ 3424    AND (c2 = SymTab.ClLong) THEN
+ 3425                                                   QbeGen.ConvRL(q, qa);
+ 3426                                                   QbeGen.CopyOp(qa, q);
+ 3427                                                   t := vt
+ 3428                                                 ELSIF ((c1 = SymTab.ClInt)
+ 3429                                                     OR (c1 =
+ 3430                                                        SymTab.ClChar)
+ 3431                                                     OR (c1 =
+ 3432                                                        SymTab.ClBool)
+ 3433                                                     OR (c1 =
+ 3434                                                        SymTab.ClEnum))
+ 3435   AND ((c2 = SymTab.ClInt)
+ 3436                                                     OR (c2 =
+ 3437                                                        SymTab.ClChar)
+ 3438                                                     OR (c2 =
+ 3439                                                        SymTab.ClBool)
+ 3440                                                     OR (c2 =
+ 3441                                                        SymTab.ClEnum)) THEN
+ 3442                                                   t := vt
+ 3443                                                 ELSIF (c1 = SymTab.ClPtr)
+ 3444   AND (c2 = SymTab.ClPtr) THEN
+ 3445                                                   t := vt
+ 3446                                                 ELSIF (c1 = SymTab.ClReal)
+ 3447   AND (c2 = SymTab.ClReal) THEN
+ 3448                                                   t := vt
+ 3449                                                 ELSE SemError(230);
+ 3450                                                   t := SymTab.InvalidType
+ 3451                                                 END
+ 3452                                               END
+ 3453                                             END; .)
+ 3454      | "(" Expr<et, q> ")"               (. t := et; astIsLit := TRUE; .)
+ 3455      | SetLit<st, sq>                    (. astIsLit := TRUE; t := st;
+ 3456                                             QbeGen.CopyOp(sq, q); .)
+ 3457      | ( "NOT" | "~" ) Fact<t2, q2>      (. astNot := astCur;
+ 3458                                             IF SymTab.BoolCheck(t2) THEN
+ 3459                                               t := SymTab.BoolType()
+ 3460                                             ELSE SemError(212);
+ 3461                                               t := SymTab.InvalidType END;
+ 3462                                             IF t # SymTab.InvalidType THEN
+ 3463                                                QbeGen.CopyOp("@", q)
+ 3464                                             ELSE QbeGen.CopyOp("0", q)
+ 3465                                             END;
+ 3466                                             astIsLit := TRUE;
+ 3467                                             astCur := AST.MakeUn(
+ 3468                                               AST.NkUnary, AST.OpNot, astNot); .)
+ 3469      )
+ 3470      (. IF NOT astIsLit THEN astCur := AST.NoNode END; .)
+ 3471             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 3472    (* Set literals are SET OF [0..255] (8 words); elements validated
+ 3473       0..255 statically when foldable (222 otherwise), runtime trap
+ 3474       for computed elements. Ranges always lower via SetRange. *)
+ 3475    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3476                                          (. VAR astNode: AST.Node; .)
+ 3477      = "{"                               (. t := SymTab.NewSet(
+ 3478                                               SymTab.NewSubR(0, 255));
+ 3479                                             astNode := AST.MakeNode(AST.NkSetLit);
+ 3480                                             QbeGen.NewSetTemp(8, q);
+ 3481                                             QbeGen.SetZero(q, 8); .)
+ 3482        [ SetElem<t, q, astNode> { "," SetElem<t, q, astNode> } ]
+ 3483        "}"                               (. astCur := astNode; .) .
+ 3484    (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set)
+ 3485       or ArrayName{...} (an array constructor, GNU Modula-2).  The
+ 3486       declared type sets the width (set) or element type (array). *)
+ 3487    TypedBraceLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3488                                          (. VAR nw: CARDINAL;
+ 3489                                               astNode, astTail: AST.Node;
+ 3490                                               savedCls: INTEGER; .)
+ 3491      = "{"                               (. savedCls := braceCls;
+ 3492                                             astNode := AST.MakeNode(AST.NkBraceLit);
+ 3493                                             AST.SetTy(astNode, vt);
+ 3494                                             astTail := astNode;
+ 3495                                             IF vt = SymTab.InvalidType THEN
+ 3496                                               braceCls := -1
+ 3497                                             ELSE braceCls :=
+ 3498                                                    SymTab.ClassOf(vt)
+ 3499                                             END;
+ 3500                                             IF braceCls = SymTab.ClSet THEN
+ 3501                                               IF vt = SymTab.InvalidType THEN
+ 3502                                                 nw := 8
+ 3503                                               ELSE nw := SymTab.SetWords(vt);
+ 3504                                                 IF nw = 0 THEN nw := 8 END
+ 3505                                               END;
+ 3506                                               QbeGen.NewSetTemp(nw, q);
+ 3507                                               QbeGen.SetZero(q, nw)
+ 3508                                             ELSIF (braceCls =
+ 3509                                                    SymTab.ClArray)
+ 3510                                                OR (braceCls =
+ 3511                                                    SymTab.ClRecord)
+ 3512                                                OR (braceCls =
+ 3513                                                    SymTab.ClClass) THEN
+ 3514                                               QbeGen.CtorBegin(vt)
+ 3515                                             ELSE
+ 3516                                               IF vt # SymTab.InvalidType THEN
+ 3517                                                 SemError(230) END;
+ 3518                                               braceCls := -1
+ 3519                                             END; .)
+ 3520        [ BraceElem<vt, q, astNode, astTail>
+ 3521          { "," BraceElem<vt, q, astNode, astTail> } ]
+ 3522        "}"                               (. IF (braceCls = SymTab.ClArray)
+ 3523                                                OR (braceCls =
+ 3524                                                   SymTab.ClRecord)
+ 3525                                                OR (braceCls =
+ 3526                                                   SymTab.ClClass) THEN
+ 3527                                               QbeGen.CtorEnd(q)
+ 3528                                             ELSIF braceCls # SymTab.ClSet THEN
+ 3529                                               QbeGen.CopyOp("0", q)
+ 3530                                             END;
+ 3531                                             braceCls := savedCls; .)
+ 3532                                          (. astCur := astNode; .) .
+ 3533    BraceElem<vt: SymTab.TypeIndex; VAR sq: QbeGen.QVal;
+ 3534              VAR node, tail: AST.Node>
+ 3535                                          (. VAR et, et2: SymTab.TypeIndex;
+ 3536                                               qe, q2: QbeGen.QVal;
+ 3537                                               v, v2, reps, k: INTEGER;
+ 3538                                               elem: SymTab.TypeIndex;
+ 3539                                               lo: INTEGER;
+ 3540                                               span: CARDINAL;
+ 3541                                               cl, cl2: INTEGER;
+ 3542                                               hasR, hasB: BOOLEAN;
+ 3543                                               astEl: AST.Node; .)
+ 3544      =                                   (. hasR := FALSE; hasB := FALSE;
+ 3545                                             reps := 1; .)
+ 3546        Expr<et, qe> (. astEl := astCur; .)
+ 3547        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
+ 3548                                               AST.NkSubrange, 0, astEl, astCur);
+ 3549                                             hasR := TRUE; .) ]
+ 3550        [ "BY" Expr<et2, q2>              (. hasB := TRUE; .) ]
+ 3551                                          (. IF braceCls = SymTab.ClSet THEN
+ 3552                                               IF hasB THEN SemError(230) END;
+ 3553                                               lo := SymTab.SetBaseLo(vt);
+ 3554                                               span := SymTab.SetCount(vt);
+ 3555                                               IF (et = SymTab.InvalidType)
+ 3556                                                  OR (hasR AND (et2 =
+ 3557                                                     SymTab.InvalidType)) THEN
+ 3558                                               ELSE cl :=
+ 3559                                                      SymTab.ClassOf(et);
+ 3560                                                 IF hasR THEN
+ 3561                                                   cl2 :=
+ 3562                                                     SymTab.ClassOf(et2)
+ 3563                                                 ELSE cl2 := SymTab.ClInt
+ 3564                                                 END;
+ 3565                                                 IF NOT SymTab.SetElemClassOk(cl)
+ 3566                                                    OR (hasR AND NOT
+ 3567                                                       SymTab.SetElemClassOk(cl2))
+ 3568                                                 THEN
+ 3569                                                   SemError(222)
+ 3570                                                 ELSIF hasR
+ 3571   AND SymTab.ConstInt(qe, v)
+ 3572   AND SymTab.ConstInt(q2,
+ 3573                                                       v2)
+ 3574   AND ((v < lo)
+ 3575                                                       OR (v2 < lo)
+ 3576                                                       OR (v >= lo +
+ 3577                                                          VAL(INTEGER, span))
+ 3578                                                       OR (v2 >= lo +
+ 3579                                                          VAL(INTEGER, span))
+ 3580                                                       OR (v > v2)) THEN
+ 3581                                                   SemError(222)
+ 3582                                                  ELSIF hasR THEN
+ 3583                                                    QbeGen.SetRange(sq, qe, q2,
+ 3584                                                      lo, span)
+ 3585                                                  ELSIF SymTab.ConstInt(qe,
+ 3586                                                          v)
+ 3587   AND ((v < lo)
+ 3588                                                        OR (v >= lo +
+ 3589                                                           VAL(INTEGER,
+ 3590                                                             span))) THEN
+ 3591                                                    SemError(222)
+ 3592                                                  ELSE QbeGen.SetBit(sq, qe,
+ 3593                                                    lo, span)
+ 3594                                                 END
+ 3595                                               END
+ 3596                                             ELSIF (braceCls = SymTab.ClArray)
+ 3597                                                OR (braceCls =
+ 3598                                                   SymTab.ClRecord)
+ 3599                                                OR (braceCls =
+ 3600                                                   SymTab.ClClass) THEN
+ 3601                                               IF hasR THEN SemError(230) END;
+ 3602                                               reps := 1;
+ 3603                                               IF hasB THEN
+ 3604                                                 IF SymTab.ConstInt(q2, v2)
+ 3605   AND (v2 >= 1) THEN
+ 3606                                                   reps := v2
+ 3607                                                 ELSE SemError(230)
+ 3608                                                 END
+ 3609                                               END;
+ 3610                                               k := 0;
+ 3611                                               WHILE k < reps DO
+ 3612                                                 QbeGen.CtorElem(qe);
+ 3613                                                 INC(k)
+ 3614                                               END
+ 3615                                             END; .)
+ 3616                                          (. (* the BY form repeats the
+ 3617                                               element; keep the AST in
+ 3618                                               step with CtorElem *)
+ 3619                                             k := 0;
+ 3620                                             WHILE k < reps DO
+ 3621                                               AstAppend(AST.NkBlock,
+ 3622                                                 node, tail, astEl);
+ 3623                                               INC(k)
+ 3624                                             END; .) .
+ 3625    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal; node: AST.Node>         (. VAR et, et2: SymTab.TypeIndex;
+ 3626                                               qe, q2: QbeGen.QVal;
+ 3627                                               v, v2: INTEGER;
+ 3628                                               lo: INTEGER;
+ 3629                                               span: CARDINAL;
+ 3630                                               cl, cl2: INTEGER;
+ 3631                                               hasR: BOOLEAN;
+ 3632                                               astEl: AST.Node; .)
+ 3633      =                                   (. hasR := FALSE; .)
+ 3634        Expr<et, qe> (. astEl := astCur; .)
+ 3635        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
+ 3636                                               AST.NkSubrange, 0, astEl, astCur);
+ 3637                                             hasR := TRUE; .) ]
+ 3638                                          (. lo := SymTab.SetBaseLo(st);
+ 3639                                             span := SymTab.SetCount(st);
+ 3640                                             IF (et = SymTab.InvalidType)
+ 3641                                                OR (hasR AND (et2 =
+ 3642                                                   SymTab.InvalidType)) THEN
+ 3643                                             ELSE cl :=
+ 3644                                                    SymTab.ClassOf(et);
+ 3645                                               IF hasR THEN
+ 3646                                                 cl2 :=
+ 3647                                                   SymTab.ClassOf(et2)
+ 3648                                               ELSE cl2 := SymTab.ClInt
+ 3649                                               END;
+ 3650                                               IF NOT SymTab.SetElemClassOk(cl)
+ 3651                                                  OR (hasR AND NOT
+ 3652                                                     SymTab.SetElemClassOk(cl2))
+ 3653                                               THEN
+ 3654                                                 SemError(222)
+ 3655                                               ELSIF hasR
+ 3656   AND SymTab.ConstInt(qe, v)
+ 3657   AND SymTab.ConstInt(q2,
+ 3658                                                     v2)
+ 3659   AND ((v < lo)
+ 3660                                                     OR (v2 < lo)
+ 3661                                                     OR (v >= lo +
+ 3662                                                        VAL(INTEGER, span))
+ 3663                                                     OR (v2 >= lo +
+ 3664                                                        VAL(INTEGER, span))
+ 3665                                                     OR (v > v2)) THEN
+ 3666                                                 SemError(222)
+ 3667                                                ELSIF hasR THEN
+ 3668                                                  QbeGen.SetRange(sq, qe, q2,
+ 3669                                                    lo, span)
+ 3670                                                ELSIF SymTab.ConstInt(qe,
+ 3671                                                        v)
+ 3672   AND ((v < lo)
+ 3673                                                      OR (v >= lo +
+ 3674                                                         VAL(INTEGER,
+ 3675                                                           span))) THEN
+ 3676                                                  SemError(222)
+ 3677                                                ELSE QbeGen.SetBit(sq, qe,
+ 3678                                                  lo, span)
+ 3679                                               END
+ 3680                                             END; .)
+ 3681                                          (. AST.SetChild(node,
+ 3682                                               AST.NChild(node), astEl); .) .
+ 3683    GetIdent<VAR n: SymTab.Name>
+ 3684      = ident                             (. LexName(n); .) .
+ 3685  
+ 3686  END M2.
 
 
     0 errors
     0 errors
 
 

+ 2 - 14
compiler/src/compiler.frm

@@ -12,7 +12,7 @@ MODULE -->Grammar;
     RefineSeen, RefineIsDef, RefineInst, RefineGen,
     RefineSeen, RefineIsDef, RefineInst, RefineGen,
     RefineActualCount, RefineActualGet, SetTwoPhase;
     RefineActualCount, RefineActualGet, SetTwoPhase;
   IMPORT
   IMPORT
-    Strings, Storage, SYSTEM, FileIO, SymTab, QbeGen, AST, Lower, Check;
+    Strings, Storage, SYSTEM, FileIO, SymTab, QbeGen, AST, Lower;
     (* and any others needed *)
     (* and any others needed *)
 
 
   TYPE
   TYPE
@@ -286,7 +286,6 @@ MODULE -->Grammar;
     nFiles: CARDINAL;
     nFiles: CARDINAL;
     f: CARDINAL;
     f: CARDINAL;
     bad: BOOLEAN;
     bad: BOOLEAN;
-    doCheck: BOOLEAN;   (* run the resolve/check pass (Check.Resolve) *)
     doTwoPhase: BOOLEAN; (* two-phase parse: defer procedure bodies *)
     doTwoPhase: BOOLEAN; (* two-phase parse: defer procedure bodies *)
 
 
     (* generics (Increment 2): module name -> source path, def and impl *)
     (* generics (Increment 2): module name -> source path, def and impl *)
@@ -405,11 +404,9 @@ MODULE -->Grammar;
     END;
     END;
     AST.Init;
     AST.Init;
     Lower.BeginUnit;
     Lower.BeginUnit;
-    Check.BeginUnit;
     SetTwoPhase(doTwoPhase);
     SetTwoPhase(doTwoPhase);
     Parse;
     Parse;
     InstEnd;
     InstEnd;
-    IF doCheck THEN Check.Resolve(GetUnit()) END;
     Lower.LowerUnitNow(GetUnit(), FALSE);
     Lower.LowerUnitNow(GetUnit(), FALSE);
     IF (src # FileIO.StdIn) & (src # FileIO.StdOut) THEN
     IF (src # FileIO.StdIn) & (src # FileIO.StdOut) THEN
       FileIO.Close(src)
       FileIO.Close(src)
@@ -420,16 +417,11 @@ MODULE -->Grammar;
   BEGIN
   BEGIN
     (* collect the session's source files (program module last) *)
     (* collect the session's source files (program module last) *)
     nFiles := 0;
     nFiles := 0;
-    doCheck := TRUE;
     doTwoPhase := TRUE;   (* two-phase parse on by default (-notwophase off) *)
     doTwoPhase := TRUE;   (* two-phase parse on by default (-notwophase off) *)
     LOOP
     LOOP
       FileIO.NextParameter(sourceName);
       FileIO.NextParameter(sourceName);
       IF (sourceName[0] = CHR(0)) OR (nFiles > HIGH(files)) THEN EXIT END;
       IF (sourceName[0] = CHR(0)) OR (nFiles > HIGH(files)) THEN EXIT END;
-      IF EqNm(sourceName, "-noresolve") THEN
-        doCheck := FALSE
-      ELSIF EqNm(sourceName, "-twophase") THEN
-        doTwoPhase := TRUE
-      ELSIF EqNm(sourceName, "-notwophase") THEN
+      IF EqNm(sourceName, "-notwophase") THEN
         doTwoPhase := FALSE
         doTwoPhase := FALSE
       ELSE
       ELSE
         Strings.Assign(sourceName, files[nFiles]);
         Strings.Assign(sourceName, files[nFiles]);
@@ -445,7 +437,6 @@ MODULE -->Grammar;
     SymTab.Init;
     SymTab.Init;
     QbeGen.OpenModule(progName);
     QbeGen.OpenModule(progName);
     Lower.BeginSession(progName);
     Lower.BeginSession(progName);
-    Check.BeginSession(progName);
     Error := StoreError;
     Error := StoreError;
 
 
     (* parse each unit into the shared session *)
     (* parse each unit into the shared session *)
@@ -467,11 +458,9 @@ MODULE -->Grammar;
       FileIO.WriteLn(FileIO.StdOut);
       FileIO.WriteLn(FileIO.StdOut);
       AST.Init;
       AST.Init;
       Lower.BeginUnit;
       Lower.BeginUnit;
-      Check.BeginUnit;
       SetTwoPhase(doTwoPhase);
       SetTwoPhase(doTwoPhase);
       Parse;
       Parse;
       UnitNameGet(uname);
       UnitNameGet(uname);
-      IF doCheck THEN Check.Resolve(GetUnit()) END;
       IF RefineSeen() THEN
       IF RefineSeen() THEN
         DoInst
         DoInst
       ELSIF UnitIsGeneric() THEN
       ELSIF UnitIsGeneric() THEN
@@ -497,7 +486,6 @@ MODULE -->Grammar;
     END;
     END;
 
 
     Lower.EndSession;
     Lower.EndSession;
-    Check.EndSession;
 
 
     IF bad OR NOT SymTab.HaveProgram()
     IF bad OR NOT SymTab.HaveProgram()
       THEN FileIO.WriteString(FileIO.StdOut, "Incorrect source")
       THEN FileIO.WriteString(FileIO.StdOut, "Incorrect source")

+ 18 - 0
docs/plan-two-phase-parse.md

@@ -287,3 +287,21 @@ alone.
     machinery — is **achieved**.  Remaining cleanup (separate): `Check`
     machinery — is **achieved**.  Remaining cleanup (separate): `Check`
     is now mostly a vestigial walk (`PropNode`/`EvalExpr`/`CheckAssign`
     is now mostly a vestigial walk (`PropNode`/`EvalExpr`/`CheckAssign`
     re-type/ re-check nothing once no node is `Ty = -1`).
     re-type/ re-check nothing once no node is `Ty = -1`).
+- **2026-10-16, cleanup — `Check` removed, scaffolding dropped.**
+  - Measured first: instrumenting `PropNode` showed it *did* re-type
+    `Ty = -1` nodes in 31 tests, but gutting `Resolve` left the emitted
+    `.ssa` **byte-identical** across all 141 suite files (and
+    `201/201`).  So the walk was cosmetic: `Lower` recomputes what it
+    needs, and `Check` emitted no diagnostics (its only source,
+    `CheckAssign`, was reachable only via the deleted `Op=1` marker).
+  - **Deleted** `Check.def`/`Check.mod` outright, its driver calls, the
+    `-noresolve` option (it only gated that pass), and the atg import.
+    `build.sh` drops `Check`; `fixpoint.sh` needs nothing (it stages
+    `src/*.def`/`*.mod` dynamically).  Also removed the now-unused
+    `procNest` and the always-true L7 scaffolding flag `twoPhase` (13
+    sites in the atg, all inert guards around AST building).
+  - **Verified**: suite **201/201**; **fixpoint OK (3,555,791 bytes)**;
+    `.ssa` byte-identical on spot-checks and the 141-file set.
+  - The pipeline is now `Parse (builds AST; bodies deferred and
+    re-parsed at unit end) -> Lower -> Emit`.  There is no separate
+    resolve/check pass because binding is late by construction.

+ 13 - 0
docs/summary_two-phase-m2-2026-10-16.md

@@ -126,6 +126,19 @@ This closes the resolve/check thread's goal.  Remaining cleanup
 (`PropNode`/`EvalExpr`/`CheckAssign` re-type/re-check nothing once no
 (`PropNode`/`EvalExpr`/`CheckAssign` re-type/re-check nothing once no
 node is `Ty = -1`).
 node is `Ty = -1`).
 
 
+## Cleanup done (same session) — `Check` removed
+
+Instrumented `PropNode` first: it did re-type `Ty = -1` nodes in 31
+tests, but **gutting `Resolve` left the emitted `.ssa` byte-identical**
+across all 141 suite files (and the suite `201/201`) — `Lower`
+recomputes what it needs and `Check` emitted no diagnostics.  So
+`Check.def`/`Check.mod` were **deleted** along with the driver calls,
+the `-noresolve` option, and the atg import; `build.sh` drops `Check`
+(`fixpoint.sh` stages sources dynamically).  Also removed the unused
+`procNest` and the always-true L7 flag `twoPhase`.  Pipeline is now
+`Parse -> Lower -> Emit`.  Suite **201/201**, fixpoint OK
+(3,555,791 bytes).
+
 ## Resume
 ## Resume
 
 
 ```sh
 ```sh