Explorar el Código

lower L7: scope-aware proc lookup, per-unit globals, qualified proc vars

Compiler-session divergence moved from QbeGen.ArrBodyItems (line ~56294)
to Fact's generic ArgList call (line ~89349).

- FindProc is now scope-aware: a nested procedure (e.g. the two `Sep`s)
  resolves to the one in the emitted procedure's chain, not the last
  duplicate.  NoteProcNode records the proc-table index in each
  NkProcDecl's ty field; LowerDecls uses ProcInfoIdx/ParamInfoIdx so a
  duplicate name gets the right uid and the right scope for its locals.
- Class/definition method headings now Lower.ScopeLeave (class method
  declarations, MethodImpl bodies and FORWARDs, and DefUnit headings);
  without it curScopeProc stayed on the heading and corrupted the proc
  parent chain.
- SymTab.MaterializeReplace: an already-visible name is updated to the
  current unit's symbol.  Lower re-emits one unit at a time and units
  share names (scopeTop, EOL), so the plain Materialize kept the first
  one and e.g. Lower.Reset emitted $QbeGen_scopeTop.
- Qualified proc-typed variables (M2S.Error(...)) are detected via
  CalleeAlias (qualIsVar) and called indirectly.
- Qualified calls (M.SymTab.StrLen) select the exact proc entry by the
  materialised alias's uid (FindProcByUid), not the base name.

Suite 204/204; FIXPOINT OK (3,758,751 bytes), session 0 errors.

Remaining: a call with more than MaxChild-1 (7) arguments is still
capped by AstCallNode (the generic ArgList has 9), so Lower drops the
tail.  Chunking the call actuals needs the arg loops to follow the
chunks.
Eric Streit hace 1 semana
padre
commit
f593a8ff1d
Se han modificado 6 ficheros con 3732 adiciones y 3574 borrados
  1. 1 0
      compiler/src/Lower.def
  2. 129 14
      compiler/src/Lower.mod
  3. 8 2
      compiler/src/M2.atg
  4. 3564 3558
      compiler/src/M2.lst
  5. 5 0
      compiler/src/SymTab.def
  6. 25 0
      compiler/src/SymTab.mod

+ 1 - 0
compiler/src/Lower.def

@@ -43,6 +43,7 @@ PROCEDURE ScopeLeave;
 PROCEDURE NoteProc (name: ARRAY OF CHAR; uid: CARDINAL;
                     res: SymTab.TypeIndex; depth: CARDINAL; ext: BOOLEAN);
 PROCEDURE MarkProcExternal;
+PROCEDURE NoteProcNode (n: AST.Node);
 PROCEDURE SetProcRes (t: SymTab.TypeIndex);
 PROCEDURE NoteParam (name: ARRAY OF CHAR; t: SymTab.TypeIndex;
                      isVar: BOOLEAN);

+ 129 - 14
compiler/src/Lower.mod

@@ -52,6 +52,8 @@ VAR
   scopeTop : CARDINAL;
   curScopeProc : INTEGER;   (* owner while parsing: enclosing proc *)
   emitProc : INTEGER;       (* owner while emitting: current proc *)
+  qualUid : CARDINAL;       (* uid of the last M.P alias resolved *)
+  qualIsVar : BOOLEAN;      (* last M.P alias is a proc-typed variable *)
   withRec  : ARRAY [0 .. 15] OF SymTab.TypeIndex;
   withTop  : CARDINAL;
   curMethCls : SymTab.TypeIndex;   (* class bound by the last obj.Method *)
@@ -200,6 +202,39 @@ PROCEDURE MarkProcExternal;
     IF nProcs > 0 THEN procExt[nProcs - 1] := TRUE END
   END MarkProcExternal;
 
