Explorar o código

lower L7: remove the dead Can* capability walkers and flip scaffolding

The Can* family (CanLower/CanExpr/CanDecls/CanProc and their helpers
CanType/CanDesign/CanStmt/CanCallArgs/...) was the old per-unit
"is this unit in the supported subset" gate; nothing calls it since the
flip made Lower the only emitter.  Also drop the dead LowerSession and
LowerUnit entry points and the unused SetLower/lowerRequested.

Kept: SaveSession/RestoreSession/SetNoEmit (the grammar still emits
suppressed) and MaterializeGlobals/MaterializeReplace (live, called
from LowerOneUnit).

Suite 204/204; FIXPOINT OK (3,451,319 bytes).
Eric Streit hai 5 días
pai
achega
d730e80a45
Modificáronse 6 ficheiros con 3634 adicións e 4154 borrados
  1. 4 11
      compiler/src/Lower.def
  2. 0 493
      compiler/src/Lower.mod
  3. 0 11
      compiler/src/M2.atg
  4. 3623 3634
      compiler/src/M2.lst
  5. 0 2
      compiler/src/parser.frm
  6. 7 3
      docs/STATUS.md

+ 4 - 11
compiler/src/Lower.def

@@ -1,10 +1,10 @@
 DEFINITION MODULE Lower;
 DEFINITION MODULE Lower;
 (* AST -> QBE walk for the two-phase frontend (docs/plan-lower.md).
 (* AST -> QBE walk for the two-phase frontend (docs/plan-lower.md).
 
 
-   Test-only: after a normal parse has built the AST and emitted the
-   legacy image, CanLower gates whether the unit is in the supported
-   subset; LowerUnit then re-emits it into a fresh QbeGen state, writing
-   gen_ssa/<mod>L.ssa for a byte-compare against the legacy image.
+   The driver (compiler.frm) drives a per-unit re-emit through
+   BeginSession/BeginUnit/LowerUnitNow/EndSession: the grammar's own
+   inline emit runs suppressed, and Lower emits each unit's AST into the
+   one session image.
 
 
    Symbol resolution is self-contained (zero SymTab surface): the grammar
    Symbol resolution is self-contained (zero SymTab surface): the grammar
    records each declaration's kind/type and each procedure's signature in
    records each declaration's kind/type and each procedure's signature in
@@ -13,10 +13,6 @@ DEFINITION MODULE Lower;
 
 
 IMPORT AST, SymTab, QbeGen;
 IMPORT AST, SymTab, QbeGen;
 
 
-PROCEDURE CanLower (unit: AST.Node): BOOLEAN;
-PROCEDURE LowerUnit (unit: AST.Node);
-PROCEDURE LowerSession (units: ARRAY OF AST.Node; n: CARDINAL;
-                        progName: ARRAY OF CHAR);
 PROCEDURE BeginSession (progName: ARRAY OF CHAR);
 PROCEDURE BeginSession (progName: ARRAY OF CHAR);
 PROCEDURE BeginUnit;
 PROCEDURE BeginUnit;
 PROCEDURE LowerUnitNow (unit: AST.Node; isProg: BOOLEAN);
 PROCEDURE LowerUnitNow (unit: AST.Node; isProg: BOOLEAN);
@@ -26,9 +22,6 @@ PROCEDURE EndSession (testSuffix: BOOLEAN);
    gm2's link pass rejects FORWARD and V3 has no whole-module pass, so
    gm2's link pass rejects FORWARD and V3 has no whole-module pass, so
    they are declared here (definition-visible throughout the
    they are declared here (definition-visible throughout the
    implementation) instead of being forward-declared. *)
    implementation) instead of being forward-declared. *)
-PROCEDURE CanExpr (n: AST.Node): BOOLEAN;
-PROCEDURE CanDecls (seq: AST.Node): BOOLEAN;
-PROCEDURE CanProc (proc: AST.Node): BOOLEAN;
 PROCEDURE IsBuiltin (nm: ARRAY OF CHAR): BOOLEAN;
 PROCEDURE IsBuiltin (nm: ARRAY OF CHAR): BOOLEAN;
 PROCEDURE LowerExpr (n: AST.Node; VAR t: SymTab.TypeIndex;
 PROCEDURE LowerExpr (n: AST.Node; VAR t: SymTab.TypeIndex;
                      VAR q: QbeGen.QVal);
                      VAR q: QbeGen.QVal);

+ 0 - 493
compiler/src/Lower.mod

