Pārlūkot izejas kodu

String: drop the pervasive predef; report unresolved forward types

String is not a gm2 built-in — it is an opaque type imported from a
definition module (DynamicStrings, or a local opaque).  So:

- remove Predef("String", ...): an unimported String is now
  'undeclared identifier' (gm2 conformance), and the opaque-pointer
  behaviour is what makes imported opaque Strings work;
- forward type references are now verified at module end: a
  module-level type name that is never declared reports 201
  (SymTab.FwdPending/FwdInfo/FwdClear; inline checks in ProgModule and
  ImplUnit after FlushPend).
- t_string.mod becomes the gm2-shaped test: an opaque String declared
  in d_string.def, completed in d_string.mod, imported by the program.
- docs corrected: String is not pervasive/magic.

Suite 169/169; fixpoint OK (2,754,353 bytes).  Corpus (conformant
rejections): testsuite 395 -> 392, stdlib 131 -> 127.
Eric Streit 1 nedēļu atpakaļ
vecāks
revīzija
417a9210e5

+ 1 - 1
compiler/run_tests.sh

@@ -75,7 +75,6 @@ expect_run t_setops.mod 42
 expect_run t_fwdtype.mod 42
 expect_run t_fwdtype.mod 42
 expect_run t_libc.mod 42
 expect_run t_libc.mod 42
 expect_run t_variant2.mod 42
 expect_run t_variant2.mod 42
-expect_run t_string.mod 42
 expect_run t_addrptr.mod 42
 expect_run t_addrptr.mod 42
 expect_run t_nestedmod.mod 42
 expect_run t_nestedmod.mod 42
 expect_run t_nestidx.mod 42
 expect_run t_nestidx.mod 42
@@ -251,6 +250,7 @@ expect_run_files TClassDefProg 8 t_classdef.def t_classdef_prog.mod
 expect_run_files DQualProg 46 d_basic.def d_basic.mod d_qual_prog.mod
 expect_run_files DQualProg 46 d_basic.def d_basic.mod d_qual_prog.mod
 expect_run_files DTypesProg 36 d_types.def d_types.mod d_types_prog.mod
 expect_run_files DTypesProg 36 d_types.def d_types.mod d_types_prog.mod
 expect_run_files DOpaqueProg 55 d_opaque.def d_opaque.mod d_opaque_prog.mod
 expect_run_files DOpaqueProg 55 d_opaque.def d_opaque.mod d_opaque_prog.mod
+expect_run_files TString 42 d_string.def d_string.mod t_string.mod
 expect_run_files FioProg 42 ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod ../runtime/syslib/FileIO.def ../runtime/syslib/FileIO.mod fio_prog.mod
 expect_run_files FioProg 42 ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod ../runtime/syslib/FileIO.def ../runtime/syslib/FileIO.mod fio_prog.mod
 expect_run_files StorageProg 42 ../stdlib/storage.def ../stdlib/storage.mod storage_prog.mod
 expect_run_files StorageProg 42 ../stdlib/storage.def ../stdlib/storage.mod storage_prog.mod
 expect_run_files ClashProg 60 d_clash_a.def d_clash_a.mod d_clash_b.def d_clash_b.mod d_clash_prog.mod
 expect_run_files ClashProg 60 d_clash_a.def d_clash_a.mod d_clash_b.def d_clash_b.mod d_clash_prog.mod

+ 34 - 2
compiler/src/M2.atg

@@ -141,7 +141,9 @@ PRODUCTIONS
                                              SemError(202) END;
                                              SemError(202) END;
                                            SymTab.EndUnit; .) .
                                            SymTab.EndUnit; .) .
   ImplUnit                              (. VAR m1, m2: SymTab.Name;
   ImplUnit                              (. VAR m1, m2: SymTab.Name;
-                                             k: CARDINAL; .)
+                                             k: CARDINAL;
+                                             fname: SymTab.Name;
+                                             unres: BOOLEAN; .)
     = "IMPLEMENTATION" "MODULE"
     = "IMPLEMENTATION" "MODULE"
       GetIdent<m1>                      (. IF NOT SymTab.BeginImpl(m1) THEN
       GetIdent<m1>                      (. IF NOT SymTab.BeginImpl(m1) THEN
                                              SemError(201) END;
                                              SemError(201) END;
@@ -151,15 +153,31 @@ PRODUCTIONS
       { Import }
       { Import }
       DeclSeq
       DeclSeq
       [ "BEGIN"                         (. FlushPend;
       [ "BEGIN"                         (. FlushPend;
+                                           k := 0;
+                                           WHILE k < SymTab.FwdPending() DO
+                                             SymTab.FwdInfo(k, fname, unres);
+                                             IF unres THEN SemError(201) END;
+                                             INC(k)
+                                           END;
+                                           SymTab.FwdClear;
                                            QbeGen.BeginInit(m1); .)
                                            QbeGen.BeginInit(m1); .)
         [ StatSeq ]                       (. QbeGen.EndInit; .) ]
         [ StatSeq ]                       (. QbeGen.EndInit; .) ]
       "END"
       "END"
       GetIdent<m2>                      (. FlushPend;
       GetIdent<m2>                      (. FlushPend;
+                                           k := 0;
+                                           WHILE k < SymTab.FwdPending() DO
+                                             SymTab.FwdInfo(k, fname, unres);
+                                             IF unres THEN SemError(201) END;
+                                             INC(k)
+                                           END;
+                                           SymTab.FwdClear;
                                            IF NOT SymTab.Equal(m1, m2) THEN
                                            IF NOT SymTab.Equal(m1, m2) THEN
                                              SemError(202) END;
                                              SemError(202) END;
                                            SymTab.EndUnit; .) .
                                            SymTab.EndUnit; .) .
   ProgModule                            (. VAR m1, m2: SymTab.Name;
   ProgModule                            (. VAR m1, m2: SymTab.Name;
-                                             k: CARDINAL; .)
+                                             k: CARDINAL;
+                                             fname: SymTab.Name;
+                                             unres: BOOLEAN; .)
     = "MODULE"
     = "MODULE"
       GetIdent<m1>                      (. IF NOT SymTab.BeginProg(m1) THEN
       GetIdent<m1>                      (. IF NOT SymTab.BeginProg(m1) THEN
                                              SemError(200) END;
                                              SemError(200) END;
@@ -170,10 +188,24 @@ PRODUCTIONS
       { Import }
       { Import }
       DeclSeq
       DeclSeq
       [ "BEGIN"                         (. FlushPend;
       [ "BEGIN"                         (. FlushPend;
+                                           k := 0;
+                                           WHILE k < SymTab.FwdPending() DO
+                                             SymTab.FwdInfo(k, fname, unres);
+                                             IF unres THEN SemError(201) END;
+                                             INC(k)
+                                           END;
+                                           SymTab.FwdClear;
                                            QbeGen.BeginBody; .)
                                            QbeGen.BeginBody; .)
         [ StatSeq ] ]
         [ StatSeq ] ]
       "END"
       "END"
       GetIdent<m2>                      (. FlushPend;
       GetIdent<m2>                      (. FlushPend;
+                                           k := 0;
+                                           WHILE k < SymTab.FwdPending() DO
+                                             SymTab.FwdInfo(k, fname, unres);
+                                             IF unres THEN SemError(201) END;
+                                             INC(k)
+                                           END;
+                                           SymTab.FwdClear;
                                            IF NOT SymTab.Equal(m1, m2) THEN
                                            IF NOT SymTab.Equal(m1, m2) THEN
                                              SemError(202) END;
                                              SemError(202) END;
                                            QbeGen.EndModule(m1);
                                            QbeGen.EndModule(m1);

+ 2860 - 2828
compiler/src/M2.lst

@@ -159,2843 +159,2875 @@ Listing:
   141                                               SemError(202) END;
   141                                               SemError(202) END;
   142                                             SymTab.EndUnit; .) .
   142                                             SymTab.EndUnit; .) .
   143    ImplUnit                              (. VAR m1, m2: SymTab.Name;
   143    ImplUnit                              (. VAR m1, m2: SymTab.Name;
-  144                                               k: CARDINAL; .)
-  145      = "IMPLEMENTATION" "MODULE"
-  146        GetIdent<m1>                      (. IF NOT SymTab.BeginImpl(m1) THEN
-  147                                               SemError(201) END;
-  148                                             nPendVar := 0;
-  149                                             QbeGen.SetModule(m1); .)
-  150        ";"
-  151        { Import }
-  152        DeclSeq
-  153        [ "BEGIN"                         (. FlushPend;
-  154                                             QbeGen.BeginInit(m1); .)
-  155          [ StatSeq ]                       (. QbeGen.EndInit; .) ]
-  156        "END"
-  157        GetIdent<m2>                      (. FlushPend;
-  158                                             IF NOT SymTab.Equal(m1, m2) THEN
-  159                                               SemError(202) END;
-  160                                             SymTab.EndUnit; .) .
-  161    ProgModule                            (. VAR m1, m2: SymTab.Name;
-  162                                               k: CARDINAL; .)
-  163      = "MODULE"
-  164        GetIdent<m1>                      (. IF NOT SymTab.BeginProg(m1) THEN
-  165                                               SemError(200) END;
-  166                                             nPendVar := 0;
-  167                                             QbeGen.SetModule(m1); .)
-  168        [ Priority ]
-  169        ";"
-  170        { Import }
-  171        DeclSeq
-  172        [ "BEGIN"                         (. FlushPend;
-  173                                             QbeGen.BeginBody; .)
-  174          [ StatSeq ] ]
-  175        "END"
-  176        GetIdent<m2>                      (. FlushPend;
-  177                                             IF NOT SymTab.Equal(m1, m2) THEN
-  178                                               SemError(202) END;
-  179                                             QbeGen.EndModule(m1);
-  180                                             SymTab.EndUnit; .) .
-  181    DeclSeq
-  182      = { ConstBlock | TypeBlock<FALSE> | VarBlock | ProcDecl ";"
-  183        | NestedModule ";" | ClassItem ";" } .
-  184    (* Local module, Wirth form. Declarations lower like top-level ones
-  185       (same QBE module prefix); a BEGIN body becomes an init function
-  186       that main calls; the EXPORT list is hoisted into the enclosing
-  187       scope at END. *)
-  188    NestedModule                          (. VAR m1, m2: SymTab.Name;
-  189                                               expNames: ARRAY [0 .. 63] OF SymTab.Name;
-  190                                               expCount, k: CARDINAL; .)
-  191      = "MODULE"
-  192        GetIdent<m1>                      (. IF NOT SymTab.Enter(m1,
-  193                                               SymTab.KindModule) THEN
-  194                                               SemError(200) END;
-  195                                             SymTab.PushScope;
-  196                                             expCount := 0; .)
-  197        [ Priority ]
-  198        ";"
-  199        { Import }
-  200        [ "EXPORT" [ "QUALIFIED" ]
-  201          GetIdent<expNames[expCount]>    (. INC(expCount); .)
-  202          { "," GetIdent<expNames[expCount]>
-  203                                          (. INC(expCount); .) }
-  204          ";" ]
-  205        DeclSeq
-  206        [ "BEGIN"                         (. QbeGen.BeginInit(m1); .)
-  207          [ StatSeq ]                     (. QbeGen.EndInit; .) ]
-  208        "END"
-  209        GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
+  144                                               k: CARDINAL;
+  145                                               fname: SymTab.Name;
+  146                                               unres: BOOLEAN; .)
+  147      = "IMPLEMENTATION" "MODULE"
+  148        GetIdent<m1>                      (. IF NOT SymTab.BeginImpl(m1) THEN
+  149                                               SemError(201) END;
+  150                                             nPendVar := 0;
+  151                                             QbeGen.SetModule(m1); .)
+  152        ";"
+  153        { Import }
+  154        DeclSeq
+  155        [ "BEGIN"                         (. FlushPend;
+  156                                             k := 0;
+  157                                             WHILE k < SymTab.FwdPending() DO
+  158                                               SymTab.FwdInfo(k, fname, unres);
+  159                                               IF unres THEN SemError(201) END;
+  160                                               INC(k)
+  161                                             END;
+  162                                             SymTab.FwdClear;
+  163                                             QbeGen.BeginInit(m1); .)
+  164          [ StatSeq ]                       (. QbeGen.EndInit; .) ]
+  165        "END"
+  166        GetIdent<m2>                      (. FlushPend;
+  167                                             k := 0;
+  168                                             WHILE k < SymTab.FwdPending() DO
+  169                                               SymTab.FwdInfo(k, fname, unres);
+  170                                               IF unres THEN SemError(201) END;
+  171                                               INC(k)
+  172                                             END;
+  173                                             SymTab.FwdClear;
+  174                                             IF NOT SymTab.Equal(m1, m2) THEN
+  175                                               SemError(202) END;
+  176                                             SymTab.EndUnit; .) .
+  177    ProgModule                            (. VAR m1, m2: SymTab.Name;
+  178                                               k: CARDINAL;
+  179                                               fname: SymTab.Name;
+  180                                               unres: BOOLEAN; .)
+  181      = "MODULE"
+  182        GetIdent<m1>                      (. IF NOT SymTab.BeginProg(m1) THEN
+  183                                               SemError(200) END;
+  184                                             nPendVar := 0;
+  185                                             QbeGen.SetModule(m1); .)
+  186        [ Priority ]
+  187        ";"
+  188        { Import }
+  189        DeclSeq
+  190        [ "BEGIN"                         (. FlushPend;
+  191                                             k := 0;
+  192                                             WHILE k < SymTab.FwdPending() DO
+  193                                               SymTab.FwdInfo(k, fname, unres);
+  194                                               IF unres THEN SemError(201) END;
+  195                                               INC(k)
+  196                                             END;
+  197                                             SymTab.FwdClear;
+  198                                             QbeGen.BeginBody; .)
+  199          [ StatSeq ] ]
+  200        "END"
+  201        GetIdent<m2>                      (. FlushPend;
+  202                                             k := 0;
+  203                                             WHILE k < SymTab.FwdPending() DO
+  204                                               SymTab.FwdInfo(k, fname, unres);
+  205                                               IF unres THEN SemError(201) END;
+  206                                               INC(k)
+  207                                             END;
+  208                                             SymTab.FwdClear;
+  209                                             IF NOT SymTab.Equal(m1, m2) THEN
   210                                               SemError(202) END;
   210                                               SemError(202) END;
-  211                                             k := 0;
-  212                                             WHILE k < expCount DO
-  213                                               SymTab.ExportUp(expNames[k]);
-  214                                               INC(k)
-  215                                             END;
-  216                                             SymTab.PopScope; .) .
-  217    Priority
-  218      = "[" integer "]"                   (. SemError(230); .) .
-  219    (* Imports (4.3): FROM materializes the names (unqualified use);
-  220       plain IMPORT only demands the module exists — qualified `L.x`
-  221       materializes on first use (Design). *)
-  222    (* Unknown modules stay unchecked stubs (legacy, so hand-written
-  223       import lines don't fail); a known module's missing export is
-  224       201. *)
-  225    Import                                (. VAR n: SymTab.Name; .)
-  226      = "FROM"
-  227        GetIdent<n>
-  228        "IMPORT"
-  229        ImpList<n> ";"
-  230      | "IMPORT"
-  231        ImpModList ";" .
-  232    ImpList<mod: SymTab.Name>             (. VAR n: SymTab.Name; .)
-  233      = ImpName<mod>
-  234        { "," ImpName<mod> } .
-  235    (* Pervasive built-ins imported from SYSTEM (e.g. TSIZE) are
-  236       accepted and ignored: the built-in applies regardless. *)
-  237    ImpName<mod: SymTab.Name>             (. VAR n: SymTab.Name; .)
-  238      = GetIdent<n>                       (. IF SymTab.Equal(mod, "libc") THEN
-  239                                               (* intrinsic C library:
-  240                                                  permissive external *)
-  241                                               IF NOT SymTab.DeclareCProc(n) THEN
-  242                                                 SemError(201) END
-  243                                             ELSIF SymTab.ModKnown(mod)
-  244                                               AND NOT SymTab.ImportFrom(mod, n) THEN
-  245                                               SemError(201) END; .)
-  246      | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN"
-  247        | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP"
-  248        | "UCHR" | "CHR8" | "UORD"
-  249        | "INC" | "DEC" ) .
-  250    ImpModList                            (. VAR n: SymTab.Name; .)
-  251      = GetIdent<n>
-  252        { "," GetIdent<n> } .
-  253    (* Opaque TYPE declarations (definition modules). The targetless
-  254       alias resolves to InvalidType until step 4 completes it. *)
-  255    (* Scalar-phase TYPEs: named types, integer subranges, enumerations.
-  256       Opaque "TYPE T;" needs isDef (definition units); elsewhere 231.
-  257       Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *)
-  258    TypeBlock<isDef: BOOLEAN>
-  259      = "TYPE"                            (. SymTab.BeginTypeBlock; .)
-  260        { TypeItem<isDef> ";" | ClassItem ";" }
-  261                                          (. SymTab.EndTypeBlock; .) .
-  262    TypeItem<isDef: BOOLEAN>              (. VAR n: SymTab.Name;
-  263                                               t, op: SymTab.TypeIndex; .)
-  264      = GetIdent<n>                       (. op := SymTab.OpaqueBase(n);
-  265                                             IF op = SymTab.InvalidType THEN
-  266                                               IF NOT SymTab.Enter(n,
-  267                                                  SymTab.KindType) THEN
-  268                                                 SemError(200) END
-  269                                             END; .)
-  270        ( "=" Type<t, FALSE>              (. IF op # SymTab.InvalidType THEN
-  271                                               SymTab.SetTarget(op, t)
-  272                                             ELSE SymTab.SetSymType(n, t)
-  273                                             END; .)
-  274        |                                 (. IF op # SymTab.InvalidType THEN
-  275                                               (* stays opaque *)
-  276                                             ELSIF NOT isDef THEN
-  277                                               SemError(231)
-  278                                             ELSE SymTab.SetSymType(n,
-  279                                               SymTab.NewAlias()) END; .) ) .
-  280    Type<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
-  281      = TypeIdent<t> [ Subrange<t> ]     (* anchored subrange: T[lo..hi] *)
-  282      | Subrange<t>
-  283      | Enum<t>
-  284      | ArrayType<t, allowOpen>
-  285      | SetType<t>
-  286      | RecordType<t>
-  287      | PointerType<t>
-  288      | ProcType<t> .
-  289    PointerType<VAR t: SymTab.TypeIndex>  (. VAR base: SymTab.TypeIndex; .)
-  290      = "POINTER" "TO" Type<base, FALSE>(. t := SymTab.NewPtr(base); .) .
-  291    (* Procedure types (step 8.5): PROCEDURE (params): result. Values
-  292       are code pointers; params are collected into the descriptor. *)
-  293    ProcType<VAR t: SymTab.TypeIndex>     (. VAR res, pt: SymTab.TypeIndex;
-  294                                               isV: BOOLEAN; .)
-  295      = "PROCEDURE"                       (. res := SymTab.InvalidType;
-  296                                             t := SymTab.NewProcType(res); .)
-  297        [ "(" [ ProcTypeSection<t> { ";" ProcTypeSection<t> } ] ")" ]
-  298        [ ":" TypeIdent<res>              (. SymTab.SetProcTypeRes(t, res); .) ] .
-  299    ProcTypeSection<t: SymTab.TypeIndex>  (. VAR pt: SymTab.TypeIndex;
-  300                                               isV: BOOLEAN;
-  301                                               cnt, k: CARDINAL;
-  302                                               names: ARRAY [0 .. 15] OF SymTab.Name; .)
-  303      =                                   (. isV := FALSE; cnt := 0; .)
-  304        [ "VAR"                           (. isV := TRUE; .) ]
-  305        ( GetIdent<names[cnt]>            (. INC(cnt); .)
-  306          { "," GetIdent<names[cnt]>      (. INC(cnt); .) }
-  307          ( ":" Type<pt, TRUE>           (. k := 0;
-  308                                             WHILE k < cnt DO
-  309                                               SymTab.ProcTypeAdd(t, isV, pt);
-  310                                               INC(k)
-  311                                             END; .)
-  312          |                               (. (* type-only parameter list:
-  313                                                each name is a type (GNU
-  314                                                shorthand used by the
-  315                                                Coco/R scanner frame) *)
-  316                                             k := 0;
-  317                                             WHILE k < cnt DO
-  318                                               IF SymTab.Lookup(names[k])
-  319                                                  AND ((SymTab.SymKind(names[k]) = SymTab.KindType)
-  320    OR (SymTab.SymKind(names[k]) = SymTab.KindPredef)) THEN
-  321                                                 pt := SymTab.SymType(names[k])
-  322                                               ELSE SemError(201);
-  323                                                 pt := SymTab.InvalidType
-  324                                               END;
-  325                                               SymTab.ProcTypeAdd(t, isV, pt);
-  326                                               INC(k)
-  327                                             END; .) )
-  328        | Type<pt, TRUE>                 (. (* unnamed parameter (PIM):
-  329                                                e.g. PROCEDURE (VAR ARRAY OF REAL) *)
-  330                                             SymTab.ProcTypeAdd(t, isV, pt); .) ) .
-  331    (* Arrays: "OF" without bounds is an open formal (allowed only
-  332       where allowOpen); "[lo..hi, ...]" nests bounded levels inside
-  333       out. Bounds are folded literals (int/char); anything else 230.
-  334       Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *)
-  335    ArrayType<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
-  336                                          (. VAR elem: SymTab.TypeIndex;
-  337                                               ok: BOOLEAN;
-  338                                               bnds, bndh: ARRAY [0 .. 7] OF INTEGER;
-  339                                               nb, k: CARDINAL;
-  340                                               idx: SymTab.TypeIndex;
-  341                                               ilo, ihi: INTEGER; .)
-  342      = "ARRAY"
-  343        ( "OF" Type<elem, FALSE>          (. IF NOT allowOpen THEN
-  344                                               SemError(230) END;
-  345                                             t := SymTab.NewOpenArray(elem); .)
-  346        | TypeIdent<idx> [ Subrange<idx> ]
-  347          "OF" Type<elem, FALSE>          (. (* index-type array: the index
-  348                                                type's ordinal bounds give the
-  349                                                [lo..hi] pair *)
-  350                                             IF SymTab.TypeBounds(idx, ilo,
-  351                                                ihi)
-  352                                             THEN t := SymTab.NewArrayB(elem,
-  353                                                    ilo, ihi)
-  354                                             ELSE SemError(230);
-  355                                               t := SymTab.InvalidType
-  356                                             END; .)
-  357        | "["                             (. SymTab.BoundBegin; ok := TRUE; .)
-  358          BoundPair<ok>
-  359          { "," BoundPair<ok> }
-  360          "]"                             (. (* snapshot before the element
-  361                                                type, which reuses the bound
-  362                                                buffer for a nested ARRAY *)
-  363                                             nb := SymTab.BoundCount();
-  364                                             k := 0;
-  365                                             WHILE k < nb DO
-  366                                               bnds[k] := SymTab.BoundLo(k);
-  367                                               bndh[k] := SymTab.BoundHi(k);
-  368                                               INC(k)
-  369                                             END; .)
-  370          "OF" Type<elem, FALSE>
-  371                                          (. IF ok THEN
-  372                                               k := nb;
-  373                                               WHILE k > 0 DO
-  374                                                 DEC(k);
-  375                                                 elem := SymTab.NewArrayB(
-  376                                                   elem, bnds[k], bndh[k])
-  377                                               END;
-  378                                               t := elem
-  379                                             ELSE t := SymTab.InvalidType
-  380                                             END; .) ) .
-  381    BoundPair<VAR ok: BOOLEAN>            (. VAR tlo, thi: SymTab.TypeIndex;
-  382                                               qlo, qhi: QbeGen.QVal;
-  383                                               lo, hi: INTEGER;
-  384                                               cl, cl2: INTEGER; .)
-  385      = Expr<tlo, qlo> ".." Expr<thi, qhi>
-  386                                          (. IF (tlo = SymTab.InvalidType)
-  387                                              OR (thi = SymTab.InvalidType) THEN
-  388                                             ok := FALSE
-  389                                           ELSE cl := SymTab.ClassOf(tlo);
-  390                                             cl2 := SymTab.ClassOf(thi);
-  391                                             IF ((cl # SymTab.ClInt)
-  392   AND (cl # SymTab.ClChar))
-  393                                                OR ((cl2 # SymTab.ClInt)
-  394   AND (cl2 # SymTab.ClChar)) THEN
-  395                                               SemError(230); ok := FALSE
-  396                                             ELSIF NOT SymTab.ConstInt(qlo, lo)
-  397                                                OR NOT SymTab.ConstInt(qhi, hi)
-  398                                                OR (lo > hi) THEN
-  399                                               SemError(230); ok := FALSE
-  400                                              ELSIF NOT SymTab.BoundAdd(lo, hi) THEN
-  401                                                SemError(230); ok := FALSE
-  402                                              END;
-  403                                            END; .) .
-  404    (* Sets: multi-word masks over bases ≤ 256 values (bool, char,
-  405       bounded subranges; enums wait for ordinals, INTEGER is
-  406       unbounded). Literals are SET OF [0..255]; assignment and
-  407       comparison across suitable bases are lenient (masks over min
-  408       words + zero-check extras), out-of-span literals are 222. *)
-  409    SetType<VAR t: SymTab.TypeIndex>      (. VAR base: SymTab.TypeIndex;
-  410                                               blo, bhi, bspan: INTEGER;
-  411                                               bcls: INTEGER; .)
-  412      = "SET" "OF" Type<base, FALSE>
-  413                                          (. IF base = SymTab.InvalidType THEN
-  414                                               t := SymTab.InvalidType
-  415                                             ELSE bcls :=
-  416                                                    SymTab.ClassOf(base);
-  417                                               IF bcls = SymTab.ClBool THEN
-  418                                                 blo := 0; bspan := 2
-  419                                               ELSIF bcls = SymTab.ClChar THEN
-  420                                                 blo := 0; bspan := 256
-  421                                               ELSIF bcls = SymTab.ClEnum THEN
-  422                                                 blo := 0;
-  423                                                 bspan := VAL(INTEGER,
-  424                                                   SymTab.EnumCount(base))
-  425                                               ELSIF SymTab.SubBounds(base,
-  426                                                       blo, bhi) THEN
-  427                                                 bspan := bhi - blo + 1
-  428                                               ELSE bspan := 0 END;
-  429                                               IF (bspan <= 0)
-  430                                                  OR (bspan > 65536) THEN
-  431                                                 SemError(230);
-  432                                                 t := SymTab.InvalidType
-  433                                               ELSE t := SymTab.NewSet(base)
-  434                                               END
-  435                                             END; .) .
-  436    (* Records: flat blobs; array fields are pointers to static
-  437       descriptors (locked amendment), nested records inline. Field
-  438       offsets static and declaration-ordered. *)
-  439    (* Field list: plain fields and (optionally) one variant part.  The
-  440       variant part is a `CASE ... END` item; because it starts with the
-  441       CASE keyword it is unambiguously distinguishable from a field
-  442       (which starts with an identifier). *)
-  443    RecordType<VAR t: SymTab.TypeIndex>   (. VAR t2: SymTab.TypeIndex;
-  444                                               tagOk: BOOLEAN; .)
-  445      = "RECORD"                          (. t := SymTab.NewRecord(); .)
-  446        [ RecItem<t> { ";" [ RecItem<t> ] } ]
-  447        "END" .
-  448    RecItem<rec: SymTab.TypeIndex>        (. VAR tt: SymTab.TypeIndex; .)
-  449      = RecField<rec>
-  450      | CaseField<rec>                    (. SymTab.MarkVariant(rec); .) .
-  451    (* A variant part: CASE tag : Type OF variants.  The layout overlays
-  452       every branch from the tag slot (see SymTab.ComputeOffsets). *)
-  453    CaseField<rec: SymTab.TypeIndex>      (. VAR tagT: SymTab.TypeIndex;
-  454                                               tagN: SymTab.Name; .)
-  455      = "CASE"                            (. SymTab.ResetFields(rec); .)
-  456        GetIdent<tagN>                    (. IF NOT SymTab.FieldPending(rec,
-  457                                               tagN) THEN
-  458                                               SemError(200) END; .)
-  459        ":" Type<tagT, FALSE>             (. IF (tagT # SymTab.InvalidType)
-  460    AND NOT SymTab.IsOrdinal(tagT) THEN
-  461                                               SemError(224)
-  462                                             END;
-  463                                             SymTab.FixPendingF(rec, tagT);
-  464                                             SymTab.SetVariantTag(rec, tagN); .)
-  465        "OF"
-  466        RecFieldList<rec>
-  467        { "|"                             (. SymTab.ResetFields(rec); .)
-  468          RecFieldList<rec> }
-  469        "END" .
-  470    RecFieldList<rec: SymTab.TypeIndex>   (. VAR lt, lq: SymTab.TypeIndex;
-  471                                               lv1, lv2: QbeGen.QVal; .)
-  472      = VarLabel<lt, lv1> [ ".." VarLabel<lq, lv2> ] ":"
-  473        RecField<rec> { ";" [ RecField<rec> ] } .
-  474    (* Variant case label: a constant (or a constant range).  Values are
-  475       not interpreted (the layout overlays regardless). *)
-  476    VarLabel<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
-  477                                          (. VAR lname: SymTab.Name; .)
-  478      = ( ident                         (. LexName(lname);
-  479                                             QbeGen.CopyOp("0", q);
-  480                                             t := SymTab.IntType(); .)
-  481        | integer                       (. LexString(lname);
-  482                                             QbeGen.CopyOp("0", q);
-  483                                             t := SymTab.IntType(); .)
-  484        | charConst                     (. LexString(lname);
-  485                                             QbeGen.CopyOp("0", q);
-  486                                             t := SymTab.CharType(); .) ) .
-  487    RecField<rec: SymTab.TypeIndex>       (. VAR n: SymTab.Name;
-  488                                               t2: SymTab.TypeIndex; .)
-  489      = RecIdents<rec> ":" Type<t2, FALSE>(. SymTab.FixPendingF(rec, t2); .) .
-  490    RecIdents<rec: SymTab.TypeIndex>      (. VAR n: SymTab.Name; .)
-  491      = GetIdent<n>                       (. IF NOT SymTab.FieldPending(rec,
-  492                                               n) THEN
-  493                                               SemError(200) END; .)
-  494        { "," GetIdent<n>                 (. IF NOT SymTab.FieldPending(rec,
-  495                                               n) THEN
-  496                                               SemError(200) END; .) } .
-  497    TypeIdent<VAR t: SymTab.TypeIndex>    (. VAR n, qid: SymTab.Name;
-  498                                               k: INTEGER;
-  499                                               dotted: BOOLEAN; .)
-  500      = GetIdent<n>                       (. dotted := FALSE;
-  501                                             IF NOT SymTab.Lookup(n) THEN
-  502                                               k := -1;
-  503                                               t := SymTab.ForwardType(n);
-  504                                               IF t = SymTab.InvalidType THEN
-  505                                                 SemError(201)
-  506                                               END
-  507                                             ELSE k := SymTab.SymKind(n);
-  508                                               IF (k = SymTab.KindType)
-  509                                                  OR (k = SymTab.KindPredef) THEN
-  510                                                 t := SymTab.SymType(n)
-  511                                               ELSE t := SymTab.InvalidType
-  512                                               END
-  513                                             END; .)
-  514        [ "." GetIdent<qid>               (. dotted := TRUE;
-  515                                             IF k = SymTab.KindModule THEN
-  516                                               t := SymTab.QualType(n, qid);
-  517                                               IF t = SymTab.InvalidType THEN
-  518                                                 SemError(201)
-  519                                               END
-  520                                             ELSE SemError(221);
-  521                                               t := SymTab.InvalidType
-  522                                             END; .) ]
-  523                                          (. IF NOT dotted THEN
-  524                                               IF (k = SymTab.KindModule)
-  525                                                  OR ((k # SymTab.KindType)
-  526    AND (k # SymTab.KindPredef)
-  527    AND (k # SymTab.KindImport)
-  528    AND (k # -1)) THEN
-  529                                                 SemError(221)
-  530                                               END
-  531                                             END; .) .
-  532    Subrange<VAR t: SymTab.TypeIndex>     (. VAR tlo, thi: SymTab.TypeIndex;
-  533                                               qlo, qhi: QbeGen.QVal;
-  534                                               lo, hi: INTEGER; .)
-  535      = "[" Expr<tlo, qlo> ".." Expr<thi, qhi>
-  536                                          (. IF (tlo = SymTab.InvalidType)
-  537                                              OR (thi = SymTab.InvalidType) THEN
-  538                                             t := SymTab.InvalidType
-  539                                           ELSIF NOT SymTab.IsOrdinal(tlo)
-  540                                              OR NOT SymTab.IsOrdinal(thi) THEN
-  541                                             SemError(230);
-  542                                             t := SymTab.InvalidType
-  543                                           ELSIF NOT SymTab.ConstInt(qlo, lo)
-  544                                              OR NOT SymTab.ConstInt(qhi, hi)
-  545                                              OR (lo > hi) THEN
-  546                                             SemError(230);
-  547                                             t := SymTab.InvalidType
-  548                                           ELSE t := SymTab.NewSubR(lo, hi)
-  549                                           END; .)
-  550        "]" .
-  551    Enum<VAR t: SymTab.TypeIndex>         (. VAR n: SymTab.Name;
-  552                                               ord: INTEGER;
-  553                                               qv: QbeGen.QVal; .)
-  554      = "("                               (. t := SymTab.NewEnum();
-  555                                             ord := 0; .)
-  556        GetIdent<n>                       (. IF NOT SymTab.Enter(n,
-  557                                               SymTab.KindConst) THEN
-  558                                               SemError(200) END;
-  559                                             SymTab.SetSymType(n, t);
-  560                                             QbeGen.IntStr(ord, qv);
-  561                                             SymTab.SetSymVal(n, qv);
-  562                                             INC(ord); .)
-  563        { "," GetIdent<n>                 (. IF NOT SymTab.Enter(n,
-  564                                               SymTab.KindConst) THEN
-  565                                               SemError(200) END;
-  566                                             SymTab.SetSymType(n, t);
-  567                                             QbeGen.IntStr(ord, qv);
-  568                                             SymTab.SetSymVal(n, qv);
-  569                                             INC(ord); .) }
-  570        ")"                               (. SymTab.SetEnumCount(t,
-  571                                               VAL(CARDINAL, ord)); .) .
-  572    (* Clarion-form classes (docs/OOP.txt): declaration + single
-  573       inheritance + IMPLEMENTATION blocks. Scopes and member checks
-  574       now; lowering (vtable, dispatch, THIS) later — one 230 per
-  575       class/impl block. Methods end with ";" per the Table example
-  576       (not "," as in the sketch). No underscores in identifiers. *)
-  577    (* Single CLASS item in both loops: separating declaration from
-  578       IMPLEMENTATION at the loop level needs 2-token lookahead
-  579       (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
-  580       The second token decides after CLASS is consumed. A misplaced
-  581       CLASS IMPLEMENTATION inside TYPE still parses (harmless: the
-  582       whole unit ends 230 until lowering). *)
-  583    ClassItem
-  584      = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
-  585    ClassRest                             (. VAR cn, m2, pn: SymTab.Name;
-  586                                               ct: SymTab.TypeIndex; .)
-  587      = GetIdent<cn>                      (. IF NOT SymTab.Enter(cn,
-  588                                               SymTab.KindType) THEN
-  589                                               SemError(200) END;
-  590                                             ct := SymTab.NewClass();
-  591                                             SymTab.SetSymType(cn, ct);
-  592                                             SymTab.PushClassScope(ct); .)
-  593        [ Parents<ct> ]
-  594        ";"
-  595        { ClassField<ct> ";" }
-  596        { MethodHeading<pn, SymTab.InvalidType> ";"
-  597                                          (. SymTab.CloseProc;
-  598                                             QbeGen.AbortFunc; .) }
-  599        "END"
-  600        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
-  601                                               SemError(202) END;
-  602                                             SymTab.LayoutClass(ct);
-  603                                             SymTab.PopScope; .) .
-  604    Parents<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name; .)
-  605      = "(" Parent1<ct>
-  606        { "," GetIdent<p>                 (. SemError(230); .) }
-  607        ")" .
-  608    Parent1<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name;
-  609                                               pt: SymTab.TypeIndex; .)
-  610      = GetIdent<p>                       (. IF NOT SymTab.Lookup(p) THEN
-  611                                               SemError(201)
-  612                                             ELSE pt := SymTab.SymType(p);
-  613                                               IF SymTab.ClassOf(pt) #
-  614                                                  SymTab.ClClass THEN
-  615                                                 SemError(230)
-  616                                               ELSE SymTab.SetParent(ct, pt)
-  617                                               END
-  618                                             END; .) .
-  619    ClassField<ct: SymTab.TypeIndex>      (. VAR n, rhs: SymTab.Name;
-  620                                               t: SymTab.TypeIndex; .)
-  621      = GetIdent<n>
-  622        ( "=" GetIdent<rhs>               (. IF NOT SymTab.Enter(n,
-  623                                               SymTab.KindConst) THEN
-  624                                               SemError(200) END;
-  625                                             IF SymTab.Lookup(rhs) THEN
-  626                                               SymTab.SetSymType(n,
-  627                                                 SymTab.SymType(rhs))
-  628                                             END; .)
-  629        |                                 (. IF NOT SymTab.FieldPending(ct,
-  630                                               n) THEN
-  631                                               SemError(200) END; .)
-  632          { "," GetIdent<n>               (. IF NOT SymTab.FieldPending(ct,
-  633                                               n) THEN
-  634                                               SemError(200) END; .) }
-  635          ":" Type<t, FALSE>              (. SymTab.FixPendingF(ct, t); .) ) .
-  636    MethodHeading<VAR pn: SymTab.Name; ct: SymTab.TypeIndex>
-  637                                          (. VAR wantVirt: BOOLEAN; .)
-  638      =                                   (. wantVirt := FALSE; .)
-  639        [ "VIRTUAL"                       (. wantVirt := TRUE; .) ]
-  640        ProcHeading<pn, ct>               (. IF wantVirt THEN
-  641                                               SymTab.MarkVirtual END; .) .
-  642    ClassImplRest                         (. VAR cn, m2: SymTab.Name;
-  643                                               ct: SymTab.TypeIndex; .)
-  644      = GetIdent<cn>                      (. IF NOT SymTab.Lookup(cn) THEN
-  645                                               SemError(201);
-  646                                               ct := SymTab.InvalidType
-  647                                             ELSE ct := SymTab.SymType(cn);
-  648                                               IF SymTab.ClassOf(ct) #
-  649                                                  SymTab.ClClass THEN
-  650                                                 SemError(230);
-  651                                                 ct := SymTab.InvalidType
-  652                                               END
-  653                                             END;
-  654                                             IF ct #
-  655                                                SymTab.InvalidType THEN
-  656                                               IF NOT SymTab.PushClassMembers(
-  657                                                      ct) THEN
-  658                                                 SemError(230) END;
-  659                                               SymTab.PushImplClass(ct)
+  211                                             QbeGen.EndModule(m1);
+  212                                             SymTab.EndUnit; .) .
+  213    DeclSeq
+  214      = { ConstBlock | TypeBlock<FALSE> | VarBlock | ProcDecl ";"
+  215        | NestedModule ";" | ClassItem ";" } .
+  216    (* Local module, Wirth form. Declarations lower like top-level ones
+  217       (same QBE module prefix); a BEGIN body becomes an init function
+  218       that main calls; the EXPORT list is hoisted into the enclosing
+  219       scope at END. *)
+  220    NestedModule                          (. VAR m1, m2: SymTab.Name;
+  221                                               expNames: ARRAY [0 .. 63] OF SymTab.Name;
+  222                                               expCount, k: CARDINAL; .)
+  223      = "MODULE"
+  224        GetIdent<m1>                      (. IF NOT SymTab.Enter(m1,
+  225                                               SymTab.KindModule) THEN
+  226                                               SemError(200) END;
+  227                                             SymTab.PushScope;
+  228                                             expCount := 0; .)
+  229        [ Priority ]
+  230        ";"
+  231        { Import }
+  232        [ "EXPORT" [ "QUALIFIED" ]
+  233          GetIdent<expNames[expCount]>    (. INC(expCount); .)
+  234          { "," GetIdent<expNames[expCount]>
+  235                                          (. INC(expCount); .) }
+  236          ";" ]
+  237        DeclSeq
+  238        [ "BEGIN"                         (. QbeGen.BeginInit(m1); .)
+  239          [ StatSeq ]                     (. QbeGen.EndInit; .) ]
+  240        "END"
+  241        GetIdent<m2>                      (. IF NOT SymTab.Equal(m1, m2) THEN
+  242                                               SemError(202) END;
+  243                                             k := 0;
+  244                                             WHILE k < expCount DO
+  245                                               SymTab.ExportUp(expNames[k]);
+  246                                               INC(k)
+  247                                             END;
+  248                                             SymTab.PopScope; .) .
+  249    Priority
+  250      = "[" integer "]"                   (. SemError(230); .) .
+  251    (* Imports (4.3): FROM materializes the names (unqualified use);
+  252       plain IMPORT only demands the module exists — qualified `L.x`
+  253       materializes on first use (Design). *)
+  254    (* Unknown modules stay unchecked stubs (legacy, so hand-written
+  255       import lines don't fail); a known module's missing export is
+  256       201. *)
+  257    Import                                (. VAR n: SymTab.Name; .)
+  258      = "FROM"
+  259        GetIdent<n>
+  260        "IMPORT"
+  261        ImpList<n> ";"
+  262      | "IMPORT"
+  263        ImpModList ";" .
+  264    ImpList<mod: SymTab.Name>             (. VAR n: SymTab.Name; .)
+  265      = ImpName<mod>
+  266        { "," ImpName<mod> } .
+  267    (* Pervasive built-ins imported from SYSTEM (e.g. TSIZE) are
+  268       accepted and ignored: the built-in applies regardless. *)
+  269    ImpName<mod: SymTab.Name>             (. VAR n: SymTab.Name; .)
+  270      = GetIdent<n>                       (. IF SymTab.Equal(mod, "libc") THEN
+  271                                               (* intrinsic C library:
+  272                                                  permissive external *)
+  273                                               IF NOT SymTab.DeclareCProc(n) THEN
+  274                                                 SemError(201) END
+  275                                             ELSIF SymTab.ModKnown(mod)
+  276                                               AND NOT SymTab.ImportFrom(mod, n) THEN
+  277                                               SemError(201) END; .)
+  278      | ( "TSIZE" | "SIZE" | "ADR" | "HIGH" | "LEN"
+  279        | "CHR" | "ORD" | "ORDL" | "VAL" | "ABS" | "CAP"
+  280        | "UCHR" | "CHR8" | "UORD"
+  281        | "INC" | "DEC" ) .
+  282    ImpModList                            (. VAR n: SymTab.Name; .)
+  283      = GetIdent<n>
+  284        { "," GetIdent<n> } .
+  285    (* Opaque TYPE declarations (definition modules). The targetless
+  286       alias resolves to InvalidType until step 4 completes it. *)
+  287    (* Scalar-phase TYPEs: named types, integer subranges, enumerations.
+  288       Opaque "TYPE T;" needs isDef (definition units); elsewhere 231.
+  289       Composite forms (ARRAY/RECORD/SET/POINTER) arrive with step 3. *)
+  290    TypeBlock<isDef: BOOLEAN>
+  291      = "TYPE"                            (. SymTab.BeginTypeBlock; .)
+  292        { TypeItem<isDef> ";" | ClassItem ";" }
+  293                                          (. SymTab.EndTypeBlock; .) .
+  294    TypeItem<isDef: BOOLEAN>              (. VAR n: SymTab.Name;
+  295                                               t, op: SymTab.TypeIndex; .)
+  296      = GetIdent<n>                       (. op := SymTab.OpaqueBase(n);
+  297                                             IF op = SymTab.InvalidType THEN
+  298                                               IF NOT SymTab.Enter(n,
+  299                                                  SymTab.KindType) THEN
+  300                                                 SemError(200) END
+  301                                             END; .)
+  302        ( "=" Type<t, FALSE>              (. IF op # SymTab.InvalidType THEN
+  303                                               SymTab.SetTarget(op, t)
+  304                                             ELSE SymTab.SetSymType(n, t)
+  305                                             END; .)
+  306        |                                 (. IF op # SymTab.InvalidType THEN
+  307                                               (* stays opaque *)
+  308                                             ELSIF NOT isDef THEN
+  309                                               SemError(231)
+  310                                             ELSE SymTab.SetSymType(n,
+  311                                               SymTab.NewAlias()) END; .) ) .
+  312    Type<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
+  313      = TypeIdent<t> [ Subrange<t> ]     (* anchored subrange: T[lo..hi] *)
+  314      | Subrange<t>
+  315      | Enum<t>
+  316      | ArrayType<t, allowOpen>
+  317      | SetType<t>
+  318      | RecordType<t>
+  319      | PointerType<t>
+  320      | ProcType<t> .
+  321    PointerType<VAR t: SymTab.TypeIndex>  (. VAR base: SymTab.TypeIndex; .)
+  322      = "POINTER" "TO" Type<base, FALSE>(. t := SymTab.NewPtr(base); .) .
+  323    (* Procedure types (step 8.5): PROCEDURE (params): result. Values
+  324       are code pointers; params are collected into the descriptor. *)
+  325    ProcType<VAR t: SymTab.TypeIndex>     (. VAR res, pt: SymTab.TypeIndex;
+  326                                               isV: BOOLEAN; .)
+  327      = "PROCEDURE"                       (. res := SymTab.InvalidType;
+  328                                             t := SymTab.NewProcType(res); .)
+  329        [ "(" [ ProcTypeSection<t> { ";" ProcTypeSection<t> } ] ")" ]
+  330        [ ":" TypeIdent<res>              (. SymTab.SetProcTypeRes(t, res); .) ] .
+  331    ProcTypeSection<t: SymTab.TypeIndex>  (. VAR pt: SymTab.TypeIndex;
+  332                                               isV: BOOLEAN;
+  333                                               cnt, k: CARDINAL;
+  334                                               names: ARRAY [0 .. 15] OF SymTab.Name; .)
+  335      =                                   (. isV := FALSE; cnt := 0; .)
+  336        [ "VAR"                           (. isV := TRUE; .) ]
+  337        ( GetIdent<names[cnt]>            (. INC(cnt); .)
+  338          { "," GetIdent<names[cnt]>      (. INC(cnt); .) }
+  339          ( ":" Type<pt, TRUE>           (. k := 0;
+  340                                             WHILE k < cnt DO
+  341                                               SymTab.ProcTypeAdd(t, isV, pt);
+  342                                               INC(k)
+  343                                             END; .)
+  344          |                               (. (* type-only parameter list:
+  345                                                each name is a type (GNU
+  346                                                shorthand used by the
+  347                                                Coco/R scanner frame) *)
+  348                                             k := 0;
+  349                                             WHILE k < cnt DO
+  350                                               IF SymTab.Lookup(names[k])
+  351                                                  AND ((SymTab.SymKind(names[k]) = SymTab.KindType)
+  352    OR (SymTab.SymKind(names[k]) = SymTab.KindPredef)) THEN
+  353                                                 pt := SymTab.SymType(names[k])
+  354                                               ELSE SemError(201);
+  355                                                 pt := SymTab.InvalidType
+  356                                               END;
+  357                                               SymTab.ProcTypeAdd(t, isV, pt);
+  358                                               INC(k)
+  359                                             END; .) )
+  360        | Type<pt, TRUE>                 (. (* unnamed parameter (PIM):
+  361                                                e.g. PROCEDURE (VAR ARRAY OF REAL) *)
+  362                                             SymTab.ProcTypeAdd(t, isV, pt); .) ) .
+  363    (* Arrays: "OF" without bounds is an open formal (allowed only
+  364       where allowOpen); "[lo..hi, ...]" nests bounded levels inside
+  365       out. Bounds are folded literals (int/char); anything else 230.
+  366       Bare-type indices ("ARRAY Color OF") wait for enum ordinals. *)
+  367    ArrayType<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
+  368                                          (. VAR elem: SymTab.TypeIndex;
+  369                                               ok: BOOLEAN;
+  370                                               bnds, bndh: ARRAY [0 .. 7] OF INTEGER;
+  371                                               nb, k: CARDINAL;
+  372                                               idx: SymTab.TypeIndex;
+  373                                               ilo, ihi: INTEGER; .)
+  374      = "ARRAY"
+  375        ( "OF" Type<elem, FALSE>          (. IF NOT allowOpen THEN
+  376                                               SemError(230) END;
+  377                                             t := SymTab.NewOpenArray(elem); .)
+  378        | TypeIdent<idx> [ Subrange<idx> ]
+  379          "OF" Type<elem, FALSE>          (. (* index-type array: the index
+  380                                                type's ordinal bounds give the
+  381                                                [lo..hi] pair *)
+  382                                             IF SymTab.TypeBounds(idx, ilo,
+  383                                                ihi)
+  384                                             THEN t := SymTab.NewArrayB(elem,
+  385                                                    ilo, ihi)
+  386                                             ELSE SemError(230);
+  387                                               t := SymTab.InvalidType
+  388                                             END; .)
+  389        | "["                             (. SymTab.BoundBegin; ok := TRUE; .)
+  390          BoundPair<ok>
+  391          { "," BoundPair<ok> }
+  392          "]"                             (. (* snapshot before the element
+  393                                                type, which reuses the bound
+  394                                                buffer for a nested ARRAY *)
+  395                                             nb := SymTab.BoundCount();
+  396                                             k := 0;
+  397                                             WHILE k < nb DO
+  398                                               bnds[k] := SymTab.BoundLo(k);
+  399                                               bndh[k] := SymTab.BoundHi(k);
+  400                                               INC(k)
+  401                                             END; .)
+  402          "OF" Type<elem, FALSE>
+  403                                          (. IF ok THEN
+  404                                               k := nb;
+  405                                               WHILE k > 0 DO
+  406                                                 DEC(k);
+  407                                                 elem := SymTab.NewArrayB(
+  408                                                   elem, bnds[k], bndh[k])
+  409                                               END;
+  410                                               t := elem
+  411                                             ELSE t := SymTab.InvalidType
+  412                                             END; .) ) .
+  413    BoundPair<VAR ok: BOOLEAN>            (. VAR tlo, thi: SymTab.TypeIndex;
+  414                                               qlo, qhi: QbeGen.QVal;
+  415                                               lo, hi: INTEGER;
+  416                                               cl, cl2: INTEGER; .)
+  417      = Expr<tlo, qlo> ".." Expr<thi, qhi>
+  418                                          (. IF (tlo = SymTab.InvalidType)
+  419                                              OR (thi = SymTab.InvalidType) THEN
+  420                                             ok := FALSE
+  421                                           ELSE cl := SymTab.ClassOf(tlo);
+  422                                             cl2 := SymTab.ClassOf(thi);
+  423                                             IF ((cl # SymTab.ClInt)
+  424   AND (cl # SymTab.ClChar))
+  425                                                OR ((cl2 # SymTab.ClInt)
+  426   AND (cl2 # SymTab.ClChar)) THEN
+  427                                               SemError(230); ok := FALSE
+  428                                             ELSIF NOT SymTab.ConstInt(qlo, lo)
+  429                                                OR NOT SymTab.ConstInt(qhi, hi)
+  430                                                OR (lo > hi) THEN
+  431                                               SemError(230); ok := FALSE
+  432                                              ELSIF NOT SymTab.BoundAdd(lo, hi) THEN
+  433                                                SemError(230); ok := FALSE
+  434                                              END;
+  435                                            END; .) .
+  436    (* Sets: multi-word masks over bases ≤ 256 values (bool, char,
+  437       bounded subranges; enums wait for ordinals, INTEGER is
+  438       unbounded). Literals are SET OF [0..255]; assignment and
+  439       comparison across suitable bases are lenient (masks over min
+  440       words + zero-check extras), out-of-span literals are 222. *)
+  441    SetType<VAR t: SymTab.TypeIndex>      (. VAR base: SymTab.TypeIndex;
+  442                                               blo, bhi, bspan: INTEGER;
+  443                                               bcls: INTEGER; .)
+  444      = "SET" "OF" Type<base, FALSE>
+  445                                          (. IF base = SymTab.InvalidType THEN
+  446                                               t := SymTab.InvalidType
+  447                                             ELSE bcls :=
+  448                                                    SymTab.ClassOf(base);
+  449                                               IF bcls = SymTab.ClBool THEN
+  450                                                 blo := 0; bspan := 2
+  451                                               ELSIF bcls = SymTab.ClChar THEN
+  452                                                 blo := 0; bspan := 256
+  453                                               ELSIF bcls = SymTab.ClEnum THEN
+  454                                                 blo := 0;
+  455                                                 bspan := VAL(INTEGER,
+  456                                                   SymTab.EnumCount(base))
+  457                                               ELSIF SymTab.SubBounds(base,
+  458                                                       blo, bhi) THEN
+  459                                                 bspan := bhi - blo + 1
+  460                                               ELSE bspan := 0 END;
+  461                                               IF (bspan <= 0)
+  462                                                  OR (bspan > 65536) THEN
+  463                                                 SemError(230);
+  464                                                 t := SymTab.InvalidType
+  465                                               ELSE t := SymTab.NewSet(base)
+  466                                               END
+  467                                             END; .) .
+  468    (* Records: flat blobs; array fields are pointers to static
+  469       descriptors (locked amendment), nested records inline. Field
+  470       offsets static and declaration-ordered. *)
+  471    (* Field list: plain fields and (optionally) one variant part.  The
+  472       variant part is a `CASE ... END` item; because it starts with the
+  473       CASE keyword it is unambiguously distinguishable from a field
+  474       (which starts with an identifier). *)
+  475    RecordType<VAR t: SymTab.TypeIndex>   (. VAR t2: SymTab.TypeIndex;
+  476                                               tagOk: BOOLEAN; .)
+  477      = "RECORD"                          (. t := SymTab.NewRecord(); .)
+  478        [ RecItem<t> { ";" [ RecItem<t> ] } ]
+  479        "END" .
+  480    RecItem<rec: SymTab.TypeIndex>        (. VAR tt: SymTab.TypeIndex; .)
+  481      = RecField<rec>
+  482      | CaseField<rec>                    (. SymTab.MarkVariant(rec); .) .
+  483    (* A variant part: CASE tag : Type OF variants.  The layout overlays
+  484       every branch from the tag slot (see SymTab.ComputeOffsets). *)
+  485    CaseField<rec: SymTab.TypeIndex>      (. VAR tagT: SymTab.TypeIndex;
+  486                                               tagN: SymTab.Name; .)
+  487      = "CASE"                            (. SymTab.ResetFields(rec); .)
+  488        GetIdent<tagN>                    (. IF NOT SymTab.FieldPending(rec,
+  489                                               tagN) THEN
+  490                                               SemError(200) END; .)
+  491        ":" Type<tagT, FALSE>             (. IF (tagT # SymTab.InvalidType)
+  492    AND NOT SymTab.IsOrdinal(tagT) THEN
+  493                                               SemError(224)
+  494                                             END;
+  495                                             SymTab.FixPendingF(rec, tagT);
+  496                                             SymTab.SetVariantTag(rec, tagN); .)
+  497        "OF"
+  498        RecFieldList<rec>
+  499        { "|"                             (. SymTab.ResetFields(rec); .)
+  500          RecFieldList<rec> }
+  501        "END" .
+  502    RecFieldList<rec: SymTab.TypeIndex>   (. VAR lt, lq: SymTab.TypeIndex;
+  503                                               lv1, lv2: QbeGen.QVal; .)
+  504      = VarLabel<lt, lv1> [ ".." VarLabel<lq, lv2> ] ":"
+  505        RecField<rec> { ";" [ RecField<rec> ] } .
+  506    (* Variant case label: a constant (or a constant range).  Values are
+  507       not interpreted (the layout overlays regardless). *)
+  508    VarLabel<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+  509                                          (. VAR lname: SymTab.Name; .)
+  510      = ( ident                         (. LexName(lname);
+  511                                             QbeGen.CopyOp("0", q);
+  512                                             t := SymTab.IntType(); .)
+  513        | integer                       (. LexString(lname);
+  514                                             QbeGen.CopyOp("0", q);
+  515                                             t := SymTab.IntType(); .)
+  516        | charConst                     (. LexString(lname);
+  517                                             QbeGen.CopyOp("0", q);
+  518                                             t := SymTab.CharType(); .) ) .
+  519    RecField<rec: SymTab.TypeIndex>       (. VAR n: SymTab.Name;
+  520                                               t2: SymTab.TypeIndex; .)
+  521      = RecIdents<rec> ":" Type<t2, FALSE>(. SymTab.FixPendingF(rec, t2); .) .
+  522    RecIdents<rec: SymTab.TypeIndex>      (. VAR n: SymTab.Name; .)
+  523      = GetIdent<n>                       (. IF NOT SymTab.FieldPending(rec,
+  524                                               n) THEN
+  525                                               SemError(200) END; .)
+  526        { "," GetIdent<n>                 (. IF NOT SymTab.FieldPending(rec,
+  527                                               n) THEN
+  528                                               SemError(200) END; .) } .
+  529    TypeIdent<VAR t: SymTab.TypeIndex>    (. VAR n, qid: SymTab.Name;
+  530                                               k: INTEGER;
+  531                                               dotted: BOOLEAN; .)
+  532      = GetIdent<n>                       (. dotted := FALSE;
+  533                                             IF NOT SymTab.Lookup(n) THEN
+  534                                               k := -1;
+  535                                               t := SymTab.ForwardType(n);
+  536                                               IF t = SymTab.InvalidType THEN
+  537                                                 SemError(201)
+  538                                               END
+  539                                             ELSE k := SymTab.SymKind(n);
+  540                                               IF (k = SymTab.KindType)
+  541                                                  OR (k = SymTab.KindPredef) THEN
+  542                                                 t := SymTab.SymType(n)
+  543                                               ELSE t := SymTab.InvalidType
+  544                                               END
+  545                                             END; .)
+  546        [ "." GetIdent<qid>               (. dotted := TRUE;
+  547                                             IF k = SymTab.KindModule THEN
+  548                                               t := SymTab.QualType(n, qid);
+  549                                               IF t = SymTab.InvalidType THEN
+  550                                                 SemError(201)
+  551                                               END
+  552                                             ELSE SemError(221);
+  553                                               t := SymTab.InvalidType
+  554                                             END; .) ]
+  555                                          (. IF NOT dotted THEN
+  556                                               IF (k = SymTab.KindModule)
+  557                                                  OR ((k # SymTab.KindType)
+  558    AND (k # SymTab.KindPredef)
+  559    AND (k # SymTab.KindImport)
+  560    AND (k # -1)) THEN
+  561                                                 SemError(221)
+  562                                               END
+  563                                             END; .) .
+  564    Subrange<VAR t: SymTab.TypeIndex>     (. VAR tlo, thi: SymTab.TypeIndex;
+  565                                               qlo, qhi: QbeGen.QVal;
+  566                                               lo, hi: INTEGER; .)
+  567      = "[" Expr<tlo, qlo> ".." Expr<thi, qhi>
+  568                                          (. IF (tlo = SymTab.InvalidType)
+  569                                              OR (thi = SymTab.InvalidType) THEN
+  570                                             t := SymTab.InvalidType
+  571                                           ELSIF NOT SymTab.IsOrdinal(tlo)
+  572                                              OR NOT SymTab.IsOrdinal(thi) THEN
+  573                                             SemError(230);
+  574                                             t := SymTab.InvalidType
+  575                                           ELSIF NOT SymTab.ConstInt(qlo, lo)
+  576                                              OR NOT SymTab.ConstInt(qhi, hi)
+  577                                              OR (lo > hi) THEN
+  578                                             SemError(230);
+  579                                             t := SymTab.InvalidType
+  580                                           ELSE t := SymTab.NewSubR(lo, hi)
+  581                                           END; .)
+  582        "]" .
+  583    Enum<VAR t: SymTab.TypeIndex>         (. VAR n: SymTab.Name;
+  584                                               ord: INTEGER;
+  585                                               qv: QbeGen.QVal; .)
+  586      = "("                               (. t := SymTab.NewEnum();
+  587                                             ord := 0; .)
+  588        GetIdent<n>                       (. IF NOT SymTab.Enter(n,
+  589                                               SymTab.KindConst) THEN
+  590                                               SemError(200) END;
+  591                                             SymTab.SetSymType(n, t);
+  592                                             QbeGen.IntStr(ord, qv);
+  593                                             SymTab.SetSymVal(n, qv);
+  594                                             INC(ord); .)
+  595        { "," GetIdent<n>                 (. IF NOT SymTab.Enter(n,
+  596                                               SymTab.KindConst) THEN
+  597                                               SemError(200) END;
+  598                                             SymTab.SetSymType(n, t);
+  599                                             QbeGen.IntStr(ord, qv);
+  600                                             SymTab.SetSymVal(n, qv);
+  601                                             INC(ord); .) }
+  602        ")"                               (. SymTab.SetEnumCount(t,
+  603                                               VAL(CARDINAL, ord)); .) .
+  604    (* Clarion-form classes (docs/OOP.txt): declaration + single
+  605       inheritance + IMPLEMENTATION blocks. Scopes and member checks
+  606       now; lowering (vtable, dispatch, THIS) later — one 230 per
+  607       class/impl block. Methods end with ";" per the Table example
+  608       (not "," as in the sketch). No underscores in identifiers. *)
+  609    (* Single CLASS item in both loops: separating declaration from
+  610       IMPLEMENTATION at the loop level needs 2-token lookahead
+  611       (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
+  612       The second token decides after CLASS is consumed. A misplaced
+  613       CLASS IMPLEMENTATION inside TYPE still parses (harmless: the
+  614       whole unit ends 230 until lowering). *)
+  615    ClassItem
+  616      = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
+  617    ClassRest                             (. VAR cn, m2, pn: SymTab.Name;
+  618                                               ct: SymTab.TypeIndex; .)
+  619      = GetIdent<cn>                      (. IF NOT SymTab.Enter(cn,
+  620                                               SymTab.KindType) THEN
+  621                                               SemError(200) END;
+  622                                             ct := SymTab.NewClass();
+  623                                             SymTab.SetSymType(cn, ct);
+  624                                             SymTab.PushClassScope(ct); .)
+  625        [ Parents<ct> ]
+  626        ";"
+  627        { ClassField<ct> ";" }
+  628        { MethodHeading<pn, SymTab.InvalidType> ";"
+  629                                          (. SymTab.CloseProc;
+  630                                             QbeGen.AbortFunc; .) }
+  631        "END"
+  632        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
+  633                                               SemError(202) END;
+  634                                             SymTab.LayoutClass(ct);
+  635                                             SymTab.PopScope; .) .
+  636    Parents<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name; .)
+  637      = "(" Parent1<ct>
+  638        { "," GetIdent<p>                 (. SemError(230); .) }
+  639        ")" .
+  640    Parent1<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name;
+  641                                               pt: SymTab.TypeIndex; .)
+  642      = GetIdent<p>                       (. IF NOT SymTab.Lookup(p) THEN
+  643                                               SemError(201)
+  644                                             ELSE pt := SymTab.SymType(p);
+  645                                               IF SymTab.ClassOf(pt) #
+  646                                                  SymTab.ClClass THEN
+  647                                                 SemError(230)
+  648                                               ELSE SymTab.SetParent(ct, pt)
+  649                                               END
+  650                                             END; .) .
+  651    ClassField<ct: SymTab.TypeIndex>      (. VAR n, rhs: SymTab.Name;
+  652                                               t: SymTab.TypeIndex; .)
+  653      = GetIdent<n>
+  654        ( "=" GetIdent<rhs>               (. IF NOT SymTab.Enter(n,
+  655                                               SymTab.KindConst) THEN
+  656                                               SemError(200) END;
+  657                                             IF SymTab.Lookup(rhs) THEN
+  658                                               SymTab.SetSymType(n,
+  659                                                 SymTab.SymType(rhs))
   660                                             END; .)
   660                                             END; .)
-  661        ";" { MethodImpl<ct> ";" }
-  662        [ "BEGIN"                         (. QbeGen.BeginInit(cn); .)
-  663          [ StatSeq ]                     (. QbeGen.EndInit; .) ]
-  664        "END"
-  665        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
-  666                                               SemError(202) END;
-  667                                             SymTab.PopImplClass;
-  668                                             SymTab.PopScope; .) .
-  669    MethodImpl<ct: SymTab.TypeIndex>      (. VAR pn: SymTab.Name;
-  670                                               thisQ: QbeGen.QVal;
-  671                                               methRes: SymTab.TypeIndex; .)
-  672      = MethodHeading<pn, ct> ";"
-  673                                          (. IF (ct #
-  674                                                SymTab.InvalidType)
-  675   AND NOT SymTab.MethodExists(ct,
-  676                                                    pn) THEN
-  677                                               SemError(201) END; .)
-  678        ( "FORWARD"                       (. SymTab.MarkFwd;
-  679                                             QbeGen.AbortFunc;
-  680                                             SymTab.CloseProc; .)
-  681        |                                 (. QbeGen.EndFuncHeader;
-  682                                             (* bind the receiver: bare
-  683                                                field names resolve
-  684                                                against THIS *)
-  685                                             QbeGen.ThisBase(thisQ);
-  686                                             QbeGen.PushWith(thisQ); .)
-  687          Block<pn>                       (. QbeGen.PopWith;
-  688                                             methRes := SymTab.CurRes();
-  689                                             SymTab.CloseProc;
-  690                                             QbeGen.EndFunc(methRes); .) ) .
-  691    ConstBlock
-  692      = "CONST" { ConstDecl ";" } .
-  693    ConstDecl                             (. VAR n: SymTab.Name;
-  694                                               t: SymTab.TypeIndex;
-  695                                               qv: QbeGen.QVal;
-  696                                               cls: INTEGER; .)
-  697      = GetIdent<n>                       (. IF NOT SymTab.Enter(n,
-  698                                               SymTab.KindConst) THEN
-  699                                               SemError(200) END; .)
-  700        "="
-  701        Expr<t, qv>                       (. SymTab.SetSymType(n, t);
-  702                                             cls := SymTab.ClassOf(t);
-  703                                             IF (cls = SymTab.ClArray)
-  704                                                OR (cls = SymTab.ClRecord)
-  705                                                OR (cls = SymTab.ClClass)
-  706                                                OR (cls = SymTab.ClStr)
-  707                                                OR (cls = SymTab.ClUStr) THEN
-  708                                               (* an aggregate/string
-  709                                                  constant: qv is its
-  710                                                  descriptor address; no
-  711                                                  scalar data *)
-  712                                               SymTab.SetSymVal(n, qv)
-  713                                             ELSIF NOT QbeGen.IsImm(qv) THEN
-  714                                               SemError(230)
-  715                                             ELSE
-  716                                               SymTab.SetSymVal(n, qv);
-  717                                               QbeGen.DeclConst(n, qv, t)
-  718                                             END; .) .
-  719    VarBlock
-  720      = "VAR" { VarDecl ";" } .
-  721    VarDecl                               (. VAR nm: SymTab.Name;
-  722                                               t: SymTab.TypeIndex;
-  723                                               i: CARDINAL;
-  724                                               cls: INTEGER; .)
-  725      = VarIdents ":"
-  726        Type<t, FALSE>                    (. cls := SymTab.ClassOf(t);
-  727                                             IF (t # SymTab.InvalidType)
-  728   AND NOT SymTab.IsUnresolved(t)
-  729   AND (cls # SymTab.ClInt)
-  730   AND (cls # SymTab.ClBool)
-  731   AND (cls # SymTab.ClChar)
-  732   AND (cls # SymTab.ClReal)
-  733   AND (cls # SymTab.ClArray)
-  734   AND (cls # SymTab.ClSet)
-  735   AND (cls # SymTab.ClRecord)
-  736   AND (cls # SymTab.ClPtr)
-  737   AND (cls # SymTab.ClLong)
-  738   AND (cls # SymTab.ClProc)
-  739   AND (cls # SymTab.ClUChar)
-  740   AND (cls # SymTab.ClUStr)
-  741   AND (cls # SymTab.ClEnum)
-  742   AND (cls # SymTab.ClClass) THEN
-  743                                               SemError(230) END;
-  744                                             IF QbeGen.LocFull() THEN
-  745                                               SemError(233) END;
-  746                                             i := 0;
-  747                                             IF SymTab.IsUnresolved(t)
-  748                                                AND NOT SymTab.InProc() THEN
-  749                                               (* a forward-typed global:
-  750                                                  defer emission until the
-  751                                                  TYPE block completes *)
-  752                                               WHILE i < SymTab.PendCount() DO
-  753                                                 SymTab.PendName(i, nm);
-  754                                                 IF nPendVar <=
-  755                                                    HIGH(pendVarName) THEN
-  756                                                   pendVarName[nPendVar] := nm;
-  757                                                   pendVarT[nPendVar] := t;
-  758                                                   INC(nPendVar)
-  759                                                 END;
-  760                                                 INC(i)
-  761                                               END
-  762                                             ELSE
-  763                                               WHILE i < SymTab.PendCount() DO
-  764                                                 SymTab.PendName(i, nm);
-  765                                                 QbeGen.DeclVar(nm, t);
-  766                                                 INC(i)
-  767                                               END
-  768                                             END;
-  769                                             (* a plain VAR list, not a
-  770                                                heading: the signature
-  771                                                result is discarded *)
-  772                                             IF NOT SymTab.FixPending(t) THEN
-  773                                             END; .) .
-  774    VarIdents                             (. VAR n: SymTab.Name; .)
-  775      = GetIdent<n>                       (. IF NOT SymTab.EnterPending(n,
-  776                                               SymTab.KindVar) THEN
-  777                                               SemError(200) END; .)
-  778        { ","
-  779          GetIdent<n>                     (. IF NOT SymTab.EnterPending(n,
-  780                                               SymTab.KindVar) THEN
-  781                                               SemError(200) END; .) } .
-  782    ParIdents<isV: BOOLEAN>               (. VAR n: SymTab.Name; .)
-  783      = GetIdent<n>                       (. IF NOT SymTab.EnterParam(n, isV) THEN
-  784                                               SemError(200) END; .)
-  785        { "," GetIdent<n>                 (. IF NOT SymTab.EnterParam(n, isV) THEN
-  786                                               SemError(200) END; .) } .
-  787    (* Procedure headings enter scopes/params/result and buffer the
-  788       QBE header; bodies lower to functions (4.1, module level only).
-  789       FORWARD marks; the body heading re-enters (signature compare
-  790       deferred). Nested procedures parse + check, lowering = 4.2. *)
-  791    ProcHeading<VAR pn: SymTab.Name; methCls: SymTab.TypeIndex>
-  792                                          (. VAR t: SymTab.TypeIndex;
-  793                                               mg: QbeGen.QVal; .)
-  794      = "PROCEDURE"
-  795        GetIdent<pn>                      (. IF methCls #
-  796                                                SymTab.InvalidType THEN
-  797                                             (* a method: resume the
-  798                                                declared symbol (reuse
-  799                                                its uid) *)
-  800                                             IF NOT SymTab.ResumeMethod(
-  801                                                  methCls, pn) THEN
-  802                                               SemError(200) END
-  803                                             ELSIF NOT SymTab.EnterProc(pn) THEN
-  804                                             IF NOT SymTab.ReenterProc(pn) THEN
-  805                                               IF NOT SymTab.ResumeProc(pn) THEN
-  806                                                 SemError(200) END
-  807                                               END
-  808                                             END;
-  809                                             IF methCls #
-  810                                                SymTab.InvalidType THEN
-  811                                               QbeGen.Mangled(pn,
-  812                                                 SymTab.MethUid(), mg)
-  813                                             ELSE
-  814                                               QbeGen.Mangled(pn,
-  815                                                 SymTab.ProcUid(pn), mg)
-  816                                             END;
-  817                                             QbeGen.BeginFunc(mg);
-  818                                             IF methCls #
-  819                                                SymTab.InvalidType THEN
-  820                                               (* hidden THIS receiver:
-  821                                                  a VAR param of the
-  822                                                  class type, pushed as
-  823                                                  the WITH base *)
-  824                                               IF NOT SymTab.EnterThisParam(
-  825                                                    methCls) THEN
-  826                                                 SemError(200) END;
-  827                                               IF NOT QbeGen.FuncParam(
-  828                                                    "THIS", TRUE,
-  829                                                    methCls) THEN
-  830                                                 SemError(233) END
-  831                                             END; .)
-  832        [ FormalParams ]
-  833        [ ":" TypeIdent<t>                (. IF NOT SymTab.SetProcRes(t) THEN
-  834                                               SemError(235) END;
-  835                                             QbeGen.SetFuncRes(t);
-  836                                             IF (t #
-  837                                                SymTab.InvalidType)
-  838   AND ((SymTab.ClassOf(t)
-  839                                                   = SymTab.ClArray)
-  840                                                OR (SymTab.ClassOf(t)
-  841                                                   = SymTab.ClRecord)
-  842                                                OR (SymTab.ClassOf(t)
-  843                                                   = SymTab.ClSet)
-  844                                                OR (SymTab.ClassOf(t)
-  845                                                   = SymTab.ClClass)) THEN
-  846                                               SemError(230) END; .) ] .
-  847    FormalParams
-  848      = "(" [ ParamSection { ";" ParamSection } ] ")" .
-  849    ParamSection                          (. VAR t: SymTab.TypeIndex;
-  850                                               nm: SymTab.Name;
-  851                                               i: CARDINAL;
-  852                                               isV: BOOLEAN; .)
-  853      =                                   (. isV := FALSE; .)
-  854        [ "VAR"                           (. isV := TRUE; .) ]
-  855        ParIdents<isV> ":" Type<t, TRUE>  (. i := 0;
-  856                                             WHILE i < SymTab.PendCount() DO
-  857                                               SymTab.PendName(i, nm);
-  858                                               (* value open arrays are
-  859                                                  passed as descriptor
-  860                                                  addresses (no copy):
-  861                                                  same representation as
-  862                                                  VAR formals *)
-  863                                               IF NOT QbeGen.FuncParam(nm,
-  864                                                    isV
-  865                                                    OR SymTab.IsOpenArray(t),
-  866                                                    t) THEN
-  867                                                 SemError(233) END;
-  868                                               INC(i)
-  869                                             END;
-  870                                             IF NOT SymTab.FixPending(t) THEN
-  871                                               SemError(235) END; .) .
-  872    (* Nested procedures lower like top-level ones (4.2): the
-  873       static link gives them their parent's frame. Methods keep
-  874       parse-now/230-later. *)
-  875    ProcDecl                              (. VAR pn: SymTab.Name; .)
-  876      = ProcHeading<pn, SymTab.InvalidType> ";"
-  877        ( "FORWARD"                       (. SymTab.MarkFwd;
-  878                                             SymTab.CloseProc;
-  879                                             QbeGen.AbortFunc; .)
-  880        | "EXTERNAL"                      (. SymTab.MarkExternal("");
-  881                                             SymTab.CloseProc;
-  882                                             QbeGen.AbortFunc; .)
-  883        |                                 (. QbeGen.EndFuncHeader; .)
-  884          Block<pn>                       (. SymTab.CloseProc;
-  885                                             QbeGen.EndFunc(
-  886                                               SymTab.ProcRes(pn)); .) ) .
-  887    Block<pn: SymTab.Name>                (. VAR m2: SymTab.Name; .)
-  888      = DeclSeq
-  889        [ "BEGIN"
-  890          [ StatSeq ] ]
-  891        "END"
-  892        GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
-  893                                               SemError(202) END; .) .
-  894    StatSeq
-  895      = Statement { ";" [ Statement ] } .
-  896    (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
-  897       are accepted: the statement after ';' is optional. *)
-  898    Statement                             (. VAR lx: QbeGen.QVal; .)
-  899      = AssOrCall
-  900      | IfStat
-  901      | WhileStat
-  902      | RepeatStat
-  903      | LoopStat
-  904      | ForStat
-  905      | CaseStat
-  906      | WithStat
-  907      | ReturnStat
-  908      | HaltStat
-  909      | NewStat
-  910      | DisposeStat
-  911      | IncDecStat
-  912      | InclExclStat
-  913      | "EXIT"                            (. IF QbeGen.TopLoop(lx) THEN
-  914                                               QbeGen.Jmp(lx)
-  915                                             ELSE SemError(230) END; .) .
-  916    (* INCL(set, elem) / EXCL(set, elem): PIM set-element builtins. *)
-  917    InclExclStat                          (. VAR at, et2: SymTab.TypeIndex;
-  918                                               dk: INTEGER;
-  919                                               qd, qe: QbeGen.QVal;
-  920                                               qn: SymTab.Name;
-  921                                               sfx, isInc: BOOLEAN; .)
-  922      = ( "INCL"                          (. isInc := TRUE; .)
-  923        | "EXCL"                          (. isInc := FALSE; .) )
-  924        "(" Design<at, dk, qd, qn, sfx> ","
-  925        Expr<et2, qe> ")"
-  926                                          (. IF at = SymTab.InvalidType THEN
-  927                                             ELSIF SymTab.ClassOf(at) #
-  928                                                   SymTab.ClSet THEN
-  929                                               SemError(222)
-  930                                             ELSE
-  931                                               IF isInc THEN
-  932                                                 QbeGen.SetBit(qd, qe,
-  933                                                   SymTab.SetBaseLo(at),
-  934                                                   SymTab.SetCount(at))
-  935                                               ELSE
-  936                                                 QbeGen.SetClearBit(qd, qe,
-  937                                                   SymTab.SetBaseLo(at),
-  938                                                   SymTab.SetCount(at))
-  939                                               END
-  940                                             END; .) .
-  941    (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an
-  942       integer designator. *)
-  943    IncDecStat                            (. VAR dt, et2: SymTab.TypeIndex;
-  944                                               dk: INTEGER;
-  945                                               qd, qv, qn2, qstep:
-  946                                                 QbeGen.QVal;
-  947                                               qn: SymTab.Name;
-  948                                               sfx, isInc: BOOLEAN; .)
-  949      =                                   (. isInc := TRUE; .)
-  950        ( "INC"                           (. isInc := TRUE; .)
-  951        | "DEC"                           (. isInc := FALSE; .) )
-  952        "("                               (. QbeGen.CopyOp("1", qstep); .)
-  953        Design<dt, dk, qd, qn, sfx>
-  954        [ "," Expr<et2, qstep> ]
-  955        ")"                               (. IF dt = SymTab.InvalidType THEN
-  956                                             ELSIF (dk # SymTab.KindVar)
-  957   AND (dk # SymTab.KindParam)
-  958   AND (dk # SymTab.KindField) THEN
-  959                                               SemError(210)
-  960                                             ELSIF NOT SymTab.IsIntFamily(dt) THEN
-  961                                               SemError(211)
+  661        |                                 (. IF NOT SymTab.FieldPending(ct,
+  662                                               n) THEN
+  663                                               SemError(200) END; .)
+  664          { "," GetIdent<n>               (. IF NOT SymTab.FieldPending(ct,
+  665                                               n) THEN
+  666                                               SemError(200) END; .) }
+  667          ":" Type<t, FALSE>              (. SymTab.FixPendingF(ct, t); .) ) .
+  668    MethodHeading<VAR pn: SymTab.Name; ct: SymTab.TypeIndex>
+  669                                          (. VAR wantVirt: BOOLEAN; .)
+  670      =                                   (. wantVirt := FALSE; .)
+  671        [ "VIRTUAL"                       (. wantVirt := TRUE; .) ]
+  672        ProcHeading<pn, ct>               (. IF wantVirt THEN
+  673                                               SymTab.MarkVirtual END; .) .
+  674    ClassImplRest                         (. VAR cn, m2: SymTab.Name;
+  675                                               ct: SymTab.TypeIndex; .)
+  676      = GetIdent<cn>                      (. IF NOT SymTab.Lookup(cn) THEN
+  677                                               SemError(201);
+  678                                               ct := SymTab.InvalidType
+  679                                             ELSE ct := SymTab.SymType(cn);
+  680                                               IF SymTab.ClassOf(ct) #
+  681                                                  SymTab.ClClass THEN
+  682                                                 SemError(230);
+  683                                                 ct := SymTab.InvalidType
+  684                                               END
+  685                                             END;
+  686                                             IF ct #
+  687                                                SymTab.InvalidType THEN
+  688                                               IF NOT SymTab.PushClassMembers(
+  689                                                      ct) THEN
+  690                                                 SemError(230) END;
+  691                                               SymTab.PushImplClass(ct)
+  692                                             END; .)
+  693        ";" { MethodImpl<ct> ";" }
+  694        [ "BEGIN"                         (. QbeGen.BeginInit(cn); .)
+  695          [ StatSeq ]                     (. QbeGen.EndInit; .) ]
+  696        "END"
+  697        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
+  698                                               SemError(202) END;
+  699                                             SymTab.PopImplClass;
+  700                                             SymTab.PopScope; .) .
+  701    MethodImpl<ct: SymTab.TypeIndex>      (. VAR pn: SymTab.Name;
+  702                                               thisQ: QbeGen.QVal;
+  703                                               methRes: SymTab.TypeIndex; .)
+  704      = MethodHeading<pn, ct> ";"
+  705                                          (. IF (ct #
+  706                                                SymTab.InvalidType)
+  707   AND NOT SymTab.MethodExists(ct,
+  708                                                    pn) THEN
+  709                                               SemError(201) END; .)
+  710        ( "FORWARD"                       (. SymTab.MarkFwd;
+  711                                             QbeGen.AbortFunc;
+  712                                             SymTab.CloseProc; .)
+  713        |                                 (. QbeGen.EndFuncHeader;
+  714                                             (* bind the receiver: bare
+  715                                                field names resolve
+  716                                                against THIS *)
+  717                                             QbeGen.ThisBase(thisQ);
+  718                                             QbeGen.PushWith(thisQ); .)
+  719          Block<pn>                       (. QbeGen.PopWith;
+  720                                             methRes := SymTab.CurRes();
+  721                                             SymTab.CloseProc;
+  722                                             QbeGen.EndFunc(methRes); .) ) .
+  723    ConstBlock
+  724      = "CONST" { ConstDecl ";" } .
+  725    ConstDecl                             (. VAR n: SymTab.Name;
+  726                                               t: SymTab.TypeIndex;
+  727                                               qv: QbeGen.QVal;
+  728                                               cls: INTEGER; .)
+  729      = GetIdent<n>                       (. IF NOT SymTab.Enter(n,
+  730                                               SymTab.KindConst) THEN
+  731                                               SemError(200) END; .)
+  732        "="
+  733        Expr<t, qv>                       (. SymTab.SetSymType(n, t);
+  734                                             cls := SymTab.ClassOf(t);
+  735                                             IF (cls = SymTab.ClArray)
+  736                                                OR (cls = SymTab.ClRecord)
+  737                                                OR (cls = SymTab.ClClass)
+  738                                                OR (cls = SymTab.ClStr)
+  739                                                OR (cls = SymTab.ClUStr) THEN
+  740                                               (* an aggregate/string
+  741                                                  constant: qv is its
+  742                                                  descriptor address; no
+  743                                                  scalar data *)
+  744                                               SymTab.SetSymVal(n, qv)
+  745                                             ELSIF NOT QbeGen.IsImm(qv) THEN
+  746                                               SemError(230)
+  747                                             ELSE
+  748                                               SymTab.SetSymVal(n, qv);
+  749                                               QbeGen.DeclConst(n, qv, t)
+  750                                             END; .) .
+  751    VarBlock
+  752      = "VAR" { VarDecl ";" } .
+  753    VarDecl                               (. VAR nm: SymTab.Name;
+  754                                               t: SymTab.TypeIndex;
+  755                                               i: CARDINAL;
+  756                                               cls: INTEGER; .)
+  757      = VarIdents ":"
+  758        Type<t, FALSE>                    (. cls := SymTab.ClassOf(t);
+  759                                             IF (t # SymTab.InvalidType)
+  760   AND NOT SymTab.IsUnresolved(t)
+  761   AND (cls # SymTab.ClInt)
+  762   AND (cls # SymTab.ClBool)
+  763   AND (cls # SymTab.ClChar)
+  764   AND (cls # SymTab.ClReal)
+  765   AND (cls # SymTab.ClArray)
+  766   AND (cls # SymTab.ClSet)
+  767   AND (cls # SymTab.ClRecord)
+  768   AND (cls # SymTab.ClPtr)
+  769   AND (cls # SymTab.ClLong)
+  770   AND (cls # SymTab.ClProc)
+  771   AND (cls # SymTab.ClUChar)
+  772   AND (cls # SymTab.ClUStr)
+  773   AND (cls # SymTab.ClEnum)
+  774   AND (cls # SymTab.ClClass) THEN
+  775                                               SemError(230) END;
+  776                                             IF QbeGen.LocFull() THEN
+  777                                               SemError(233) END;
+  778                                             i := 0;
+  779                                             IF SymTab.IsUnresolved(t)
+  780                                                AND NOT SymTab.InProc() THEN
+  781                                               (* a forward-typed global:
+  782                                                  defer emission until the
+  783                                                  TYPE block completes *)
+  784                                               WHILE i < SymTab.PendCount() DO
+  785                                                 SymTab.PendName(i, nm);
+  786                                                 IF nPendVar <=
+  787                                                    HIGH(pendVarName) THEN
+  788                                                   pendVarName[nPendVar] := nm;
+  789                                                   pendVarT[nPendVar] := t;
+  790                                                   INC(nPendVar)
+  791                                                 END;
+  792                                                 INC(i)
+  793                                               END
+  794                                             ELSE
+  795                                               WHILE i < SymTab.PendCount() DO
+  796                                                 SymTab.PendName(i, nm);
+  797                                                 QbeGen.DeclVar(nm, t);
+  798                                                 INC(i)
+  799                                               END
+  800                                             END;
+  801                                             (* a plain VAR list, not a
+  802                                                heading: the signature
+  803                                                result is discarded *)
+  804                                             IF NOT SymTab.FixPending(t) THEN
+  805                                             END; .) .
+  806    VarIdents                             (. VAR n: SymTab.Name; .)
+  807      = GetIdent<n>                       (. IF NOT SymTab.EnterPending(n,
+  808                                               SymTab.KindVar) THEN
+  809                                               SemError(200) END; .)
+  810        { ","
+  811          GetIdent<n>                     (. IF NOT SymTab.EnterPending(n,
+  812                                               SymTab.KindVar) THEN
+  813                                               SemError(200) END; .) } .
+  814    ParIdents<isV: BOOLEAN>               (. VAR n: SymTab.Name; .)
+  815      = GetIdent<n>                       (. IF NOT SymTab.EnterParam(n, isV) THEN
+  816                                               SemError(200) END; .)
+  817        { "," GetIdent<n>                 (. IF NOT SymTab.EnterParam(n, isV) THEN
+  818                                               SemError(200) END; .) } .
+  819    (* Procedure headings enter scopes/params/result and buffer the
+  820       QBE header; bodies lower to functions (4.1, module level only).
+  821       FORWARD marks; the body heading re-enters (signature compare
+  822       deferred). Nested procedures parse + check, lowering = 4.2. *)
+  823    ProcHeading<VAR pn: SymTab.Name; methCls: SymTab.TypeIndex>
+  824                                          (. VAR t: SymTab.TypeIndex;
+  825                                               mg: QbeGen.QVal; .)
+  826      = "PROCEDURE"
+  827        GetIdent<pn>                      (. IF methCls #
+  828                                                SymTab.InvalidType THEN
+  829                                             (* a method: resume the
+  830                                                declared symbol (reuse
+  831                                                its uid) *)
+  832                                             IF NOT SymTab.ResumeMethod(
+  833                                                  methCls, pn) THEN
+  834                                               SemError(200) END
+  835                                             ELSIF NOT SymTab.EnterProc(pn) THEN
+  836                                             IF NOT SymTab.ReenterProc(pn) THEN
+  837                                               IF NOT SymTab.ResumeProc(pn) THEN
+  838                                                 SemError(200) END
+  839                                               END
+  840                                             END;
+  841                                             IF methCls #
+  842                                                SymTab.InvalidType THEN
+  843                                               QbeGen.Mangled(pn,
+  844                                                 SymTab.MethUid(), mg)
+  845                                             ELSE
+  846                                               QbeGen.Mangled(pn,
+  847                                                 SymTab.ProcUid(pn), mg)
+  848                                             END;
+  849                                             QbeGen.BeginFunc(mg);
+  850                                             IF methCls #
+  851                                                SymTab.InvalidType THEN
+  852                                               (* hidden THIS receiver:
+  853                                                  a VAR param of the
+  854                                                  class type, pushed as
+  855                                                  the WITH base *)
+  856                                               IF NOT SymTab.EnterThisParam(
+  857                                                    methCls) THEN
+  858                                                 SemError(200) END;
+  859                                               IF NOT QbeGen.FuncParam(
+  860                                                    "THIS", TRUE,
+  861                                                    methCls) THEN
+  862                                                 SemError(233) END
+  863                                             END; .)
+  864        [ FormalParams ]
+  865        [ ":" TypeIdent<t>                (. IF NOT SymTab.SetProcRes(t) THEN
+  866                                               SemError(235) END;
+  867                                             QbeGen.SetFuncRes(t);
+  868                                             IF (t #
+  869                                                SymTab.InvalidType)
+  870   AND ((SymTab.ClassOf(t)
+  871                                                   = SymTab.ClArray)
+  872                                                OR (SymTab.ClassOf(t)
+  873                                                   = SymTab.ClRecord)
+  874                                                OR (SymTab.ClassOf(t)
+  875                                                   = SymTab.ClSet)
+  876                                                OR (SymTab.ClassOf(t)
+  877                                                   = SymTab.ClClass)) THEN
+  878                                               SemError(230) END; .) ] .
+  879    FormalParams
+  880      = "(" [ ParamSection { ";" ParamSection } ] ")" .
+  881    ParamSection                          (. VAR t: SymTab.TypeIndex;
+  882                                               nm: SymTab.Name;
+  883                                               i: CARDINAL;
+  884                                               isV: BOOLEAN; .)
+  885      =                                   (. isV := FALSE; .)
+  886        [ "VAR"                           (. isV := TRUE; .) ]
+  887        ParIdents<isV> ":" Type<t, TRUE>  (. i := 0;
+  888                                             WHILE i < SymTab.PendCount() DO
+  889                                               SymTab.PendName(i, nm);
+  890                                               (* value open arrays are
+  891                                                  passed as descriptor
+  892                                                  addresses (no copy):
+  893                                                  same representation as
+  894                                                  VAR formals *)
+  895                                               IF NOT QbeGen.FuncParam(nm,
+  896                                                    isV
+  897                                                    OR SymTab.IsOpenArray(t),
+  898                                                    t) THEN
+  899                                                 SemError(233) END;
+  900                                               INC(i)
+  901                                             END;
+  902                                             IF NOT SymTab.FixPending(t) THEN
+  903                                               SemError(235) END; .) .
+  904    (* Nested procedures lower like top-level ones (4.2): the
+  905       static link gives them their parent's frame. Methods keep
+  906       parse-now/230-later. *)
+  907    ProcDecl                              (. VAR pn: SymTab.Name; .)
+  908      = ProcHeading<pn, SymTab.InvalidType> ";"
+  909        ( "FORWARD"                       (. SymTab.MarkFwd;
+  910                                             SymTab.CloseProc;
+  911                                             QbeGen.AbortFunc; .)
+  912        | "EXTERNAL"                      (. SymTab.MarkExternal("");
+  913                                             SymTab.CloseProc;
+  914                                             QbeGen.AbortFunc; .)
+  915        |                                 (. QbeGen.EndFuncHeader; .)
+  916          Block<pn>                       (. SymTab.CloseProc;
+  917                                             QbeGen.EndFunc(
+  918                                               SymTab.ProcRes(pn)); .) ) .
+  919    Block<pn: SymTab.Name>                (. VAR m2: SymTab.Name; .)
+  920      = DeclSeq
+  921        [ "BEGIN"
+  922          [ StatSeq ] ]
+  923        "END"
+  924        GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
+  925                                               SemError(202) END; .) .
+  926    StatSeq
+  927      = Statement { ";" [ Statement ] } .
+  928    (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
+  929       are accepted: the statement after ';' is optional. *)
+  930    Statement                             (. VAR lx: QbeGen.QVal; .)
+  931      = AssOrCall
+  932      | IfStat
+  933      | WhileStat
+  934      | RepeatStat
+  935      | LoopStat
+  936      | ForStat
+  937      | CaseStat
+  938      | WithStat
+  939      | ReturnStat
+  940      | HaltStat
+  941      | NewStat
+  942      | DisposeStat
+  943      | IncDecStat
+  944      | InclExclStat
+  945      | "EXIT"                            (. IF QbeGen.TopLoop(lx) THEN
+  946                                               QbeGen.Jmp(lx)
+  947                                             ELSE SemError(230) END; .) .
+  948    (* INCL(set, elem) / EXCL(set, elem): PIM set-element builtins. *)
+  949    InclExclStat                          (. VAR at, et2: SymTab.TypeIndex;
+  950                                               dk: INTEGER;
+  951                                               qd, qe: QbeGen.QVal;
+  952                                               qn: SymTab.Name;
+  953                                               sfx, isInc: BOOLEAN; .)
+  954      = ( "INCL"                          (. isInc := TRUE; .)
+  955        | "EXCL"                          (. isInc := FALSE; .) )
+  956        "(" Design<at, dk, qd, qn, sfx> ","
+  957        Expr<et2, qe> ")"
+  958                                          (. IF at = SymTab.InvalidType THEN
+  959                                             ELSIF SymTab.ClassOf(at) #
+  960                                                   SymTab.ClSet THEN
+  961                                               SemError(222)
   962                                             ELSE
   962                                             ELSE
-  963                                               IF sfx
-  964                                                  OR (dk = SymTab.KindField) THEN
-  965                                                 QbeGen.ElemLoad(qd, dt, qv)
-  966                                               ELSE QbeGen.LoadVar(qn,
-  967                                                 FALSE, qv)
-  968                                               END;
-  969                                               QbeGen.NewTemp(qn2);
-  970                                               IF isInc THEN
-  971                                                 QbeGen.Op3("add", qn2, qv,
-  972                                                   qstep, FALSE)
-  973                                               ELSE QbeGen.Op3("sub", qn2, qv,
-  974                                                   qstep, FALSE)
-  975                                               END;
-  976                                               IF sfx
-  977                                                  OR (dk = SymTab.KindField) THEN
-  978                                                 QbeGen.ElemStore(qd, qn2,
-  979                                                   dt)
-  980                                               ELSE QbeGen.StoreVar(qn,
-  981                                                 qn2, FALSE)
-  982                                               END
-  983                                             END; .) .
-  984    (* NEW/DISPOSE as builtin statements (no call syntax until step 4).
-  985       Targets are pointer designators; DISPOSE nils afterwards (safer
-  986       than Wirth-undefined; documented). DISPOSE is shallow. *)
-  987    NewStat                               (. VAR dt: SymTab.TypeIndex;
-  988                                               dk: INTEGER;
-  989                                               qd, qm: QbeGen.QVal;
-  990                                               qn: SymTab.Name;
-  991                                               sfx: BOOLEAN;
-  992                                               bt: SymTab.TypeIndex; .)
-  993      = "NEW" "(" Design<dt, dk, qd, qn, sfx> ")"
-  994                                          (. IF dt = SymTab.InvalidType THEN
-  995                                             ELSIF (dk # SymTab.KindVar)
-  996   AND (dk # SymTab.KindParam)
-  997   AND (dk # SymTab.KindField) THEN
-  998                                               SemError(210)
-  999                                             ELSIF SymTab.ClassOf(dt) #
- 1000                                                   SymTab.ClPtr THEN
- 1001                                               SemError(219)
- 1002                                             ELSE bt := SymTab.PtrBase(dt);
- 1003                                               IF bt #
- 1004                                                  SymTab.InvalidType THEN
- 1005                                                 QbeGen.NewHeap(bt, qm);
- 1006                                                 QbeGen.InitHeap(qm, bt);
- 1007                                                 IF sfx
- 1008                                                    OR (dk =
- 1009                                                       SymTab.KindField) THEN
- 1010                                                   QbeGen.ElemStore(qd, qm,
- 1011                                                     dt)
- 1012                                                 ELSE QbeGen.StorePtr(qn,
- 1013                                                   qm)
- 1014                                                 END
- 1015                                               END
- 1016                                             END; .) .
- 1017    DisposeStat                           (. VAR dt: SymTab.TypeIndex;
- 1018                                               dk: INTEGER;
- 1019                                               qd, qv: QbeGen.QVal;
- 1020                                               qn: SymTab.Name;
- 1021                                               sfx: BOOLEAN; .)
- 1022      = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> ")"
- 1023                                          (. IF dt = SymTab.InvalidType THEN
- 1024                                             ELSIF (dk # SymTab.KindVar)
- 1025   AND (dk # SymTab.KindParam)
- 1026   AND (dk # SymTab.KindField) THEN
- 1027                                               SemError(210)
- 1028                                             ELSIF SymTab.ClassOf(dt) #
- 1029                                                   SymTab.ClPtr THEN
- 1030                                               SemError(219)
- 1031                                             ELSE
- 1032                                               IF sfx
- 1033                                                  OR (dk =
- 1034                                                     SymTab.KindField) THEN
- 1035                                                 QbeGen.ElemLoad(qd, dt,
- 1036                                                   qv)
- 1037                                               ELSE QbeGen.LoadPtr(qn, qv)
- 1038                                               END;
- 1039                                               QbeGen.FreeHeap(qv);
- 1040                                               IF sfx
- 1041                                                  OR (dk =
- 1042                                                     SymTab.KindField) THEN
- 1043                                                 QbeGen.ElemStore(qd, "0",
- 1044                                                   dt)
- 1045                                               ELSE QbeGen.StorePtr(qn,
- 1046                                                 "0")
+  963                                               IF isInc THEN
+  964                                                 QbeGen.SetBit(qd, qe,
+  965                                                   SymTab.SetBaseLo(at),
+  966                                                   SymTab.SetCount(at))
+  967                                               ELSE
+  968                                                 QbeGen.SetClearBit(qd, qe,
+  969                                                   SymTab.SetBaseLo(at),
+  970                                                   SymTab.SetCount(at))
+  971                                               END
+  972                                             END; .) .
+  973    (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an
+  974       integer designator. *)
+  975    IncDecStat                            (. VAR dt, et2: SymTab.TypeIndex;
+  976                                               dk: INTEGER;
+  977                                               qd, qv, qn2, qstep:
+  978                                                 QbeGen.QVal;
+  979                                               qn: SymTab.Name;
+  980                                               sfx, isInc: BOOLEAN; .)
+  981      =                                   (. isInc := TRUE; .)
+  982        ( "INC"                           (. isInc := TRUE; .)
+  983        | "DEC"                           (. isInc := FALSE; .) )
+  984        "("                               (. QbeGen.CopyOp("1", qstep); .)
+  985        Design<dt, dk, qd, qn, sfx>
+  986        [ "," Expr<et2, qstep> ]
+  987        ")"                               (. IF dt = SymTab.InvalidType THEN
+  988                                             ELSIF (dk # SymTab.KindVar)
+  989   AND (dk # SymTab.KindParam)
+  990   AND (dk # SymTab.KindField) THEN
+  991                                               SemError(210)
+  992                                             ELSIF NOT SymTab.IsIntFamily(dt) THEN
+  993                                               SemError(211)
+  994                                             ELSE
+  995                                               IF sfx
+  996                                                  OR (dk = SymTab.KindField) THEN
+  997                                                 QbeGen.ElemLoad(qd, dt, qv)
+  998                                               ELSE QbeGen.LoadVar(qn,
+  999                                                 FALSE, qv)
+ 1000                                               END;
+ 1001                                               QbeGen.NewTemp(qn2);
+ 1002                                               IF isInc THEN
+ 1003                                                 QbeGen.Op3("add", qn2, qv,
+ 1004                                                   qstep, FALSE)
+ 1005                                               ELSE QbeGen.Op3("sub", qn2, qv,
+ 1006                                                   qstep, FALSE)
+ 1007                                               END;
+ 1008                                               IF sfx
+ 1009                                                  OR (dk = SymTab.KindField) THEN
+ 1010                                                 QbeGen.ElemStore(qd, qn2,
+ 1011                                                   dt)
+ 1012                                               ELSE QbeGen.StoreVar(qn,
+ 1013                                                 qn2, FALSE)
+ 1014                                               END
+ 1015                                             END; .) .
+ 1016    (* NEW/DISPOSE as builtin statements (no call syntax until step 4).
+ 1017       Targets are pointer designators; DISPOSE nils afterwards (safer
+ 1018       than Wirth-undefined; documented). DISPOSE is shallow. *)
+ 1019    NewStat                               (. VAR dt: SymTab.TypeIndex;
+ 1020                                               dk: INTEGER;
+ 1021                                               qd, qm: QbeGen.QVal;
+ 1022                                               qn: SymTab.Name;
+ 1023                                               sfx: BOOLEAN;
+ 1024                                               bt: SymTab.TypeIndex; .)
+ 1025      = "NEW" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 1026                                          (. IF dt = SymTab.InvalidType THEN
+ 1027                                             ELSIF (dk # SymTab.KindVar)
+ 1028   AND (dk # SymTab.KindParam)
+ 1029   AND (dk # SymTab.KindField) THEN
+ 1030                                               SemError(210)
+ 1031                                             ELSIF SymTab.ClassOf(dt) #
+ 1032                                                   SymTab.ClPtr THEN
+ 1033                                               SemError(219)
+ 1034                                             ELSE bt := SymTab.PtrBase(dt);
+ 1035                                               IF bt #
+ 1036                                                  SymTab.InvalidType THEN
+ 1037                                                 QbeGen.NewHeap(bt, qm);
+ 1038                                                 QbeGen.InitHeap(qm, bt);
+ 1039                                                 IF sfx
+ 1040                                                    OR (dk =
+ 1041                                                       SymTab.KindField) THEN
+ 1042                                                   QbeGen.ElemStore(qd, qm,
+ 1043                                                     dt)
+ 1044                                                 ELSE QbeGen.StorePtr(qn,
+ 1045                                                   qm)
+ 1046                                                 END
  1047                                               END
  1047                                               END
  1048                                             END; .) .
  1048                                             END; .) .
- 1049    (* WITH pushes each record's fields (inner wins) plus its base
- 1050       address; field designators resolve through both stacks. *)
- 1051    WithStat                              (. VAR nW: CARDINAL; .)
- 1052      = "WITH"                            (. nW := 0; .)
- 1053        WithItem<nW> { "," WithItem<nW> }
- 1054        "DO" [ StatSeq ] "END"
- 1055                                          (. WHILE nW > 0 DO
- 1056                                               SymTab.PopScope;
- 1057                                               QbeGen.PopWith;
- 1058                                               DEC(nW)
- 1059                                             END; .) .
- 1060    WithItem<VAR nW: CARDINAL>            (. VAR dt: SymTab.TypeIndex;
- 1061                                               dk: INTEGER;
- 1062                                               qd, qe: QbeGen.QVal;
- 1063                                               qn: SymTab.Name;
- 1064                                               sfx: BOOLEAN; .)
- 1065      = Design<dt, dk, qd, qn, sfx>
- 1066                                          (. IF dt = SymTab.InvalidType THEN
- 1067                                             ELSIF (SymTab.ClassOf(dt) #
- 1068                                                    SymTab.ClRecord)
- 1069   AND (SymTab.ClassOf(dt) #
- 1070                                                   SymTab.ClClass) THEN
- 1071                                               SemError(215)
- 1072                                             ELSIF SymTab.PushRecord(dt) THEN
- 1073                                               QbeGen.PushWith(qd);
- 1074                                               INC(nW)
- 1075                                             END; .) .
- 1076    (* Assignment or procedure-statement call (4.1, module level).
- 1077       Bare `P;` is a syntax error; function-as-statement is 233. *)
- 1078    AssOrCall                             (. VAR dt, et: SymTab.TypeIndex;
- 1079                                               dk: INTEGER;
- 1080                                               qd, qe, qt, ql: QbeGen.QVal;
- 1081                                               qn: SymTab.Name;
- 1082                                               ct2, res0: SymTab.TypeIndex;
- 1083                                               q2, mg0: QbeGen.QVal;
- 1084                                               isR, conv, wconv: BOOLEAN;
- 1085                                               called, sfx: BOOLEAN; .)
- 1086      = Design<dt, dk, qd, qn, sfx>
- 1087        ( ":="
- 1088          Expr<et, qe>                    (. IF (dt # SymTab.InvalidType)
- 1089   AND (dk # SymTab.KindVar)
- 1090   AND (dk # SymTab.KindParam)
- 1091   AND (dk # SymTab.KindField) THEN
- 1092                                             SemError(210)
- 1093                                           ELSIF NOT SymTab.Assignable(et,
- 1094                                                    dt) THEN
- 1095                                             SemError(210)
- 1096                                           ELSIF (dt # SymTab.InvalidType)
- 1097   AND (SymTab.ClassOf(dt) =
- 1098                                                 SymTab.ClClass) THEN
- 1099                                             SemError(230) END;
- 1100                                           isR := (dt #
- 1101                                                   SymTab.InvalidType)
- 1102   AND (SymTab.ClassOf(dt)
- 1103                                                     = SymTab.ClReal);
- 1104                                           conv := isR
- 1105   AND SymTab.IsIntFamily(et);
- 1106                                           wconv := (dt #
- 1107                                                     SymTab.InvalidType)
- 1108   AND SymTab.IsLongFamily(dt)
- 1109   AND SymTab.IsIntFamily(et);
- 1110                                           IF ((dk = SymTab.KindVar)
- 1111                                               OR (dk = SymTab.KindParam)
- 1112                                               OR (dk = SymTab.KindField))
- 1113   AND (dt # SymTab.InvalidType)
- 1114   AND (et # SymTab.InvalidType)
- 1115   AND (SymTab.ClassOf(dt) #
- 1116                                                 SymTab.ClClass) THEN
- 1117                                             IF sfx
- 1118                                                OR (dk = SymTab.KindField) THEN
- 1119                                               IF SymTab.ClassOf(dt) =
- 1120                                                  SymTab.ClArray THEN
- 1121                                                 IF (et # SymTab.InvalidType)
- 1122    AND (SymTab.ClassOf(et) = SymTab.ClUStr)
- 1123    AND SymTab.IsUCharArray(dt) THEN
- 1124                                                   QbeGen.UAssign(qd, qe)
- 1125                                                 ELSIF SymTab.StrCompat(dt,
- 1126                                                      et) THEN
- 1127                                                   QbeGen.StrAssign(qd,
- 1128                                                     qe)
- 1129                                                 ELSE
- 1130                                                   QbeGen.CopyArray(qd,
- 1131                                                     qe, dt)
- 1132                                                 END
- 1133                                               ELSIF SymTab.ClassOf(dt) =
- 1134                                                   SymTab.ClSet THEN
- 1135                                                 QbeGen.CopySet(qd, qe,
- 1136                                                   SymTab.SetWords(dt),
- 1137                                                   SymTab.SetWords(et))
- 1138                                               ELSIF SymTab.ClassOf(dt) =
- 1139                                                   SymTab.ClRecord THEN
- 1140                                                 QbeGen.CopyRecord(qd, qe,
- 1141                                                   dt)
- 1142                                               ELSIF SymTab.IsLongFamily(dt) THEN
- 1143                                                 IF wconv THEN
- 1144                                                   QbeGen.WidenLong(qe, ql);
- 1145                                                   QbeGen.ElemStore(qd, ql,
- 1146                                                     dt)
- 1147                                                 ELSE QbeGen.ElemStore(qd, qe,
- 1148                                                   dt)
- 1149                                                 END
- 1150                                               ELSIF conv THEN
- 1151                                                 QbeGen.ConvIR(qe, qt);
- 1152                                                 QbeGen.ElemStore(qd, qt,
- 1153                                                   dt)
- 1154                                               ELSE QbeGen.ElemStore(qd, qe,
- 1155                                                 dt)
- 1156                                               END
- 1157                                             ELSIF SymTab.ClassOf(dt) =
- 1158                                                   SymTab.ClArray THEN
- 1159                                               IF (et # SymTab.InvalidType)
- 1160    AND (SymTab.ClassOf(et) = SymTab.ClUStr)
- 1161    AND SymTab.IsUCharArray(dt) THEN
- 1162                                                 QbeGen.UAssign(qd, qe)
- 1163                                               ELSIF SymTab.StrCompat(dt,
- 1164                                                    et) THEN
- 1165                                                 QbeGen.StrAssign(qd, qe)
- 1166                                               ELSE
- 1167                                                 QbeGen.CopyArray(qd, qe,
- 1168                                                   dt)
- 1169                                               END
- 1170                                             ELSIF SymTab.ClassOf(dt) =
- 1171                                                   SymTab.ClSet THEN
- 1172                                               QbeGen.CopySet(qd, qe,
- 1173                                                 SymTab.SetWords(dt),
- 1174                                                 SymTab.SetWords(et))
- 1175                                             ELSIF SymTab.ClassOf(dt) =
- 1176                                                   SymTab.ClRecord THEN
- 1177                                               QbeGen.CopyRecord(qd, qe, dt)
- 1178                                             ELSIF (SymTab.ClassOf(dt) =
- 1179                                                   SymTab.ClPtr)
- 1180                                                OR (SymTab.ClassOf(dt) =
- 1181                                                   SymTab.ClProc) THEN
- 1182                                               QbeGen.StorePtr(qn, qe)
- 1183                                             ELSIF SymTab.IsLongFamily(dt) THEN
- 1184                                               IF wconv THEN
- 1185                                                 QbeGen.WidenLong(qe, ql);
- 1186                                                 QbeGen.StoreLong(qn, ql)
- 1187                                               ELSE QbeGen.StoreLong(qn, qe)
+ 1049    DisposeStat                           (. VAR dt: SymTab.TypeIndex;
+ 1050                                               dk: INTEGER;
+ 1051                                               qd, qv: QbeGen.QVal;
+ 1052                                               qn: SymTab.Name;
+ 1053                                               sfx: BOOLEAN; .)
+ 1054      = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 1055                                          (. IF dt = SymTab.InvalidType THEN
+ 1056                                             ELSIF (dk # SymTab.KindVar)
+ 1057   AND (dk # SymTab.KindParam)
+ 1058   AND (dk # SymTab.KindField) THEN
+ 1059                                               SemError(210)
+ 1060                                             ELSIF SymTab.ClassOf(dt) #
+ 1061                                                   SymTab.ClPtr THEN
+ 1062                                               SemError(219)
+ 1063                                             ELSE
+ 1064                                               IF sfx
+ 1065                                                  OR (dk =
+ 1066                                                     SymTab.KindField) THEN
+ 1067                                                 QbeGen.ElemLoad(qd, dt,
+ 1068                                                   qv)
+ 1069                                               ELSE QbeGen.LoadPtr(qn, qv)
+ 1070                                               END;
+ 1071                                               QbeGen.FreeHeap(qv);
+ 1072                                               IF sfx
+ 1073                                                  OR (dk =
+ 1074                                                     SymTab.KindField) THEN
+ 1075                                                 QbeGen.ElemStore(qd, "0",
+ 1076                                                   dt)
+ 1077                                               ELSE QbeGen.StorePtr(qn,
+ 1078                                                 "0")
+ 1079                                               END
+ 1080                                             END; .) .
+ 1081    (* WITH pushes each record's fields (inner wins) plus its base
+ 1082       address; field designators resolve through both stacks. *)
+ 1083    WithStat                              (. VAR nW: CARDINAL; .)
+ 1084      = "WITH"                            (. nW := 0; .)
+ 1085        WithItem<nW> { "," WithItem<nW> }
+ 1086        "DO" [ StatSeq ] "END"
+ 1087                                          (. WHILE nW > 0 DO
+ 1088                                               SymTab.PopScope;
+ 1089                                               QbeGen.PopWith;
+ 1090                                               DEC(nW)
+ 1091                                             END; .) .
+ 1092    WithItem<VAR nW: CARDINAL>            (. VAR dt: SymTab.TypeIndex;
+ 1093                                               dk: INTEGER;
+ 1094                                               qd, qe: QbeGen.QVal;
+ 1095                                               qn: SymTab.Name;
+ 1096                                               sfx: BOOLEAN; .)
+ 1097      = Design<dt, dk, qd, qn, sfx>
+ 1098                                          (. IF dt = SymTab.InvalidType THEN
+ 1099                                             ELSIF (SymTab.ClassOf(dt) #
+ 1100                                                    SymTab.ClRecord)
+ 1101   AND (SymTab.ClassOf(dt) #
+ 1102                                                   SymTab.ClClass) THEN
+ 1103                                               SemError(215)
+ 1104                                             ELSIF SymTab.PushRecord(dt) THEN
+ 1105                                               QbeGen.PushWith(qd);
+ 1106                                               INC(nW)
+ 1107                                             END; .) .
+ 1108    (* Assignment or procedure-statement call (4.1, module level).
+ 1109       Bare `P;` is a syntax error; function-as-statement is 233. *)
+ 1110    AssOrCall                             (. VAR dt, et: SymTab.TypeIndex;
+ 1111                                               dk: INTEGER;
+ 1112                                               qd, qe, qt, ql: QbeGen.QVal;
+ 1113                                               qn: SymTab.Name;
+ 1114                                               ct2, res0: SymTab.TypeIndex;
+ 1115                                               q2, mg0: QbeGen.QVal;
+ 1116                                               isR, conv, wconv: BOOLEAN;
+ 1117                                               called, sfx: BOOLEAN; .)
+ 1118      = Design<dt, dk, qd, qn, sfx>
+ 1119        ( ":="
+ 1120          Expr<et, qe>                    (. IF (dt # SymTab.InvalidType)
+ 1121   AND (dk # SymTab.KindVar)
+ 1122   AND (dk # SymTab.KindParam)
+ 1123   AND (dk # SymTab.KindField) THEN
+ 1124                                             SemError(210)
+ 1125                                           ELSIF NOT SymTab.Assignable(et,
+ 1126                                                    dt) THEN
+ 1127                                             SemError(210)
+ 1128                                           ELSIF (dt # SymTab.InvalidType)
+ 1129   AND (SymTab.ClassOf(dt) =
+ 1130                                                 SymTab.ClClass) THEN
+ 1131                                             SemError(230) END;
+ 1132                                           isR := (dt #
+ 1133                                                   SymTab.InvalidType)
+ 1134   AND (SymTab.ClassOf(dt)
+ 1135                                                     = SymTab.ClReal);
+ 1136                                           conv := isR
+ 1137   AND SymTab.IsIntFamily(et);
+ 1138                                           wconv := (dt #
+ 1139                                                     SymTab.InvalidType)
+ 1140   AND SymTab.IsLongFamily(dt)
+ 1141   AND SymTab.IsIntFamily(et);
+ 1142                                           IF ((dk = SymTab.KindVar)
+ 1143                                               OR (dk = SymTab.KindParam)
+ 1144                                               OR (dk = SymTab.KindField))
+ 1145   AND (dt # SymTab.InvalidType)
+ 1146   AND (et # SymTab.InvalidType)
+ 1147   AND (SymTab.ClassOf(dt) #
+ 1148                                                 SymTab.ClClass) THEN
+ 1149                                             IF sfx
+ 1150                                                OR (dk = SymTab.KindField) THEN
+ 1151                                               IF SymTab.ClassOf(dt) =
+ 1152                                                  SymTab.ClArray THEN
+ 1153                                                 IF (et # SymTab.InvalidType)
+ 1154    AND (SymTab.ClassOf(et) = SymTab.ClUStr)
+ 1155    AND SymTab.IsUCharArray(dt) THEN
+ 1156                                                   QbeGen.UAssign(qd, qe)
+ 1157                                                 ELSIF SymTab.StrCompat(dt,
+ 1158                                                      et) THEN
+ 1159                                                   QbeGen.StrAssign(qd,
+ 1160                                                     qe)
+ 1161                                                 ELSE
+ 1162                                                   QbeGen.CopyArray(qd,
+ 1163                                                     qe, dt)
+ 1164                                                 END
+ 1165                                               ELSIF SymTab.ClassOf(dt) =
+ 1166                                                   SymTab.ClSet THEN
+ 1167                                                 QbeGen.CopySet(qd, qe,
+ 1168                                                   SymTab.SetWords(dt),
+ 1169                                                   SymTab.SetWords(et))
+ 1170                                               ELSIF SymTab.ClassOf(dt) =
+ 1171                                                   SymTab.ClRecord THEN
+ 1172                                                 QbeGen.CopyRecord(qd, qe,
+ 1173                                                   dt)
+ 1174                                               ELSIF SymTab.IsLongFamily(dt) THEN
+ 1175                                                 IF wconv THEN
+ 1176                                                   QbeGen.WidenLong(qe, ql);
+ 1177                                                   QbeGen.ElemStore(qd, ql,
+ 1178                                                     dt)
+ 1179                                                 ELSE QbeGen.ElemStore(qd, qe,
+ 1180                                                   dt)
+ 1181                                                 END
+ 1182                                               ELSIF conv THEN
+ 1183                                                 QbeGen.ConvIR(qe, qt);
+ 1184                                                 QbeGen.ElemStore(qd, qt,
+ 1185                                                   dt)
+ 1186                                               ELSE QbeGen.ElemStore(qd, qe,
+ 1187                                                 dt)
  1188                                               END
  1188                                               END
- 1189                                             ELSIF conv THEN
- 1190                                               QbeGen.ConvIR(qe, qt);
- 1191                                               QbeGen.StoreVar(qn, qt, TRUE)
- 1192                                             ELSE
- 1193                                               QbeGen.StoreVar(qn, qe, isR)
- 1194                                             END
- 1195                                           END; .)
- 1196        | ArgList<qn, dt, qd, FALSE, methCls, ct2, q2, called>
- 1197        |                                 (* bare `P;`: proper parameterless
- 1198                                              procedure call; anything else
- 1199                                              here is 233 (was a bare syntax
- 1200                                              error before 4.2) *)
- 1201                                          (. IF (dk = SymTab.KindProc)
- 1202   AND NOT sfx THEN
- 1203                                               res0 := SymTab.ProcRes(qn);
- 1204                                               IF res0 #
- 1205                                                  SymTab.InvalidType THEN
- 1206                                                 SemError(233)
- 1207                                               ELSIF SymTab.ProcNPar(qn) #
- 1208                                                       0 THEN
- 1209                                                 SemError(233)
- 1210                                               ELSE QbeGen.Mangled(qn,
- 1211                                                 SymTab.ProcUid(qn), mg0);
- 1212                                                 QbeGen.CallBegin(mg0,
- 1213                                                   res0,
- 1214                                                   SymTab.ProcDepthOf(qn),
- 1215                                                   SymTab.IsExternal(qn));
- 1216                                                 QbeGen.CallEnd(FALSE, q2)
- 1217                                               END
- 1218                                             ELSE SemError(233)
- 1219                                             END; .) ) .
- 1220    (* Actual-parameter list shared by statement and expression calls.
- 1221       want selects CallEnd's result handling; t/q carry the call
- 1222       value (statement calls discard). Arity/type failures are 233;
- 1223       evaluation code still emits so the .ssa stays assembleable. *)
- 1224    ArgList<pn: SymTab.Name; pt: SymTab.TypeIndex; callee: QbeGen.QVal;
- 1225            want: BOOLEAN; methCls: SymTab.TypeIndex;
- 1226            VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
- 1227            VAR called: BOOLEAN>          (. VAR i, np: CARDINAL;
- 1228                                               vs: INTEGER;
- 1229                                               res: SymTab.TypeIndex;
- 1230                                               mg: QbeGen.QVal;
- 1231                                               ok, ind, isMeth, va: BOOLEAN; .)
- 1232      = "("                               (. called := TRUE;
- 1233                                             ok := TRUE;
- 1234                                             ind := FALSE;
- 1235                                             isMeth := methCls #
- 1236                                               SymTab.InvalidType;
- 1237                                             IF isMeth THEN
- 1238                                               (* class method: the
- 1239                                                  receiver is armed.
- 1240                                                  Virtual -> dispatch
- 1241                                                  through the vtable;
- 1242                                                  otherwise a static
- 1243                                                  call. *)
- 1244                                               res := SymTab.ClassMethodRes(
- 1245                                                 methCls, pn);
- 1246                                               vs := SymTab.VirtSlot(
- 1247                                                 methCls, pn);
- 1248                                               IF vs >= 0 THEN
- 1249                                                 QbeGen.VirtCallBegin(
- 1250                                                   callee, vs, res)
- 1251                                               ELSE
- 1252                                                 QbeGen.Mangled(pn,
- 1253                                                   SymTab.ClassMethodUid(
- 1254                                                   methCls, pn), mg);
- 1255                                                 QbeGen.CallBegin(mg, res, 0,
- 1256                                                   FALSE)
- 1257                                               END
- 1258                                             ELSIF SymTab.SymKind(pn) =
- 1259                                                SymTab.KindProc THEN
- 1260                                               res := SymTab.ProcRes(pn);
- 1261                                               QbeGen.Mangled(pn,
- 1262                                                 SymTab.ProcUid(pn), mg);
- 1263                                               QbeGen.CallBegin(mg, res,
- 1264                                                 SymTab.ProcDepthOf(pn),
- 1265                                                 SymTab.IsExternal(pn))
- 1266                                             ELSIF (pt # SymTab.InvalidType)
- 1267    AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN
- 1268                                               ind := TRUE;
- 1269                                               res :=
- 1270                                                 SymTab.ProcTypeRes(pt);
- 1271                                               QbeGen.CallBeginInd(callee,
- 1272                                                 res, FALSE)
- 1273                                             ELSE SemError(233);
- 1274                                               ok := FALSE;
- 1275                                               res := SymTab.InvalidType
- 1276                                             END;
- 1277                                             i := 0; .)
- 1278        [ ActParam<pn, pt, ind, methCls, i>        (. INC(i); .)
- 1279          { "," ActParam<pn, pt, ind, methCls, i>  (. INC(i); .) } ]
- 1280        ")"                               (. IF ok THEN
- 1281                                               IF isMeth THEN
- 1282                                                 np := SymTab.ClassMethodNPar(
- 1283                                                   methCls, pn)
- 1284                                               ELSIF ind THEN
- 1285                                                 np := SymTab.ProcTypeNPar(pt)
- 1286                                               ELSE np := SymTab.ProcNPar(pn)
- 1287                                               END;
- 1288                                               va := (NOT isMeth) AND (NOT ind)
- 1289                                                 AND (SymTab.SymKind(pn) =
- 1290                                                      SymTab.KindProc)
- 1291                                                 AND SymTab.Varargs(pn);
- 1292                                               IF (i # np) AND NOT va THEN
- 1293                                                 SemError(233); ok := FALSE
- 1294                                               END
- 1295                                             END;
- 1296                                             IF NOT ok THEN
- 1297                                               t := SymTab.InvalidType;
- 1298                                               QbeGen.CopyOp("0", q)
- 1299                                             ELSIF want THEN
- 1300                                               IF res =
- 1301                                                  SymTab.InvalidType THEN
- 1302                                                 SemError(233);
- 1303                                                 t := SymTab.InvalidType;
- 1304                                                 QbeGen.CopyOp("0", q)
- 1305                                               ELSE t := res;
- 1306                                                 QbeGen.CallEnd(TRUE, q)
- 1307                                               END
- 1308                                             ELSE
- 1309                                               IF res #
- 1310                                                  SymTab.InvalidType THEN
- 1311                                                 SemError(233)
- 1312                                               END;
- 1313                                               t := SymTab.InvalidType;
- 1314                                               QbeGen.CopyOp("0", q);
- 1315                                               QbeGen.CallEnd(FALSE, q)
- 1316                                             END; .) .
- 1317    (* One actual: VAR formals take recorded designator addresses
- 1318       (233 otherwise); value formals take converted expressions. *)
- 1319    ActParam<pn: SymTab.Name; pt: SymTab.TypeIndex; ind: BOOLEAN;
- 1320             methCls: SymTab.TypeIndex; i: CARDINAL>
- 1321                                          (. VAR at, ft: SymTab.TypeIndex;
- 1322                                               qe, qa, qt: QbeGen.QVal;
- 1323                                               isV, conv, va: BOOLEAN;
- 1324                                               cl: CHAR; .)
- 1325      = Expr<at, qe>                      (. va := (NOT ind)
- 1326                                               AND (methCls =
- 1327                                                  SymTab.InvalidType)
- 1328                                               AND (SymTab.SymKind(pn) =
- 1329                                                  SymTab.KindProc)
- 1330                                               AND SymTab.Varargs(pn);
- 1331                                             IF ind THEN
- 1332                                               ft :=
- 1333                                                 SymTab.ProcTypeParamType(pt,
- 1334                                                   i);
- 1335                                               isV :=
- 1336                                                 SymTab.ProcTypeParamIsVar(pt,
- 1337                                                   i)
- 1338                                             ELSIF methCls #
- 1339                                                SymTab.InvalidType THEN
- 1340                                               ft :=
- 1341                                                 SymTab.ClassMethodParamType(
- 1342                                                 methCls, pn, i);
- 1343                                               isV :=
- 1344                                                 SymTab.ClassMethodParamIsVar(
- 1345                                                 methCls, pn, i)
- 1346                                             ELSE
- 1347                                               ft := SymTab.ParamType(pn, i);
- 1348                                               isV := SymTab.ParamIsVar(pn, i)
- 1349                                             END;
- 1350                                             IF (at = SymTab.InvalidType) THEN
- 1351                                             ELSIF ft = SymTab.InvalidType THEN
- 1352                                               IF va THEN
- 1353                                                 QbeGen.CArgAdd(qe, at, qa, cl)
- 1354                                               END
- 1355                                             ELSIF isV THEN
- 1356                                               IF (SymTab.ClassOf(at)
- 1357                                                  = SymTab.ClChar)
- 1358    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
- 1359    AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
- 1360         = SymTab.ClChar)
- 1361    AND QbeGen.IsImm(qe) THEN
- 1362                                                 (* 1-char string
- 1363                                                    literal passed to
- 1364                                                    a VAR ARRAY OF CHAR *)
- 1365                                                 QbeGen.DeclCharStr(qe,
- 1366                                                      qa);
- 1367                                                 IF NOT QbeGen.CallArg(qa,
- 1368                                                    "l") THEN
- 1369                                                   SemError(233)
- 1370                                                 END
- 1371                                               ELSIF NOT QbeGen.AddrOfVal(qe,
- 1372                                                    qa) THEN
- 1373                                                 SemError(233)
- 1374                                               ELSIF NOT SymTab.VarParamOk(at,
- 1375                                                        ft) THEN
- 1376                                                 SemError(233)
- 1377                                               ELSIF NOT QbeGen.CallArg(qa,
- 1378                                                        "l") THEN
- 1379                                                 SemError(233)
- 1380                                               END
- 1381                                             ELSE
- 1382                                               IF (SymTab.ClassOf(at)
- 1383                                                  = SymTab.ClChar)
- 1384    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
- 1385    AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
- 1386         = SymTab.ClChar)
- 1387    AND QbeGen.IsImm(qe) THEN
- 1388                                                 (* 1-char string
- 1389                                                    literal passed to
- 1390                                                    ARRAY OF CHAR *)
- 1391                                                 QbeGen.DeclCharStr(qe,
- 1392                                                      qa);
- 1393                                                 IF NOT QbeGen.CallArg(qa,
- 1394                                                    "l") THEN
- 1395                                                   SemError(233)
- 1396                                                 END
- 1397                                               ELSIF NOT SymTab.Assignable(at,
- 1398                                                    ft) THEN
- 1399                                                 SemError(233)
- 1400                                               ELSE
- 1401                                                 conv := (SymTab.ClassOf(
- 1402                                                   ft) = SymTab.ClReal)
- 1403   AND SymTab.IsIntFamily(at);
- 1404                                                 IF conv THEN
- 1405                                                   QbeGen.ConvIR(qe, qt);
- 1406                                                   IF NOT QbeGen.CallArg(qt,
- 1407                                                      "d") THEN
- 1408                                                     SemError(233)
- 1409                                                   END
- 1410                                                 ELSIF NOT QbeGen.CallArg(qe,
- 1411                                                   QbeGen.ArgClass(ft)) THEN
- 1412                                                   SemError(233)
- 1413                                                 END
- 1414                                               END
- 1415                                             END; .) .
- 1416    IfStat                                (. VAR t: SymTab.TypeIndex;
- 1417                                               q, lThen, lElse, lEnd:
- 1418                                                 QbeGen.QVal;
- 1419                                               hasElse: BOOLEAN; .)
- 1420      = "IF"                              (. hasElse := FALSE; .)
- 1421        Expr<t, q>                        (. IF NOT SymTab.BoolCheck(t) THEN
- 1422                                               SemError(214) END;
- 1423                                             QbeGen.NewLabel(lThen);
- 1424                                             QbeGen.NewLabel(lElse);
- 1425                                             QbeGen.NewLabel(lEnd);
- 1426                                             QbeGen.Jnz(q, lThen, lElse);
- 1427                                             QbeGen.EmitLabel(lThen); .)
- 1428        "THEN" [ StatSeq ]                (. QbeGen.Jmp(lEnd); .)
- 1429        { "ELSIF"                         (. QbeGen.EmitLabel(lElse);
- 1430                                             QbeGen.NewLabel(lElse); .)
- 1431          Expr<t, q>                      (. IF NOT SymTab.BoolCheck(t) THEN
- 1432                                               SemError(214) END;
- 1433                                             QbeGen.NewLabel(lThen);
- 1434                                             QbeGen.Jnz(q, lThen, lElse);
- 1435                                             QbeGen.EmitLabel(lThen); .)
- 1436          "THEN" [ StatSeq ]              (. QbeGen.Jmp(lEnd); .) }
- 1437        [ "ELSE"                          (. QbeGen.EmitLabel(lElse);
- 1438                                             hasElse := TRUE; .)
- 1439          [ StatSeq ] ]
- 1440        "END"                             (. IF hasElse THEN
- 1441                                               QbeGen.EmitLabel(lEnd)
- 1442                                             ELSE QbeGen.EmitLabel(lElse);
- 1443                                               QbeGen.EmitLabel(lEnd)
- 1444                                             END; .) .
- 1445    WhileStat                             (. VAR t: SymTab.TypeIndex;
- 1446                                               q, lTop, lBody, lEnd:
- 1447                                                 QbeGen.QVal; .)
- 1448      = "WHILE"                           (. QbeGen.NewLabel(lTop);
- 1449                                             QbeGen.NewLabel(lBody);
- 1450                                             QbeGen.NewLabel(lEnd);
- 1451                                             QbeGen.EmitLabel(lTop); .)
- 1452        Expr<t, q>                        (. IF NOT SymTab.BoolCheck(t) THEN
- 1453                                               SemError(214) END;
- 1454                                             QbeGen.Jnz(q, lBody, lEnd);
- 1455                                             QbeGen.EmitLabel(lBody); .)
- 1456        "DO" [ StatSeq ]                      (. QbeGen.Jmp(lTop); .)
- 1457        "END"                             (. QbeGen.EmitLabel(lEnd); .) .
- 1458    RepeatStat                            (. VAR t: SymTab.TypeIndex;
- 1459                                               q, lTop, lEnd: QbeGen.QVal; .)
- 1460      = "REPEAT"                          (. QbeGen.NewLabel(lTop);
- 1461                                             QbeGen.NewLabel(lEnd);
- 1462                                             QbeGen.EmitLabel(lTop); .)
- 1463        [ StatSeq ]
- 1464        "UNTIL" Expr<t, q>                (. IF NOT SymTab.BoolCheck(t) THEN
- 1465                                               SemError(214) END;
- 1466                                             QbeGen.Jnz(q, lEnd, lTop);
- 1467                                             QbeGen.EmitLabel(lEnd); .) .
- 1468    LoopStat                              (. VAR lTop, lEnd: QbeGen.QVal; .)
- 1469      = "LOOP"                            (. QbeGen.NewLabel(lTop);
- 1470                                             QbeGen.NewLabel(lEnd);
- 1471                                             QbeGen.PushLoop(lEnd);
- 1472                                             QbeGen.EmitLabel(lTop); .)
- 1473        [ StatSeq ]
- 1474        "END"                             (. QbeGen.Jmp(lTop);
- 1475                                             QbeGen.PopLoop;
- 1476                                             QbeGen.EmitLabel(lEnd); .) .
- 1477    (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
- 1478       Runtime direction would need a compare-select; the literal
- 1479       sign picks cslew/csegew at "DO" time. *)
- 1480    ForStat                               (. VAR lv: SymTab.Name;
- 1481                                               tlo, thi, tby:
- 1482                                                 SymTab.TypeIndex;
- 1483                                               qlo, qhi, qby, qt, qk, qb:
- 1484                                                 QbeGen.QVal;
- 1485                                               lTop, lBody, lEnd:
- 1486                                                 QbeGen.QVal;
- 1487                                               by: INTEGER;
- 1488                                               ok: BOOLEAN; .)
- 1489      = "FOR"                             (. by := 1; .)
- 1490        GetIdent<lv>                      (. ok := SymTab.Lookup(lv);
- 1491                                             IF NOT ok THEN
- 1492                                               SemError(201)
- 1493                                             ELSIF (SymTab.SymKind(lv) #
- 1494                                                    SymTab.KindVar)
- 1495   AND (SymTab.SymKind(lv) #
- 1496                                                   SymTab.KindParam) THEN
- 1497                                               SemError(220); ok := FALSE
- 1498                                             ELSIF NOT SymTab.IsIntFamily(
- 1499                                                     SymTab.SymType(lv)) THEN
- 1500                                               SemError(220); ok := FALSE
- 1501                                             END; .)
- 1502        ":=" Expr<tlo, qlo>               (. IF NOT SymTab.IsIntFamily(tlo) THEN
- 1503                                               SemError(220); ok := FALSE
- 1504                                             END; .)
- 1505        "TO" Expr<thi, qhi>               (. IF NOT SymTab.IsIntFamily(thi) THEN
- 1506                                               SemError(220); ok := FALSE
- 1507                                             END; .)
- 1508        [ "BY" Expr<tby, qby>             (. IF (tby #
- 1509                                               SymTab.InvalidType)
- 1510   AND NOT SymTab.IsIntFamily(tby) THEN
- 1511                                               SemError(220); ok := FALSE
- 1512                                             END;
- 1513                                             IF NOT SymTab.ConstInt(qby, by) THEN
- 1514                                               SemError(230); by := 1
- 1515                                             ELSIF by = 0 THEN
- 1516                                               SemError(220); by := 1
- 1517                                             END; .) ]
- 1518        "DO"                              (. IF ok THEN
- 1519                                               QbeGen.StoreVar(lv, qlo,
- 1520                                                 FALSE) END;
- 1521                                             QbeGen.NewLabel(lTop);
- 1522                                             QbeGen.NewLabel(lBody);
- 1523                                             QbeGen.NewLabel(lEnd);
- 1524                                             QbeGen.EmitLabel(lTop);
- 1525                                             QbeGen.LoadVar(lv, FALSE, qt);
- 1526                                             QbeGen.NewTemp(qk);
- 1527                                             IF by > 0 THEN
- 1528                                               QbeGen.Op3("cslew", qk,
- 1529                                                 qt, qhi, FALSE)
- 1530                                             ELSE QbeGen.Op3("csgew", qk,
- 1531                                               qt, qhi, FALSE)
- 1532                                             END;
- 1533                                             QbeGen.Jnz(qk, lBody, lEnd);
- 1534                                             QbeGen.EmitLabel(lBody); .)
- 1535        [ StatSeq ]
- 1536        "END"                             (. IF ok THEN
- 1537                                               QbeGen.LoadVar(lv, FALSE,
- 1538                                                 qt);
- 1539                                               QbeGen.IntStr(by, qb);
- 1540                                               QbeGen.NewTemp(qk);
- 1541                                               QbeGen.Op3("add", qk,
- 1542                                                 qt, qb, FALSE);
- 1543                                               QbeGen.StoreVar(lv, qk,
- 1544                                                 FALSE) END;
- 1545                                             QbeGen.Jmp(lTop);
- 1546                                             QbeGen.EmitLabel(lEnd); .) .
- 1547    CaseStat                              (. VAR tsel: SymTab.TypeIndex;
- 1548                                               qsel, lEnd: QbeGen.QVal; .)
- 1549      = "CASE" Expr<tsel, qsel>           (. QbeGen.NewLabel(lEnd); .)
- 1550        "OF" CaseAlt<tsel, qsel, lEnd>
- 1551        { "|" CaseAlt<tsel, qsel, lEnd> }
- 1552        [ "ELSE" [ StatSeq ] ]
- 1553        "END"                             (. QbeGen.EmitLabel(lEnd); .) .
- 1554    (* Compare-chain lowering: each alternative ends its match-tests
- 1555       with "jmp lAfter", so the no-match fallthrough skips the body:
- 1556       "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
- 1557       lAfter:". Falls into the next alternative, ELSE, or END. *)
- 1558    CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
- 1559            lEnd: QbeGen.QVal>            (. VAR lBody, lAfter: QbeGen.QVal; .)
- 1560      =                                   (. QbeGen.NewLabel(lBody);
- 1561                                             QbeGen.NewLabel(lAfter); .)
- 1562        CaseLabel<tsel, qsel, lBody>
- 1563        { "," CaseLabel<tsel, qsel, lBody> }
- 1564        ":"                               (. QbeGen.Jmp(lAfter);
- 1565                                             QbeGen.EmitLabel(lBody); .)
- 1566        [ StatSeq ]                       (. QbeGen.Jmp(lEnd);
- 1567                                             QbeGen.EmitLabel(lAfter); .) .
- 1568    CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
- 1569              lBody: QbeGen.QVal>         (. VAR t2, t3: SymTab.TypeIndex;
- 1570                                               q2, q3, qc, qd, qe:
- 1571                                                 QbeGen.QVal;
- 1572                                               lNext: QbeGen.QVal; .)
- 1573      = Expr<t2, q2>                      (. IF (t2 #
- 1574                                               SymTab.InvalidType)
- 1575   AND (tsel #
- 1576                                                 SymTab.InvalidType)
- 1577   AND ((SymTab.ClassOf(t2) =
- 1578                                                  SymTab.ClSet)
- 1579                                                 OR (SymTab.ClassOf(tsel) =
- 1580                                                     SymTab.ClSet)) THEN
- 1581                                               SemError(230)
- 1582                                             ELSIF (t2 #
- 1583                                               SymTab.InvalidType)
- 1584   AND (tsel #
- 1585                                                 SymTab.InvalidType)
- 1586   AND NOT SymTab.EqCheck(t2,
- 1587                                                   tsel) THEN
- 1588                                               SemError(213) END;
- 1589                                             IF NOT QbeGen.IsImm(q2) THEN
- 1590                                               SemError(230);
- 1591                                               QbeGen.CopyOp("0", q2)
- 1592                                             END;
- 1593                                             QbeGen.NewLabel(lNext);
- 1594                                             QbeGen.Cmp(SymTab.OpEq,
- 1595                                               qsel, q2, qc, FALSE);
- 1596                                             QbeGen.Jnz(qc, lBody, lNext);
- 1597                                             QbeGen.EmitLabel(lNext); .)
- 1598        [ ".." Expr<t3, q3>               (. IF (t3 #
- 1599                                               SymTab.InvalidType)
- 1600   AND (tsel #
- 1601                                                 SymTab.InvalidType)
- 1602   AND NOT SymTab.EqCheck(t3,
- 1603                                                   tsel) THEN
- 1604                                               SemError(213) END;
- 1605                                             IF NOT QbeGen.IsImm(q3) THEN
- 1606                                               SemError(230);
- 1607                                               QbeGen.CopyOp("0", q3)
- 1608                                             END;
- 1609                                             QbeGen.Cmp(SymTab.OpGe,
- 1610                                               qsel, q2, qc, FALSE);
- 1611                                             QbeGen.Cmp(SymTab.OpLe,
- 1612                                               qsel, q3, qd, FALSE);
- 1613                                             QbeGen.NewTemp(qe);
- 1614                                             QbeGen.Op3("and", qe, qc, qd,
- 1615                                               FALSE);
- 1616                                             QbeGen.NewLabel(lNext);
- 1617                                             QbeGen.Jnz(qe, lBody, lNext);
- 1618                                             QbeGen.EmitLabel(lNext); .) ] .
- 1619    ReturnStat                            (. VAR t: SymTab.TypeIndex;
- 1620                                               q, qt: QbeGen.QVal;
- 1621                                               res: SymTab.TypeIndex;
- 1622                                               hadE, conv: BOOLEAN; .)
- 1623      = "RETURN"                          (. hadE := FALSE; .)
- 1624        [ Expr<t, q>                      (. hadE := TRUE; .) ]
- 1625                                          (. conv := FALSE;
- 1626                                             IF NOT SymTab.InProc() THEN
- 1627                                               SemError(232)
- 1628                                             ELSE res := SymTab.CurRes();
- 1629                                               IF NOT hadE THEN
- 1630                                                 IF res #
- 1631                                                    SymTab.InvalidType THEN
- 1632                                                   SemError(232)
- 1633                                                 ELSE QbeGen.EmitRet(q,
- 1634                                                   FALSE)
- 1635                                                 END
- 1636                                               ELSIF (res =
- 1637                                                      SymTab.InvalidType)
- 1638                                                  OR (t #
- 1639                                                      SymTab.InvalidType)
- 1640   AND NOT SymTab.Assignable(t,
- 1641                                                       res) THEN
- 1642                                                 SemError(232)
- 1643                                               ELSE
- 1644                                                 conv := (SymTab.ClassOf(
- 1645                                                   res) = SymTab.ClReal)
- 1646   AND SymTab.IsIntFamily(t);
- 1647                                                 IF conv THEN
- 1648                                                   QbeGen.ConvIR(q, qt);
- 1649                                                   QbeGen.EmitRet(qt, TRUE)
- 1650                                                 ELSE QbeGen.EmitRet(q, TRUE)
- 1651                                                 END
- 1652                                               END
- 1653                                             END; .) .
- 1654    HaltStat                              (. VAR t: SymTab.TypeIndex;
- 1655                                               q: QbeGen.QVal; .)
- 1656      = "HALT" [ "(" Expr<t, q> ")" ]     (. QbeGen.HaltQ; .) .
- 1657    (* Designator: scalar loads, array addresses, and index suffixes.
- 1658       Each index descends one level (bounds-checked, trap on breach);
- 1659       nested levels reload the inner descriptor address. q ends as the
- 1660       value (scalars), the descriptor address (plain arrays), or the
- 1661       element address (indexed); sfx marks the indexed form. *)
- 1662    Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
- 1663           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
- 1664                                          (. VAR n, fn, mal: SymTab.Name;
- 1665                                               cls: INTEGER;
- 1666                                               ic: SymTab.TypeIndex;
- 1667                                               curT, it, eT, bt:
- 1668                                                 SymTab.TypeIndex;
- 1669                                               iq, ql, qlo, qhi, qe:
- 1670                                                 QbeGen.QVal;
- 1671                                               lo, hi: INTEGER;
- 1672                                               fo: INTEGER;
- 1673                                               isOpen: BOOLEAN;
- 1674                                               qb, cv: QbeGen.QVal; .)
- 1675      = GetIdent<n>                       (. methCls := SymTab.InvalidType;
- 1676                                             QbeGen.CopyOp(n, qn);
- 1677                                             sfx := FALSE;
- 1678                                             IF NOT SymTab.Lookup(n) THEN
- 1679                                               (* a bare method name inside
- 1680                                                  a CLASS IMPLEMENTATION
- 1681                                                  is a sibling call on
- 1682                                                  THIS *)
- 1683                                               ic := SymTab.CurImplClass();
- 1684                                               IF (ic #
- 1685                                                  SymTab.InvalidType)
- 1686    AND SymTab.MethodExists(ic, n) THEN
- 1687                                                 sfx := FALSE;
- 1688                                                 QbeGen.ThisBase(q);
- 1689                                                 QbeGen.ArmRecv(q);
- 1690                                                 methCls := ic;
- 1691                                                 k := SymTab.KindProc;
- 1692                                                 t := SymTab.InvalidType
- 1693                                               ELSE
- 1694                                                 SemError(201);
- 1695                                                 t :=
- 1696                                                   SymTab.InvalidType;
- 1697                                                 k := -1;
- 1698                                                 QbeGen.CopyOp("0", q)
- 1699                                               END
- 1700                                             ELSE
- 1701                                               t := SymTab.SymType(n);
- 1702                                               k := SymTab.SymKind(n);
- 1703                                               IF k = SymTab.KindConst THEN
- 1704                                                 IF SymTab.Equal(n,
- 1705                                                    "TRUE") THEN
- 1706                                                   t := SymTab.BoolType();
- 1707                                                   QbeGen.CopyOp("1", q)
- 1708                                                 ELSIF SymTab.Equal(n,
- 1709                                                    "FALSE") THEN
- 1710                                                   t := SymTab.BoolType();
- 1711                                                   QbeGen.CopyOp("0", q)
- 1712                                                 ELSIF SymTab.Equal(n,
- 1713                                                    "NIL") THEN
- 1714                                                   QbeGen.CopyOp("0", q)
- 1715                                                 ELSE
- 1716                                                   cls :=
- 1717                                                     SymTab.ClassOf(t);
- 1718                                                   IF (t #
- 1719                                                       SymTab.InvalidType)
- 1720   AND ((cls = SymTab.ClInt)
- 1721                                                      OR (cls
- 1722                                                          = SymTab.ClChar)
- 1723                                                      OR (cls
- 1724                                                          = SymTab.ClEnum)
- 1725                                                      OR (cls
- 1726                                                          = SymTab.ClReal)
- 1727                                                      OR (cls
- 1728                                                          = SymTab.ClLong)
- 1729                                                      OR (cls
- 1730                                                          = SymTab.ClNil)) THEN
- 1731                                                     IF cls = SymTab.ClNil THEN
- 1732                                                       QbeGen.CopyOp("0", q)
- 1733                                                     ELSIF ((cls
- 1734                                                         = SymTab.ClInt)
- 1735                                                       OR (cls
- 1736                                                         = SymTab.ClChar)
- 1737                                                       OR (cls
- 1738                                                         = SymTab.ClEnum)
- 1739                                                       OR (cls
- 1740                                                         = SymTab.ClLong))
- 1741    AND SymTab.GetSymVal(n, cv)
- 1742    AND QbeGen.IsImm(cv) THEN
- 1743                                                       QbeGen.CopyOp(cv, q)
- 1744                                                     ELSE
- 1745                                                       QbeGen.LoadVar(n,
- 1746                                                         cls = SymTab.ClReal,
- 1747                                                         q)
- 1748                                                     END
- 1749                                                   ELSIF (cls = SymTab.ClArray)
- 1750                                                      OR (cls = SymTab.ClRecord)
- 1751                                                      OR (cls = SymTab.ClClass)
- 1752                                                      OR (cls = SymTab.ClStr)
- 1753                                                      OR (cls = SymTab.ClUStr) THEN
- 1754                                                     (* aggregate constant:
- 1755                                                        its value IS the
- 1756                                                        descriptor address *)
- 1757                                                     IF SymTab.GetSymVal(n, cv) THEN
- 1758                                                       QbeGen.CopyOp(cv, q)
- 1759                                                     ELSE
- 1760                                                       QbeGen.CopyOp("0", q)
- 1761                                                     END
- 1762                                                   ELSE
- 1763                                                     IF t #
- 1764                                                        SymTab.InvalidType THEN
- 1765                                                       SemError(230)
- 1766                                                     END;
- 1767                                                     QbeGen.CopyOp("0", q)
- 1768                                                   END
- 1769                                                 END
- 1770                                               ELSIF (k = SymTab.KindVar)
- 1771                                                  OR (k = SymTab.KindParam) THEN
- 1772                                                 cls :=
- 1773                                                   SymTab.ClassOf(t);
- 1774                                                 IF (cls = SymTab.ClInt)
- 1775                                                    OR (cls = SymTab.ClBool)
- 1776                                                    OR (cls = SymTab.ClChar)
- 1777                                                    OR (cls = SymTab.ClUChar)
- 1778                                                    OR (cls = SymTab.ClEnum)
- 1779                                                    OR (cls
- 1780                                                        = SymTab.ClReal) THEN
- 1781                                                   QbeGen.LoadVar(n,
- 1782                                                     cls = SymTab.ClReal, q)
- 1783                                                 ELSIF (cls = SymTab.ClPtr)
- 1784                                                    OR (cls = SymTab.ClProc) THEN
- 1785                                                   QbeGen.LoadPtr(n, q)
- 1786                                                 ELSIF cls = SymTab.ClLong THEN
- 1787                                                   QbeGen.LoadLong(n, q)
- 1788                                                 ELSIF (cls
- 1789                                                         = SymTab.ClArray)
- 1790                                                    OR (cls
- 1791                                                        = SymTab.ClSet)
- 1792                                                    OR (cls
- 1793                                                        = SymTab.ClRecord)
- 1794                                                    OR (cls
- 1795                                                        = SymTab.ClUStr)
- 1796                                                    OR (cls
- 1797                                                        = SymTab.ClClass) THEN
- 1798                                                   QbeGen.AddrOf(n, q)
- 1799                                                 ELSE SemError(230);
- 1800                                                   QbeGen.CopyOp("0", q)
+ 1189                                             ELSIF SymTab.ClassOf(dt) =
+ 1190                                                   SymTab.ClArray THEN
+ 1191                                               IF (et # SymTab.InvalidType)
+ 1192    AND (SymTab.ClassOf(et) = SymTab.ClUStr)
+ 1193    AND SymTab.IsUCharArray(dt) THEN
+ 1194                                                 QbeGen.UAssign(qd, qe)
+ 1195                                               ELSIF SymTab.StrCompat(dt,
+ 1196                                                    et) THEN
+ 1197                                                 QbeGen.StrAssign(qd, qe)
+ 1198                                               ELSE
+ 1199                                                 QbeGen.CopyArray(qd, qe,
+ 1200                                                   dt)
+ 1201                                               END
+ 1202                                             ELSIF SymTab.ClassOf(dt) =
+ 1203                                                   SymTab.ClSet THEN
+ 1204                                               QbeGen.CopySet(qd, qe,
+ 1205                                                 SymTab.SetWords(dt),
+ 1206                                                 SymTab.SetWords(et))
+ 1207                                             ELSIF SymTab.ClassOf(dt) =
+ 1208                                                   SymTab.ClRecord THEN
+ 1209                                               QbeGen.CopyRecord(qd, qe, dt)
+ 1210                                             ELSIF (SymTab.ClassOf(dt) =
+ 1211                                                   SymTab.ClPtr)
+ 1212                                                OR (SymTab.ClassOf(dt) =
+ 1213                                                   SymTab.ClProc) THEN
+ 1214                                               QbeGen.StorePtr(qn, qe)
+ 1215                                             ELSIF SymTab.IsLongFamily(dt) THEN
+ 1216                                               IF wconv THEN
+ 1217                                                 QbeGen.WidenLong(qe, ql);
+ 1218                                                 QbeGen.StoreLong(qn, ql)
+ 1219                                               ELSE QbeGen.StoreLong(qn, qe)
+ 1220                                               END
+ 1221                                             ELSIF conv THEN
+ 1222                                               QbeGen.ConvIR(qe, qt);
+ 1223                                               QbeGen.StoreVar(qn, qt, TRUE)
+ 1224                                             ELSE
+ 1225                                               QbeGen.StoreVar(qn, qe, isR)
+ 1226                                             END
+ 1227                                           END; .)
+ 1228        | ArgList<qn, dt, qd, FALSE, methCls, ct2, q2, called>
+ 1229        |                                 (* bare `P;`: proper parameterless
+ 1230                                              procedure call; anything else
+ 1231                                              here is 233 (was a bare syntax
+ 1232                                              error before 4.2) *)
+ 1233                                          (. IF (dk = SymTab.KindProc)
+ 1234   AND NOT sfx THEN
+ 1235                                               res0 := SymTab.ProcRes(qn);
+ 1236                                               IF res0 #
+ 1237                                                  SymTab.InvalidType THEN
+ 1238                                                 SemError(233)
+ 1239                                               ELSIF SymTab.ProcNPar(qn) #
+ 1240                                                       0 THEN
+ 1241                                                 SemError(233)
+ 1242                                               ELSE QbeGen.Mangled(qn,
+ 1243                                                 SymTab.ProcUid(qn), mg0);
+ 1244                                                 QbeGen.CallBegin(mg0,
+ 1245                                                   res0,
+ 1246                                                   SymTab.ProcDepthOf(qn),
+ 1247                                                   SymTab.IsExternal(qn));
+ 1248                                                 QbeGen.CallEnd(FALSE, q2)
+ 1249                                               END
+ 1250                                             ELSE SemError(233)
+ 1251                                             END; .) ) .
+ 1252    (* Actual-parameter list shared by statement and expression calls.
+ 1253       want selects CallEnd's result handling; t/q carry the call
+ 1254       value (statement calls discard). Arity/type failures are 233;
+ 1255       evaluation code still emits so the .ssa stays assembleable. *)
+ 1256    ArgList<pn: SymTab.Name; pt: SymTab.TypeIndex; callee: QbeGen.QVal;
+ 1257            want: BOOLEAN; methCls: SymTab.TypeIndex;
+ 1258            VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
+ 1259            VAR called: BOOLEAN>          (. VAR i, np: CARDINAL;
+ 1260                                               vs: INTEGER;
+ 1261                                               res: SymTab.TypeIndex;
+ 1262                                               mg: QbeGen.QVal;
+ 1263                                               ok, ind, isMeth, va: BOOLEAN; .)
+ 1264      = "("                               (. called := TRUE;
+ 1265                                             ok := TRUE;
+ 1266                                             ind := FALSE;
+ 1267                                             isMeth := methCls #
+ 1268                                               SymTab.InvalidType;
+ 1269                                             IF isMeth THEN
+ 1270                                               (* class method: the
+ 1271                                                  receiver is armed.
+ 1272                                                  Virtual -> dispatch
+ 1273                                                  through the vtable;
+ 1274                                                  otherwise a static
+ 1275                                                  call. *)
+ 1276                                               res := SymTab.ClassMethodRes(
+ 1277                                                 methCls, pn);
+ 1278                                               vs := SymTab.VirtSlot(
+ 1279                                                 methCls, pn);
+ 1280                                               IF vs >= 0 THEN
+ 1281                                                 QbeGen.VirtCallBegin(
+ 1282                                                   callee, vs, res)
+ 1283                                               ELSE
+ 1284                                                 QbeGen.Mangled(pn,
+ 1285                                                   SymTab.ClassMethodUid(
+ 1286                                                   methCls, pn), mg);
+ 1287                                                 QbeGen.CallBegin(mg, res, 0,
+ 1288                                                   FALSE)
+ 1289                                               END
+ 1290                                             ELSIF SymTab.SymKind(pn) =
+ 1291                                                SymTab.KindProc THEN
+ 1292                                               res := SymTab.ProcRes(pn);
+ 1293                                               QbeGen.Mangled(pn,
+ 1294                                                 SymTab.ProcUid(pn), mg);
+ 1295                                               QbeGen.CallBegin(mg, res,
+ 1296                                                 SymTab.ProcDepthOf(pn),
+ 1297                                                 SymTab.IsExternal(pn))
+ 1298                                             ELSIF (pt # SymTab.InvalidType)
+ 1299    AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN
+ 1300                                               ind := TRUE;
+ 1301                                               res :=
+ 1302                                                 SymTab.ProcTypeRes(pt);
+ 1303                                               QbeGen.CallBeginInd(callee,
+ 1304                                                 res, FALSE)
+ 1305                                             ELSE SemError(233);
+ 1306                                               ok := FALSE;
+ 1307                                               res := SymTab.InvalidType
+ 1308                                             END;
+ 1309                                             i := 0; .)
+ 1310        [ ActParam<pn, pt, ind, methCls, i>        (. INC(i); .)
+ 1311          { "," ActParam<pn, pt, ind, methCls, i>  (. INC(i); .) } ]
+ 1312        ")"                               (. IF ok THEN
+ 1313                                               IF isMeth THEN
+ 1314                                                 np := SymTab.ClassMethodNPar(
+ 1315                                                   methCls, pn)
+ 1316                                               ELSIF ind THEN
+ 1317                                                 np := SymTab.ProcTypeNPar(pt)
+ 1318                                               ELSE np := SymTab.ProcNPar(pn)
+ 1319                                               END;
+ 1320                                               va := (NOT isMeth) AND (NOT ind)
+ 1321                                                 AND (SymTab.SymKind(pn) =
+ 1322                                                      SymTab.KindProc)
+ 1323                                                 AND SymTab.Varargs(pn);
+ 1324                                               IF (i # np) AND NOT va THEN
+ 1325                                                 SemError(233); ok := FALSE
+ 1326                                               END
+ 1327                                             END;
+ 1328                                             IF NOT ok THEN
+ 1329                                               t := SymTab.InvalidType;
+ 1330                                               QbeGen.CopyOp("0", q)
+ 1331                                             ELSIF want THEN
+ 1332                                               IF res =
+ 1333                                                  SymTab.InvalidType THEN
+ 1334                                                 SemError(233);
+ 1335                                                 t := SymTab.InvalidType;
+ 1336                                                 QbeGen.CopyOp("0", q)
+ 1337                                               ELSE t := res;
+ 1338                                                 QbeGen.CallEnd(TRUE, q)
+ 1339                                               END
+ 1340                                             ELSE
+ 1341                                               IF res #
+ 1342                                                  SymTab.InvalidType THEN
+ 1343                                                 SemError(233)
+ 1344                                               END;
+ 1345                                               t := SymTab.InvalidType;
+ 1346                                               QbeGen.CopyOp("0", q);
+ 1347                                               QbeGen.CallEnd(FALSE, q)
+ 1348                                             END; .) .
+ 1349    (* One actual: VAR formals take recorded designator addresses
+ 1350       (233 otherwise); value formals take converted expressions. *)
+ 1351    ActParam<pn: SymTab.Name; pt: SymTab.TypeIndex; ind: BOOLEAN;
+ 1352             methCls: SymTab.TypeIndex; i: CARDINAL>
+ 1353                                          (. VAR at, ft: SymTab.TypeIndex;
+ 1354                                               qe, qa, qt: QbeGen.QVal;
+ 1355                                               isV, conv, va: BOOLEAN;
+ 1356                                               cl: CHAR; .)
+ 1357      = Expr<at, qe>                      (. va := (NOT ind)
+ 1358                                               AND (methCls =
+ 1359                                                  SymTab.InvalidType)
+ 1360                                               AND (SymTab.SymKind(pn) =
+ 1361                                                  SymTab.KindProc)
+ 1362                                               AND SymTab.Varargs(pn);
+ 1363                                             IF ind THEN
+ 1364                                               ft :=
+ 1365                                                 SymTab.ProcTypeParamType(pt,
+ 1366                                                   i);
+ 1367                                               isV :=
+ 1368                                                 SymTab.ProcTypeParamIsVar(pt,
+ 1369                                                   i)
+ 1370                                             ELSIF methCls #
+ 1371                                                SymTab.InvalidType THEN
+ 1372                                               ft :=
+ 1373                                                 SymTab.ClassMethodParamType(
+ 1374                                                 methCls, pn, i);
+ 1375                                               isV :=
+ 1376                                                 SymTab.ClassMethodParamIsVar(
+ 1377                                                 methCls, pn, i)
+ 1378                                             ELSE
+ 1379                                               ft := SymTab.ParamType(pn, i);
+ 1380                                               isV := SymTab.ParamIsVar(pn, i)
+ 1381                                             END;
+ 1382                                             IF (at = SymTab.InvalidType) THEN
+ 1383                                             ELSIF ft = SymTab.InvalidType THEN
+ 1384                                               IF va THEN
+ 1385                                                 QbeGen.CArgAdd(qe, at, qa, cl)
+ 1386                                               END
+ 1387                                             ELSIF isV THEN
+ 1388                                               IF (SymTab.ClassOf(at)
+ 1389                                                  = SymTab.ClChar)
+ 1390    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
+ 1391    AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
+ 1392         = SymTab.ClChar)
+ 1393    AND QbeGen.IsImm(qe) THEN
+ 1394                                                 (* 1-char string
+ 1395                                                    literal passed to
+ 1396                                                    a VAR ARRAY OF CHAR *)
+ 1397                                                 QbeGen.DeclCharStr(qe,
+ 1398                                                      qa);
+ 1399                                                 IF NOT QbeGen.CallArg(qa,
+ 1400                                                    "l") THEN
+ 1401                                                   SemError(233)
+ 1402                                                 END
+ 1403                                               ELSIF NOT QbeGen.AddrOfVal(qe,
+ 1404                                                    qa) THEN
+ 1405                                                 SemError(233)
+ 1406                                               ELSIF NOT SymTab.VarParamOk(at,
+ 1407                                                        ft) THEN
+ 1408                                                 SemError(233)
+ 1409                                               ELSIF NOT QbeGen.CallArg(qa,
+ 1410                                                        "l") THEN
+ 1411                                                 SemError(233)
+ 1412                                               END
+ 1413                                             ELSE
+ 1414                                               IF (SymTab.ClassOf(at)
+ 1415                                                  = SymTab.ClChar)
+ 1416    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
+ 1417    AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
+ 1418         = SymTab.ClChar)
+ 1419    AND QbeGen.IsImm(qe) THEN
+ 1420                                                 (* 1-char string
+ 1421                                                    literal passed to
+ 1422                                                    ARRAY OF CHAR *)
+ 1423                                                 QbeGen.DeclCharStr(qe,
+ 1424                                                      qa);
+ 1425                                                 IF NOT QbeGen.CallArg(qa,
+ 1426                                                    "l") THEN
+ 1427                                                   SemError(233)
+ 1428                                                 END
+ 1429                                               ELSIF NOT SymTab.Assignable(at,
+ 1430                                                    ft) THEN
+ 1431                                                 SemError(233)
+ 1432                                               ELSE
+ 1433                                                 conv := (SymTab.ClassOf(
+ 1434                                                   ft) = SymTab.ClReal)
+ 1435   AND SymTab.IsIntFamily(at);
+ 1436                                                 IF conv THEN
+ 1437                                                   QbeGen.ConvIR(qe, qt);
+ 1438                                                   IF NOT QbeGen.CallArg(qt,
+ 1439                                                      "d") THEN
+ 1440                                                     SemError(233)
+ 1441                                                   END
+ 1442                                                 ELSIF NOT QbeGen.CallArg(qe,
+ 1443                                                   QbeGen.ArgClass(ft)) THEN
+ 1444                                                   SemError(233)
+ 1445                                                 END
+ 1446                                               END
+ 1447                                             END; .) .
+ 1448    IfStat                                (. VAR t: SymTab.TypeIndex;
+ 1449                                               q, lThen, lElse, lEnd:
+ 1450                                                 QbeGen.QVal;
+ 1451                                               hasElse: BOOLEAN; .)
+ 1452      = "IF"                              (. hasElse := FALSE; .)
+ 1453        Expr<t, q>                        (. IF NOT SymTab.BoolCheck(t) THEN
+ 1454                                               SemError(214) END;
+ 1455                                             QbeGen.NewLabel(lThen);
+ 1456                                             QbeGen.NewLabel(lElse);
+ 1457                                             QbeGen.NewLabel(lEnd);
+ 1458                                             QbeGen.Jnz(q, lThen, lElse);
+ 1459                                             QbeGen.EmitLabel(lThen); .)
+ 1460        "THEN" [ StatSeq ]                (. QbeGen.Jmp(lEnd); .)
+ 1461        { "ELSIF"                         (. QbeGen.EmitLabel(lElse);
+ 1462                                             QbeGen.NewLabel(lElse); .)
+ 1463          Expr<t, q>                      (. IF NOT SymTab.BoolCheck(t) THEN
+ 1464                                               SemError(214) END;
+ 1465                                             QbeGen.NewLabel(lThen);
+ 1466                                             QbeGen.Jnz(q, lThen, lElse);
+ 1467                                             QbeGen.EmitLabel(lThen); .)
+ 1468          "THEN" [ StatSeq ]              (. QbeGen.Jmp(lEnd); .) }
+ 1469        [ "ELSE"                          (. QbeGen.EmitLabel(lElse);
+ 1470                                             hasElse := TRUE; .)
+ 1471          [ StatSeq ] ]
+ 1472        "END"                             (. IF hasElse THEN
+ 1473                                               QbeGen.EmitLabel(lEnd)
+ 1474                                             ELSE QbeGen.EmitLabel(lElse);
+ 1475                                               QbeGen.EmitLabel(lEnd)
+ 1476                                             END; .) .
+ 1477    WhileStat                             (. VAR t: SymTab.TypeIndex;
+ 1478                                               q, lTop, lBody, lEnd:
+ 1479                                                 QbeGen.QVal; .)
+ 1480      = "WHILE"                           (. QbeGen.NewLabel(lTop);
+ 1481                                             QbeGen.NewLabel(lBody);
+ 1482                                             QbeGen.NewLabel(lEnd);
+ 1483                                             QbeGen.EmitLabel(lTop); .)
+ 1484        Expr<t, q>                        (. IF NOT SymTab.BoolCheck(t) THEN
+ 1485                                               SemError(214) END;
+ 1486                                             QbeGen.Jnz(q, lBody, lEnd);
+ 1487                                             QbeGen.EmitLabel(lBody); .)
+ 1488        "DO" [ StatSeq ]                      (. QbeGen.Jmp(lTop); .)
+ 1489        "END"                             (. QbeGen.EmitLabel(lEnd); .) .
+ 1490    RepeatStat                            (. VAR t: SymTab.TypeIndex;
+ 1491                                               q, lTop, lEnd: QbeGen.QVal; .)
+ 1492      = "REPEAT"                          (. QbeGen.NewLabel(lTop);
+ 1493                                             QbeGen.NewLabel(lEnd);
+ 1494                                             QbeGen.EmitLabel(lTop); .)
+ 1495        [ StatSeq ]
+ 1496        "UNTIL" Expr<t, q>                (. IF NOT SymTab.BoolCheck(t) THEN
+ 1497                                               SemError(214) END;
+ 1498                                             QbeGen.Jnz(q, lEnd, lTop);
+ 1499                                             QbeGen.EmitLabel(lEnd); .) .
+ 1500    LoopStat                              (. VAR lTop, lEnd: QbeGen.QVal; .)
+ 1501      = "LOOP"                            (. QbeGen.NewLabel(lTop);
+ 1502                                             QbeGen.NewLabel(lEnd);
+ 1503                                             QbeGen.PushLoop(lEnd);
+ 1504                                             QbeGen.EmitLabel(lTop); .)
+ 1505        [ StatSeq ]
+ 1506        "END"                             (. QbeGen.Jmp(lTop);
+ 1507                                             QbeGen.PopLoop;
+ 1508                                             QbeGen.EmitLabel(lEnd); .) .
+ 1509    (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
+ 1510       Runtime direction would need a compare-select; the literal
+ 1511       sign picks cslew/csegew at "DO" time. *)
+ 1512    ForStat                               (. VAR lv: SymTab.Name;
+ 1513                                               tlo, thi, tby:
+ 1514                                                 SymTab.TypeIndex;
+ 1515                                               qlo, qhi, qby, qt, qk, qb:
+ 1516                                                 QbeGen.QVal;
+ 1517                                               lTop, lBody, lEnd:
+ 1518                                                 QbeGen.QVal;
+ 1519                                               by: INTEGER;
+ 1520                                               ok: BOOLEAN; .)
+ 1521      = "FOR"                             (. by := 1; .)
+ 1522        GetIdent<lv>                      (. ok := SymTab.Lookup(lv);
+ 1523                                             IF NOT ok THEN
+ 1524                                               SemError(201)
+ 1525                                             ELSIF (SymTab.SymKind(lv) #
+ 1526                                                    SymTab.KindVar)
+ 1527   AND (SymTab.SymKind(lv) #
+ 1528                                                   SymTab.KindParam) THEN
+ 1529                                               SemError(220); ok := FALSE
+ 1530                                             ELSIF NOT SymTab.IsIntFamily(
+ 1531                                                     SymTab.SymType(lv)) THEN
+ 1532                                               SemError(220); ok := FALSE
+ 1533                                             END; .)
+ 1534        ":=" Expr<tlo, qlo>               (. IF NOT SymTab.IsIntFamily(tlo) THEN
+ 1535                                               SemError(220); ok := FALSE
+ 1536                                             END; .)
+ 1537        "TO" Expr<thi, qhi>               (. IF NOT SymTab.IsIntFamily(thi) THEN
+ 1538                                               SemError(220); ok := FALSE
+ 1539                                             END; .)
+ 1540        [ "BY" Expr<tby, qby>             (. IF (tby #
+ 1541                                               SymTab.InvalidType)
+ 1542   AND NOT SymTab.IsIntFamily(tby) THEN
+ 1543                                               SemError(220); ok := FALSE
+ 1544                                             END;
+ 1545                                             IF NOT SymTab.ConstInt(qby, by) THEN
+ 1546                                               SemError(230); by := 1
+ 1547                                             ELSIF by = 0 THEN
+ 1548                                               SemError(220); by := 1
+ 1549                                             END; .) ]
+ 1550        "DO"                              (. IF ok THEN
+ 1551                                               QbeGen.StoreVar(lv, qlo,
+ 1552                                                 FALSE) END;
+ 1553                                             QbeGen.NewLabel(lTop);
+ 1554                                             QbeGen.NewLabel(lBody);
+ 1555                                             QbeGen.NewLabel(lEnd);
+ 1556                                             QbeGen.EmitLabel(lTop);
+ 1557                                             QbeGen.LoadVar(lv, FALSE, qt);
+ 1558                                             QbeGen.NewTemp(qk);
+ 1559                                             IF by > 0 THEN
+ 1560                                               QbeGen.Op3("cslew", qk,
+ 1561                                                 qt, qhi, FALSE)
+ 1562                                             ELSE QbeGen.Op3("csgew", qk,
+ 1563                                               qt, qhi, FALSE)
+ 1564                                             END;
+ 1565                                             QbeGen.Jnz(qk, lBody, lEnd);
+ 1566                                             QbeGen.EmitLabel(lBody); .)
+ 1567        [ StatSeq ]
+ 1568        "END"                             (. IF ok THEN
+ 1569                                               QbeGen.LoadVar(lv, FALSE,
+ 1570                                                 qt);
+ 1571                                               QbeGen.IntStr(by, qb);
+ 1572                                               QbeGen.NewTemp(qk);
+ 1573                                               QbeGen.Op3("add", qk,
+ 1574                                                 qt, qb, FALSE);
+ 1575                                               QbeGen.StoreVar(lv, qk,
+ 1576                                                 FALSE) END;
+ 1577                                             QbeGen.Jmp(lTop);
+ 1578                                             QbeGen.EmitLabel(lEnd); .) .
+ 1579    CaseStat                              (. VAR tsel: SymTab.TypeIndex;
+ 1580                                               qsel, lEnd: QbeGen.QVal; .)
+ 1581      = "CASE" Expr<tsel, qsel>           (. QbeGen.NewLabel(lEnd); .)
+ 1582        "OF" CaseAlt<tsel, qsel, lEnd>
+ 1583        { "|" CaseAlt<tsel, qsel, lEnd> }
+ 1584        [ "ELSE" [ StatSeq ] ]
+ 1585        "END"                             (. QbeGen.EmitLabel(lEnd); .) .
+ 1586    (* Compare-chain lowering: each alternative ends its match-tests
+ 1587       with "jmp lAfter", so the no-match fallthrough skips the body:
+ 1588       "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
+ 1589       lAfter:". Falls into the next alternative, ELSE, or END. *)
+ 1590    CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
+ 1591            lEnd: QbeGen.QVal>            (. VAR lBody, lAfter: QbeGen.QVal; .)
+ 1592      =                                   (. QbeGen.NewLabel(lBody);
+ 1593                                             QbeGen.NewLabel(lAfter); .)
+ 1594        CaseLabel<tsel, qsel, lBody>
+ 1595        { "," CaseLabel<tsel, qsel, lBody> }
+ 1596        ":"                               (. QbeGen.Jmp(lAfter);
+ 1597                                             QbeGen.EmitLabel(lBody); .)
+ 1598        [ StatSeq ]                       (. QbeGen.Jmp(lEnd);
+ 1599                                             QbeGen.EmitLabel(lAfter); .) .
+ 1600    CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
+ 1601              lBody: QbeGen.QVal>         (. VAR t2, t3: SymTab.TypeIndex;
+ 1602                                               q2, q3, qc, qd, qe:
+ 1603                                                 QbeGen.QVal;
+ 1604                                               lNext: QbeGen.QVal; .)
+ 1605      = Expr<t2, q2>                      (. IF (t2 #
+ 1606                                               SymTab.InvalidType)
+ 1607   AND (tsel #
+ 1608                                                 SymTab.InvalidType)
+ 1609   AND ((SymTab.ClassOf(t2) =
+ 1610                                                  SymTab.ClSet)
+ 1611                                                 OR (SymTab.ClassOf(tsel) =
+ 1612                                                     SymTab.ClSet)) THEN
+ 1613                                               SemError(230)
+ 1614                                             ELSIF (t2 #
+ 1615                                               SymTab.InvalidType)
+ 1616   AND (tsel #
+ 1617                                                 SymTab.InvalidType)
+ 1618   AND NOT SymTab.EqCheck(t2,
+ 1619                                                   tsel) THEN
+ 1620                                               SemError(213) END;
+ 1621                                             IF NOT QbeGen.IsImm(q2) THEN
+ 1622                                               SemError(230);
+ 1623                                               QbeGen.CopyOp("0", q2)
+ 1624                                             END;
+ 1625                                             QbeGen.NewLabel(lNext);
+ 1626                                             QbeGen.Cmp(SymTab.OpEq,
+ 1627                                               qsel, q2, qc, FALSE);
+ 1628                                             QbeGen.Jnz(qc, lBody, lNext);
+ 1629                                             QbeGen.EmitLabel(lNext); .)
+ 1630        [ ".." Expr<t3, q3>               (. IF (t3 #
+ 1631                                               SymTab.InvalidType)
+ 1632   AND (tsel #
+ 1633                                                 SymTab.InvalidType)
+ 1634   AND NOT SymTab.EqCheck(t3,
+ 1635                                                   tsel) THEN
+ 1636                                               SemError(213) END;
+ 1637                                             IF NOT QbeGen.IsImm(q3) THEN
+ 1638                                               SemError(230);
+ 1639                                               QbeGen.CopyOp("0", q3)
+ 1640                                             END;
+ 1641                                             QbeGen.Cmp(SymTab.OpGe,
+ 1642                                               qsel, q2, qc, FALSE);
+ 1643                                             QbeGen.Cmp(SymTab.OpLe,
+ 1644                                               qsel, q3, qd, FALSE);
+ 1645                                             QbeGen.NewTemp(qe);
+ 1646                                             QbeGen.Op3("and", qe, qc, qd,
+ 1647                                               FALSE);
+ 1648                                             QbeGen.NewLabel(lNext);
+ 1649                                             QbeGen.Jnz(qe, lBody, lNext);
+ 1650                                             QbeGen.EmitLabel(lNext); .) ] .
+ 1651    ReturnStat                            (. VAR t: SymTab.TypeIndex;
+ 1652                                               q, qt: QbeGen.QVal;
+ 1653                                               res: SymTab.TypeIndex;
+ 1654                                               hadE, conv: BOOLEAN; .)
+ 1655      = "RETURN"                          (. hadE := FALSE; .)
+ 1656        [ Expr<t, q>                      (. hadE := TRUE; .) ]
+ 1657                                          (. conv := FALSE;
+ 1658                                             IF NOT SymTab.InProc() THEN
+ 1659                                               SemError(232)
+ 1660                                             ELSE res := SymTab.CurRes();
+ 1661                                               IF NOT hadE THEN
+ 1662                                                 IF res #
+ 1663                                                    SymTab.InvalidType THEN
+ 1664                                                   SemError(232)
+ 1665                                                 ELSE QbeGen.EmitRet(q,
+ 1666                                                   FALSE)
+ 1667                                                 END
+ 1668                                               ELSIF (res =
+ 1669                                                      SymTab.InvalidType)
+ 1670                                                  OR (t #
+ 1671                                                      SymTab.InvalidType)
+ 1672   AND NOT SymTab.Assignable(t,
+ 1673                                                       res) THEN
+ 1674                                                 SemError(232)
+ 1675                                               ELSE
+ 1676                                                 conv := (SymTab.ClassOf(
+ 1677                                                   res) = SymTab.ClReal)
+ 1678   AND SymTab.IsIntFamily(t);
+ 1679                                                 IF conv THEN
+ 1680                                                   QbeGen.ConvIR(q, qt);
+ 1681                                                   QbeGen.EmitRet(qt, TRUE)
+ 1682                                                 ELSE QbeGen.EmitRet(q, TRUE)
+ 1683                                                 END
+ 1684                                               END
+ 1685                                             END; .) .
+ 1686    HaltStat                              (. VAR t: SymTab.TypeIndex;
+ 1687                                               q: QbeGen.QVal; .)
+ 1688      = "HALT" [ "(" Expr<t, q> ")" ]     (. QbeGen.HaltQ; .) .
+ 1689    (* Designator: scalar loads, array addresses, and index suffixes.
+ 1690       Each index descends one level (bounds-checked, trap on breach);
+ 1691       nested levels reload the inner descriptor address. q ends as the
+ 1692       value (scalars), the descriptor address (plain arrays), or the
+ 1693       element address (indexed); sfx marks the indexed form. *)
+ 1694    Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
+ 1695           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
+ 1696                                          (. VAR n, fn, mal: SymTab.Name;
+ 1697                                               cls: INTEGER;
+ 1698                                               ic: SymTab.TypeIndex;
+ 1699                                               curT, it, eT, bt:
+ 1700                                                 SymTab.TypeIndex;
+ 1701                                               iq, ql, qlo, qhi, qe:
+ 1702                                                 QbeGen.QVal;
+ 1703                                               lo, hi: INTEGER;
+ 1704                                               fo: INTEGER;
+ 1705                                               isOpen: BOOLEAN;
+ 1706                                               qb, cv: QbeGen.QVal; .)
+ 1707      = GetIdent<n>                       (. methCls := SymTab.InvalidType;
+ 1708                                             QbeGen.CopyOp(n, qn);
+ 1709                                             sfx := FALSE;
+ 1710                                             IF NOT SymTab.Lookup(n) THEN
+ 1711                                               (* a bare method name inside
+ 1712                                                  a CLASS IMPLEMENTATION
+ 1713                                                  is a sibling call on
+ 1714                                                  THIS *)
+ 1715                                               ic := SymTab.CurImplClass();
+ 1716                                               IF (ic #
+ 1717                                                  SymTab.InvalidType)
+ 1718    AND SymTab.MethodExists(ic, n) THEN
+ 1719                                                 sfx := FALSE;
+ 1720                                                 QbeGen.ThisBase(q);
+ 1721                                                 QbeGen.ArmRecv(q);
+ 1722                                                 methCls := ic;
+ 1723                                                 k := SymTab.KindProc;
+ 1724                                                 t := SymTab.InvalidType
+ 1725                                               ELSE
+ 1726                                                 SemError(201);
+ 1727                                                 t :=
+ 1728                                                   SymTab.InvalidType;
+ 1729                                                 k := -1;
+ 1730                                                 QbeGen.CopyOp("0", q)
+ 1731                                               END
+ 1732                                             ELSE
+ 1733                                               t := SymTab.SymType(n);
+ 1734                                               k := SymTab.SymKind(n);
+ 1735                                               IF k = SymTab.KindConst THEN
+ 1736                                                 IF SymTab.Equal(n,
+ 1737                                                    "TRUE") THEN
+ 1738                                                   t := SymTab.BoolType();
+ 1739                                                   QbeGen.CopyOp("1", q)
+ 1740                                                 ELSIF SymTab.Equal(n,
+ 1741                                                    "FALSE") THEN
+ 1742                                                   t := SymTab.BoolType();
+ 1743                                                   QbeGen.CopyOp("0", q)
+ 1744                                                 ELSIF SymTab.Equal(n,
+ 1745                                                    "NIL") THEN
+ 1746                                                   QbeGen.CopyOp("0", q)
+ 1747                                                 ELSE
+ 1748                                                   cls :=
+ 1749                                                     SymTab.ClassOf(t);
+ 1750                                                   IF (t #
+ 1751                                                       SymTab.InvalidType)
+ 1752   AND ((cls = SymTab.ClInt)
+ 1753                                                      OR (cls
+ 1754                                                          = SymTab.ClChar)
+ 1755                                                      OR (cls
+ 1756                                                          = SymTab.ClEnum)
+ 1757                                                      OR (cls
+ 1758                                                          = SymTab.ClReal)
+ 1759                                                      OR (cls
+ 1760                                                          = SymTab.ClLong)
+ 1761                                                      OR (cls
+ 1762                                                          = SymTab.ClNil)) THEN
+ 1763                                                     IF cls = SymTab.ClNil THEN
+ 1764                                                       QbeGen.CopyOp("0", q)
+ 1765                                                     ELSIF ((cls
+ 1766                                                         = SymTab.ClInt)
+ 1767                                                       OR (cls
+ 1768                                                         = SymTab.ClChar)
+ 1769                                                       OR (cls
+ 1770                                                         = SymTab.ClEnum)
+ 1771                                                       OR (cls
+ 1772                                                         = SymTab.ClLong))
+ 1773    AND SymTab.GetSymVal(n, cv)
+ 1774    AND QbeGen.IsImm(cv) THEN
+ 1775                                                       QbeGen.CopyOp(cv, q)
+ 1776                                                     ELSE
+ 1777                                                       QbeGen.LoadVar(n,
+ 1778                                                         cls = SymTab.ClReal,
+ 1779                                                         q)
+ 1780                                                     END
+ 1781                                                   ELSIF (cls = SymTab.ClArray)
+ 1782                                                      OR (cls = SymTab.ClRecord)
+ 1783                                                      OR (cls = SymTab.ClClass)
+ 1784                                                      OR (cls = SymTab.ClStr)
+ 1785                                                      OR (cls = SymTab.ClUStr) THEN
+ 1786                                                     (* aggregate constant:
+ 1787                                                        its value IS the
+ 1788                                                        descriptor address *)
+ 1789                                                     IF SymTab.GetSymVal(n, cv) THEN
+ 1790                                                       QbeGen.CopyOp(cv, q)
+ 1791                                                     ELSE
+ 1792                                                       QbeGen.CopyOp("0", q)
+ 1793                                                     END
+ 1794                                                   ELSE
+ 1795                                                     IF t #
+ 1796                                                        SymTab.InvalidType THEN
+ 1797                                                       SemError(230)
+ 1798                                                     END;
+ 1799                                                     QbeGen.CopyOp("0", q)
+ 1800                                                   END
  1801                                                 END
  1801                                                 END
- 1802                                               ELSE QbeGen.CopyOp("0", q);
- 1803                                                 IF k = SymTab.KindImport THEN
- 1804                                                   SemError(230)
- 1805                                                 ELSIF k =
- 1806                                                    SymTab.KindProc THEN
- 1807                                                   (* bare procedure name:
- 1808                                                      a following ArgList
- 1809                                                      makes it a call;
- 1810                                                      otherwise Fact
- 1811                                                      reports 230 *)
- 1812                                                 ELSE
- 1813                                                   IF k = SymTab.KindField THEN
- 1814                                                     IF QbeGen.TopWith(qb) THEN
- 1815                                                       fo :=
- 1816                                                         SymTab.FieldOffset(
- 1817                                                         SymTab.FieldOwner(n),
- 1818                                                         n);
- 1819                                                       QbeGen.FieldAddr(qb,
- 1820                                                         fo, q);
- 1821                                                       sfx := TRUE
- 1822                                                     ELSE SemError(230);
- 1823                                                       QbeGen.CopyOp("0", q)
- 1824                                                     END
- 1825                                                   END
- 1826                                                 END
- 1827                                               END
- 1828                                             END; .)
- 1829        { "[" Expr<it, iq>
- 1830                                          (. IF t = SymTab.InvalidType THEN
- 1831                                             ELSIF SymTab.ClassOf(t) #
- 1832                                                   SymTab.ClArray THEN
- 1833                                               SemError(217);
- 1834                                               t := SymTab.InvalidType
- 1835                                             ELSIF NOT SymTab.IsIntFamily(it)
- 1836   AND (SymTab.ClassOf(it) #
- 1837                                                   SymTab.ClChar)
- 1838   AND (SymTab.ClassOf(it) #
- 1839                                                   SymTab.ClEnum) THEN
- 1840                                               SemError(218);
- 1841                                               t := SymTab.InvalidType
- 1842                                             ELSE
- 1843                                               QbeGen.WidenIndex(iq, ql);
- 1844                                               isOpen :=
- 1845                                                 SymTab.IsOpenArray(t);
- 1846                                               IF isOpen THEN
- 1847                                                 QbeGen.CopyOp("0", qlo);
- 1848                                                 IF SymTab.IsCharArray(t)
- 1849    OR SymTab.IsUCharArray(t) THEN
- 1850                                                   QbeGen.OpenHiChar(q, qhi)
- 1851                                                 ELSE QbeGen.OpenHi(q, qhi)
- 1852                                                 END
- 1853                                               ELSE
- 1854                                                 lo := SymTab.ArrayLo(t);
- 1855                                                 hi := SymTab.ArrayHi(t);
- 1856                                                 IF SymTab.IsCharArray(t)
- 1857    OR SymTab.IsUCharArray(t) THEN
- 1858                                                   hi := hi + 1
- 1859                                                 END;
- 1860                                                 QbeGen.IntStr(lo, qlo);
- 1861                                                 QbeGen.IntStr(hi, qhi)
- 1862                                               END;
- 1863                                               QbeGen.CheckRange(ql, qlo,
- 1864                                                 qhi);
- 1865                                               eT := SymTab.ArrayElem(t);
- 1866                                               QbeGen.ElemAddr(q, ql, qlo,
- 1867                                                 t, qe);
- 1868                                               IF SymTab.ClassOf(eT) =
- 1869                                                  SymTab.ClArray THEN
- 1870                                                 QbeGen.ElemLoad(qe, eT, q)
- 1871                                               ELSE QbeGen.CopyOp(qe, q)
- 1872                                               END;
- 1873                                               t := eT; sfx := TRUE
- 1874                                             END; .)
- 1875          { "," Expr<it, iq>
- 1876                                          (. IF t = SymTab.InvalidType THEN
- 1877                                             ELSIF SymTab.ClassOf(t) #
- 1878                                                   SymTab.ClArray THEN
- 1879                                               SemError(217);
- 1880                                               t := SymTab.InvalidType
- 1881                                             ELSIF NOT SymTab.IsIntFamily(it)
- 1882   AND (SymTab.ClassOf(it) #
- 1883                                                   SymTab.ClChar)
- 1884   AND (SymTab.ClassOf(it) #
- 1885                                                   SymTab.ClEnum) THEN
- 1886                                               SemError(218);
- 1887                                               t := SymTab.InvalidType
- 1888                                             ELSE
- 1889                                               QbeGen.WidenIndex(iq, ql);
- 1890                                               isOpen :=
- 1891                                                 SymTab.IsOpenArray(t);
- 1892                                               IF isOpen THEN
- 1893                                                 QbeGen.CopyOp("0", qlo);
- 1894                                                 IF SymTab.IsCharArray(t)
- 1895    OR SymTab.IsUCharArray(t) THEN
- 1896                                                   QbeGen.OpenHiChar(q, qhi)
- 1897                                                 ELSE QbeGen.OpenHi(q, qhi)
- 1898                                                 END
- 1899                                               ELSE
- 1900                                                 lo := SymTab.ArrayLo(t);
- 1901                                                 hi := SymTab.ArrayHi(t);
- 1902                                                 IF SymTab.IsCharArray(t)
- 1903    OR SymTab.IsUCharArray(t) THEN
- 1904                                                   hi := hi + 1
- 1905                                                 END;
- 1906                                                 QbeGen.IntStr(lo, qlo);
- 1907                                                 QbeGen.IntStr(hi, qhi)
- 1908                                               END;
- 1909                                               QbeGen.CheckRange(ql, qlo,
- 1910                                                 qhi);
- 1911                                               eT := SymTab.ArrayElem(t);
- 1912                                               QbeGen.ElemAddr(q, ql, qlo,
- 1913                                                 t, qe);
- 1914                                               IF SymTab.ClassOf(eT) =
- 1915                                                  SymTab.ClArray THEN
- 1916                                                 QbeGen.ElemLoad(qe, eT, q)
- 1917                                               ELSE QbeGen.CopyOp(qe, q)
- 1918                                               END;
- 1919                                               t := eT; sfx := TRUE
- 1920                                             END; .) }
- 1921          "]"
- 1922        | "." GetIdent<fn>
- 1923                                          (. IF k = SymTab.KindModule THEN
- 1924                                               (* qualified L.x: materialize
- 1925                                                  the export, then load it *)
- 1926                                               IF NOT SymTab.MaterializeAlias(n,
- 1927                                                    fn, mal) THEN
- 1928                                                 SemError(201);
- 1929                                                 t := SymTab.InvalidType;
- 1930                                                 QbeGen.CopyOp("0", q)
+ 1802                                               ELSIF (k = SymTab.KindVar)
+ 1803                                                  OR (k = SymTab.KindParam) THEN
+ 1804                                                 cls :=
+ 1805                                                   SymTab.ClassOf(t);
+ 1806                                                 IF (cls = SymTab.ClInt)
+ 1807                                                    OR (cls = SymTab.ClBool)
+ 1808                                                    OR (cls = SymTab.ClChar)
+ 1809                                                    OR (cls = SymTab.ClUChar)
+ 1810                                                    OR (cls = SymTab.ClEnum)
+ 1811                                                    OR (cls
+ 1812                                                        = SymTab.ClReal) THEN
+ 1813                                                   QbeGen.LoadVar(n,
+ 1814                                                     cls = SymTab.ClReal, q)
+ 1815                                                 ELSIF (cls = SymTab.ClPtr)
+ 1816                                                    OR (cls = SymTab.ClProc) THEN
+ 1817                                                   QbeGen.LoadPtr(n, q)
+ 1818                                                 ELSIF cls = SymTab.ClLong THEN
+ 1819                                                   QbeGen.LoadLong(n, q)
+ 1820                                                 ELSIF (cls
+ 1821                                                         = SymTab.ClArray)
+ 1822                                                    OR (cls
+ 1823                                                        = SymTab.ClSet)
+ 1824                                                    OR (cls
+ 1825                                                        = SymTab.ClRecord)
+ 1826                                                    OR (cls
+ 1827                                                        = SymTab.ClUStr)
+ 1828                                                    OR (cls
+ 1829                                                        = SymTab.ClClass) THEN
+ 1830                                                   QbeGen.AddrOf(n, q)
+ 1831                                                 ELSE SemError(230);
+ 1832                                                   QbeGen.CopyOp("0", q)
+ 1833                                                 END
+ 1834                                               ELSE QbeGen.CopyOp("0", q);
+ 1835                                                 IF k = SymTab.KindImport THEN
+ 1836                                                   SemError(230)
+ 1837                                                 ELSIF k =
+ 1838                                                    SymTab.KindProc THEN
+ 1839                                                   (* bare procedure name:
+ 1840                                                      a following ArgList
+ 1841                                                      makes it a call;
+ 1842                                                      otherwise Fact
+ 1843                                                      reports 230 *)
+ 1844                                                 ELSE
+ 1845                                                   IF k = SymTab.KindField THEN
+ 1846                                                     IF QbeGen.TopWith(qb) THEN
+ 1847                                                       fo :=
+ 1848                                                         SymTab.FieldOffset(
+ 1849                                                         SymTab.FieldOwner(n),
+ 1850                                                         n);
+ 1851                                                       QbeGen.FieldAddr(qb,
+ 1852                                                         fo, q);
+ 1853                                                       sfx := TRUE
+ 1854                                                     ELSE SemError(230);
+ 1855                                                       QbeGen.CopyOp("0", q)
+ 1856                                                     END
+ 1857                                                   END
+ 1858                                                 END
+ 1859                                               END
+ 1860                                             END; .)
+ 1861        { "[" Expr<it, iq>
+ 1862                                          (. IF t = SymTab.InvalidType THEN
+ 1863                                             ELSIF SymTab.ClassOf(t) #
+ 1864                                                   SymTab.ClArray THEN
+ 1865                                               SemError(217);
+ 1866                                               t := SymTab.InvalidType
+ 1867                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 1868   AND (SymTab.ClassOf(it) #
+ 1869                                                   SymTab.ClChar)
+ 1870   AND (SymTab.ClassOf(it) #
+ 1871                                                   SymTab.ClEnum) THEN
+ 1872                                               SemError(218);
+ 1873                                               t := SymTab.InvalidType
+ 1874                                             ELSE
+ 1875                                               QbeGen.WidenIndex(iq, ql);
+ 1876                                               isOpen :=
+ 1877                                                 SymTab.IsOpenArray(t);
+ 1878                                               IF isOpen THEN
+ 1879                                                 QbeGen.CopyOp("0", qlo);
+ 1880                                                 IF SymTab.IsCharArray(t)
+ 1881    OR SymTab.IsUCharArray(t) THEN
+ 1882                                                   QbeGen.OpenHiChar(q, qhi)
+ 1883                                                 ELSE QbeGen.OpenHi(q, qhi)
+ 1884                                                 END
+ 1885                                               ELSE
+ 1886                                                 lo := SymTab.ArrayLo(t);
+ 1887                                                 hi := SymTab.ArrayHi(t);
+ 1888                                                 IF SymTab.IsCharArray(t)
+ 1889    OR SymTab.IsUCharArray(t) THEN
+ 1890                                                   hi := hi + 1
+ 1891                                                 END;
+ 1892                                                 QbeGen.IntStr(lo, qlo);
+ 1893                                                 QbeGen.IntStr(hi, qhi)
+ 1894                                               END;
+ 1895                                               QbeGen.CheckRange(ql, qlo,
+ 1896                                                 qhi);
+ 1897                                               eT := SymTab.ArrayElem(t);
+ 1898                                               QbeGen.ElemAddr(q, ql, qlo,
+ 1899                                                 t, qe);
+ 1900                                               IF SymTab.ClassOf(eT) =
+ 1901                                                  SymTab.ClArray THEN
+ 1902                                                 QbeGen.ElemLoad(qe, eT, q)
+ 1903                                               ELSE QbeGen.CopyOp(qe, q)
+ 1904                                               END;
+ 1905                                               t := eT; sfx := TRUE
+ 1906                                             END; .)
+ 1907          { "," Expr<it, iq>
+ 1908                                          (. IF t = SymTab.InvalidType THEN
+ 1909                                             ELSIF SymTab.ClassOf(t) #
+ 1910                                                   SymTab.ClArray THEN
+ 1911                                               SemError(217);
+ 1912                                               t := SymTab.InvalidType
+ 1913                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 1914   AND (SymTab.ClassOf(it) #
+ 1915                                                   SymTab.ClChar)
+ 1916   AND (SymTab.ClassOf(it) #
+ 1917                                                   SymTab.ClEnum) THEN
+ 1918                                               SemError(218);
+ 1919                                               t := SymTab.InvalidType
+ 1920                                             ELSE
+ 1921                                               QbeGen.WidenIndex(iq, ql);
+ 1922                                               isOpen :=
+ 1923                                                 SymTab.IsOpenArray(t);
+ 1924                                               IF isOpen THEN
+ 1925                                                 QbeGen.CopyOp("0", qlo);
+ 1926                                                 IF SymTab.IsCharArray(t)
+ 1927    OR SymTab.IsUCharArray(t) THEN
+ 1928                                                   QbeGen.OpenHiChar(q, qhi)
+ 1929                                                 ELSE QbeGen.OpenHi(q, qhi)
+ 1930                                                 END
  1931                                               ELSE
  1931                                               ELSE
- 1932                                                 QbeGen.CopyOp(mal, qn);
- 1933                                                 t := SymTab.SymType(mal);
- 1934                                                 k := SymTab.SymKind(mal);
- 1935                                                 sfx := FALSE;
- 1936                                                 IF k = SymTab.KindProc THEN
- 1937                                                   (* call: ArgList supplies
- 1938                                                      the value *)
- 1939                                                   QbeGen.CopyOp("0", q)
- 1940                                                 ELSIF NOT QbeGen.LoadDesignator(
- 1941                                                      mal, t, k, q) THEN
- 1942                                                   SemError(230);
- 1943                                                   QbeGen.CopyOp("0", q)
- 1944                                                 END
- 1945                                               END
- 1946                                             ELSIF t = SymTab.InvalidType THEN
- 1947                                             ELSIF (SymTab.ClassOf(t) #
- 1948                                                    SymTab.ClRecord)
- 1949   AND (SymTab.ClassOf(t) #
- 1950                                                   SymTab.ClClass) THEN
- 1951                                               SemError(215);
- 1952                                               t := SymTab.InvalidType
- 1953                                             ELSIF (SymTab.ClassOf(t) =
- 1954                                                    SymTab.ClClass)
- 1955    AND SymTab.MethodExists(t, fn) THEN
- 1956                                               (* obj.Method: bind the
- 1957                                                  method and pass obj as
- 1958                                                  the hidden receiver; q
- 1959                                                  already holds the
- 1960                                                  object's address *)
- 1961                                               QbeGen.ArmRecv(q);
- 1962                                               QbeGen.CopyOp(fn, n);
- 1963                                               QbeGen.CopyOp(fn, qn);
- 1964                                               methCls := t;
- 1965                                               k := SymTab.KindProc;
- 1966                                               t := SymTab.InvalidType
- 1967                                             ELSIF NOT SymTab.FieldExists(t,
- 1968                                                      fn) THEN
- 1969                                               SemError(216);
- 1970                                               t := SymTab.InvalidType
- 1971                                             ELSE
- 1972                                               fo := SymTab.FieldOffset(t,
- 1973                                                 fn);
- 1974                                               t := SymTab.FieldType(t, fn);
- 1975                                               QbeGen.FieldAddr(q, fo, qe);
- 1976                                               (* array fields are inline:
- 1977                                                  the field address is the
- 1978                                                  descriptor, like records *)
- 1979                                               QbeGen.CopyOp(qe, q);
- 1980                                               sfx := TRUE
- 1981                                             END; .)
- 1982        | "^"
- 1983                                          (. IF t = SymTab.InvalidType THEN
- 1984                                             ELSIF SymTab.ClassOf(t) #
- 1985                                                   SymTab.ClPtr THEN
- 1986                                               SemError(219);
- 1987                                               t := SymTab.InvalidType
- 1988                                             ELSE
- 1989                                               bt := SymTab.PtrBase(t);
- 1990                                               IF bt = SymTab.InvalidType THEN
- 1991                                               ELSE
- 1992                                                 IF sfx THEN
- 1993                                                   QbeGen.ElemLoad(q, t,
- 1994                                                     qb);
- 1995                                                   QbeGen.CopyOp(qb, q)
- 1996                                                 END;
- 1997                                                 t := bt;
- 1998                                                 (* q holds the pointee
- 1999                                                    address: Fact loads
- 2000                                                    scalars/pointers and uses
- 2001                                                    the address for
- 2002                                                    aggregates; the VAR-actual
- 2003                                                    note is q itself. *)
- 2004                                                 sfx := TRUE
- 2005                                               END
- 2006                                             END; .) } .
- 2007    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2008                                          (. VAR t2: SymTab.TypeIndex;
- 2009                                               op: INTEGER;
- 2010                                               q2, qt, wl: QbeGen.QVal;
- 2011                                               isR: BOOLEAN; .)
- 2012      = SimExpr<t, q>
- 2013        [ Rel<op> SimExpr<t2, q2>
- 2014          (. IF op = SymTab.OpIn THEN
- 2015               IF SymTab.InCheck(t, t2) THEN
- 2016                 IF (t = SymTab.InvalidType)
- 2017                    OR (t2 = SymTab.InvalidType) THEN
- 2018                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 2019                 ELSE
- 2020                   QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2),
- 2021                     SymTab.SetCount(t2), qt);
- 2022                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 2023                 END
- 2024               ELSE SemError(222); t := SymTab.InvalidType;
- 2025                 QbeGen.CopyOp("0", q)
- 2026               END
- 2027             ELSIF SymTab.RelCheck(t, t2, op) THEN
- 2028               IF (t = SymTab.InvalidType)
- 2029                  OR (t2 = SymTab.InvalidType) THEN
- 2030                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 2031               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
- 2032                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
- 2033                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
- 2034   AND (op # SymTab.OpNeq2) THEN
- 2035                   SemError(213); t := SymTab.InvalidType;
- 2036                   QbeGen.CopyOp("0", q)
- 2037                 ELSE
- 2038                   QbeGen.CmpL(op, q, q2, qt);
- 2039                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 2040                 END
- 2041               ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
- 2042                  OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 2043                 QbeGen.CmpSet(op, q, q2,
- 2044                   SymTab.SetWords(t), SymTab.SetWords(t2), qt);
- 2045                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 2046               ELSIF SymTab.StrCompat(t, t2) THEN
- 2047                 QbeGen.StrEq(op, q, q2, qt);
- 2048                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 2049               ELSIF SymTab.IsLongFamily(t)
- 2050                  OR SymTab.IsLongFamily(t2) THEN
- 2051                 IF SymTab.IsIntFamily(t) THEN
- 2052                   QbeGen.WidenLong(q, wl); QbeGen.CopyOp(wl, q)
- 2053                 END;
- 2054                 IF SymTab.IsIntFamily(t2) THEN
- 2055                   QbeGen.WidenLong(q2, wl); QbeGen.CopyOp(wl, q2)
- 2056                 END;
- 2057                 QbeGen.CmpLong(op, q, q2, qt);
- 2058                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 2059               ELSE
- 2060                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 2061                 t := SymTab.BoolType();
- 2062                 QbeGen.Cmp(op, q, q2, qt, isR);
- 2063                 QbeGen.CopyOp(qt, q)
- 2064               END
- 2065             ELSE SemError(213); t := SymTab.InvalidType;
- 2066               QbeGen.CopyOp("0", q)
- 2067             END; .) ] .
- 2068    Rel<VAR op: INTEGER>
- 2069      = "="                               (. op := SymTab.OpEq; .)
- 2070      | "#"                               (. op := SymTab.OpNeq1; .)
- 2071      | "<"                               (. op := SymTab.OpLt; .)
- 2072      | "<="                              (. op := SymTab.OpLe; .)
- 2073      | ">"                               (. op := SymTab.OpGt; .)
- 2074      | ">="                              (. op := SymTab.OpGe; .)
- 2075      | "IN"                              (. op := SymTab.OpIn; .) .
- 2076    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2077                                          (. VAR t2, res2, lt, rt:
- 2078                                                 SymTab.TypeIndex;
- 2079                                               op: INTEGER;
- 2080                                               q2, qt, wq, qf, q2a, q2b:
- 2081                                                 QbeGen.QVal;
- 2082                                               neg, isR, isL, folded:
- 2083                                                 BOOLEAN;
- 2084                                               fok: BOOLEAN;
- 2085                                               lw, rw, mw: CARDINAL;
- 2086                                               lTrue, lNext, lDone, qr, qs:
- 2087                                                 QbeGen.QVal; .)
- 2088      =                                   (. neg := FALSE; .)
- 2089        [ "+" | "-"                       (. neg := TRUE; .) ]
- 2090        Term<t, q>                        (. IF neg THEN
- 2091                                             IF QbeGen.IsImm(q) THEN
- 2092                                               QbeGen.NegFold(q, q)
- 2093                                             ELSE QbeGen.NewTemp(qt);
- 2094                                               QbeGen.NegQ(q, qt,
- 2095                                                 SymTab.ClassOf(t)
- 2096                                                 = SymTab.ClReal);
- 2097                                               QbeGen.CopyOp(qt, q)
- 2098                                             END
- 2099                                           END; .)
- 2100        { AddOp<op>                       (. IF op = SymTab.OpOr THEN
- 2101                                               QbeGen.DelayBegin END; .)
- 2102          Term<t2, q2>                     (. IF op = SymTab.OpOr THEN
- 2103                                               QbeGen.DelayEnd END; .)
- 2104          (. IF op = SymTab.OpOr THEN
- 2105               (* short-circuit: if q is true the RHS is skipped *)
- 2106               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 2107                 t := SymTab.BoolType()
- 2108               ELSE SemError(212); t := SymTab.InvalidType END;
- 2109               IF t # SymTab.InvalidType THEN
- 2110                 QbeGen.Slot4(qs);
- 2111                 QbeGen.NewLabel(lTrue);
- 2112                 QbeGen.NewLabel(lNext);
- 2113                 QbeGen.NewLabel(lDone);
- 2114                 QbeGen.Jnz(q, lTrue, lNext);
- 2115                 QbeGen.EmitLabel(lTrue);
- 2116                 QbeGen.StoreW(qs, "1");
- 2117                 QbeGen.Jmp(lDone);
- 2118                 QbeGen.EmitLabel(lNext);
- 2119                 QbeGen.DelayFlush;
- 2120                 QbeGen.StoreW(qs, q2);
- 2121                 QbeGen.Jmp(lDone);
- 2122                 QbeGen.EmitLabel(lDone);
- 2123                 QbeGen.LoadW(qs, qr);
- 2124                 QbeGen.CopyOp(qr, q)
- 2125               ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
- 2126               END
- 2127             ELSIF (op = SymTab.OpAdd)
- 2128               AND (SymTab.UStrCompat(t, t2)
- 2129                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
- 2130                   AND (SymTab.ClassOf(t2) = SymTab.ClUStr))
- 2131                 OR ((SymTab.ClassOf(t) = SymTab.ClUStr)
- 2132                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))
- 2133                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
- 2134                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN
- 2135               (* UString concatenation: a UCHAR operand becomes a
- 2136                  1-codepoint UString; the result is a descriptor in the
- 2137                  shim's concat buffer.  Work on copies so neither
- 2138                  operand is clobbered. *)
- 2139               IF SymTab.ClassOf(t) = SymTab.ClUStr THEN
- 2140                 QbeGen.CopyOp(q, q2a)
- 2141               ELSE
- 2142                 QbeGen.UStrFrom(q, q2a)
- 2143               END;
- 2144               IF SymTab.ClassOf(t2) = SymTab.ClUStr THEN
- 2145                 QbeGen.UStrCat(q2a, q2, qt)
- 2146               ELSE
- 2147                 QbeGen.UStrFrom(q2, q2b);
- 2148                 QbeGen.UStrCat(q2a, q2b, qt)
- 2149               END;
- 2150               t := SymTab.NewUStr();
- 2151               QbeGen.CopyOp(qt, q)
- 2152             ELSIF (op = SymTab.OpAdd)
- 2153               AND (SymTab.StrCompat(t, t2)
- 2154                 OR (SymTab.IsStrType(t)
- 2155                   AND (SymTab.ClassOf(t2) = SymTab.ClChar))
- 2156                 OR ((SymTab.ClassOf(t) = SymTab.ClChar)
- 2157                   AND SymTab.IsStrType(t2))) THEN
- 2158               (* string concatenation; a CHAR operand becomes a
- 2159                  1-character string literal.  When both operands are
- 2160                  constants, fold to a single string literal so a
- 2161                  constructor element stays compile-time. *)
- 2162               QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2),
- 2163                 qt, fok);
- 2164               IF NOT fok THEN
- 2165                 IF SymTab.StrCompat(t, t2) THEN
- 2166                   QbeGen.StrCat(q, q2, qt)
- 2167                 ELSIF SymTab.IsStrType(t) THEN
- 2168                   QbeGen.DeclCharStr(q2, qs);
- 2169                   QbeGen.StrCat(q, qs, qt)
- 2170                 ELSE
- 2171                   QbeGen.DeclCharStr(q, qs);
- 2172                   QbeGen.StrCat(qs, q2, qt)
- 2173                 END
- 2174               END;
- 2175               t := SymTab.NewStr();
- 2176               QbeGen.CopyOp(qt, q)
- 2177             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 2178   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 2179   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 2180               lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 2181               mw := lw;
- 2182               IF rw > mw THEN mw := rw END;
- 2183               IF op = SymTab.OpAdd THEN
- 2184                 QbeGen.SetBinOp(0, q, q2, lw, rw, qt)
- 2185               ELSE
- 2186                 QbeGen.SetBinOp(2, q, q2, lw, rw, qt)
- 2187               END;
- 2188               t := SymTab.NewSet(
- 2189                      SymTab.NewSubR(0,
- 2190                        VAL(INTEGER, mw) * 32 - 1));
- 2191               QbeGen.CopyOp(qt, q)
- 2192             ELSE
- 2193               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
- 2194                 lt := t; rt := t2; t := res2
- 2195               ELSE SemError(211); t := SymTab.InvalidType END;
- 2196               IF t # SymTab.InvalidType THEN
- 2197                 isL := SymTab.IsLongFamily(t);
- 2198                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 2199                 folded := FALSE;
- 2200                 IF (NOT isL) AND (NOT isR)
- 2201    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 2202                   IF op = SymTab.OpAdd THEN
- 2203                     folded := QbeGen.Fold2(0, q, q2, qf)
- 2204                   ELSE
- 2205                     folded := QbeGen.Fold2(1, q, q2, qf)
- 2206                   END
- 2207                 END;
- 2208                 IF folded THEN QbeGen.CopyOp(qf, q)
- 2209                 ELSE
- 2210                 IF isL THEN
- 2211                   IF SymTab.IsIntFamily(lt) THEN
- 2212                     QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
- 2213                   END;
- 2214                   IF SymTab.IsIntFamily(rt) THEN
- 2215                     QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
- 2216                   END;
- 2217                   QbeGen.NewTemp(qt);
- 2218                   IF op = SymTab.OpAdd THEN
- 2219                     QbeGen.Op3L("add", qt, q, q2)
- 2220                   ELSE
- 2221                     QbeGen.Op3L("sub", qt, q, q2)
- 2222                   END
- 2223                 ELSE
- 2224                   QbeGen.NewTemp(qt);
- 2225                   IF op = SymTab.OpAdd THEN
- 2226                     QbeGen.Op3("add", qt, q, q2, isR)
- 2227                   ELSE
- 2228                     QbeGen.Op3("sub", qt, q, q2, isR)
- 2229                   END
- 2230                 END;
- 2231                 QbeGen.CopyOp(qt, q)
- 2232                 END
- 2233               ELSE QbeGen.CopyOp("0", q)
- 2234               END
- 2235             END; .) } .
- 2236    AddOp<VAR op: INTEGER>
- 2237      = "+"                               (. op := SymTab.OpAdd; .)
- 2238      | "-"                               (. op := SymTab.OpSub; .)
- 2239      | "OR"                              (. op := SymTab.OpOr; .) .
- 2240    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2241                                          (. VAR t2, res2, lt, rt:
- 2242                                                 SymTab.TypeIndex;
- 2243                                               op: INTEGER;
- 2244                                               q2, qt, wq, qf:
- 2245                                                 QbeGen.QVal;
- 2246                                               isR, isL, folded: BOOLEAN;
- 2247                                               lw, rw, mw: CARDINAL;
- 2248                                               lNext, lFalse, lDone, qr, qs:
- 2249                                                 QbeGen.QVal; .)
- 2250      = Fact<t, q> { MulOp<op>            (. IF op = SymTab.OpAnd THEN
- 2251                                               QbeGen.DelayBegin END; .)
- 2252          Fact<t2, q2>                    (. IF op = SymTab.OpAnd THEN
- 2253                                               QbeGen.DelayEnd END; .)
- 2254        (. IF op = SymTab.OpAnd THEN
- 2255             (* short-circuit: if q is false the RHS is skipped *)
- 2256             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 2257               t := SymTab.BoolType()
- 2258             ELSE SemError(212); t := SymTab.InvalidType END;
- 2259             IF t # SymTab.InvalidType THEN
- 2260               QbeGen.Slot4(qs);
- 2261               QbeGen.NewLabel(lNext);
- 2262               QbeGen.NewLabel(lFalse);
- 2263               QbeGen.NewLabel(lDone);
- 2264               QbeGen.Jnz(q, lNext, lFalse);
- 2265               QbeGen.EmitLabel(lNext);
- 2266               QbeGen.DelayFlush;
- 2267               QbeGen.StoreW(qs, q2);
- 2268               QbeGen.Jmp(lDone);
- 2269               QbeGen.EmitLabel(lFalse);
- 2270               QbeGen.StoreW(qs, "0");
- 2271               QbeGen.Jmp(lDone);
- 2272               QbeGen.EmitLabel(lDone);
- 2273               QbeGen.LoadW(qs, qr);
- 2274               QbeGen.CopyOp(qr, q)
- 2275             ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
- 2276             END
- 2277           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 2278   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 2279   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 2280             lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 2281             mw := lw;
- 2282             IF rw > mw THEN mw := rw END;
- 2283             IF op = SymTab.OpTimes THEN
- 2284               QbeGen.SetBinOp(1, q, q2, lw, rw, qt)
- 2285             ELSE
- 2286               QbeGen.SetBinOp(3, q, q2, lw, rw, qt)
- 2287             END;
- 2288             t := SymTab.NewSet(
- 2289                    SymTab.NewSubR(0,
- 2290                      VAL(INTEGER, mw) * 32 - 1));
- 2291             QbeGen.CopyOp(qt, q)
- 2292           ELSE
- 2293             IF SymTab.ArithCheck(t, t2,
- 2294                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
- 2295                  res2) THEN
- 2296               lt := t; rt := t2; t := res2
- 2297             ELSE SemError(211); t := SymTab.InvalidType END;
- 2298             IF t # SymTab.InvalidType THEN
- 2299               isL := SymTab.IsLongFamily(t);
- 2300               isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 2301               folded := FALSE;
- 2302               IF (NOT isL) AND (NOT isR)
- 2303    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 2304                 IF op = SymTab.OpTimes THEN
- 2305                   folded := QbeGen.Fold2(2, q, q2, qf)
- 2306                 ELSIF op = SymTab.OpDiv THEN
- 2307                   folded := QbeGen.Fold2(3, q, q2, qf)
- 2308                 ELSIF op = SymTab.OpMod THEN
- 2309                   folded := QbeGen.Fold2(4, q, q2, qf)
- 2310                 END
- 2311               END;
- 2312               IF folded THEN QbeGen.CopyOp(qf, q)
- 2313               ELSE
- 2314               IF isL THEN
- 2315                 IF SymTab.IsIntFamily(lt) THEN
- 2316                   QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
- 2317                 END;
- 2318                 IF SymTab.IsIntFamily(rt) THEN
- 2319                   QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
- 2320                 END;
- 2321                 QbeGen.NewTemp(qt);
- 2322                 IF op = SymTab.OpTimes THEN
- 2323                   QbeGen.Op3L("mul", qt, q, q2)
- 2324                 ELSIF (op = SymTab.OpDiv)
- 2325                    OR (op = SymTab.OpSlash) THEN
- 2326                   QbeGen.Op3L("div", qt, q, q2)
- 2327                 ELSE
- 2328                   QbeGen.Op3L("rem", qt, q, q2)
- 2329                 END
- 2330               ELSE
- 2331                 QbeGen.NewTemp(qt);
- 2332                 IF op = SymTab.OpTimes THEN
- 2333                   QbeGen.Op3("mul", qt, q, q2, isR)
- 2334                 ELSIF (op = SymTab.OpDiv)
- 2335                    OR (op = SymTab.OpSlash) THEN
- 2336                   QbeGen.Op3("div", qt, q, q2, isR)
- 2337                 ELSE
- 2338                   QbeGen.Op3("rem", qt, q, q2, isR)
- 2339                 END
- 2340               END;
- 2341               QbeGen.CopyOp(qt, q)
- 2342               END
- 2343             ELSE QbeGen.CopyOp("0", q)
- 2344             END
- 2345           END; .) } .
- 2346    MulOp<VAR op: INTEGER>
- 2347      = "*"                               (. op := SymTab.OpTimes; .)
- 2348      | "/"                               (. op := SymTab.OpSlash; .)
- 2349      | "DIV"                             (. op := SymTab.OpDiv; .)
- 2350      | "MOD"                             (. op := SymTab.OpMod; .)
- 2351      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
- 2352    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2353                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
- 2354                                               et, dt, t2, st, ct2, et2:
- 2355                                                 SymTab.TypeIndex;
- 2356                                               dk: INTEGER;
- 2357                                               qd, q2, sq, qa, qm0, qr, qt:
- 2358                                                 QbeGen.QVal;
- 2359                                               qn, vn: SymTab.Name;
- 2360                                               vt: SymTab.TypeIndex;
- 2361                                               c1, c2: INTEGER;
- 2362                                               lo, hi: INTEGER;
- 2363                                               isMax: BOOLEAN;
- 2364                                               called, isHigh, sfx, isCh,
- 2365                                               isU, uok, isStr: BOOLEAN;
- 2366                                               ucp: INTEGER; .)
- 2367      = integer                           (. LexString(s);
- 2368                                             QbeGen.NormInt(s, q);
- 2369                                             t := SymTab.IntType(); .)
- 2370      | charConst                         (. LexString(s);
- 2371                                             QbeGen.NormLit(s, q, isCh);
- 2372                                             t := SymTab.CharType(); .)
- 2373      | real                              (. LexString(s);
- 2374                                             QbeGen.NormReal(s, q);
- 2375                                             t := SymTab.RealType(); .)
- 2376      | string                            (. LexString(s);
- 2377                                             IF SymTab.StrLen(s) = 3 THEN
- 2378                                               t := SymTab.CharType();
- 2379                                               QbeGen.IntStr(
- 2380                                                 QbeGen.CharVal(s), q)
- 2381                                             ELSE t := SymTab.NewStr();
- 2382                                               QbeGen.DeclStr(s, q);
- 2383                                               (* a literal's value IS its
- 2384                                                  static descriptor address *)
- 2385                                               QbeGen.NoteAddr(q, q)
- 2386                                             END; .)
- 2387      | ustring                           (. LexString(s);
- 2388                                             QbeGen.DeclUStr(s, q, isU, ucp,
- 2389                                               uok);
- 2390                                             IF NOT uok THEN
- 2391                                               SemError(234);
- 2392                                               t := SymTab.InvalidType
- 2393                                             ELSIF isU THEN
- 2394                                               t := SymTab.UCharType();
- 2395                                               QbeGen.IntStr(ucp, q)
- 2396                                             ELSE
- 2397                                               t := SymTab.NewUStr();
- 2398                                               QbeGen.NoteAddr(q, q)
- 2399                                             END; .)
- 2400      | Design<dt, dk, qd, qn, sfx>       (. called := FALSE;
- 2401                                             t := dt;
- 2402                                             IF sfx THEN
- 2403                                               IF dt =
- 2404                                                  SymTab.InvalidType THEN
- 2405                                                 QbeGen.CopyOp("0", q)
- 2406                                               ELSIF (SymTab.ClassOf(dt) =
- 2407                                                      SymTab.ClRecord)
- 2408                                                  OR (SymTab.ClassOf(dt) =
- 2409                                                      SymTab.ClSet)
- 2410                                                  OR (SymTab.ClassOf(dt) =
- 2411                                                      SymTab.ClArray)
- 2412                                                  OR (SymTab.ClassOf(dt) =
- 2413                                                      SymTab.ClClass) THEN
- 2414                                                 QbeGen.CopyOp(qd, q)
- 2415                                               ELSE QbeGen.ElemLoad(qd, dt,
- 2416                                                 q)
- 2417                                               END
- 2418                                             ELSE QbeGen.CopyOp(qd, q)
- 2419                                             END;
- 2420                                             IF (dk = SymTab.KindVar)
- 2421                                                OR (dk = SymTab.KindParam)
- 2422                                                OR (dk =
- 2423                                                   SymTab.KindField) THEN
- 2424                                               IF sfx THEN
- 2425                                                 QbeGen.NoteAddr(q, qd)
- 2426                                               ELSE
- 2427                                                 QbeGen.AddrOf(qn, qa);
- 2428                                                 QbeGen.NoteAddr(q, qa)
- 2429                                               END
- 2430                                             ELSIF sfx
- 2431   AND (dt #
- 2432                                                   SymTab.InvalidType)
- 2433   AND ((SymTab.ClassOf(dt) =
- 2434                                                    SymTab.ClArray)
- 2435                                                   OR (SymTab.ClassOf(dt) =
- 2436                                                       SymTab.ClSet)
- 2437                                                   OR (SymTab.ClassOf(dt) =
- 2438                                                       SymTab.ClRecord)) THEN
- 2439                                               QbeGen.NoteAddr(qd, qd)
- 2440                                             END; .)
- 2441        [ TypedBraceLit<dt, q>            (. t := dt; .) ]
- 2442        [ ArgList<qn, dt, qd, TRUE, methCls, ct2, q2, called>
- 2443                                          (. t := ct2;
- 2444                                             QbeGen.CopyOp(q2, q); .) ]
- 2445                                          (. IF NOT called
- 2446   AND (dk = SymTab.KindProc) THEN
- 2447                                               (* bare zero-arg function
- 2448                                                  call (parentheses may be
- 2449                                                  omitted); a proper or
- 2450                                                  parameterised proc here
- 2451                                                  is 230 *)
- 2452                                               IF (SymTab.ProcNPar(qn) = 0)
- 2453   AND (SymTab.ProcRes(qn) #
- 2454                                                     SymTab.InvalidType) THEN
- 2455                                                 QbeGen.Mangled(qn,
- 2456                                                   SymTab.ProcUid(qn), qm0);
- 2457                                                 QbeGen.CallBegin(qm0,
- 2458                                                   SymTab.ProcRes(qn),
- 2459                                                   SymTab.ProcDepthOf(qn),
- 2460                                                   SymTab.IsExternal(qn));
- 2461                                                 QbeGen.CallEnd(TRUE, q);
- 2462                                                 t := SymTab.ProcRes(qn)
- 2463                                               ELSE
- 2464                                                 (* procedure used as a
- 2465                                                    value (assign to a
- 2466                                                    procedure variable):
- 2467                                                    its code address *)
- 2468                                                 t := SymTab.ProcTypeOf(qn);
- 2469                                                 QbeGen.Mangled(qn,
- 2470                                                   SymTab.ProcUid(qn), qm0);
- 2471                                                 QbeGen.ProcAddr(qm0, q)
- 2472                                               END
- 2473                                             END; .)
- 2474      | ( "HIGH"                          (. isHigh := TRUE; .)
- 2475        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
- 2476        "(" ( Design<dt, dk, qd, qn, sfx> (. isStr := FALSE;
- 2477                                              isU := FALSE; .)
- 2478            | string                       (. LexString(s);
- 2479                                              isStr := TRUE;
- 2480                                              isU := FALSE;
- 2481                                              IF SymTab.StrLen(s) = 3 THEN
- 2482                                                dt := SymTab.CharType();
- 2483                                                QbeGen.IntStr(QbeGen.CharVal(s),
- 2484                                                  qd)
- 2485                                              ELSE
- 2486                                                dt := SymTab.NewStr();
- 2487                                                QbeGen.DeclStr(s, qd);
- 2488                                                QbeGen.NoteAddr(qd, qd)
- 2489                                              END;
- 2490                                              dk := -1;
- 2491                                              qn[0] := CHR(0); .)
- 2492            | ustring                      (. LexString(s);
- 2493                                              QbeGen.DeclUStr(s, qd, isU, ucp,
- 2494                                                uok);
- 2495                                              isStr := FALSE;
- 2496                                              IF NOT uok THEN
- 2497                                                SemError(234);
- 2498                                                dt := SymTab.InvalidType
- 2499                                              ELSIF isU THEN
- 2500                                                (* one codepoint: a UCHAR;
- 2501                                                   LEN is 1, HIGH is 0 *)
- 2502                                                dt := SymTab.UCharType();
- 2503                                                QbeGen.IntStr(ucp, qd)
- 2504                                              ELSE
- 2505                                                dt := SymTab.NewUStr();
- 2506                                                QbeGen.NoteAddr(qd, qd)
- 2507                                              END;
- 2508                                              dk := -1;
- 2509                                              qn[0] := CHR(0); .) )
- 2510        ")"
- 2511                                          (. IF (dt # SymTab.InvalidType)
- 2512    AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN
- 2513                                               (* UString: the count is
- 2514                                                  the descriptor header *)
- 2515                                               IF isHigh THEN
- 2516                                                 QbeGen.UStrLen(qd, qr);
- 2517                                                 QbeGen.DecQ(qr)
- 2518                                               ELSE
- 2519                                                 QbeGen.UStrLen(qd, qr)
- 2520                                               END;
- 2521                                               t := SymTab.IntType();
- 2522                                               QbeGen.CopyOp(qr, q)
- 2523                                             ELSIF (dt # SymTab.InvalidType)
- 2524    AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN
- 2525                                               (* single UCHAR codepoint *)
- 2526                                               IF isHigh THEN
- 2527                                                 QbeGen.CopyOp("0", qr)
- 2528                                               ELSE
- 2529                                                 QbeGen.CopyOp("1", qr)
- 2530                                               END;
- 2531                                               t := SymTab.IntType();
- 2532                                               QbeGen.CopyOp(qr, q)
- 2533                                             ELSIF isStr THEN
- 2534                                               (* fold: content length at
- 2535                                                  compile time *)
- 2536                                               IF SymTab.StrLen(s) = 3 THEN
- 2537                                                 c1 := 1
- 2538                                               ELSE
- 2539                                                 c1 :=
- 2540                                                   SymTab.StrLen(s) - 2
- 2541                                               END;
- 2542                                               IF isHigh THEN
- 2543                                                 DEC(c1)
- 2544                                               END;
- 2545                                               QbeGen.IntStr(c1, qr);
- 2546                                               t := SymTab.IntType();
- 2547                                               QbeGen.CopyOp(qr, q)
- 2548                                             ELSIF dt = SymTab.InvalidType THEN
- 2549                                               t := SymTab.InvalidType;
- 2550                                               QbeGen.CopyOp("0", q)
- 2551                                             ELSIF SymTab.ClassOf(dt) #
- 2552                                                   SymTab.ClArray THEN
- 2553                                               SemError(217);
- 2554                                               t := SymTab.InvalidType;
- 2555                                               QbeGen.CopyOp("0", q)
- 2556                                             ELSE
- 2557                                               IF isHigh THEN
- 2558                                                 IF SymTab.IsOpenArray(dt) THEN
- 2559                                                   QbeGen.OpenHi(qd, qr)
- 2560                                                 ELSE
- 2561                                                   QbeGen.IntStr(
- 2562                                                     SymTab.ArrayHi(dt), qr)
- 2563                                                 END
- 2564                                               ELSE
- 2565                                                 IF SymTab.IsOpenArray(dt) THEN
- 2566                                                   QbeGen.LoadCount(qd, qr)
- 2567                                                 ELSE
- 2568                                                   QbeGen.IntStr(VAL(
- 2569                                                     INTEGER,
- 2570                                                     SymTab.ArrayLen(dt)),
- 2571                                                     qr)
- 2572                                                 END
+ 1932                                                 lo := SymTab.ArrayLo(t);
+ 1933                                                 hi := SymTab.ArrayHi(t);
+ 1934                                                 IF SymTab.IsCharArray(t)
+ 1935    OR SymTab.IsUCharArray(t) THEN
+ 1936                                                   hi := hi + 1
+ 1937                                                 END;
+ 1938                                                 QbeGen.IntStr(lo, qlo);
+ 1939                                                 QbeGen.IntStr(hi, qhi)
+ 1940                                               END;
+ 1941                                               QbeGen.CheckRange(ql, qlo,
+ 1942                                                 qhi);
+ 1943                                               eT := SymTab.ArrayElem(t);
+ 1944                                               QbeGen.ElemAddr(q, ql, qlo,
+ 1945                                                 t, qe);
+ 1946                                               IF SymTab.ClassOf(eT) =
+ 1947                                                  SymTab.ClArray THEN
+ 1948                                                 QbeGen.ElemLoad(qe, eT, q)
+ 1949                                               ELSE QbeGen.CopyOp(qe, q)
+ 1950                                               END;
+ 1951                                               t := eT; sfx := TRUE
+ 1952                                             END; .) }
+ 1953          "]"
+ 1954        | "." GetIdent<fn>
+ 1955                                          (. IF k = SymTab.KindModule THEN
+ 1956                                               (* qualified L.x: materialize
+ 1957                                                  the export, then load it *)
+ 1958                                               IF NOT SymTab.MaterializeAlias(n,
+ 1959                                                    fn, mal) THEN
+ 1960                                                 SemError(201);
+ 1961                                                 t := SymTab.InvalidType;
+ 1962                                                 QbeGen.CopyOp("0", q)
+ 1963                                               ELSE
+ 1964                                                 QbeGen.CopyOp(mal, qn);
+ 1965                                                 t := SymTab.SymType(mal);
+ 1966                                                 k := SymTab.SymKind(mal);
+ 1967                                                 sfx := FALSE;
+ 1968                                                 IF k = SymTab.KindProc THEN
+ 1969                                                   (* call: ArgList supplies
+ 1970                                                      the value *)
+ 1971                                                   QbeGen.CopyOp("0", q)
+ 1972                                                 ELSIF NOT QbeGen.LoadDesignator(
+ 1973                                                      mal, t, k, q) THEN
+ 1974                                                   SemError(230);
+ 1975                                                   QbeGen.CopyOp("0", q)
+ 1976                                                 END
+ 1977                                               END
+ 1978                                             ELSIF t = SymTab.InvalidType THEN
+ 1979                                             ELSIF (SymTab.ClassOf(t) #
+ 1980                                                    SymTab.ClRecord)
+ 1981   AND (SymTab.ClassOf(t) #
+ 1982                                                   SymTab.ClClass) THEN
+ 1983                                               SemError(215);
+ 1984                                               t := SymTab.InvalidType
+ 1985                                             ELSIF (SymTab.ClassOf(t) =
+ 1986                                                    SymTab.ClClass)
+ 1987    AND SymTab.MethodExists(t, fn) THEN
+ 1988                                               (* obj.Method: bind the
+ 1989                                                  method and pass obj as
+ 1990                                                  the hidden receiver; q
+ 1991                                                  already holds the
+ 1992                                                  object's address *)
+ 1993                                               QbeGen.ArmRecv(q);
+ 1994                                               QbeGen.CopyOp(fn, n);
+ 1995                                               QbeGen.CopyOp(fn, qn);
+ 1996                                               methCls := t;
+ 1997                                               k := SymTab.KindProc;
+ 1998                                               t := SymTab.InvalidType
+ 1999                                             ELSIF NOT SymTab.FieldExists(t,
+ 2000                                                      fn) THEN
+ 2001                                               SemError(216);
+ 2002                                               t := SymTab.InvalidType
+ 2003                                             ELSE
+ 2004                                               fo := SymTab.FieldOffset(t,
+ 2005                                                 fn);
+ 2006                                               t := SymTab.FieldType(t, fn);
+ 2007                                               QbeGen.FieldAddr(q, fo, qe);
+ 2008                                               (* array fields are inline:
+ 2009                                                  the field address is the
+ 2010                                                  descriptor, like records *)
+ 2011                                               QbeGen.CopyOp(qe, q);
+ 2012                                               sfx := TRUE
+ 2013                                             END; .)
+ 2014        | "^"
+ 2015                                          (. IF t = SymTab.InvalidType THEN
+ 2016                                             ELSIF SymTab.ClassOf(t) #
+ 2017                                                   SymTab.ClPtr THEN
+ 2018                                               SemError(219);
+ 2019                                               t := SymTab.InvalidType
+ 2020                                             ELSE
+ 2021                                               bt := SymTab.PtrBase(t);
+ 2022                                               IF bt = SymTab.InvalidType THEN
+ 2023                                               ELSE
+ 2024                                                 IF sfx THEN
+ 2025                                                   QbeGen.ElemLoad(q, t,
+ 2026                                                     qb);
+ 2027                                                   QbeGen.CopyOp(qb, q)
+ 2028                                                 END;
+ 2029                                                 t := bt;
+ 2030                                                 (* q holds the pointee
+ 2031                                                    address: Fact loads
+ 2032                                                    scalars/pointers and uses
+ 2033                                                    the address for
+ 2034                                                    aggregates; the VAR-actual
+ 2035                                                    note is q itself. *)
+ 2036                                                 sfx := TRUE
+ 2037                                               END
+ 2038                                             END; .) } .
+ 2039    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2040                                          (. VAR t2: SymTab.TypeIndex;
+ 2041                                               op: INTEGER;
+ 2042                                               q2, qt, wl: QbeGen.QVal;
+ 2043                                               isR: BOOLEAN; .)
+ 2044      = SimExpr<t, q>
+ 2045        [ Rel<op> SimExpr<t2, q2>
+ 2046          (. IF op = SymTab.OpIn THEN
+ 2047               IF SymTab.InCheck(t, t2) THEN
+ 2048                 IF (t = SymTab.InvalidType)
+ 2049                    OR (t2 = SymTab.InvalidType) THEN
+ 2050                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 2051                 ELSE
+ 2052                   QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2),
+ 2053                     SymTab.SetCount(t2), qt);
+ 2054                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 2055                 END
+ 2056               ELSE SemError(222); t := SymTab.InvalidType;
+ 2057                 QbeGen.CopyOp("0", q)
+ 2058               END
+ 2059             ELSIF SymTab.RelCheck(t, t2, op) THEN
+ 2060               IF (t = SymTab.InvalidType)
+ 2061                  OR (t2 = SymTab.InvalidType) THEN
+ 2062                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 2063               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
+ 2064                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
+ 2065                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
+ 2066   AND (op # SymTab.OpNeq2) THEN
+ 2067                   SemError(213); t := SymTab.InvalidType;
+ 2068                   QbeGen.CopyOp("0", q)
+ 2069                 ELSE
+ 2070                   QbeGen.CmpL(op, q, q2, qt);
+ 2071                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 2072                 END
+ 2073               ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
+ 2074                  OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 2075                 QbeGen.CmpSet(op, q, q2,
+ 2076                   SymTab.SetWords(t), SymTab.SetWords(t2), qt);
+ 2077                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 2078               ELSIF SymTab.StrCompat(t, t2) THEN
+ 2079                 QbeGen.StrEq(op, q, q2, qt);
+ 2080                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 2081               ELSIF SymTab.IsLongFamily(t)
+ 2082                  OR SymTab.IsLongFamily(t2) THEN
+ 2083                 IF SymTab.IsIntFamily(t) THEN
+ 2084                   QbeGen.WidenLong(q, wl); QbeGen.CopyOp(wl, q)
+ 2085                 END;
+ 2086                 IF SymTab.IsIntFamily(t2) THEN
+ 2087                   QbeGen.WidenLong(q2, wl); QbeGen.CopyOp(wl, q2)
+ 2088                 END;
+ 2089                 QbeGen.CmpLong(op, q, q2, qt);
+ 2090                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 2091               ELSE
+ 2092                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 2093                 t := SymTab.BoolType();
+ 2094                 QbeGen.Cmp(op, q, q2, qt, isR);
+ 2095                 QbeGen.CopyOp(qt, q)
+ 2096               END
+ 2097             ELSE SemError(213); t := SymTab.InvalidType;
+ 2098               QbeGen.CopyOp("0", q)
+ 2099             END; .) ] .
+ 2100    Rel<VAR op: INTEGER>
+ 2101      = "="                               (. op := SymTab.OpEq; .)
+ 2102      | "#"                               (. op := SymTab.OpNeq1; .)
+ 2103      | "<"                               (. op := SymTab.OpLt; .)
+ 2104      | "<="                              (. op := SymTab.OpLe; .)
+ 2105      | ">"                               (. op := SymTab.OpGt; .)
+ 2106      | ">="                              (. op := SymTab.OpGe; .)
+ 2107      | "IN"                              (. op := SymTab.OpIn; .) .
+ 2108    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2109                                          (. VAR t2, res2, lt, rt:
+ 2110                                                 SymTab.TypeIndex;
+ 2111                                               op: INTEGER;
+ 2112                                               q2, qt, wq, qf, q2a, q2b:
+ 2113                                                 QbeGen.QVal;
+ 2114                                               neg, isR, isL, folded:
+ 2115                                                 BOOLEAN;
+ 2116                                               fok: BOOLEAN;
+ 2117                                               lw, rw, mw: CARDINAL;
+ 2118                                               lTrue, lNext, lDone, qr, qs:
+ 2119                                                 QbeGen.QVal; .)
+ 2120      =                                   (. neg := FALSE; .)
+ 2121        [ "+" | "-"                       (. neg := TRUE; .) ]
+ 2122        Term<t, q>                        (. IF neg THEN
+ 2123                                             IF QbeGen.IsImm(q) THEN
+ 2124                                               QbeGen.NegFold(q, q)
+ 2125                                             ELSE QbeGen.NewTemp(qt);
+ 2126                                               QbeGen.NegQ(q, qt,
+ 2127                                                 SymTab.ClassOf(t)
+ 2128                                                 = SymTab.ClReal);
+ 2129                                               QbeGen.CopyOp(qt, q)
+ 2130                                             END
+ 2131                                           END; .)
+ 2132        { AddOp<op>                       (. IF op = SymTab.OpOr THEN
+ 2133                                               QbeGen.DelayBegin END; .)
+ 2134          Term<t2, q2>                     (. IF op = SymTab.OpOr THEN
+ 2135                                               QbeGen.DelayEnd END; .)
+ 2136          (. IF op = SymTab.OpOr THEN
+ 2137               (* short-circuit: if q is true the RHS is skipped *)
+ 2138               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 2139                 t := SymTab.BoolType()
+ 2140               ELSE SemError(212); t := SymTab.InvalidType END;
+ 2141               IF t # SymTab.InvalidType THEN
+ 2142                 QbeGen.Slot4(qs);
+ 2143                 QbeGen.NewLabel(lTrue);
+ 2144                 QbeGen.NewLabel(lNext);
+ 2145                 QbeGen.NewLabel(lDone);
+ 2146                 QbeGen.Jnz(q, lTrue, lNext);
+ 2147                 QbeGen.EmitLabel(lTrue);
+ 2148                 QbeGen.StoreW(qs, "1");
+ 2149                 QbeGen.Jmp(lDone);
+ 2150                 QbeGen.EmitLabel(lNext);
+ 2151                 QbeGen.DelayFlush;
+ 2152                 QbeGen.StoreW(qs, q2);
+ 2153                 QbeGen.Jmp(lDone);
+ 2154                 QbeGen.EmitLabel(lDone);
+ 2155                 QbeGen.LoadW(qs, qr);
+ 2156                 QbeGen.CopyOp(qr, q)
+ 2157               ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
+ 2158               END
+ 2159             ELSIF (op = SymTab.OpAdd)
+ 2160               AND (SymTab.UStrCompat(t, t2)
+ 2161                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
+ 2162                   AND (SymTab.ClassOf(t2) = SymTab.ClUStr))
+ 2163                 OR ((SymTab.ClassOf(t) = SymTab.ClUStr)
+ 2164                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))
+ 2165                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
+ 2166                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN
+ 2167               (* UString concatenation: a UCHAR operand becomes a
+ 2168                  1-codepoint UString; the result is a descriptor in the
+ 2169                  shim's concat buffer.  Work on copies so neither
+ 2170                  operand is clobbered. *)
+ 2171               IF SymTab.ClassOf(t) = SymTab.ClUStr THEN
+ 2172                 QbeGen.CopyOp(q, q2a)
+ 2173               ELSE
+ 2174                 QbeGen.UStrFrom(q, q2a)
+ 2175               END;
+ 2176               IF SymTab.ClassOf(t2) = SymTab.ClUStr THEN
+ 2177                 QbeGen.UStrCat(q2a, q2, qt)
+ 2178               ELSE
+ 2179                 QbeGen.UStrFrom(q2, q2b);
+ 2180                 QbeGen.UStrCat(q2a, q2b, qt)
+ 2181               END;
+ 2182               t := SymTab.NewUStr();
+ 2183               QbeGen.CopyOp(qt, q)
+ 2184             ELSIF (op = SymTab.OpAdd)
+ 2185               AND (SymTab.StrCompat(t, t2)
+ 2186                 OR (SymTab.IsStrType(t)
+ 2187                   AND (SymTab.ClassOf(t2) = SymTab.ClChar))
+ 2188                 OR ((SymTab.ClassOf(t) = SymTab.ClChar)
+ 2189                   AND SymTab.IsStrType(t2))) THEN
+ 2190               (* string concatenation; a CHAR operand becomes a
+ 2191                  1-character string literal.  When both operands are
+ 2192                  constants, fold to a single string literal so a
+ 2193                  constructor element stays compile-time. *)
+ 2194               QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2),
+ 2195                 qt, fok);
+ 2196               IF NOT fok THEN
+ 2197                 IF SymTab.StrCompat(t, t2) THEN
+ 2198                   QbeGen.StrCat(q, q2, qt)
+ 2199                 ELSIF SymTab.IsStrType(t) THEN
+ 2200                   QbeGen.DeclCharStr(q2, qs);
+ 2201                   QbeGen.StrCat(q, qs, qt)
+ 2202                 ELSE
+ 2203                   QbeGen.DeclCharStr(q, qs);
+ 2204                   QbeGen.StrCat(qs, q2, qt)
+ 2205                 END
+ 2206               END;
+ 2207               t := SymTab.NewStr();
+ 2208               QbeGen.CopyOp(qt, q)
+ 2209             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 2210   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 2211   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 2212               lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 2213               mw := lw;
+ 2214               IF rw > mw THEN mw := rw END;
+ 2215               IF op = SymTab.OpAdd THEN
+ 2216                 QbeGen.SetBinOp(0, q, q2, lw, rw, qt)
+ 2217               ELSE
+ 2218                 QbeGen.SetBinOp(2, q, q2, lw, rw, qt)
+ 2219               END;
+ 2220               t := SymTab.NewSet(
+ 2221                      SymTab.NewSubR(0,
+ 2222                        VAL(INTEGER, mw) * 32 - 1));
+ 2223               QbeGen.CopyOp(qt, q)
+ 2224             ELSE
+ 2225               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
+ 2226                 lt := t; rt := t2; t := res2
+ 2227               ELSE SemError(211); t := SymTab.InvalidType END;
+ 2228               IF t # SymTab.InvalidType THEN
+ 2229                 isL := SymTab.IsLongFamily(t);
+ 2230                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 2231                 folded := FALSE;
+ 2232                 IF (NOT isL) AND (NOT isR)
+ 2233    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 2234                   IF op = SymTab.OpAdd THEN
+ 2235                     folded := QbeGen.Fold2(0, q, q2, qf)
+ 2236                   ELSE
+ 2237                     folded := QbeGen.Fold2(1, q, q2, qf)
+ 2238                   END
+ 2239                 END;
+ 2240                 IF folded THEN QbeGen.CopyOp(qf, q)
+ 2241                 ELSE
+ 2242                 IF isL THEN
+ 2243                   IF SymTab.IsIntFamily(lt) THEN
+ 2244                     QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
+ 2245                   END;
+ 2246                   IF SymTab.IsIntFamily(rt) THEN
+ 2247                     QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
+ 2248                   END;
+ 2249                   QbeGen.NewTemp(qt);
+ 2250                   IF op = SymTab.OpAdd THEN
+ 2251                     QbeGen.Op3L("add", qt, q, q2)
+ 2252                   ELSE
+ 2253                     QbeGen.Op3L("sub", qt, q, q2)
+ 2254                   END
+ 2255                 ELSE
+ 2256                   QbeGen.NewTemp(qt);
+ 2257                   IF op = SymTab.OpAdd THEN
+ 2258                     QbeGen.Op3("add", qt, q, q2, isR)
+ 2259                   ELSE
+ 2260                     QbeGen.Op3("sub", qt, q, q2, isR)
+ 2261                   END
+ 2262                 END;
+ 2263                 QbeGen.CopyOp(qt, q)
+ 2264                 END
+ 2265               ELSE QbeGen.CopyOp("0", q)
+ 2266               END
+ 2267             END; .) } .
+ 2268    AddOp<VAR op: INTEGER>
+ 2269      = "+"                               (. op := SymTab.OpAdd; .)
+ 2270      | "-"                               (. op := SymTab.OpSub; .)
+ 2271      | "OR"                              (. op := SymTab.OpOr; .) .
+ 2272    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2273                                          (. VAR t2, res2, lt, rt:
+ 2274                                                 SymTab.TypeIndex;
+ 2275                                               op: INTEGER;
+ 2276                                               q2, qt, wq, qf:
+ 2277                                                 QbeGen.QVal;
+ 2278                                               isR, isL, folded: BOOLEAN;
+ 2279                                               lw, rw, mw: CARDINAL;
+ 2280                                               lNext, lFalse, lDone, qr, qs:
+ 2281                                                 QbeGen.QVal; .)
+ 2282      = Fact<t, q> { MulOp<op>            (. IF op = SymTab.OpAnd THEN
+ 2283                                               QbeGen.DelayBegin END; .)
+ 2284          Fact<t2, q2>                    (. IF op = SymTab.OpAnd THEN
+ 2285                                               QbeGen.DelayEnd END; .)
+ 2286        (. IF op = SymTab.OpAnd THEN
+ 2287             (* short-circuit: if q is false the RHS is skipped *)
+ 2288             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 2289               t := SymTab.BoolType()
+ 2290             ELSE SemError(212); t := SymTab.InvalidType END;
+ 2291             IF t # SymTab.InvalidType THEN
+ 2292               QbeGen.Slot4(qs);
+ 2293               QbeGen.NewLabel(lNext);
+ 2294               QbeGen.NewLabel(lFalse);
+ 2295               QbeGen.NewLabel(lDone);
+ 2296               QbeGen.Jnz(q, lNext, lFalse);
+ 2297               QbeGen.EmitLabel(lNext);
+ 2298               QbeGen.DelayFlush;
+ 2299               QbeGen.StoreW(qs, q2);
+ 2300               QbeGen.Jmp(lDone);
+ 2301               QbeGen.EmitLabel(lFalse);
+ 2302               QbeGen.StoreW(qs, "0");
+ 2303               QbeGen.Jmp(lDone);
+ 2304               QbeGen.EmitLabel(lDone);
+ 2305               QbeGen.LoadW(qs, qr);
+ 2306               QbeGen.CopyOp(qr, q)
+ 2307             ELSE QbeGen.DelayFlush; QbeGen.CopyOp("0", q)
+ 2308             END
+ 2309           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 2310   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 2311   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 2312             lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 2313             mw := lw;
+ 2314             IF rw > mw THEN mw := rw END;
+ 2315             IF op = SymTab.OpTimes THEN
+ 2316               QbeGen.SetBinOp(1, q, q2, lw, rw, qt)
+ 2317             ELSE
+ 2318               QbeGen.SetBinOp(3, q, q2, lw, rw, qt)
+ 2319             END;
+ 2320             t := SymTab.NewSet(
+ 2321                    SymTab.NewSubR(0,
+ 2322                      VAL(INTEGER, mw) * 32 - 1));
+ 2323             QbeGen.CopyOp(qt, q)
+ 2324           ELSE
+ 2325             IF SymTab.ArithCheck(t, t2,
+ 2326                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
+ 2327                  res2) THEN
+ 2328               lt := t; rt := t2; t := res2
+ 2329             ELSE SemError(211); t := SymTab.InvalidType END;
+ 2330             IF t # SymTab.InvalidType THEN
+ 2331               isL := SymTab.IsLongFamily(t);
+ 2332               isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 2333               folded := FALSE;
+ 2334               IF (NOT isL) AND (NOT isR)
+ 2335    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 2336                 IF op = SymTab.OpTimes THEN
+ 2337                   folded := QbeGen.Fold2(2, q, q2, qf)
+ 2338                 ELSIF op = SymTab.OpDiv THEN
+ 2339                   folded := QbeGen.Fold2(3, q, q2, qf)
+ 2340                 ELSIF op = SymTab.OpMod THEN
+ 2341                   folded := QbeGen.Fold2(4, q, q2, qf)
+ 2342                 END
+ 2343               END;
+ 2344               IF folded THEN QbeGen.CopyOp(qf, q)
+ 2345               ELSE
+ 2346               IF isL THEN
+ 2347                 IF SymTab.IsIntFamily(lt) THEN
+ 2348                   QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
+ 2349                 END;
+ 2350                 IF SymTab.IsIntFamily(rt) THEN
+ 2351                   QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
+ 2352                 END;
+ 2353                 QbeGen.NewTemp(qt);
+ 2354                 IF op = SymTab.OpTimes THEN
+ 2355                   QbeGen.Op3L("mul", qt, q, q2)
+ 2356                 ELSIF (op = SymTab.OpDiv)
+ 2357                    OR (op = SymTab.OpSlash) THEN
+ 2358                   QbeGen.Op3L("div", qt, q, q2)
+ 2359                 ELSE
+ 2360                   QbeGen.Op3L("rem", qt, q, q2)
+ 2361                 END
+ 2362               ELSE
+ 2363                 QbeGen.NewTemp(qt);
+ 2364                 IF op = SymTab.OpTimes THEN
+ 2365                   QbeGen.Op3("mul", qt, q, q2, isR)
+ 2366                 ELSIF (op = SymTab.OpDiv)
+ 2367                    OR (op = SymTab.OpSlash) THEN
+ 2368                   QbeGen.Op3("div", qt, q, q2, isR)
+ 2369                 ELSE
+ 2370                   QbeGen.Op3("rem", qt, q, q2, isR)
+ 2371                 END
+ 2372               END;
+ 2373               QbeGen.CopyOp(qt, q)
+ 2374               END
+ 2375             ELSE QbeGen.CopyOp("0", q)
+ 2376             END
+ 2377           END; .) } .
+ 2378    MulOp<VAR op: INTEGER>
+ 2379      = "*"                               (. op := SymTab.OpTimes; .)
+ 2380      | "/"                               (. op := SymTab.OpSlash; .)
+ 2381      | "DIV"                             (. op := SymTab.OpDiv; .)
+ 2382      | "MOD"                             (. op := SymTab.OpMod; .)
+ 2383      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
+ 2384    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2385                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
+ 2386                                               et, dt, t2, st, ct2, et2:
+ 2387                                                 SymTab.TypeIndex;
+ 2388                                               dk: INTEGER;
+ 2389                                               qd, q2, sq, qa, qm0, qr, qt:
+ 2390                                                 QbeGen.QVal;
+ 2391                                               qn, vn: SymTab.Name;
+ 2392                                               vt: SymTab.TypeIndex;
+ 2393                                               c1, c2: INTEGER;
+ 2394                                               lo, hi: INTEGER;
+ 2395                                               isMax: BOOLEAN;
+ 2396                                               called, isHigh, sfx, isCh,
+ 2397                                               isU, uok, isStr: BOOLEAN;
+ 2398                                               ucp: INTEGER; .)
+ 2399      = integer                           (. LexString(s);
+ 2400                                             QbeGen.NormInt(s, q);
+ 2401                                             t := SymTab.IntType(); .)
+ 2402      | charConst                         (. LexString(s);
+ 2403                                             QbeGen.NormLit(s, q, isCh);
+ 2404                                             t := SymTab.CharType(); .)
+ 2405      | real                              (. LexString(s);
+ 2406                                             QbeGen.NormReal(s, q);
+ 2407                                             t := SymTab.RealType(); .)
+ 2408      | string                            (. LexString(s);
+ 2409                                             IF SymTab.StrLen(s) = 3 THEN
+ 2410                                               t := SymTab.CharType();
+ 2411                                               QbeGen.IntStr(
+ 2412                                                 QbeGen.CharVal(s), q)
+ 2413                                             ELSE t := SymTab.NewStr();
+ 2414                                               QbeGen.DeclStr(s, q);
+ 2415                                               (* a literal's value IS its
+ 2416                                                  static descriptor address *)
+ 2417                                               QbeGen.NoteAddr(q, q)
+ 2418                                             END; .)
+ 2419      | ustring                           (. LexString(s);
+ 2420                                             QbeGen.DeclUStr(s, q, isU, ucp,
+ 2421                                               uok);
+ 2422                                             IF NOT uok THEN
+ 2423                                               SemError(234);
+ 2424                                               t := SymTab.InvalidType
+ 2425                                             ELSIF isU THEN
+ 2426                                               t := SymTab.UCharType();
+ 2427                                               QbeGen.IntStr(ucp, q)
+ 2428                                             ELSE
+ 2429                                               t := SymTab.NewUStr();
+ 2430                                               QbeGen.NoteAddr(q, q)
+ 2431                                             END; .)
+ 2432      | Design<dt, dk, qd, qn, sfx>       (. called := FALSE;
+ 2433                                             t := dt;
+ 2434                                             IF sfx THEN
+ 2435                                               IF dt =
+ 2436                                                  SymTab.InvalidType THEN
+ 2437                                                 QbeGen.CopyOp("0", q)
+ 2438                                               ELSIF (SymTab.ClassOf(dt) =
+ 2439                                                      SymTab.ClRecord)
+ 2440                                                  OR (SymTab.ClassOf(dt) =
+ 2441                                                      SymTab.ClSet)
+ 2442                                                  OR (SymTab.ClassOf(dt) =
+ 2443                                                      SymTab.ClArray)
+ 2444                                                  OR (SymTab.ClassOf(dt) =
+ 2445                                                      SymTab.ClClass) THEN
+ 2446                                                 QbeGen.CopyOp(qd, q)
+ 2447                                               ELSE QbeGen.ElemLoad(qd, dt,
+ 2448                                                 q)
+ 2449                                               END
+ 2450                                             ELSE QbeGen.CopyOp(qd, q)
+ 2451                                             END;
+ 2452                                             IF (dk = SymTab.KindVar)
+ 2453                                                OR (dk = SymTab.KindParam)
+ 2454                                                OR (dk =
+ 2455                                                   SymTab.KindField) THEN
+ 2456                                               IF sfx THEN
+ 2457                                                 QbeGen.NoteAddr(q, qd)
+ 2458                                               ELSE
+ 2459                                                 QbeGen.AddrOf(qn, qa);
+ 2460                                                 QbeGen.NoteAddr(q, qa)
+ 2461                                               END
+ 2462                                             ELSIF sfx
+ 2463   AND (dt #
+ 2464                                                   SymTab.InvalidType)
+ 2465   AND ((SymTab.ClassOf(dt) =
+ 2466                                                    SymTab.ClArray)
+ 2467                                                   OR (SymTab.ClassOf(dt) =
+ 2468                                                       SymTab.ClSet)
+ 2469                                                   OR (SymTab.ClassOf(dt) =
+ 2470                                                       SymTab.ClRecord)) THEN
+ 2471                                               QbeGen.NoteAddr(qd, qd)
+ 2472                                             END; .)
+ 2473        [ TypedBraceLit<dt, q>            (. t := dt; .) ]
+ 2474        [ ArgList<qn, dt, qd, TRUE, methCls, ct2, q2, called>
+ 2475                                          (. t := ct2;
+ 2476                                             QbeGen.CopyOp(q2, q); .) ]
+ 2477                                          (. IF NOT called
+ 2478   AND (dk = SymTab.KindProc) THEN
+ 2479                                               (* bare zero-arg function
+ 2480                                                  call (parentheses may be
+ 2481                                                  omitted); a proper or
+ 2482                                                  parameterised proc here
+ 2483                                                  is 230 *)
+ 2484                                               IF (SymTab.ProcNPar(qn) = 0)
+ 2485   AND (SymTab.ProcRes(qn) #
+ 2486                                                     SymTab.InvalidType) THEN
+ 2487                                                 QbeGen.Mangled(qn,
+ 2488                                                   SymTab.ProcUid(qn), qm0);
+ 2489                                                 QbeGen.CallBegin(qm0,
+ 2490                                                   SymTab.ProcRes(qn),
+ 2491                                                   SymTab.ProcDepthOf(qn),
+ 2492                                                   SymTab.IsExternal(qn));
+ 2493                                                 QbeGen.CallEnd(TRUE, q);
+ 2494                                                 t := SymTab.ProcRes(qn)
+ 2495                                               ELSE
+ 2496                                                 (* procedure used as a
+ 2497                                                    value (assign to a
+ 2498                                                    procedure variable):
+ 2499                                                    its code address *)
+ 2500                                                 t := SymTab.ProcTypeOf(qn);
+ 2501                                                 QbeGen.Mangled(qn,
+ 2502                                                   SymTab.ProcUid(qn), qm0);
+ 2503                                                 QbeGen.ProcAddr(qm0, q)
+ 2504                                               END
+ 2505                                             END; .)
+ 2506      | ( "HIGH"                          (. isHigh := TRUE; .)
+ 2507        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
+ 2508        "(" ( Design<dt, dk, qd, qn, sfx> (. isStr := FALSE;
+ 2509                                              isU := FALSE; .)
+ 2510            | string                       (. LexString(s);
+ 2511                                              isStr := TRUE;
+ 2512                                              isU := FALSE;
+ 2513                                              IF SymTab.StrLen(s) = 3 THEN
+ 2514                                                dt := SymTab.CharType();
+ 2515                                                QbeGen.IntStr(QbeGen.CharVal(s),
+ 2516                                                  qd)
+ 2517                                              ELSE
+ 2518                                                dt := SymTab.NewStr();
+ 2519                                                QbeGen.DeclStr(s, qd);
+ 2520                                                QbeGen.NoteAddr(qd, qd)
+ 2521                                              END;
+ 2522                                              dk := -1;
+ 2523                                              qn[0] := CHR(0); .)
+ 2524            | ustring                      (. LexString(s);
+ 2525                                              QbeGen.DeclUStr(s, qd, isU, ucp,
+ 2526                                                uok);
+ 2527                                              isStr := FALSE;
+ 2528                                              IF NOT uok THEN
+ 2529                                                SemError(234);
+ 2530                                                dt := SymTab.InvalidType
+ 2531                                              ELSIF isU THEN
+ 2532                                                (* one codepoint: a UCHAR;
+ 2533                                                   LEN is 1, HIGH is 0 *)
+ 2534                                                dt := SymTab.UCharType();
+ 2535                                                QbeGen.IntStr(ucp, qd)
+ 2536                                              ELSE
+ 2537                                                dt := SymTab.NewUStr();
+ 2538                                                QbeGen.NoteAddr(qd, qd)
+ 2539                                              END;
+ 2540                                              dk := -1;
+ 2541                                              qn[0] := CHR(0); .) )
+ 2542        ")"
+ 2543                                          (. IF (dt # SymTab.InvalidType)
+ 2544    AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN
+ 2545                                               (* UString: the count is
+ 2546                                                  the descriptor header *)
+ 2547                                               IF isHigh THEN
+ 2548                                                 QbeGen.UStrLen(qd, qr);
+ 2549                                                 QbeGen.DecQ(qr)
+ 2550                                               ELSE
+ 2551                                                 QbeGen.UStrLen(qd, qr)
+ 2552                                               END;
+ 2553                                               t := SymTab.IntType();
+ 2554                                               QbeGen.CopyOp(qr, q)
+ 2555                                             ELSIF (dt # SymTab.InvalidType)
+ 2556    AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN
+ 2557                                               (* single UCHAR codepoint *)
+ 2558                                               IF isHigh THEN
+ 2559                                                 QbeGen.CopyOp("0", qr)
+ 2560                                               ELSE
+ 2561                                                 QbeGen.CopyOp("1", qr)
+ 2562                                               END;
+ 2563                                               t := SymTab.IntType();
+ 2564                                               QbeGen.CopyOp(qr, q)
+ 2565                                             ELSIF isStr THEN
+ 2566                                               (* fold: content length at
+ 2567                                                  compile time *)
+ 2568                                               IF SymTab.StrLen(s) = 3 THEN
+ 2569                                                 c1 := 1
+ 2570                                               ELSE
+ 2571                                                 c1 :=
+ 2572                                                   SymTab.StrLen(s) - 2
  2573                                               END;
  2573                                               END;
- 2574                                                t := SymTab.IntType();
- 2575                                                QbeGen.CopyOp(qr, q)
- 2576                                              END; .)
- 2577      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
- 2578                                          (. IF dt = SymTab.InvalidType THEN
- 2579                                               t := SymTab.InvalidType;
- 2580                                               QbeGen.CopyOp("0", q)
- 2581                                             ELSE
- 2582                                               QbeGen.IntStr(VAL(INTEGER,
- 2583                                                 SymTab.ObjectSize(dt)), q);
- 2584                                               t := SymTab.IntType()
- 2585                                             END; .)
- 2586      | ( "SHIFT"                         (. isMax := FALSE; .)
- 2587        | "ROTATE"                        (. isMax := TRUE; .) )
- 2588        "(" Expr<et, q> "," Expr<et2, q2> ")"
- 2589                                          (. (* set shift/rotate: isMax
- 2590                                                doubles as "rotate" *)
- 2591                                             IF (et # SymTab.InvalidType)
- 2592                                                AND (SymTab.ClassOf(et) =
- 2593                                                   SymTab.ClSet) THEN
- 2594                                               QbeGen.SetShift(q, q2,
- 2595                                                 SymTab.SetWords(et),
- 2596                                                 SymTab.SetCount(et), isMax,
- 2597                                                 qt);
- 2598                                               t := et;
- 2599                                               QbeGen.CopyOp(qt, q)
- 2600                                             ELSE SemError(230);
- 2601                                               t := SymTab.InvalidType;
- 2602                                               QbeGen.CopyOp("0", q)
- 2603                                             END; .)
- 2604      | ( "MIN"                           (. isMax := FALSE; .)
- 2605        | "MAX"                           (. isMax := TRUE; .) )
- 2606        "(" Design<dt, dk, qd, qn, sfx> ")"
- 2607                                          (. IF (dt # SymTab.InvalidType)
- 2608   AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN
- 2609                                               (* REAL/LONGREAL: the
- 2610                                                  implementation bounds *)
- 2611                                               IF isMax THEN
- 2612                                                 QbeGen.NormReal(
- 2613                                                   "3.402823e38", q)
- 2614                                               ELSE QbeGen.NormReal(
- 2615                                                   "-3.402823e38", q)
- 2616                                               END;
- 2617                                               t := SymTab.RealType()
- 2618                                             ELSIF (dt #
- 2619                                                SymTab.InvalidType)
- 2620   AND (SymTab.ClassOf(dt) =
- 2621                                                   SymTab.ClLong) THEN
- 2622                                               IF isMax THEN
- 2623                                                 QbeGen.CopyOp(
- 2624                                                   "9223372036854775807", q)
- 2625                                               ELSE QbeGen.CopyOp(
- 2626                                                   "-9223372036854775808", q)
- 2627                                               END;
- 2628                                               t := SymTab.LongType()
- 2629                                             ELSIF SymTab.TypeBounds(dt, lo,
- 2630                                                      hi) THEN
- 2631                                               IF isMax THEN
- 2632                                                 QbeGen.IntStr(hi, q)
- 2633                                               ELSE QbeGen.IntStr(lo, q)
- 2634                                               END;
- 2635                                               t := SymTab.IntType()
- 2636                                             ELSE SemError(230);
- 2637                                               t := SymTab.InvalidType;
- 2638                                               QbeGen.CopyOp("0", q)
- 2639                                             END; .)
- 2640      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
- 2641                                          (. IF dt = SymTab.InvalidType THEN
- 2642                                               t := SymTab.InvalidType;
- 2643                                               QbeGen.CopyOp("0", q)
- 2644                                             ELSE
- 2645                                               IF sfx THEN
- 2646                                                 QbeGen.CopyOp(qd, q)
- 2647                                               ELSIF (dk = SymTab.KindVar)
- 2648                                                  OR (dk = SymTab.KindParam) THEN
- 2649                                                 QbeGen.AddrOf(qn, q)
- 2650                                               ELSE SemError(230);
- 2651                                                 QbeGen.CopyOp("0", q)
- 2652                                               END;
- 2653                                               t := SymTab.AddrType()
- 2654                                             END; .)
- 2655      | "CHR" "(" Expr<et, q> ")"
- 2656                                          (. IF (et # SymTab.InvalidType)
- 2657   AND NOT SymTab.IsIntFamily(et) THEN
- 2658                                               SemError(211) END;
- 2659                                             t := SymTab.CharType(); .)
- 2660      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
- 2661                                          (. IF et # SymTab.InvalidType THEN
- 2662                                               IF (SymTab.ClassOf(et) #
- 2663                                                   SymTab.ClChar)
- 2664   AND (SymTab.ClassOf(et) #
- 2665                                                     SymTab.ClBool)
- 2666   AND (SymTab.ClassOf(et) #
- 2667                                                     SymTab.ClEnum)
- 2668   AND NOT SymTab.IsIntFamily(et) THEN
- 2669                                                 SemError(211) END
- 2670                                             END;
- 2671                                             t := SymTab.IntType(); .)
- 2672      | "CAP" "(" Expr<et, q> ")"
- 2673                                          (. QbeGen.CapQ(q, qa);
- 2674                                             QbeGen.CopyOp(qa, q);
- 2675                                             t := SymTab.CharType(); .)
- 2676      | "UCHR" "(" Expr<et, q> ")"
- 2677                                          (. (* UCHR: the UCHAR constructor.
- 2678                                                CHAR -> UCHAR (identity);
- 2679                                                INTEGER familly -> UCHAR
- 2680                                                (codepoint value). *)
- 2681                                             IF (et # SymTab.InvalidType)
- 2682    AND (SymTab.ClassOf(et) # SymTab.ClChar)
- 2683    AND NOT SymTab.IsIntFamily(et) THEN
- 2684                                               SemError(211) END;
- 2685                                             t := SymTab.UCharType(); .)
- 2686      | "CHR8" "(" Expr<et, q> ")"
- 2687                                          (. IF (et # SymTab.InvalidType)
- 2688    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
- 2689                                               SemError(211) END;
- 2690                                             QbeGen.WidenLong(q, qa);
- 2691                                             QbeGen.CheckRange(qa, "0", "255");
- 2692                                             t := SymTab.CharType(); .)
- 2693      | "UORD" "(" Expr<et, q> ")"
- 2694                                          (. (* UORD(u): the codepoint as a
- 2695                                                32-bit ordinal (INTEGER),
- 2696                                                cf. ORD for CHAR. *)
- 2697                                             IF (et # SymTab.InvalidType)
- 2698    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
- 2699                                               SemError(211) END;
- 2700                                             t := SymTab.IntType(); .)
- 2701      | "ABS" "(" Expr<et, q> ")"
- 2702                                          (. IF (et # SymTab.InvalidType)
- 2703   AND NOT SymTab.IsIntFamily(et)
- 2704   AND (SymTab.ClassOf(et) #
- 2705                                                  SymTab.ClReal) THEN
- 2706                                               SemError(211)
- 2707                                             ELSE QbeGen.AbsQ(q, qa,
- 2708                                                    SymTab.ClassOf(et) =
- 2709                                                      SymTab.ClReal);
- 2710                                               QbeGen.CopyOp(qa, q)
- 2711                                             END;
- 2712                                             t := et; .)
- 2713      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
- 2714                                          (. IF NOT SymTab.Lookup(vn) THEN
- 2715                                               SemError(201);
- 2716                                               t := SymTab.InvalidType
- 2717                                             ELSE vt := SymTab.SymType(vn);
- 2718                                               IF vt = SymTab.InvalidType THEN
- 2719                                                 t := SymTab.InvalidType
- 2720                                               ELSIF et =
- 2721                                                  SymTab.InvalidType THEN
- 2722                                                 t := vt
- 2723                                               ELSE
- 2724                                                 c1 := SymTab.ClassOf(et);
- 2725                                                 c2 := SymTab.ClassOf(vt);
- 2726                                                 IF (c1 = SymTab.ClInt)
- 2727    AND (c2 = SymTab.ClLong) THEN
- 2728                                                   QbeGen.WidenLong(q, qa);
- 2729                                                   QbeGen.CopyOp(qa, q);
- 2730                                                   t := vt
- 2731                                                 ELSIF (c1 = SymTab.ClLong)
- 2732    AND (c2 = SymTab.ClInt) THEN
- 2733                                                   QbeGen.NarrowLong(q, qa);
- 2734                                                   QbeGen.CopyOp(qa, q);
- 2735                                                   t := vt
- 2736                                                 ELSIF (c1 = SymTab.ClInt)
- 2737    AND (c2 = SymTab.ClReal) THEN
- 2738                                                   QbeGen.ConvIR(q, qa);
- 2739                                                   QbeGen.CopyOp(qa, q);
- 2740                                                   t := vt
- 2741                                                 ELSIF (c1 = SymTab.ClLong)
- 2742    AND (c2 = SymTab.ClReal) THEN
- 2743                                                   QbeGen.ConvLR(q, qa);
- 2744                                                   QbeGen.CopyOp(qa, q);
- 2745                                                   t := vt
- 2746                                                 ELSIF (c1 = SymTab.ClReal)
- 2747    AND (c2 = SymTab.ClInt) THEN
- 2748                                                   QbeGen.ConvRI(q, qa);
- 2749                                                   QbeGen.CopyOp(qa, q);
- 2750                                                   t := vt
- 2751                                                 ELSIF (c1 = SymTab.ClReal)
- 2752    AND (c2 = SymTab.ClLong) THEN
- 2753                                                   QbeGen.ConvRL(q, qa);
- 2754                                                   QbeGen.CopyOp(qa, q);
- 2755                                                   t := vt
- 2756                                                 ELSIF ((c1 = SymTab.ClInt)
- 2757                                                     OR (c1 =
- 2758                                                        SymTab.ClChar)
- 2759                                                     OR (c1 =
- 2760                                                        SymTab.ClBool)
- 2761                                                     OR (c1 =
- 2762                                                        SymTab.ClEnum))
- 2763   AND ((c2 = SymTab.ClInt)
- 2764                                                     OR (c2 =
- 2765                                                        SymTab.ClChar)
- 2766                                                     OR (c2 =
- 2767                                                        SymTab.ClBool)
- 2768                                                     OR (c2 =
- 2769                                                        SymTab.ClEnum)) THEN
- 2770                                                   t := vt
- 2771                                                 ELSIF (c1 = SymTab.ClPtr)
- 2772   AND (c2 = SymTab.ClPtr) THEN
- 2773                                                   t := vt
- 2774                                                 ELSIF (c1 = SymTab.ClReal)
- 2775   AND (c2 = SymTab.ClReal) THEN
- 2776                                                   t := vt
- 2777                                                 ELSE SemError(230);
- 2778                                                   t := SymTab.InvalidType
- 2779                                                 END
- 2780                                               END
- 2781                                             END; .)
- 2782      | "(" Expr<et, q> ")"               (. t := et; .)
- 2783      | SetLit<st, sq>                    (. t := st;
- 2784                                             QbeGen.CopyOp(sq, q); .)
- 2785      | ( "NOT" | "~" ) Fact<t2, q2>      (. IF SymTab.BoolCheck(t2) THEN
- 2786                                               t := SymTab.BoolType()
- 2787                                             ELSE SemError(212);
- 2788                                               t := SymTab.InvalidType END;
- 2789                                             IF t # SymTab.InvalidType THEN
- 2790                                               QbeGen.NotQ(q2, q)
- 2791                                             ELSE QbeGen.CopyOp("0", q)
- 2792                                             END; .) .
- 2793    (* Set literals are SET OF [0..255] (8 words); elements validated
- 2794       0..255 statically when foldable (222 otherwise), runtime trap
- 2795       for computed elements. Ranges always lower via SetRange. *)
- 2796    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2797      = "{"                               (. t := SymTab.NewSet(
- 2798                                               SymTab.NewSubR(0, 255));
- 2799                                             QbeGen.NewSetTemp(8, q);
- 2800                                             QbeGen.SetZero(q, 8); .)
- 2801        [ SetElem<t, q> { "," SetElem<t, q> } ]
- 2802        "}" .
- 2803    (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set)
- 2804       or ArrayName{...} (an array constructor, GNU Modula-2).  The
- 2805       declared type sets the width (set) or element type (array). *)
- 2806    TypedBraceLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2807                                          (. VAR nw: CARDINAL;
- 2808                                               savedCls: INTEGER; .)
- 2809      = "{"                               (. savedCls := braceCls;
- 2810                                             IF vt = SymTab.InvalidType THEN
- 2811                                               braceCls := -1
- 2812                                             ELSE braceCls :=
- 2813                                                    SymTab.ClassOf(vt)
- 2814                                             END;
- 2815                                             IF braceCls = SymTab.ClSet THEN
- 2816                                               IF vt = SymTab.InvalidType THEN
- 2817                                                 nw := 8
- 2818                                               ELSE nw := SymTab.SetWords(vt);
- 2819                                                 IF nw = 0 THEN nw := 8 END
- 2820                                               END;
- 2821                                               QbeGen.NewSetTemp(nw, q);
- 2822                                               QbeGen.SetZero(q, nw)
- 2823                                             ELSIF (braceCls =
- 2824                                                    SymTab.ClArray)
- 2825                                                OR (braceCls =
- 2826                                                    SymTab.ClRecord)
- 2827                                                OR (braceCls =
- 2828                                                    SymTab.ClClass) THEN
- 2829                                               QbeGen.CtorBegin(vt)
- 2830                                             ELSE
- 2831                                               IF vt # SymTab.InvalidType THEN
- 2832                                                 SemError(230) END;
- 2833                                               braceCls := -1
- 2834                                             END; .)
- 2835        [ BraceElem<vt, q> { "," BraceElem<vt, q> } ]
- 2836        "}"                               (. IF (braceCls = SymTab.ClArray)
- 2837                                                OR (braceCls =
- 2838                                                   SymTab.ClRecord)
- 2839                                                OR (braceCls =
- 2840                                                   SymTab.ClClass) THEN
- 2841                                               QbeGen.CtorEnd(q)
- 2842                                             ELSIF braceCls # SymTab.ClSet THEN
- 2843                                               QbeGen.CopyOp("0", q)
- 2844                                             END;
- 2845                                             braceCls := savedCls; .) .
- 2846    BraceElem<vt: SymTab.TypeIndex; VAR sq: QbeGen.QVal>
- 2847                                          (. VAR et, et2: SymTab.TypeIndex;
- 2848                                               qe, q2: QbeGen.QVal;
- 2849                                               v, v2, reps, k: INTEGER;
- 2850                                               elem: SymTab.TypeIndex;
- 2851                                               lo: INTEGER;
- 2852                                               span: CARDINAL;
- 2853                                               cl, cl2: INTEGER;
- 2854                                               hasR, hasB: BOOLEAN; .)
- 2855      =                                   (. hasR := FALSE; hasB := FALSE; .)
- 2856        Expr<et, qe>
- 2857        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
- 2858        [ "BY" Expr<et2, q2>              (. hasB := TRUE; .) ]
- 2859                                          (. IF braceCls = SymTab.ClSet THEN
- 2860                                               IF hasB THEN SemError(230) END;
- 2861                                               lo := SymTab.SetBaseLo(vt);
- 2862                                               span := SymTab.SetCount(vt);
- 2863                                               IF (et = SymTab.InvalidType)
- 2864                                                  OR (hasR AND (et2 =
- 2865                                                     SymTab.InvalidType)) THEN
- 2866                                               ELSE cl :=
- 2867                                                      SymTab.ClassOf(et);
- 2868                                                 IF hasR THEN
- 2869                                                   cl2 :=
- 2870                                                     SymTab.ClassOf(et2)
- 2871                                                 ELSE cl2 := SymTab.ClInt
- 2872                                                 END;
- 2873                                                 IF NOT SymTab.SetElemClassOk(cl)
- 2874                                                    OR (hasR AND NOT
- 2875                                                       SymTab.SetElemClassOk(cl2))
- 2876                                                 THEN
- 2877                                                   SemError(222)
- 2878                                                 ELSIF hasR
- 2879   AND SymTab.ConstInt(qe, v)
- 2880   AND SymTab.ConstInt(q2,
- 2881                                                       v2)
- 2882   AND ((v < lo)
- 2883                                                       OR (v2 < lo)
- 2884                                                       OR (v >= lo +
- 2885                                                          VAL(INTEGER, span))
- 2886                                                       OR (v2 >= lo +
- 2887                                                          VAL(INTEGER, span))
- 2888                                                       OR (v > v2)) THEN
- 2889                                                   SemError(222)
- 2890                                                  ELSIF hasR THEN
- 2891                                                    QbeGen.SetRange(sq, qe, q2,
- 2892                                                      lo, span)
- 2893                                                  ELSIF SymTab.ConstInt(qe,
- 2894                                                          v)
- 2895   AND ((v < lo)
- 2896                                                        OR (v >= lo +
- 2897                                                           VAL(INTEGER,
- 2898                                                             span))) THEN
- 2899                                                    SemError(222)
- 2900                                                  ELSE QbeGen.SetBit(sq, qe,
- 2901                                                    lo, span)
- 2902                                                 END
- 2903                                               END
- 2904                                             ELSIF (braceCls = SymTab.ClArray)
- 2905                                                OR (braceCls =
- 2906                                                   SymTab.ClRecord)
- 2907                                                OR (braceCls =
- 2908                                                   SymTab.ClClass) THEN
- 2909                                               IF hasR THEN SemError(230) END;
- 2910                                               reps := 1;
- 2911                                               IF hasB THEN
- 2912                                                 IF SymTab.ConstInt(q2, v2)
- 2913   AND (v2 >= 1) THEN
- 2914                                                   reps := v2
- 2915                                                 ELSE SemError(230)
- 2916                                                 END
- 2917                                               END;
- 2918                                               k := 0;
- 2919                                               WHILE k < reps DO
- 2920                                                 QbeGen.CtorElem(qe);
- 2921                                                 INC(k)
- 2922                                               END
- 2923                                             END; .) .
- 2924    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
- 2925                                               qe, q2: QbeGen.QVal;
- 2926                                               v, v2: INTEGER;
- 2927                                               lo: INTEGER;
- 2928                                               span: CARDINAL;
- 2929                                               cl, cl2: INTEGER;
- 2930                                               hasR: BOOLEAN; .)
- 2931      =                                   (. hasR := FALSE; .)
- 2932        Expr<et, qe>
- 2933        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
- 2934                                          (. lo := SymTab.SetBaseLo(st);
- 2935                                             span := SymTab.SetCount(st);
- 2936                                             IF (et = SymTab.InvalidType)
- 2937                                                OR (hasR AND (et2 =
- 2938                                                   SymTab.InvalidType)) THEN
- 2939                                             ELSE cl :=
- 2940                                                    SymTab.ClassOf(et);
- 2941                                               IF hasR THEN
- 2942                                                 cl2 :=
- 2943                                                   SymTab.ClassOf(et2)
- 2944                                               ELSE cl2 := SymTab.ClInt
- 2945                                               END;
- 2946                                               IF NOT SymTab.SetElemClassOk(cl)
- 2947                                                  OR (hasR AND NOT
- 2948                                                     SymTab.SetElemClassOk(cl2))
- 2949                                               THEN
- 2950                                                 SemError(222)
- 2951                                               ELSIF hasR
- 2952   AND SymTab.ConstInt(qe, v)
- 2953   AND SymTab.ConstInt(q2,
- 2954                                                     v2)
- 2955   AND ((v < lo)
- 2956                                                     OR (v2 < lo)
- 2957                                                     OR (v >= lo +
- 2958                                                        VAL(INTEGER, span))
- 2959                                                     OR (v2 >= lo +
- 2960                                                        VAL(INTEGER, span))
- 2961                                                     OR (v > v2)) THEN
- 2962                                                 SemError(222)
- 2963                                                ELSIF hasR THEN
- 2964                                                  QbeGen.SetRange(sq, qe, q2,
- 2965                                                    lo, span)
- 2966                                                ELSIF SymTab.ConstInt(qe,
- 2967                                                        v)
- 2968   AND ((v < lo)
- 2969                                                      OR (v >= lo +
- 2970                                                         VAL(INTEGER,
- 2971                                                           span))) THEN
- 2972                                                  SemError(222)
- 2973                                                ELSE QbeGen.SetBit(sq, qe,
- 2974                                                  lo, span)
- 2975                                               END
- 2976                                             END; .) .
- 2977    GetIdent<VAR n: SymTab.Name>
- 2978      = ident                             (. LexName(n); .) .
- 2979  
- 2980  END M2.
+ 2574                                               IF isHigh THEN
+ 2575                                                 DEC(c1)
+ 2576                                               END;
+ 2577                                               QbeGen.IntStr(c1, qr);
+ 2578                                               t := SymTab.IntType();
+ 2579                                               QbeGen.CopyOp(qr, q)
+ 2580                                             ELSIF dt = SymTab.InvalidType THEN
+ 2581                                               t := SymTab.InvalidType;
+ 2582                                               QbeGen.CopyOp("0", q)
+ 2583                                             ELSIF SymTab.ClassOf(dt) #
+ 2584                                                   SymTab.ClArray THEN
+ 2585                                               SemError(217);
+ 2586                                               t := SymTab.InvalidType;
+ 2587                                               QbeGen.CopyOp("0", q)
+ 2588                                             ELSE
+ 2589                                               IF isHigh THEN
+ 2590                                                 IF SymTab.IsOpenArray(dt) THEN
+ 2591                                                   QbeGen.OpenHi(qd, qr)
+ 2592                                                 ELSE
+ 2593                                                   QbeGen.IntStr(
+ 2594                                                     SymTab.ArrayHi(dt), qr)
+ 2595                                                 END
+ 2596                                               ELSE
+ 2597                                                 IF SymTab.IsOpenArray(dt) THEN
+ 2598                                                   QbeGen.LoadCount(qd, qr)
+ 2599                                                 ELSE
+ 2600                                                   QbeGen.IntStr(VAL(
+ 2601                                                     INTEGER,
+ 2602                                                     SymTab.ArrayLen(dt)),
+ 2603                                                     qr)
+ 2604                                                 END
+ 2605                                               END;
+ 2606                                                t := SymTab.IntType();
+ 2607                                                QbeGen.CopyOp(qr, q)
+ 2608                                              END; .)
+ 2609      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
+ 2610                                          (. IF dt = SymTab.InvalidType THEN
+ 2611                                               t := SymTab.InvalidType;
+ 2612                                               QbeGen.CopyOp("0", q)
+ 2613                                             ELSE
+ 2614                                               QbeGen.IntStr(VAL(INTEGER,
+ 2615                                                 SymTab.ObjectSize(dt)), q);
+ 2616                                               t := SymTab.IntType()
+ 2617                                             END; .)
+ 2618      | ( "SHIFT"                         (. isMax := FALSE; .)
+ 2619        | "ROTATE"                        (. isMax := TRUE; .) )
+ 2620        "(" Expr<et, q> "," Expr<et2, q2> ")"
+ 2621                                          (. (* set shift/rotate: isMax
+ 2622                                                doubles as "rotate" *)
+ 2623                                             IF (et # SymTab.InvalidType)
+ 2624                                                AND (SymTab.ClassOf(et) =
+ 2625                                                   SymTab.ClSet) THEN
+ 2626                                               QbeGen.SetShift(q, q2,
+ 2627                                                 SymTab.SetWords(et),
+ 2628                                                 SymTab.SetCount(et), isMax,
+ 2629                                                 qt);
+ 2630                                               t := et;
+ 2631                                               QbeGen.CopyOp(qt, q)
+ 2632                                             ELSE SemError(230);
+ 2633                                               t := SymTab.InvalidType;
+ 2634                                               QbeGen.CopyOp("0", q)
+ 2635                                             END; .)
+ 2636      | ( "MIN"                           (. isMax := FALSE; .)
+ 2637        | "MAX"                           (. isMax := TRUE; .) )
+ 2638        "(" Design<dt, dk, qd, qn, sfx> ")"
+ 2639                                          (. IF (dt # SymTab.InvalidType)
+ 2640   AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN
+ 2641                                               (* REAL/LONGREAL: the
+ 2642                                                  implementation bounds *)
+ 2643                                               IF isMax THEN
+ 2644                                                 QbeGen.NormReal(
+ 2645                                                   "3.402823e38", q)
+ 2646                                               ELSE QbeGen.NormReal(
+ 2647                                                   "-3.402823e38", q)
+ 2648                                               END;
+ 2649                                               t := SymTab.RealType()
+ 2650                                             ELSIF (dt #
+ 2651                                                SymTab.InvalidType)
+ 2652   AND (SymTab.ClassOf(dt) =
+ 2653                                                   SymTab.ClLong) THEN
+ 2654                                               IF isMax THEN
+ 2655                                                 QbeGen.CopyOp(
+ 2656                                                   "9223372036854775807", q)
+ 2657                                               ELSE QbeGen.CopyOp(
+ 2658                                                   "-9223372036854775808", q)
+ 2659                                               END;
+ 2660                                               t := SymTab.LongType()
+ 2661                                             ELSIF SymTab.TypeBounds(dt, lo,
+ 2662                                                      hi) THEN
+ 2663                                               IF isMax THEN
+ 2664                                                 QbeGen.IntStr(hi, q)
+ 2665                                               ELSE QbeGen.IntStr(lo, q)
+ 2666                                               END;
+ 2667                                               t := SymTab.IntType()
+ 2668                                             ELSE SemError(230);
+ 2669                                               t := SymTab.InvalidType;
+ 2670                                               QbeGen.CopyOp("0", q)
+ 2671                                             END; .)
+ 2672      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 2673                                          (. IF dt = SymTab.InvalidType THEN
+ 2674                                               t := SymTab.InvalidType;
+ 2675                                               QbeGen.CopyOp("0", q)
+ 2676                                             ELSE
+ 2677                                               IF sfx THEN
+ 2678                                                 QbeGen.CopyOp(qd, q)
+ 2679                                               ELSIF (dk = SymTab.KindVar)
+ 2680                                                  OR (dk = SymTab.KindParam) THEN
+ 2681                                                 QbeGen.AddrOf(qn, q)
+ 2682                                               ELSE SemError(230);
+ 2683                                                 QbeGen.CopyOp("0", q)
+ 2684                                               END;
+ 2685                                               t := SymTab.AddrType()
+ 2686                                             END; .)
+ 2687      | "CHR" "(" Expr<et, q> ")"
+ 2688                                          (. IF (et # SymTab.InvalidType)
+ 2689   AND NOT SymTab.IsIntFamily(et) THEN
+ 2690                                               SemError(211) END;
+ 2691                                             t := SymTab.CharType(); .)
+ 2692      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
+ 2693                                          (. IF et # SymTab.InvalidType THEN
+ 2694                                               IF (SymTab.ClassOf(et) #
+ 2695                                                   SymTab.ClChar)
+ 2696   AND (SymTab.ClassOf(et) #
+ 2697                                                     SymTab.ClBool)
+ 2698   AND (SymTab.ClassOf(et) #
+ 2699                                                     SymTab.ClEnum)
+ 2700   AND NOT SymTab.IsIntFamily(et) THEN
+ 2701                                                 SemError(211) END
+ 2702                                             END;
+ 2703                                             t := SymTab.IntType(); .)
+ 2704      | "CAP" "(" Expr<et, q> ")"
+ 2705                                          (. QbeGen.CapQ(q, qa);
+ 2706                                             QbeGen.CopyOp(qa, q);
+ 2707                                             t := SymTab.CharType(); .)
+ 2708      | "UCHR" "(" Expr<et, q> ")"
+ 2709                                          (. (* UCHR: the UCHAR constructor.
+ 2710                                                CHAR -> UCHAR (identity);
+ 2711                                                INTEGER familly -> UCHAR
+ 2712                                                (codepoint value). *)
+ 2713                                             IF (et # SymTab.InvalidType)
+ 2714    AND (SymTab.ClassOf(et) # SymTab.ClChar)
+ 2715    AND NOT SymTab.IsIntFamily(et) THEN
+ 2716                                               SemError(211) END;
+ 2717                                             t := SymTab.UCharType(); .)
+ 2718      | "CHR8" "(" Expr<et, q> ")"
+ 2719                                          (. IF (et # SymTab.InvalidType)
+ 2720    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
+ 2721                                               SemError(211) END;
+ 2722                                             QbeGen.WidenLong(q, qa);
+ 2723                                             QbeGen.CheckRange(qa, "0", "255");
+ 2724                                             t := SymTab.CharType(); .)
+ 2725      | "UORD" "(" Expr<et, q> ")"
+ 2726                                          (. (* UORD(u): the codepoint as a
+ 2727                                                32-bit ordinal (INTEGER),
+ 2728                                                cf. ORD for CHAR. *)
+ 2729                                             IF (et # SymTab.InvalidType)
+ 2730    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
+ 2731                                               SemError(211) END;
+ 2732                                             t := SymTab.IntType(); .)
+ 2733      | "ABS" "(" Expr<et, q> ")"
+ 2734                                          (. IF (et # SymTab.InvalidType)
+ 2735   AND NOT SymTab.IsIntFamily(et)
+ 2736   AND (SymTab.ClassOf(et) #
+ 2737                                                  SymTab.ClReal) THEN
+ 2738                                               SemError(211)
+ 2739                                             ELSE QbeGen.AbsQ(q, qa,
+ 2740                                                    SymTab.ClassOf(et) =
+ 2741                                                      SymTab.ClReal);
+ 2742                                               QbeGen.CopyOp(qa, q)
+ 2743                                             END;
+ 2744                                             t := et; .)
+ 2745      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
+ 2746                                          (. IF NOT SymTab.Lookup(vn) THEN
+ 2747                                               SemError(201);
+ 2748                                               t := SymTab.InvalidType
+ 2749                                             ELSE vt := SymTab.SymType(vn);
+ 2750                                               IF vt = SymTab.InvalidType THEN
+ 2751                                                 t := SymTab.InvalidType
+ 2752                                               ELSIF et =
+ 2753                                                  SymTab.InvalidType THEN
+ 2754                                                 t := vt
+ 2755                                               ELSE
+ 2756                                                 c1 := SymTab.ClassOf(et);
+ 2757                                                 c2 := SymTab.ClassOf(vt);
+ 2758                                                 IF (c1 = SymTab.ClInt)
+ 2759    AND (c2 = SymTab.ClLong) THEN
+ 2760                                                   QbeGen.WidenLong(q, qa);
+ 2761                                                   QbeGen.CopyOp(qa, q);
+ 2762                                                   t := vt
+ 2763                                                 ELSIF (c1 = SymTab.ClLong)
+ 2764    AND (c2 = SymTab.ClInt) THEN
+ 2765                                                   QbeGen.NarrowLong(q, qa);
+ 2766                                                   QbeGen.CopyOp(qa, q);
+ 2767                                                   t := vt
+ 2768                                                 ELSIF (c1 = SymTab.ClInt)
+ 2769    AND (c2 = SymTab.ClReal) THEN
+ 2770                                                   QbeGen.ConvIR(q, qa);
+ 2771                                                   QbeGen.CopyOp(qa, q);
+ 2772                                                   t := vt
+ 2773                                                 ELSIF (c1 = SymTab.ClLong)
+ 2774    AND (c2 = SymTab.ClReal) THEN
+ 2775                                                   QbeGen.ConvLR(q, qa);
+ 2776                                                   QbeGen.CopyOp(qa, q);
+ 2777                                                   t := vt
+ 2778                                                 ELSIF (c1 = SymTab.ClReal)
+ 2779    AND (c2 = SymTab.ClInt) THEN
+ 2780                                                   QbeGen.ConvRI(q, qa);
+ 2781                                                   QbeGen.CopyOp(qa, q);
+ 2782                                                   t := vt
+ 2783                                                 ELSIF (c1 = SymTab.ClReal)
+ 2784    AND (c2 = SymTab.ClLong) THEN
+ 2785                                                   QbeGen.ConvRL(q, qa);
+ 2786                                                   QbeGen.CopyOp(qa, q);
+ 2787                                                   t := vt
+ 2788                                                 ELSIF ((c1 = SymTab.ClInt)
+ 2789                                                     OR (c1 =
+ 2790                                                        SymTab.ClChar)
+ 2791                                                     OR (c1 =
+ 2792                                                        SymTab.ClBool)
+ 2793                                                     OR (c1 =
+ 2794                                                        SymTab.ClEnum))
+ 2795   AND ((c2 = SymTab.ClInt)
+ 2796                                                     OR (c2 =
+ 2797                                                        SymTab.ClChar)
+ 2798                                                     OR (c2 =
+ 2799                                                        SymTab.ClBool)
+ 2800                                                     OR (c2 =
+ 2801                                                        SymTab.ClEnum)) THEN
+ 2802                                                   t := vt
+ 2803                                                 ELSIF (c1 = SymTab.ClPtr)
+ 2804   AND (c2 = SymTab.ClPtr) THEN
+ 2805                                                   t := vt
+ 2806                                                 ELSIF (c1 = SymTab.ClReal)
+ 2807   AND (c2 = SymTab.ClReal) THEN
+ 2808                                                   t := vt
+ 2809                                                 ELSE SemError(230);
+ 2810                                                   t := SymTab.InvalidType
+ 2811                                                 END
+ 2812                                               END
+ 2813                                             END; .)
+ 2814      | "(" Expr<et, q> ")"               (. t := et; .)
+ 2815      | SetLit<st, sq>                    (. t := st;
+ 2816                                             QbeGen.CopyOp(sq, q); .)
+ 2817      | ( "NOT" | "~" ) Fact<t2, q2>      (. IF SymTab.BoolCheck(t2) THEN
+ 2818                                               t := SymTab.BoolType()
+ 2819                                             ELSE SemError(212);
+ 2820                                               t := SymTab.InvalidType END;
+ 2821                                             IF t # SymTab.InvalidType THEN
+ 2822                                               QbeGen.NotQ(q2, q)
+ 2823                                             ELSE QbeGen.CopyOp("0", q)
+ 2824                                             END; .) .
+ 2825    (* Set literals are SET OF [0..255] (8 words); elements validated
+ 2826       0..255 statically when foldable (222 otherwise), runtime trap
+ 2827       for computed elements. Ranges always lower via SetRange. *)
+ 2828    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2829      = "{"                               (. t := SymTab.NewSet(
+ 2830                                               SymTab.NewSubR(0, 255));
+ 2831                                             QbeGen.NewSetTemp(8, q);
+ 2832                                             QbeGen.SetZero(q, 8); .)
+ 2833        [ SetElem<t, q> { "," SetElem<t, q> } ]
+ 2834        "}" .
+ 2835    (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set)
+ 2836       or ArrayName{...} (an array constructor, GNU Modula-2).  The
+ 2837       declared type sets the width (set) or element type (array). *)
+ 2838    TypedBraceLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2839                                          (. VAR nw: CARDINAL;
+ 2840                                               savedCls: INTEGER; .)
+ 2841      = "{"                               (. savedCls := braceCls;
+ 2842                                             IF vt = SymTab.InvalidType THEN
+ 2843                                               braceCls := -1
+ 2844                                             ELSE braceCls :=
+ 2845                                                    SymTab.ClassOf(vt)
+ 2846                                             END;
+ 2847                                             IF braceCls = SymTab.ClSet THEN
+ 2848                                               IF vt = SymTab.InvalidType THEN
+ 2849                                                 nw := 8
+ 2850                                               ELSE nw := SymTab.SetWords(vt);
+ 2851                                                 IF nw = 0 THEN nw := 8 END
+ 2852                                               END;
+ 2853                                               QbeGen.NewSetTemp(nw, q);
+ 2854                                               QbeGen.SetZero(q, nw)
+ 2855                                             ELSIF (braceCls =
+ 2856                                                    SymTab.ClArray)
+ 2857                                                OR (braceCls =
+ 2858                                                    SymTab.ClRecord)
+ 2859                                                OR (braceCls =
+ 2860                                                    SymTab.ClClass) THEN
+ 2861                                               QbeGen.CtorBegin(vt)
+ 2862                                             ELSE
+ 2863                                               IF vt # SymTab.InvalidType THEN
+ 2864                                                 SemError(230) END;
+ 2865                                               braceCls := -1
+ 2866                                             END; .)
+ 2867        [ BraceElem<vt, q> { "," BraceElem<vt, q> } ]
+ 2868        "}"                               (. IF (braceCls = SymTab.ClArray)
+ 2869                                                OR (braceCls =
+ 2870                                                   SymTab.ClRecord)
+ 2871                                                OR (braceCls =
+ 2872                                                   SymTab.ClClass) THEN
+ 2873                                               QbeGen.CtorEnd(q)
+ 2874                                             ELSIF braceCls # SymTab.ClSet THEN
+ 2875                                               QbeGen.CopyOp("0", q)
+ 2876                                             END;
+ 2877                                             braceCls := savedCls; .) .
+ 2878    BraceElem<vt: SymTab.TypeIndex; VAR sq: QbeGen.QVal>
+ 2879                                          (. VAR et, et2: SymTab.TypeIndex;
+ 2880                                               qe, q2: QbeGen.QVal;
+ 2881                                               v, v2, reps, k: INTEGER;
+ 2882                                               elem: SymTab.TypeIndex;
+ 2883                                               lo: INTEGER;
+ 2884                                               span: CARDINAL;
+ 2885                                               cl, cl2: INTEGER;
+ 2886                                               hasR, hasB: BOOLEAN; .)
+ 2887      =                                   (. hasR := FALSE; hasB := FALSE; .)
+ 2888        Expr<et, qe>
+ 2889        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
+ 2890        [ "BY" Expr<et2, q2>              (. hasB := TRUE; .) ]
+ 2891                                          (. IF braceCls = SymTab.ClSet THEN
+ 2892                                               IF hasB THEN SemError(230) END;
+ 2893                                               lo := SymTab.SetBaseLo(vt);
+ 2894                                               span := SymTab.SetCount(vt);
+ 2895                                               IF (et = SymTab.InvalidType)
+ 2896                                                  OR (hasR AND (et2 =
+ 2897                                                     SymTab.InvalidType)) THEN
+ 2898                                               ELSE cl :=
+ 2899                                                      SymTab.ClassOf(et);
+ 2900                                                 IF hasR THEN
+ 2901                                                   cl2 :=
+ 2902                                                     SymTab.ClassOf(et2)
+ 2903                                                 ELSE cl2 := SymTab.ClInt
+ 2904                                                 END;
+ 2905                                                 IF NOT SymTab.SetElemClassOk(cl)
+ 2906                                                    OR (hasR AND NOT
+ 2907                                                       SymTab.SetElemClassOk(cl2))
+ 2908                                                 THEN
+ 2909                                                   SemError(222)
+ 2910                                                 ELSIF hasR
+ 2911   AND SymTab.ConstInt(qe, v)
+ 2912   AND SymTab.ConstInt(q2,
+ 2913                                                       v2)
+ 2914   AND ((v < lo)
+ 2915                                                       OR (v2 < lo)
+ 2916                                                       OR (v >= lo +
+ 2917                                                          VAL(INTEGER, span))
+ 2918                                                       OR (v2 >= lo +
+ 2919                                                          VAL(INTEGER, span))
+ 2920                                                       OR (v > v2)) THEN
+ 2921                                                   SemError(222)
+ 2922                                                  ELSIF hasR THEN
+ 2923                                                    QbeGen.SetRange(sq, qe, q2,
+ 2924                                                      lo, span)
+ 2925                                                  ELSIF SymTab.ConstInt(qe,
+ 2926                                                          v)
+ 2927   AND ((v < lo)
+ 2928                                                        OR (v >= lo +
+ 2929                                                           VAL(INTEGER,
+ 2930                                                             span))) THEN
+ 2931                                                    SemError(222)
+ 2932                                                  ELSE QbeGen.SetBit(sq, qe,
+ 2933                                                    lo, span)
+ 2934                                                 END
+ 2935                                               END
+ 2936                                             ELSIF (braceCls = SymTab.ClArray)
+ 2937                                                OR (braceCls =
+ 2938                                                   SymTab.ClRecord)
+ 2939                                                OR (braceCls =
+ 2940                                                   SymTab.ClClass) THEN
+ 2941                                               IF hasR THEN SemError(230) END;
+ 2942                                               reps := 1;
+ 2943                                               IF hasB THEN
+ 2944                                                 IF SymTab.ConstInt(q2, v2)
+ 2945   AND (v2 >= 1) THEN
+ 2946                                                   reps := v2
+ 2947                                                 ELSE SemError(230)
+ 2948                                                 END
+ 2949                                               END;
+ 2950                                               k := 0;
+ 2951                                               WHILE k < reps DO
+ 2952                                                 QbeGen.CtorElem(qe);
+ 2953                                                 INC(k)
+ 2954                                               END
+ 2955                                             END; .) .
+ 2956    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
+ 2957                                               qe, q2: QbeGen.QVal;
+ 2958                                               v, v2: INTEGER;
+ 2959                                               lo: INTEGER;
+ 2960                                               span: CARDINAL;
+ 2961                                               cl, cl2: INTEGER;
+ 2962                                               hasR: BOOLEAN; .)
+ 2963      =                                   (. hasR := FALSE; .)
+ 2964        Expr<et, qe>
+ 2965        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
+ 2966                                          (. lo := SymTab.SetBaseLo(st);
+ 2967                                             span := SymTab.SetCount(st);
+ 2968                                             IF (et = SymTab.InvalidType)
+ 2969                                                OR (hasR AND (et2 =
+ 2970                                                   SymTab.InvalidType)) THEN
+ 2971                                             ELSE cl :=
+ 2972                                                    SymTab.ClassOf(et);
+ 2973                                               IF hasR THEN
+ 2974                                                 cl2 :=
+ 2975                                                   SymTab.ClassOf(et2)
+ 2976                                               ELSE cl2 := SymTab.ClInt
+ 2977                                               END;
+ 2978                                               IF NOT SymTab.SetElemClassOk(cl)
+ 2979                                                  OR (hasR AND NOT
+ 2980                                                     SymTab.SetElemClassOk(cl2))
+ 2981                                               THEN
+ 2982                                                 SemError(222)
+ 2983                                               ELSIF hasR
+ 2984   AND SymTab.ConstInt(qe, v)
+ 2985   AND SymTab.ConstInt(q2,
+ 2986                                                     v2)
+ 2987   AND ((v < lo)
+ 2988                                                     OR (v2 < lo)
+ 2989                                                     OR (v >= lo +
+ 2990                                                        VAL(INTEGER, span))
+ 2991                                                     OR (v2 >= lo +
+ 2992                                                        VAL(INTEGER, span))
+ 2993                                                     OR (v > v2)) THEN
+ 2994                                                 SemError(222)
+ 2995                                                ELSIF hasR THEN
+ 2996                                                  QbeGen.SetRange(sq, qe, q2,
+ 2997                                                    lo, span)
+ 2998                                                ELSIF SymTab.ConstInt(qe,
+ 2999                                                        v)
+ 3000   AND ((v < lo)
+ 3001                                                      OR (v >= lo +
+ 3002                                                         VAL(INTEGER,
+ 3003                                                           span))) THEN
+ 3004                                                  SemError(222)
+ 3005                                                ELSE QbeGen.SetBit(sq, qe,
+ 3006                                                  lo, span)
+ 3007                                               END
+ 3008                                             END; .) .
+ 3009    GetIdent<VAR n: SymTab.Name>
+ 3010      = ident                             (. LexName(n); .) .
+ 3011  
+ 3012  END M2.
 
 
     0 errors
     0 errors
 
 

+ 5 - 0
compiler/src/SymTab.def

@@ -432,6 +432,11 @@ PROCEDURE ForwardType (name: ARRAY OF CHAR): TypeIndex;
 
 
 PROCEDURE IsUnresolved (t: TypeIndex): BOOLEAN;
 PROCEDURE IsUnresolved (t: TypeIndex): BOOLEAN;
 (* TRUE for a forward placeholder whose target is not yet declared. *)
 (* TRUE for a forward placeholder whose target is not yet declared. *)
+PROCEDURE FwdPending (): CARDINAL;
+PROCEDURE FwdInfo (i: CARDINAL; VAR name: Name; VAR unresolved: BOOLEAN);
+(* Module-level forward type references: enumerate them at module end
+   and flag those never completed (undeclared type). *)
+PROCEDURE FwdClear;
 
 
 PROCEDURE IntType (): TypeIndex;
 PROCEDURE IntType (): TypeIndex;
 PROCEDURE UCharType (): TypeIndex;
 PROCEDURE UCharType (): TypeIndex;

+ 25 - 2
compiler/src/SymTab.mod

@@ -87,6 +87,10 @@ VAR
   tlo : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
   tlo : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
   thi : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
   thi : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
   tenum : ARRAY [0 .. MaxTypes - 1] OF CARDINAL; (* enum literal count *)
   tenum : ARRAY [0 .. MaxTypes - 1] OF CARDINAL; (* enum literal count *)
+  (* module-level forward type references awaiting completion *)
+  pfwdN : CARDINAL;
+  pfwdName : ARRAY [0 .. 255] OF Name;
+  pfwdT : ARRAY [0 .. 255] OF TypeIndex;
   tparent : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
   tparent : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
   tscope : ARRAY [0 .. MaxTypes - 1] OF ScopePtr;
   tscope : ARRAY [0 .. MaxTypes - 1] OF ScopePtr;
   tdone : ARRAY [0 .. MaxTypes - 1] OF BOOLEAN;
   tdone : ARRAY [0 .. MaxTypes - 1] OF BOOLEAN;
@@ -2366,9 +2370,30 @@ PROCEDURE ForwardType (name: ARRAY OF CHAR): TypeIndex;
     IF NOT Enter(name, KindType) THEN RETURN InvalidType END;
     IF NOT Enter(name, KindType) THEN RETURN InvalidType END;
     t := NewAlias();
     t := NewAlias();
     SetSymType(name, t);
     SetSymType(name, t);
+    IF (typeBlockDepth = 0) AND (pfwdN <= HIGH(pfwdName)) THEN
+      Assign(pfwdName[pfwdN], name);
+      pfwdT[pfwdN] := t;
+      INC(pfwdN)
+    END;
     RETURN t
     RETURN t
   END ForwardType;
   END ForwardType;
 
 
+PROCEDURE FwdPending (): CARDINAL;
+  BEGIN RETURN pfwdN END FwdPending;
+
+PROCEDURE FwdInfo (i: CARDINAL; VAR name: Name; VAR unresolved: BOOLEAN);
+  BEGIN
+    name[0] := CHR(0);
+    unresolved := FALSE;
+    IF i < pfwdN THEN
+      Assign(name, pfwdName[i]);
+      unresolved := Resolve(pfwdT[i]) = InvalidType
+    END
+  END FwdInfo;
+
+PROCEDURE FwdClear;
+  BEGIN pfwdN := 0 END FwdClear;
+
 PROCEDURE QualNode (mod, name: ARRAY OF CHAR): SymPtr;
 PROCEDURE QualNode (mod, name: ARRAY OF CHAR): SymPtr;
   VAR i : INTEGER;
   VAR i : INTEGER;
   BEGIN
   BEGIN
@@ -2966,8 +2991,6 @@ PROCEDURE Init;
     Predef("CARDINAL16", KindPredef, dCard);
     Predef("CARDINAL16", KindPredef, dCard);
     Predef("CARDINAL32", KindPredef, dCard);
     Predef("CARDINAL32", KindPredef, dCard);
     Predef("CARDINAL64", KindPredef, dLong);
     Predef("CARDINAL64", KindPredef, dLong);
-    (* gm2's pervasive opaque dynamic-string type (pointer-sized). *)
-    Predef("String", KindPredef, dAddr);
     Predef("NIL", KindConst, dNil)
     Predef("NIL", KindConst, dNil)
   END Init;
   END Init;
 
 

+ 8 - 0
compiler/tests/d_string.def

@@ -0,0 +1,8 @@
+DEFINITION MODULE DString;
+(* gm2-style opaque dynamic string: TYPE String; completed in the
+   implementation (DynamicStrings model). *)
+TYPE String;
+PROCEDURE Make(n : INTEGER) : String;
+PROCEDURE Get(s : String) : INTEGER;
+PROCEDURE IsNil(s : String) : BOOLEAN;
+END DString.

+ 11 - 0
compiler/tests/d_string.mod

@@ -0,0 +1,11 @@
+IMPLEMENTATION MODULE DString;
+(* Completes the opaque String here; clients see only the opaque type. *)
+TYPE String = POINTER TO RECORD v : INTEGER END;
+PROCEDURE Make(n : INTEGER) : String;
+VAR s : String;
+BEGIN NEW(s); s^.v := n; RETURN s END Make;
+PROCEDURE Get(s : String) : INTEGER;
+BEGIN RETURN s^.v END Get;
+PROCEDURE IsNil(s : String) : BOOLEAN;
+BEGIN RETURN s = NIL END IsNil;
+END DString.

+ 8 - 5
compiler/tests/t_string.mod

@@ -1,8 +1,11 @@
-MODULE tstring;
-// gm2's pervasive opaque String type (pointer-like).
+MODULE TString;
+// gm2-style opaque String, imported (not pervasive): value ops on an
+// opaque type are pointer-like.
+FROM DString IMPORT String, Make, Get, IsNil;
 VAR s, t : String;
 VAR s, t : String;
 VAR ExitCode : INTEGER;
 VAR ExitCode : INTEGER;
 BEGIN
 BEGIN
-  s := NIL; t := s;
-  IF (s = NIL) AND (t = NIL) THEN ExitCode := 42 ELSE ExitCode := 1 END
-END tstring.
+  s := Make(42);
+  t := s;
+  IF (Get(t) = 42) AND NOT IsNil(t) THEN ExitCode := 42 ELSE ExitCode := 1 END
+END TString.

+ 8 - 5
docs/analysis_gaps.md

@@ -1,12 +1,12 @@
 # m2compiler-V3 — gap analysis (2026-09-30)
 # m2compiler-V3 — gap analysis (2026-09-30)
 
 
-Suite **169/169**, self-hosting fixpoint OK (2,730,510 bytes).
+Suite **169/169**, self-hosting fixpoint OK (2,754,353 bytes).
 Corpus at this point (with `$V3_LIBS`):
 Corpus at this point (with `$V3_LIBS`):
 
 
 | corpus | compile-OK | CRASH | LANG |
 | corpus | compile-OK | CRASH | LANG |
 | --- | --- | --- | --- |
 | --- | --- | --- | --- |
-| gm2 testsuite (612) | 395 | 0 | 209 |
-| gm2 stdlib (336) | 131 | 0 | 205 |
+| gm2 testsuite (612) | 392 | 0 | 212 |
+| gm2 stdlib (336) | 127 | 0 | 209 |
 
 
 Failure taxonomy (testsuite, per file): `undeclared identifier` 65,
 Failure taxonomy (testsuite, per file): `undeclared identifier` 65,
 `not supported yet` 43, `invalid call` 25, `incompatible assignment`
 `not supported yet` 43, `invalid call` 25, `incompatible assignment`
@@ -46,7 +46,10 @@ Ranked by corpus impact (each verified by a failing file or a probe):
    sized-bit names (`INCL`/`EXCL`/`SHIFT` recur).
    sized-bit names (`INCL`/`EXCL`/`SHIFT` recur).
 5. **Enum subranges / BOOLEAN bounds** — `[a..d]`,
 5. **Enum subranges / BOOLEAN bounds** — `[a..d]`,
    `ARRAY [FALSE..TRUE] …` are `230`.
    `ARRAY [FALSE..TRUE] …` are `230`.
-6. **`String`** (gm2 magic type) — used throughout the stdlib corpus.
+6. **`String`** — *not* a gm2 built-in: it is an opaque type imported
+   from a definition module (`DynamicStrings`, or a local `opaque`).
+   V3 now treats unresolved (opaque/forward) aliases as pointer-like,
+   which is the real fix.
 7. **`GOTO` + labels** — parse error.
 7. **`GOTO` + labels** — parse error.
 8. **Whole-variant-record assignment/equality** — deliberately `236`.
 8. **Whole-variant-record assignment/equality** — deliberately `236`.
 9. **Nested local `MODULE`** — parsed, not lowered.
 9. **Nested local `MODULE`** — parsed, not lowered.
@@ -101,7 +104,7 @@ hex, `NOT`/`AND`/`OR` only, TopSpeed legacy isolated in the sidecar.
 5. ~~**Forward type references**~~ ✅ (module-level globals; TYPE-block
 5. ~~**Forward type references**~~ ✅ (module-level globals; TYPE-block
    forwards already worked)
    forwards already worked)
 
 
-Also done: `String` (opaque/pointer-like), variant-record
+Also done: opaque/pointer-like types (incl. `String`), variant-record
 assignment (flat blit), nested-`MODULE` lowering, `ADDRESS`↔pointer
 assignment (flat blit), nested-`MODULE` lowering, `ADDRESS`↔pointer
 assignment.
 assignment.
 
 

+ 5 - 3
docs/features.md

@@ -60,9 +60,11 @@ Legend: ✅ done · 🔄 partial · ⏸ not started / deferred.
 - ✅ Variant records (`RECORD CASE … OF … END`); whole-record
 - ✅ Variant records (`RECORD CASE … OF … END`); whole-record
   assignment is a flat byte blit (correct for overlapping fields) and
   assignment is a flat byte blit (correct for overlapping fields) and
   whole-record `=` is 213.
   whole-record `=` is 213.
-- ✅ gm2's pervasive opaque `String`: an undeclared/opaque type is
-  pointer-like (assign `NIL`, copy, compare, pass), and `String` is
-  predefined (imported definitions shadow it).
+- ✅ Opaque/forward types used as values: an unresolved (opaque or
+  forward) alias is pointer-like (assign `NIL`, copy, compare, pass).
+  gm2's `String` is **not** built in — it is an opaque type imported
+  from a definition module (`DynamicStrings`, or a local `opaque`);
+  an undeclared type name is an error as in gm2.
 
 
 ## Declarations
 ## Declarations
 - ✅ `CONST` (integer/char/real literals, folded), `VAR`, `TYPE`,
 - ✅ `CONST` (integer/char/real literals, folded), `VAR`, `TYPE`,

+ 6 - 3
docs/summary_string-variant-nested.md

@@ -1,6 +1,6 @@
 # Session summary — 2026-09-30 (b): constructors, corpus gaps, String/variant/nested
 # Session summary — 2026-09-30 (b): constructors, corpus gaps, String/variant/nested
 
 
-Suite **169/169**; self-hosting fixpoint **OK** (image **2,730,510
+Suite **169/169**; self-hosting fixpoint **OK** (image **2,754,353
 bytes**). `master`, tree clean except the user's uncommitted
 bytes**). `master`, tree clean except the user's uncommitted
 `compiler/toto.mod`.
 `compiler/toto.mod`.
 
 
@@ -50,8 +50,10 @@ nine corpus-driven gaps.
 
 
 - **Opaque/forward/undeclared aliases are pointer-like** — `ClassOf`
 - **Opaque/forward/undeclared aliases are pointer-like** — `ClassOf`
   returns `ClPtr` for an unresolved alias, so `Design`/`DeclVar`/
   returns `ClPtr` for an unresolved alias, so `Design`/`DeclVar`/
-  `ResClass`/`AssOrCall` treat them as pointers; gm2's pervasive
-  **`String`** is predefined (imported definitions shadow it).
+  `ResClass`/`AssOrCall` treat them as pointers.  This is what gm2's
+  opaque **`String`** needs: `String` is *not* built-in, it is an
+  opaque type imported from a definition module (`DynamicStrings`, or a
+  local `opaque`); an undeclared type name is an error, as in gm2.
 - **Variant-record assignment** — `CopyRecord` is a flat byte blit of
 - **Variant-record assignment** — `CopyRecord` is a flat byte blit of
   `TypeSize(t)` (records are flat blobs; the only correct choice for
   `TypeSize(t)` (records are flat blobs; the only correct choice for
   overlapping variant fields); variant records are emitted as one
   overlapping variant fields); variant records are emitted as one
@@ -69,6 +71,7 @@ nine corpus-driven gaps.
 | `v3-ctor-gaps` | 301 | 115 |
 | `v3-ctor-gaps` | 301 | 115 |
 | `v3-gaps-1-5` | 376 | 124 |
 | `v3-gaps-1-5` | 376 | 124 |
 | `v3-string-variant-nested` | **395** | **131** |
 | `v3-string-variant-nested` | **395** | **131** |
+| after conformant `String` cleanup | **392** | **127** |
 
 
 CRASH 0 throughout.  Remaining testsuite taxonomy: `undeclared
 CRASH 0 throughout.  Remaining testsuite taxonomy: `undeclared
 identifier` 65, `not supported yet` 34, `invalid call` 27,
 identifier` 65, `not supported yet` 34, `invalid call` 27,

+ 11 - 7
docs/summary_v3-corpus.md

@@ -22,19 +22,19 @@ gap).
 
 
 | | no libs | with `$V3_LIBS` |
 | | no libs | with `$V3_LIBS` |
 | --- | --- | --- |
 | --- | --- | --- |
-| **compile-OK** | 242 | **395** |
+| **compile-OK** | 242 | **392** |
 | CRASH | 0 | 0 |
 | CRASH | 0 | 0 |
 | LIB | 185 | **9** |
 | LIB | 185 | **9** |
-| LANG | 185 | **209** |
+| LANG | 185 | **212** |
 
 
 **2. gm2 standard libraries** (`m2pim`/`m2iso`/`m2log`/`m2cor`/`m2min`,
 **2. gm2 standard libraries** (`m2pim`/`m2iso`/`m2log`/`m2cor`/`m2min`,
 336 files):
 336 files):
 
 
 | | no libs | with `$V3_LIBS` |
 | | no libs | with `$V3_LIBS` |
 | --- | --- | --- |
 | --- | --- | --- |
-| **compile-OK** | 78 | **131** |
+| **compile-OK** | 78 | **127** |
 | LIB | 176 | **0** |
 | LIB | 176 | **0** |
-| LANG | 82 | **205** |
+| LANG | 82 | **209** |
 
 
 (With the import path set, LIB noise is gone and the true LANG counts
 (With the import path set, LIB noise is gone and the true LANG counts
 are visible.)
 are visible.)
@@ -104,9 +104,13 @@ are visible.)
 17. **Module-level forward type references** — a global may name a type
 17. **Module-level forward type references** — a global may name a type
     declared further down; emission is deferred until the TYPE block
     declared further down; emission is deferred until the TYPE block
     completes (TYPE-block forwards already worked).
     completes (TYPE-block forwards already worked).
-18. **`String` and opaque/forward types** — an undeclared or opaque
-    alias is pointer-like (`NIL`, copy, compare, pass); gm2's pervasive
-    `String` is predefined (imported definitions shadow it).
+18. **`String` and opaque/forward types** — an unresolved (opaque or
+    forward) alias is pointer-like (assign `NIL`, copy, compare, pass),
+    which is what gm2's opaque `String` needs.  `String` is **not**
+    built-in: it is imported from a definition module
+    (`DynamicStrings`/`opaque`), as in gm2.  An undeclared type name at
+    module level is reported (`201`, undeclared identifier) once the
+    module's TYPE declarations are known (`FwdPending`/`FwdInfo`).
 19. **Variant-record assignment** — whole-record assignment is now a
 19. **Variant-record assignment** — whole-record assignment is now a
     flat byte blit of the (max) record size, correct for overlapping
     flat byte blit of the (max) record size, correct for overlapping
     variant fields; variant records are emitted as a zeroed blob.
     variant fields; variant records are emitted as a zeroed blob.