+PROCEDURE NoteProcNode (n: AST.Node);
+(* Records the proc-table index in the NkProcDecl's ty field, so
+   LowerDecls can find the exact entry.  FindProc(name) would return the
+   last duplicate (e.g. the two nested `Sep`s), giving the wrong uid and
+   the wrong scope for its locals. *)
+  BEGIN
+    IF nProcs > 0 THEN AST.SetTy(n, VAL(INTEGER, nProcs - 1)) END
+  END NoteProcNode;
+
+PROCEDURE ProcInfoIdx (pi: INTEGER; VAR uid: CARDINAL;
+                       VAR res: SymTab.TypeIndex; VAR depth: CARDINAL;
+                       VAR ext: BOOLEAN; VAR npar: CARDINAL): BOOLEAN;
+  BEGIN
+    IF (pi < 0) OR (pi >= VAL(INTEGER, nProcs)) THEN RETURN FALSE END;
+    uid := procUid[pi]; res := procRes[pi]; depth := procDep[pi];
+    ext := procExt[pi]; npar := procNpar[pi];
+    IF npar > MaxPar THEN npar := MaxPar END;
+    RETURN TRUE
+  END ProcInfoIdx;
+
+PROCEDURE ParamInfoIdx (pi: INTEGER; i: CARDINAL;
+                        VAR t: SymTab.TypeIndex; VAR isVar: BOOLEAN;
+                        VAR pn: ARRAY OF CHAR): BOOLEAN;
+  BEGIN
+    IF (pi < 0) OR (i >= procNpar[pi]) OR (procNpar[pi] > MaxPar) THEN
+      RETURN FALSE
+    END;
+    t := parTy[VAL(CARDINAL, pi) * MaxPar + i];
+    isVar := parVar[VAL(CARDINAL, pi) * MaxPar + i];
+    CopySpan(parName, pn, VAL(CARDINAL, pi) * MaxPar * 64 + i * 64, 0);
+    RETURN TRUE
+  END ParamInfoIdx;
+
 PROCEDURE SetProcRes (t: SymTab.TypeIndex);
   BEGIN
     IF nProcs > 0 THEN procRes[nProcs - 1] := t END
@@ -287,11 +322,71 @@ PROCEDURE GetConstVal (name: ARRAY OF CHAR; VAR v: ARRAY OF CHAR): BOOLEAN;
     RETURN v[0] # CHR(0)
   END GetConstVal;
 
+PROCEDURE ProcNameEq (i: CARDINAL; name: ARRAY OF CHAR): BOOLEAN;
+  VAR j: CARDINAL;
+  BEGIN
+    j := 0;
+    WHILE (j < MaxName) AND (name[j] # CHR(0)) DO
+      IF procName[i * 64 + j] # name[j] THEN RETURN FALSE END;
+      INC(j)
+    END;
+    RETURN procName[i * 64 + j] = name[j]
+  END ProcNameEq;
+
+PROCEDURE ProcVisible (i: INTEGER): BOOLEAN;
+(* TRUE when proc i is nested directly in the emitted procedure or one
+   of its enclosing procedures (or is module-level). *)
+  VAR owner: INTEGER;
+  BEGIN
+    owner := emitProc;
+    WHILE owner >= 0 DO
+      IF procParent[i] = owner THEN RETURN TRUE END;
+      owner := procParent[owner]
+    END;
+    RETURN procParent[i] = -1
+  END ProcVisible;
+
 PROCEDURE FindProc (name: ARRAY OF CHAR): INTEGER;
+(* Scope-aware: a nested procedure (e.g. one of two `Sep`s) must resolve
+   to the one in the emitted procedure's chain, not the last duplicate. *)
+  VAR i: INTEGER; owner: INTEGER;
   BEGIN
-    RETURN HashGet(procHash, procName, name)
+    i := HashGet(procHash, procName, name);
+    IF (i >= 0) AND ProcVisible(i) THEN RETURN i END;
+    owner := emitProc;
+    WHILE owner >= 0 DO
+      i := VAL(INTEGER, nProcs) - 1;
+      WHILE i > 0 DO
+        DEC(i);
+        IF (procParent[i] = owner) AND ProcNameEq(VAL(CARDINAL, i), name) THEN
+          RETURN i
+        END
+      END;
+      owner := procParent[owner]
+    END;
+    i := VAL(INTEGER, nProcs) - 1;
+    WHILE i > 0 DO
+      DEC(i);
+      IF (procParent[i] = -1) AND ProcNameEq(VAL(CARDINAL, i), name) THEN
+        RETURN i
+      END
+    END;
+    RETURN -1
   END FindProc;
 
+PROCEDURE FindProcByUid (uid: CARDINAL): INTEGER;
+(* Exact proc entry for a module-qualified call (M.P): the base name may
+   be duplicated across modules, but the uid is unique. *)
+  VAR i: INTEGER;
+  BEGIN
+    i := VAL(INTEGER, nProcs);
+    WHILE i > 0 DO
+      DEC(i);
+      IF procUid[i] = uid THEN RETURN i END
+    END;
+    RETURN -1
+  END FindProcByUid;
+
 PROCEDURE Resolve (nm: ARRAY OF CHAR; VAR k: INTEGER;
                    VAR t: SymTab.TypeIndex): BOOLEAN;
   VAR kind: INTEGER; ti: SymTab.TypeIndex;
@@ -645,7 +740,10 @@ PROCEDURE CalleeAlias (call: AST.Node; VAR mal: SymTab.Name): BOOLEAN;
     Name(AST.Child(sel, 0), fn);
     IF NOT SymTab.MaterializeAlias(nm, fn, al) THEN RETURN FALSE END;
     (* Lower's proc table is keyed by the base name (the mangled symbol
-       is <base>_<uid>), so return fn, not the materialized alias. *)
+       is <base>_<uid>), so return fn, not the materialized alias.  The
+       uid comes from the alias, which is module-exact. *)
+    qualIsVar := SymTab.SymKind(al) # SymTab.KindProc;
+    qualUid := SymTab.ProcUid(al);
     CopyN(fn, mal);
     RETURN TRUE
   END CalleeAlias;