@@ -569,142 +569,6 @@ PROCEDURE CalleeName (call: AST.Node; VAR nm: SymTab.Name);
     IF (d # AST.NoNode) AND (AST.Kind(d) = AST.NkIdent) THEN Name(d, nm) END
     IF (d # AST.NoNode) AND (AST.Kind(d) = AST.NkIdent) THEN Name(d, nm) END
   END CalleeName;
   END CalleeName;
 
 
-PROCEDURE IsCall (n: AST.Node): BOOLEAN;
-  VAR nm: SymTab.Name;
-  BEGIN
-    IF (AST.Kind(n) # AST.NkCall) OR (AST.NChild(n) < 1) THEN RETURN FALSE END;
-    CalleeName(n, nm);
-    RETURN FindProc(nm) >= 0
-  END IsCall;
-
-PROCEDURE CanCallArgs (n: AST.Node): BOOLEAN;
-  VAR nm: SymTab.Name; i: CARDINAL;
-      uid, depth, np: CARDINAL; res: SymTab.TypeIndex; ext: BOOLEAN;
-  BEGIN
-    CalleeName(n, nm);
-    IF NOT ProcInfo(nm, uid, res, depth, ext, np) THEN RETURN FALSE END;
-    IF np # (AST.NChild(n) - 1) THEN RETURN FALSE END;
-    i := 1;
-    WHILE i < AST.NChild(n) DO
-      IF NOT CanExpr(AST.Child(n, i)) THEN RETURN FALSE END;
-      INC(i)
-    END;
-    RETURN TRUE
-  END CanCallArgs;
-
-PROCEDURE CanType (t: SymTab.TypeIndex): BOOLEAN;
-  VAR cls: INTEGER;
-  BEGIN
-    IF t = SymTab.InvalidType THEN RETURN FALSE END;
-    cls := SymTab.ClassOf(t);
-    RETURN (cls = SymTab.ClInt) OR (cls = SymTab.ClBool)
-        OR (cls = SymTab.ClChar) OR (cls = SymTab.ClUChar)
-        OR (cls = SymTab.ClEnum) OR (cls = SymTab.ClReal)
-        OR (cls = SymTab.ClLong) OR (cls = SymTab.ClArray)
-        OR (cls = SymTab.ClSet) OR (cls = SymTab.ClRecord)
-        OR (cls = SymTab.ClPtr) OR (cls = SymTab.ClClass)
-  END CanType;
-
-PROCEDURE CanWithField (nm: ARRAY OF CHAR; VAR t: SymTab.TypeIndex): BOOLEAN;
-  VAR wt: CARDINAL;
-  BEGIN
-    wt := withTop;
-    WHILE wt > 0 DO
-      DEC(wt);
-      IF SymTab.FieldExists(withRec[wt], nm) THEN
-        t := SymTab.FieldType(withRec[wt], nm); RETURN TRUE
-      END
-    END;
-    RETURN FALSE
-  END CanWithField;
-
-PROCEDURE DesignTypeOf (n: AST.Node): SymTab.TypeIndex;
-(* Static type of a designator (no emit); used to push WITH scopes. *)
-  VAR nm, fn: SymTab.Name; k: INTEGER; t: SymTab.TypeIndex;
-      i: CARDINAL; sel: AST.Node;
-  BEGIN
-    IF (n = AST.NoNode) OR (AST.Kind(n) # AST.NkDesignator) THEN
-      RETURN SymTab.InvalidType
-    END;
-    Name(AST.Child(n, 0), nm);
-    IF NOT Resolve(nm, k, t) THEN
-      IF NOT CanWithField(nm, t) THEN RETURN SymTab.InvalidType END
-    END;
-    i := 1;
-    WHILE i < AST.NChild(n) DO
-      sel := AST.Child(n, i);
-      IF AST.Op(sel) = AST.SelField THEN
-        Name(AST.Child(sel, 0), fn); t := SymTab.FieldType(t, fn)
-      ELSIF AST.Op(sel) = AST.SelIndex THEN
-        t := SymTab.ArrayElem(t)
-      ELSIF AST.Op(sel) = AST.SelDeref THEN
-        t := SymTab.PtrBase(t)
-      END;
-      INC(i)
-    END;
-    RETURN t
-  END DesignTypeOf;
-
-PROCEDURE CanDesign (n: AST.Node): BOOLEAN;
-  VAR nm, fn, mal: SymTab.Name; k: INTEGER; t: SymTab.TypeIndex;
-      i: CARDINAL; sel: AST.Node;
-  BEGIN
-    IF AST.Kind(n) # AST.NkDesignator THEN RETURN FALSE END;
-    IF AST.Kind(AST.Child(n, 0)) # AST.NkIdent THEN RETURN FALSE END;
-    Name(AST.Child(n, 0), nm);
-    IF NOT Resolve(nm, k, t) THEN
-      IF CanWithField(nm, t) THEN
-        k := SymTab.KindField
-      ELSIF (curImplCls # SymTab.InvalidType)
-         AND SymTab.MethodExists(curImplCls, nm) THEN
-        k := SymTab.KindProc
-      ELSE RETURN FALSE
-      END
-    END;
-    IF k = SymTab.KindModule THEN
-      (* qualified name: the first .field resolves the export *)
-    ELSE
-      IF (k # SymTab.KindVar) AND (k # SymTab.KindParam)
-         AND (k # SymTab.KindConst) AND (k # SymTab.KindField) THEN
-        RETURN FALSE
-      END;
-      IF NOT CanType(t) THEN RETURN FALSE END
-    END;
-    i := 1;
-    WHILE i < AST.NChild(n) DO
-      sel := AST.Child(n, i);
-      IF AST.Op(sel) = AST.SelField THEN
-        Name(AST.Child(sel, 0), fn);
-        IF k = SymTab.KindModule THEN
-          IF NOT SymTab.MaterializeAlias(nm, fn, mal) THEN RETURN FALSE END;
-          t := SymTab.SymType(mal); k := SymTab.SymKind(mal)
-        ELSIF t = SymTab.InvalidType THEN RETURN FALSE
-        ELSIF (SymTab.ClassOf(t) = SymTab.ClClass)
-           AND SymTab.MethodExists(t, fn) THEN
-          k := SymTab.KindProc; t := SymTab.InvalidType
-        ELSIF (SymTab.ClassOf(t) # SymTab.ClRecord)
-           AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
-          RETURN FALSE
-        ELSIF NOT SymTab.FieldExists(t, fn) THEN RETURN FALSE
-        ELSE t := SymTab.FieldType(t, fn)
-        END
-      ELSIF AST.Op(sel) = AST.SelIndex THEN
-        IF (t = SymTab.InvalidType)
-           OR (SymTab.ClassOf(t) # SymTab.ClArray) THEN RETURN FALSE END;
-        IF NOT CanExpr(AST.Child(sel, 0)) THEN RETURN FALSE END;
-        t := SymTab.ArrayElem(t)
-      ELSIF AST.Op(sel) = AST.SelDeref THEN
-        IF (t = SymTab.InvalidType)
-           OR (SymTab.ClassOf(t) # SymTab.ClPtr) THEN RETURN FALSE END;
-        t := SymTab.PtrBase(t)
-      ELSE RETURN FALSE
-      END;
-      IF (k # SymTab.KindProc) AND NOT CanType(t) THEN RETURN FALSE END;
-      INC(i)
-    END;
-    RETURN TRUE
-  END CanDesign;
-
 PROCEDURE IsMethodCall (n: AST.Node): BOOLEAN;
 PROCEDURE IsMethodCall (n: AST.Node): BOOLEAN;
 (* n is a call whose callee resolves to a class method: `obj.Method`,
 (* n is a call whose callee resolves to a class method: `obj.Method`,
    `p^.Method`, or a bare sibling name inside an implementation. *)
    `p^.Method`, or a bare sibling name inside an implementation. *)
@@ -752,18 +616,6 @@ PROCEDURE IsMethodCall (n: AST.Node): BOOLEAN;
     RETURN FALSE
     RETURN FALSE
   END IsMethodCall;
   END IsMethodCall;
 
 
-PROCEDURE CanMethodCall (n: AST.Node): BOOLEAN;
-  VAR i: CARDINAL;
-  BEGIN
-    IF NOT IsMethodCall(n) THEN RETURN FALSE END;
-    i := 1;
-    WHILE i < AST.NChild(n) DO
-      IF NOT CanExpr(AST.Child(n, i)) THEN RETURN FALSE END;
-      INC(i)
-    END;
-    RETURN TRUE
-  END CanMethodCall;
-
 PROCEDURE CalleeAlias (call: AST.Node; VAR mal: SymTab.Name): BOOLEAN;
 PROCEDURE CalleeAlias (call: AST.Node; VAR mal: SymTab.Name): BOOLEAN;
 (* Callee is `M.P` (module-qualified): materialize the export alias. *)
 (* Callee is `M.P` (module-qualified): materialize the export alias. *)
   VAR d, sel: AST.Node; nm, fn, al: SymTab.Name; k: INTEGER;
   VAR d, sel: AST.Node; nm, fn, al: SymTab.Name; k: INTEGER;
@@ -788,307 +640,6 @@ PROCEDURE CalleeAlias (call: AST.Node; VAR mal: SymTab.Name): BOOLEAN;
     CopyN(fn, mal);
     CopyN(fn, mal);
     RETURN TRUE
     RETURN TRUE
   END CalleeAlias;
   END CalleeAlias;
-
-PROCEDURE IsQualifiedCall (n: AST.Node): BOOLEAN;
-  VAR mal: SymTab.Name;
-  BEGIN
-    IF AST.Kind(n) # AST.NkCall THEN RETURN FALSE END;
-    RETURN CalleeAlias(n, mal)
-  END IsQualifiedCall;
-
-PROCEDURE CanQualifiedCall (n: AST.Node): BOOLEAN;
-  VAR i: CARDINAL;
-  BEGIN
-    i := 1;
-    WHILE i < AST.NChild(n) DO
-      IF NOT CanExpr(AST.Child(n, i)) THEN RETURN FALSE END;
-      INC(i)
-    END;
-    RETURN TRUE
-  END CanQualifiedCall;
-
-PROCEDURE CanBuiltin (n: AST.Node): BOOLEAN;
-  VAR i: CARDINAL;
-  BEGIN
-    i := 1;
-    WHILE i < AST.NChild(n) DO
-      IF NOT CanExpr(AST.Child(n, i)) THEN RETURN FALSE END;
-      INC(i)
-    END;
-    RETURN TRUE
-  END CanBuiltin;
-
-PROCEDURE CanCaseLabel (lab: AST.Node): BOOLEAN;
-  BEGIN
-    IF AST.Kind(lab) = AST.NkSubrange THEN
-      RETURN CanExpr(AST.Child(lab, 0)) AND CanExpr(AST.Child(lab, 1))
-    END;
-    RETURN CanExpr(lab)
-  END CanCaseLabel;
-
-PROCEDURE CanExpr (n: AST.Node): BOOLEAN;
-  VAR op: INTEGER; nm: SymTab.Name; i: CARDINAL;
-  BEGIN
-    IF n = AST.NoNode THEN RETURN FALSE END;
-    IF AST.Kind(n) = AST.NkIntLit THEN RETURN TRUE END;
-    IF AST.Kind(n) = AST.NkCharLit THEN RETURN TRUE END;
-    IF AST.Kind(n) = AST.NkRealLit THEN RETURN TRUE END;
-    IF AST.Kind(n) = AST.NkStrLit THEN RETURN TRUE END;
-    IF AST.Kind(n) = AST.NkSetLit THEN
-      i := 0;
-      WHILE i < AST.NChild(n) DO
-        IF AST.Kind(AST.Child(n, i)) = AST.NkSubrange THEN
-          IF NOT CanExpr(AST.Child(AST.Child(n, i), 0)) THEN RETURN FALSE END;
-          IF NOT CanExpr(AST.Child(AST.Child(n, i), 1)) THEN RETURN FALSE END
-        ELSIF NOT CanExpr(AST.Child(n, i)) THEN RETURN FALSE
-        END;
-        INC(i)
-      END;
-      RETURN TRUE
-    END;
-    IF AST.Kind(n) = AST.NkDesignator THEN RETURN CanDesign(n) END;
-    IF AST.Kind(n) = AST.NkCall THEN
-      IF IsMethodCall(n) THEN RETURN CanMethodCall(n) END;
-      IF IsQualifiedCall(n) THEN RETURN CanQualifiedCall(n) END;
-      CalleeName(n, nm);
-      IF IsBuiltin(nm) THEN RETURN CanBuiltin(n) END;
-      RETURN IsCall(n) AND CanCallArgs(n)
-    END;
-    IF AST.Kind(n) = AST.NkUnary THEN
-      op := AST.Op(n);
-      IF (op # AST.OpSub) AND (op # AST.OpNot) THEN RETURN FALSE END;
-      RETURN CanExpr(AST.Child(n, 0))
-    END;
-    IF AST.Kind(n) = AST.NkBinExpr THEN
-      op := AST.Op(n);
-      IF NOT (IsArith(op) OR IsRel(op)
-              OR (op = AST.OpAnd) OR (op = AST.OpOr)) THEN
-        RETURN FALSE END;
-      RETURN CanExpr(AST.Child(n, 0)) AND CanExpr(AST.Child(n, 1))
-    END;
-    RETURN FALSE
-  END CanExpr;
-
-PROCEDURE CanStmt (n: AST.Node): BOOLEAN;
-  VAR i: CARDINAL; k: INTEGER; by: AST.Node; nm: SymTab.Name;
-      arm: AST.Node; j: CARDINAL; withSave: CARDINAL; ok: BOOLEAN;
-  BEGIN
-    IF n = AST.NoNode THEN RETURN TRUE END;
-    k := AST.Kind(n);
-    IF k = AST.NkBlock THEN
-      i := 0;
-      WHILE i < AST.NChild(n) DO
-        IF NOT CanStmt(AST.Child(n, i)) THEN RETURN FALSE END;
-        INC(i)
-      END;
-      RETURN TRUE
-    END;
-    IF k = AST.NkAssign THEN
-      RETURN CanDesign(AST.Child(n, 0)) AND CanExpr(AST.Child(n, 1))
-    END;
-    IF k = AST.NkIf THEN
-      RETURN CanExpr(AST.Child(n, 0)) AND CanStmt(AST.Child(n, 1))
-             AND CanStmt(AST.Child(n, 2))
-    END;
-    IF k = AST.NkWhile THEN
-      RETURN CanExpr(AST.Child(n, 0)) AND CanStmt(AST.Child(n, 1))
-    END;
-    IF k = AST.NkRepeat THEN
-      RETURN CanStmt(AST.Child(n, 0)) AND CanExpr(AST.Child(n, 1))
-    END;
-    IF k = AST.NkLoop THEN RETURN CanStmt(AST.Child(n, 0)) END;
-    IF k = AST.NkExit THEN RETURN TRUE END;
-    IF k = AST.NkFor THEN
-      by := AST.Child(n, 3);
-      IF (by # AST.NoNode) AND (AST.Kind(by) # AST.NkIntLit) THEN
-        RETURN FALSE END;
-      RETURN (AST.Kind(AST.Child(n, 0)) = AST.NkIdent)
-             AND CanExpr(AST.Child(n, 1)) AND CanExpr(AST.Child(n, 2))
-             AND CanStmt(AST.Child(n, 4))
-    END;
-    IF k = AST.NkWith THEN
-      withSave := withTop;
-      j := 0;
-      WHILE j + 1 < AST.NChild(n) DO
-        IF NOT CanDesign(AST.Child(n, j)) THEN
-          withTop := withSave; RETURN FALSE
-        END;
-        IF withTop <= HIGH(withRec) THEN
-          withRec[withTop] := DesignTypeOf(AST.Child(n, j)); INC(withTop)
-        END;
-        INC(j)
-      END;
-      ok := CanStmt(AST.Child(n, AST.NChild(n) - 1));
-      withTop := withSave;
-      RETURN ok
-    END;
-    IF k = AST.NkCase THEN
-      IF NOT CanExpr(AST.Child(n, 0)) THEN RETURN FALSE END;
-      i := 1;
-      WHILE i < AST.NChild(n) DO
-        arm := AST.Child(n, i);
-        IF AST.Op(arm) = 1 THEN
-          IF NOT CanStmt(AST.Child(arm, 0)) THEN RETURN FALSE END
-        ELSE
-          j := 0;
-          WHILE j + 1 < AST.NChild(arm) DO
-            IF NOT CanCaseLabel(AST.Child(arm, j)) THEN RETURN FALSE END;
-            INC(j)
-          END;
-          IF NOT CanStmt(AST.Child(arm, AST.NChild(arm) - 1)) THEN
-            RETURN FALSE
-          END
-        END;
-        INC(i)
-      END;
-      RETURN TRUE
-    END;
-    IF k = AST.NkHalt THEN
-      IF AST.Child(n, 0) = AST.NoNode THEN RETURN TRUE END;
-      RETURN CanExpr(AST.Child(n, 0))
-    END;
-    IF k = AST.NkReturn THEN
-      IF AST.Child(n, 0) = AST.NoNode THEN RETURN TRUE END;
-      RETURN CanExpr(AST.Child(n, 0))
-    END;
-    IF k = AST.NkCall THEN
-      IF IsMethodCall(n) THEN RETURN CanMethodCall(n) END;
-      IF IsQualifiedCall(n) THEN RETURN CanQualifiedCall(n) END;
-      CalleeName(n, nm);
-      IF IsBuiltin(nm) THEN RETURN CanBuiltin(n) END;
-      RETURN IsCall(n) AND CanCallArgs(n)
-    END;
-    RETURN FALSE
-  END CanStmt;
-
-PROCEDURE CanMethod (m: AST.Node; ct: SymTab.TypeIndex): BOOLEAN;
-  VAR nm: SymTab.Name; uid, depth, np: CARDINAL; res, t: SymTab.TypeIndex;
-      ext, isV: BOOLEAN; pn: SymTab.Name; i: CARDINAL; ok: BOOLEAN;
-      save: CARDINAL; saveCls: SymTab.TypeIndex;
-  BEGIN
-    IF (AST.Op(m) # 0) AND (AST.Op(m) # 3) THEN RETURN FALSE END;
-    Name(AST.Child(m, 0), nm);
-    IF NOT ProcInfo(nm, uid, res, depth, ext, np) THEN RETURN FALSE END;
-    IF (res # SymTab.InvalidType) AND NOT CanType(res) THEN RETURN FALSE END;
-    i := 0;
-    WHILE i < np DO
-      IF NOT ParamInfo(nm, i, t, isV, pn) THEN RETURN FALSE END;
-      IF NOT CanType(t) THEN RETURN FALSE END;
-      INC(i)
-    END;
-    save := withTop;
-    saveCls := curImplCls;
-    curImplCls := ct;
-    IF withTop <= HIGH(withRec) THEN withRec[withTop] := ct; INC(withTop) END;
-    ok := CanDecls(AST.Child(m, 2)) AND CanStmt(AST.Child(m, 1));
-    withTop := save;
-    curImplCls := saveCls;
-    RETURN ok
-  END CanMethod;
-
-PROCEDURE CanMethods (seq: AST.Node; ct: SymTab.TypeIndex): BOOLEAN;
-  VAR i: CARDINAL; m: AST.Node;
-  BEGIN
-    IF seq = AST.NoNode THEN RETURN TRUE END;
-    i := 0;
-    WHILE i < AST.NChild(seq) DO
-      m := AST.Child(seq, i);
-      IF i = AST.MaxChild - 1 THEN
-        IF NOT CanMethods(m, ct) THEN RETURN FALSE END
-      ELSIF AST.Kind(m) = AST.NkFieldDecl THEN
-        IF NOT CanMethods(m, ct) THEN RETURN FALSE END
-      ELSIF AST.Kind(m) = AST.NkProcDecl THEN
-        IF NOT CanMethod(m, ct) THEN RETURN FALSE END
-      END;
-      INC(i)
-    END;
-    RETURN TRUE
-  END CanMethods;
-
-PROCEDURE CanDecl (c: AST.Node): BOOLEAN;
-  VAR i: CARDINAL; nm: SymTab.Name; k: INTEGER; ct: SymTab.TypeIndex;
-  BEGIN
-    IF AST.Kind(c) = AST.NkClassDecl THEN
-      IF AST.Op(c) = 1 THEN
-        Name(AST.Child(c, 0), nm);
-        IF NOT Resolve(nm, k, ct) THEN RETURN FALSE END;
-        IF SymTab.ClassOf(ct) # SymTab.ClClass THEN RETURN FALSE END;
-        IF NOT CanMethods(AST.Child(c, 3), ct) THEN RETURN FALSE END;
-        IF AST.Child(c, 2) # AST.NoNode THEN
-          IF NOT CanStmt(AST.Child(c, 2)) THEN RETURN FALSE END
-        END;
-        RETURN TRUE
-      END;
-      RETURN TRUE
-    END;
-    IF AST.Kind(c) = AST.NkUnit THEN
-      IF AST.Child(c, 3) # AST.NoNode THEN RETURN FALSE END;
-      RETURN CanDecls(AST.Child(c, 1)) AND CanStmt(AST.Child(c, 2))
-    END;
-    IF AST.Kind(c) = AST.NkTypeDecl THEN RETURN TRUE END;
-    IF AST.Kind(c) = AST.NkVarDecl THEN
-      IF NOT CanType(AST.Ty(c)) THEN RETURN FALSE END;
-      IF AST.NChild(c) < 1 THEN RETURN FALSE END;
-      i := 0;
-      WHILE i < AST.NChild(c) DO
-        IF AST.Kind(AST.Child(c, i)) # AST.NkIdent THEN RETURN FALSE END;
-        INC(i)
-      END;
-      RETURN TRUE
-    END;
-    IF AST.Kind(c) = AST.NkConstDecl THEN
-      RETURN IsScalarClass(SymTab.ClassOf(AST.Ty(c)))
-             AND (AST.Kind(AST.Child(c, 1)) = AST.NkIntLit)
-    END;
-    IF AST.Kind(c) = AST.NkProcDecl THEN RETURN CanProc(c) END;
-    RETURN FALSE
-  END CanDecl;
-
-PROCEDURE CanDecls (seq: AST.Node): BOOLEAN;
-  VAR i: CARDINAL; c: AST.Node;
-  BEGIN
-    IF seq = AST.NoNode THEN RETURN TRUE END;
-    i := 0;
-    WHILE i < AST.NChild(seq) DO
-      c := AST.Child(seq, i);
-      IF i = AST.MaxChild - 1 THEN
-        IF NOT CanDecls(c) THEN RETURN FALSE END
-      ELSIF AST.Kind(c) = AST.NkDeclSeq THEN
-        IF NOT CanDecls(c) THEN RETURN FALSE END
-      ELSIF NOT CanDecl(c) THEN RETURN FALSE
-      END;
-      INC(i)
-    END;
-    RETURN TRUE
-  END CanDecls;
-
-PROCEDURE CanLower (unit: AST.Node): BOOLEAN;
-  BEGIN
-    withTop := 0;
-    curImplCls := SymTab.InvalidType;
-    IF AST.Kind(unit) # AST.NkUnit THEN RETURN FALSE END;
-    IF AST.Kind(AST.Child(unit, 0)) # AST.NkIdent THEN RETURN FALSE END;
-    RETURN CanDecls(AST.Child(unit, 1)) AND CanStmt(AST.Child(unit, 2))
-  END CanLower;
-
-PROCEDURE CanProc (proc: AST.Node): BOOLEAN;
-  VAR nm: SymTab.Name; i: CARDINAL;
-      uid, depth, np: CARDINAL; res: SymTab.TypeIndex; ext: BOOLEAN;
-      t: SymTab.TypeIndex; isV: BOOLEAN; pn: SymTab.Name;
-  BEGIN
-    IF AST.Op(proc) # 0 THEN RETURN FALSE END;
-    Name(AST.Child(proc, 0), nm);
-    IF NOT ProcInfo(nm, uid, res, depth, ext, np) THEN RETURN FALSE END;
-    IF (res # SymTab.InvalidType) AND NOT IsScalarClass(SymTab.ClassOf(res)) THEN
-      RETURN FALSE END;
-    i := 0;
-    WHILE i < np DO
-      IF NOT ParamInfo(nm, i, t, isV, pn) THEN RETURN FALSE END;
-      IF NOT CanType(t) THEN RETURN FALSE END;
-      INC(i)
-    END;
-    RETURN CanDecls(AST.Child(proc, 2)) AND CanStmt(AST.Child(proc, 1))
-  END CanProc;
 PROCEDURE FinalLoad (t: SymTab.TypeIndex; sfx: BOOLEAN; VAR q: QbeGen.QVal);
 PROCEDURE FinalLoad (t: SymTab.TypeIndex; sfx: BOOLEAN; VAR q: QbeGen.QVal);
 (* Fact's final load after a designator/result suffix: scalars/pointers
 (* Fact's final load after a designator/result suffix: scalars/pointers
    are loaded from their address; aggregates keep the address. *)
    are loaded from their address; aggregates keep the address. *)
@@ -2609,30 +2160,6 @@ PROCEDURE LowerOneUnit (u: AST.Node; isProg: BOOLEAN);
     END
     END
   END LowerOneUnit;
   END LowerOneUnit;
 
 
-PROCEDURE LowerSession (units: ARRAY OF AST.Node; n: CARDINAL;
-                        progName: ARRAY OF CHAR);
-(* Re-emit a whole session (all units, in order) into one image. *)
-  VAR i, j: CARDINAL; out: ARRAY [0 .. 255] OF CHAR; pn: SymTab.Name;
-  BEGIN
-    IF n = 0 THEN RETURN END;
-    Name(AST.Child(units[n - 1], 0), pn);
-    j := 0;
-    WHILE (j <= 254) AND (pn[j] # CHR(0)) DO
-      out[j] := pn[j]; INC(j)
-    END;
-    out[j] := "L"; INC(j); out[j] := CHR(0);
-    withTop := 0;
-    curImplCls := SymTab.InvalidType;
-    QbeGen.OpenModule(progName);
-    QbeGen.SetOutName(out);
-    i := 0;
-    WHILE i < n DO
-      LowerOneUnit(units[i], i = n - 1);
-      INC(i)
-    END;
-    QbeGen.EndModule(pn)
-  END LowerSession;
-
 PROCEDURE BeginSession (progName: ARRAY OF CHAR);
 PROCEDURE BeginSession (progName: ARRAY OF CHAR);
 (* Per-unit Lower emission.  The grammar still runs its inline emit while
 (* Per-unit Lower emission.  The grammar still runs its inline emit while
    parsing, but under NoEmit it only mutates QbeGen's counters (nothing
    parsing, but under NoEmit it only mutates QbeGen's counters (nothing
@@ -2682,26 +2209,6 @@ PROCEDURE EndSession (testSuffix: BOOLEAN);
     QbeGen.EndModule(curUnitName)
     QbeGen.EndModule(curUnitName)
   END EndSession;
   END EndSession;
 
 
-PROCEDURE LowerUnit (unit: AST.Node);
-  VAR nm: SymTab.Name; out: ARRAY [0 .. 255] OF CHAR; i: CARDINAL;
-  BEGIN
-    withTop := 0;
-    curImplCls := SymTab.InvalidType;
-    Name(AST.Child(unit, 0), nm);
-    i := 0;
-    WHILE (i <= 254) AND (i <= HIGH(nm)) AND (nm[i] # CHR(0)) DO
-      out[i] := nm[i]; INC(i)
-    END;
-    out[i] := "L"; INC(i); out[i] := CHR(0);
-    QbeGen.OpenModule(nm);
-    QbeGen.SetOutName(out);
-    QbeGen.SetModule(nm);
-    LowerDecls(AST.Child(unit, 1));
-    QbeGen.BeginBody;
-    LowerStmt(AST.Child(unit, 2));
-    QbeGen.EndModule(nm)
-  END LowerUnit;
-
 BEGIN
 BEGIN
   scopeTop := 0; curScopeProc := -1; emitProc := -1
   scopeTop := 0; curScopeProc := -1; emitProc := -1
 END Lower.
 END Lower.

+ 0 - 11
compiler/src/M2.atg

@@ -88,11 +88,6 @@ VAR
   (* Unit-AST root (slice 7): NkUnit(name, decls, body). *)
   (* Unit-AST root (slice 7): NkUnit(name, decls, body). *)
   astUnit: AST.Node;
   astUnit: AST.Node;
 
 
-  (* Test-only: when TRUE the program unit is re-emitted from the AST via
-     Lower right after the legacy EndModule (before EndUnit closes the
-     module scope, so Lower can still resolve names). *)
-  lowerRequested: BOOLEAN;
-
   (* Import accumulator (slice 11): `{ Import }` appends NkImport
   (* Import accumulator (slice 11): `{ Import }` appends NkImport
      nodes here; each unit stores them as NkUnit child[3]. *)
      nodes here; each unit stores them as NkUnit child[3]. *)
   astImp, astImpTail: AST.Node;
   astImp, astImpTail: AST.Node;
@@ -213,12 +208,6 @@ PROCEDURE GetUnit (): AST.Node;
     RETURN astUnit
     RETURN astUnit
   END GetUnit;
   END GetUnit;
 
 
-PROCEDURE SetLower (b: BOOLEAN);
-(* Enables the test-only Lower re-emit at program-unit end. *)
-  BEGIN
-    lowerRequested := b
-  END SetLower;
-
 CHARACTERS
 CHARACTERS
   eol      = CHR(13) .
   eol      = CHR(13) .
   lf       = CHR(10) .
   lf       = CHR(10) .

+ 3623 - 3634
compiler/src/M2.lst

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

+ 0 - 2
compiler/src/parser.frm

@@ -135,8 +135,6 @@ PROCEDURE Successful (): BOOLEAN;
 PROCEDURE GetUnit (): AST.Node;
 PROCEDURE GetUnit (): AST.Node;
 (* The most recently parsed unit's AST root (for the Lower comparison) *)
 (* The most recently parsed unit's AST root (for the Lower comparison) *)
 
 
-PROCEDURE SetLower (b: BOOLEAN);
-(* Enables the test-only Lower re-emit at program-unit end *)
 (* Returns TRUE if no errors have been recorded while parsing *)
 (* Returns TRUE if no errors have been recorded while parsing *)
 
 
 PROCEDURE SynError (errNo: INTEGER);
 PROCEDURE SynError (errNo: INTEGER);

+ 7 - 3
docs/STATUS.md

@@ -145,9 +145,13 @@ Still to do:
    not cleanup.
    not cleanup.
 6. Retire the `-lower` test flag and the now-degenerate byte-compare
 6. Retire the `-lower` test flag and the now-degenerate byte-compare
    tests in `run_tests.sh`.
    tests in `run_tests.sh`.
-7. Remove the dead scaffolding: `LowerSession`, `MaterializeGlobals`,
-   `SaveSession`/`RestoreSession` and the `SetNoEmit` machinery (once
-   nothing emits inline), plus the dead `SetLower`/`lowerRequested`.
+7. Remove the dead scaffolding.  Done 2026-10-08: `LowerSession`,
+   `LowerUnit`, the whole `Can*` capability-walker family,
+   `CanLower`/`CanExpr`/`CanDecls`/`CanProc`, and the dead
+   `SetLower`/`lowerRequested`.  Still needed until the inline emit is
+   gone: `SaveSession`/`RestoreSession`/`SetNoEmit` (the grammar still
+   emits suppressed) and `MaterializeGlobals`/`MaterializeReplace`
+   (called from `LowerOneUnit`).
 
 
 Note: full deletion to zero is gated on moving constant folding into
 Note: full deletion to zero is gated on moving constant folding into
 `Lower` (item 4).  Until then the expression/value layer stays.
 `Lower` (item 4).  Until then the expression/value layer stays.