@@ -1094,15 +1192,29 @@ PROCEDURE LowerCall (n: AST.Node; VAR t: SymTab.TypeIndex;
                      VAR q: QbeGen.QVal; want: BOOLEAN);
   VAR nm, pn, cqn: SymTab.Name; i: CARDINAL; at, ft, res: SymTab.TypeIndex;
       qa, qt, qe, mg: QbeGen.QVal; conv, isV, qual, ind: BOOLEAN;
-      uid, depth, np: CARDINAL; ext: BOOLEAN; ck: INTEGER;
+      uid, depth, np: CARDINAL; ext: BOOLEAN; ck: INTEGER; pi: INTEGER;
       ct: SymTab.TypeIndex; csfx: BOOLEAN;
   BEGIN
     qual := CalleeAlias(n, nm);
     ind := FALSE;
-    IF qual THEN
-      (* A qualified callee (M.P) resolves to the real name; use Lower's
-         tables, not SymTab, whose scopes are closed by now. *)
-      IF ProcInfo(nm, uid, res, depth, ext, np) THEN
+    IF qual AND qualIsVar THEN
+      (* M.Error where Error is a procedure-typed variable: indirect. *)
+      LowerDesign(AST.Child(n, 0), ct, ck, qa, cqn, csfx);
+      IF (ct # SymTab.InvalidType)
+         AND (SymTab.ClassOf(ct) = SymTab.ClProc) THEN
+        ind := TRUE;
+        res := SymTab.ProcTypeRes(ct);
+        np := SymTab.ProcTypeNPar(ct);
+        QbeGen.CallBeginInd(qa, res, FALSE)
+      ELSE
+        res := SymTab.InvalidType;
+        QbeGen.CallBegin(nm, res, 0, FALSE)
+      END
+    ELSIF qual THEN
+      (* M.P: the base name may be duplicated across modules, so select
+         the exact proc entry by the alias's uid. *)
+      pi := FindProcByUid(qualUid);
+      IF ProcInfoIdx(pi, uid, res, depth, ext, np) THEN
         IF ext THEN QbeGen.CopyOp(nm, mg) ELSE QbeGen.Mangled(nm, uid, mg) END;
         QbeGen.CallBegin(mg, res, depth, ext)
       ELSE
@@ -1121,6 +1233,7 @@ PROCEDURE LowerCall (n: AST.Node; VAR t: SymTab.TypeIndex;
         np := SymTab.ProcTypeNPar(ct);
         QbeGen.CallBeginInd(qa, res, FALSE)
       ELSIF ProcInfo(nm, uid, res, depth, ext, np) THEN
+        pi := FindProc(nm);
         IF ext THEN
           (* External callee: bind to its C link name (the procedure's
              own name); SymTab.ProcLink cannot be consulted after
@@ -1142,7 +1255,7 @@ PROCEDURE LowerCall (n: AST.Node; VAR t: SymTab.TypeIndex;
         ft := SymTab.ProcTypeParamType(ct, i - 1);
         isV := SymTab.ProcTypeParamIsVar(ct, i - 1)
       ELSE
-        IF NOT ParamInfo(nm, i - 1, ft, isV, pn) THEN END
+        IF NOT ParamInfoIdx(pi, i - 1, ft, isV, pn) THEN END
       END;
       IF isV THEN
         IF QbeGen.AddrOfVal(qe, qa) THEN
@@ -2039,7 +2152,7 @@ PROCEDURE LowerDecls (seq: AST.Node);
   VAR i, j: CARDINAL; c: AST.Node; nm, txt: SymTab.Name; qv: QbeGen.QVal;
       mg: QbeGen.QVal; uid, depth, np: CARDINAL; res, pt: SymTab.TypeIndex;
       ext, pv: BOOLEAN; kk: INTEGER; ct: SymTab.TypeIndex; savedProc: INTEGER;
-      chunk, vn: AST.Node;
+      chunk, vn: AST.Node; pi: INTEGER;
   BEGIN
     IF seq = AST.NoNode THEN RETURN END;
     i := 0;
@@ -2103,12 +2216,14 @@ PROCEDURE LowerDecls (seq: AST.Node);
         END
       ELSIF AST.Kind(c) = AST.NkProcDecl THEN
         Name(AST.Child(c, 0), nm);
-        IF ProcInfo(nm, uid, res, depth, ext, np) THEN
+        pi := AST.Ty(c);   (* proc-table index recorded by NoteProcNode *)
+        IF (pi < 0) OR (pi >= VAL(INTEGER, nProcs)) THEN pi := FindProc(nm) END;
+        IF ProcInfoIdx(pi, uid, res, depth, ext, np) THEN
           QbeGen.Mangled(nm, uid, mg);
           QbeGen.BeginFunc(mg);
           j := 0;
           WHILE j < np DO
-            IF ParamInfo(nm, j, pt, pv, txt) THEN
+            IF ParamInfoIdx(pi, j, pt, pv, txt) THEN
               IF NOT QbeGen.FuncParam(txt, pv OR SymTab.IsOpenArray(pt), pt) THEN END
             END;
             INC(j)
@@ -2120,7 +2235,7 @@ PROCEDURE LowerDecls (seq: AST.Node);
           ELSE
             QbeGen.EndFuncHeader;
             savedProc := emitProc;
-            emitProc := FindProc(nm);
+            emitProc := pi;
             LowerDecls(AST.Child(c, 2));
             LowerStmt(AST.Child(c, 1));
             emitProc := savedProc;
@@ -2151,7 +2266,7 @@ PROCEDURE MaterializeGlobals (unitName: ARRAY OF CHAR; decls: AST.Node);
             vn := AST.Child(chunk, j);
             IF AST.Kind(vn) = AST.NkIdent THEN
               Name(vn, nm);
-              IF NOT SymTab.Materialize(unitName, nm) THEN END
+              IF NOT SymTab.MaterializeReplace(unitName, nm) THEN END
             END;
             INC(j)
           END;
@@ -2164,7 +2279,7 @@ PROCEDURE MaterializeGlobals (unitName: ARRAY OF CHAR; decls: AST.Node);
       ELSIF (AST.Kind(c) = AST.NkTypeDecl) OR (AST.Kind(c) = AST.NkClassDecl) THEN
         IF AST.NChild(c) >= 1 THEN
           Name(AST.Child(c, 0), nm);
-          IF NOT SymTab.Materialize(unitName, nm) THEN END
+          IF NOT SymTab.MaterializeReplace(unitName, nm) THEN END
         END
       END;
       INC(i)

+ 8 - 2
compiler/src/M2.atg

@@ -288,6 +288,8 @@ PRODUCTIONS
                                              AST.MakeLeaf(AST.NkIdent, pn));
                                            AstAppend(AST.NkDeclSeq,
                                              astSeq, astTail, astProc);
+                                           Lower.NoteProcNode(astProc);
+                                           Lower.ScopeLeave;
                                            SymTab.CloseProc;
                                            QbeGen.AbortFunc; .) }
                                         (. astUnit := AST.MakeNode(AST.NkUnit);
@@ -868,7 +870,8 @@ PRODUCTIONS
       ";"
       { ClassField<ct> ";" }
       { MethodHeading<pn, SymTab.InvalidType> ";"
-                                        (. SymTab.CloseProc;
+                                        (. Lower.ScopeLeave;
+                                           SymTab.CloseProc;
                                            QbeGen.AbortFunc; .) }
       "END"
       GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
@@ -998,6 +1001,7 @@ PRODUCTIONS
       ( "FORWARD"                       (. AST.SetOp(astMethod, 1);
                                            SymTab.MarkFwd;
                                            QbeGen.AbortFunc;
+                                           Lower.ScopeLeave;
                                            SymTab.CloseProc; .)
       |                                 (. QbeGen.EndFuncHeader;
                                            (* bind the receiver: bare
@@ -1008,6 +1012,7 @@ PRODUCTIONS
         Block<pn>                       (. AST.SetChild(astMethod, 1, astStmt);
                                            QbeGen.PopWith;
                                            methRes := SymTab.CurRes();
+                                           Lower.ScopeLeave;
                                            SymTab.CloseProc;
                                            QbeGen.EndFunc(methRes); .) ) .
   ConstBlock                            (. VAR astSeq, astTail: AST.Node; .)
@@ -1242,7 +1247,8 @@ PRODUCTIONS
                                         (. astNode := AST.MakeNode(AST.NkProcDecl);
                                            AST.SetOp(astNode, 0);
                                            AST.SetChild(astNode, 0,
-                                             AST.MakeLeaf(AST.NkIdent, pn)); .)
+                                             AST.MakeLeaf(AST.NkIdent, pn));
+                                           Lower.NoteProcNode(astNode); .)
       ( "FORWARD"                       (. AST.SetOp(astNode, 1);
                                            astDecl := astNode;
                                            Lower.ScopeLeave;

+ 3564 - 3558
compiler/src/M2.lst

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

+ 5 - 0
compiler/src/SymTab.def

@@ -291,6 +291,11 @@ PROCEDURE Materialize (mod, name: ARRAY OF CHAR): BOOLEAN;
 (* FROM-import: clones mod's export into the current scope under
    its plain name. FALSE when mod/name is unknown. *)
 
+PROCEDURE MaterializeReplace (mod, name: ARRAY OF CHAR): BOOLEAN;
+(* Like Materialize, but an already-visible name is updated to mod's
+   symbol (the current unit's global must win for Lower's per-unit
+   re-emit, where units share names like scopeTop/EOL). *)
+
 PROCEDURE MaterializeAlias (mod, name: ARRAY OF CHAR;
                              VAR alias: Name): BOOLEAN;
 (* Qualified access: clones mod's export under a per-module alias

+ 25 - 0
compiler/src/SymTab.mod

@@ -2561,6 +2561,31 @@ PROCEDURE Materialize (mod, name: ARRAY OF CHAR): BOOLEAN;
     RETURN TRUE
   END Materialize;
 
+PROCEDURE MaterializeReplace (mod, name: ARRAY OF CHAR): BOOLEAN;
+(* Like Materialize, but when `name` is already visible it is updated in
+   place to the given module's symbol.  Lower re-emits one unit at a time
+   and every unit has its own `scopeTop`/`EOL`/..., so the current unit's
+   global must win GlobalRef; the plain Materialize keeps the first one. *)
+  VAR src, node, l, r : SymPtr; sc : ScopePtr;
+  BEGIN
+    src := QualNode(mod, name);
+    IF src = NIL THEN RETURN FALSE END;
+    node := TreeFind(curScope^.root, name);
+    IF node # NIL THEN
+      l := node^.left; r := node^.right; sc := node^.scope;
+      node^ := src^;
+      node^.left := l; node^.right := r; node^.scope := sc;
+      RETURN TRUE
+    END;
+    NEW(node);
+    node^ := src^;
+    node^.left := NIL;
+    node^.right := NIL;
+    node^.scope := curScope;
+    IF NOT TreeInsert(curScope, node) THEN RETURN FALSE END;
+    RETURN TRUE
+  END MaterializeReplace;
+
 PROCEDURE BuildAlias (mod, name: ARRAY OF CHAR; VAR alias: Name);
 (* alias := "<mod>$<name>" (a key no identifier can collide with). *)
   VAR i, j : CARDINAL;