瀏覽代碼

language: implement ISO PACKEDSET (1/2/4-byte storage)

PACKEDSET OF <ordinal> now uses its own 1/2/4-byte representation for spans up to 32 bits instead of aliasing SET. SIZE reports the packed width, ORD loads the mask, and INCL/EXCL/IN, assignment, set operations, packed array/record elements, and value/VAR parameters all operate on packed values. Wider spans report 230. Add t_packedset. The onebyte* corpus files still fail earlier on declaration order (module variable r used before its declaration), not PACKEDSET.
Eric Streit 2 天之前
父節點
當前提交
6b2df4c574

+ 3 - 3
README.md

@@ -45,10 +45,10 @@ vendor/            qbe toolchain pin
 docs/              STATUS.md, plan.md, plan-*.md, analysis_*.md, summary_*.md
 ```
 
-## Status (2026-10-22)
+## Status (2026-10-23)
 
-- Suite **262/262**; self-hosting **fixpoint OK** (byte-identical
-  stage2/stage3, 4,032,793 bytes); corpus **511/612 compile-OK,
+- Suite **263/263**; self-hosting **fixpoint OK** (byte-identical
+  stage2/stage3, 4,075,853 bytes); corpus **511/612 compile-OK,
   0 crashes** (`tools/v3-corpus`; the corpus is gm2's testsuite, so it
   mixes conforming Modula-2 with gm2 leniencies — see `docs/gaps/`).
 - Active branch **`master`**.

+ 1 - 0
compiler/run_tests.sh

@@ -73,6 +73,7 @@ expect_run t_system.mod 42
 expect_run t_proctype2.mod 42
 expect_run t_byte.mod 42
 expect_run t_word16.mod 42
+expect_run t_packedset.mod 42
 expect_run t_smallgaps.mod 42
 expect_run t_ctor1.mod 0
 expect_run t_ctor2.mod 0

+ 45 - 8
compiler/src/Lower.mod

@@ -1365,6 +1365,16 @@ PROCEDURE LowerCall (n: AST.Node; VAR t: SymTab.TypeIndex;
               QbeGen.OpenScalarDesc(qe, at, ft, qa);
               IF NOT QbeGen.CallArg(qa, "l") THEN END
             ELSE
+              (* A SET/PACKEDSET value actual with a different
+                 representation is converted to a temporary of the
+                 formal type before the call. *)
+              IF (SymTab.ClassOf(ft) = SymTab.ClSet)
+                 AND (SymTab.ClassOf(at) = SymTab.ClSet)
+                 AND (SymTab.IsPackedSet(ft) # SymTab.IsPackedSet(at)) THEN
+                QbeGen.NewSetTemp(SymTab.SetWords(ft), qt);
+                QbeGen.CopySetVal(qt, ft, qe, at);
+                QbeGen.CopyOp(qt, qe)
+              END;
               conv := (SymTab.ClassOf(ft) = SymTab.ClReal)
                       AND SymTab.IsIntFamily(at);
               IF conv THEN
@@ -1459,7 +1469,11 @@ PROCEDURE LowerBuiltinExpr (n: AST.Node; nm: SymTab.Name;
     ELSIF SymTab.Equal(nm, "CHR") THEN
       LowerExpr(AST.Child(n, 1), et, q); t := SymTab.CharType()
     ELSIF SymTab.Equal(nm, "ORD") THEN
-      LowerExpr(AST.Child(n, 1), et, q); t := SymTab.IntType()
+      LowerExpr(AST.Child(n, 1), et, q);
+      IF SymTab.IsPackedSet(et) THEN
+        QbeGen.LoadPacked(q, et, qa); QbeGen.CopyOp(qa, q)
+      END;
+      t := SymTab.IntType()
     ELSIF SymTab.Equal(nm, "UCHR") THEN
       LowerExpr(AST.Child(n, 1), et, q); t := SymTab.UCharType()
     ELSIF SymTab.Equal(nm, "CHR8") THEN
@@ -1639,7 +1653,15 @@ PROCEDURE LowerBuiltinStmt (n: AST.Node; nm: SymTab.Name);
       IF at = SymTab.InvalidType THEN
       ELSIF SymTab.ClassOf(at) # SymTab.ClSet THEN
       ELSE
-        IF isInc THEN QbeGen.SetBit(qd, qe, SymTab.SetBaseLo(at), SymTab.SetCount(at))
+        IF SymTab.IsPackedSet(at) THEN
+          IF isInc THEN QbeGen.PackedSetBit(qd, at, qe,
+                                             SymTab.SetBaseLo(at),
+                                             SymTab.SetCount(at))
+          ELSE QbeGen.PackedSetClearBit(qd, at, qe,
+                                         SymTab.SetBaseLo(at),
+                                         SymTab.SetCount(at))
+          END
+        ELSIF isInc THEN QbeGen.SetBit(qd, qe, SymTab.SetBaseLo(at), SymTab.SetCount(at))
         ELSE QbeGen.SetClearBit(qd, qe, SymTab.SetBaseLo(at), SymTab.SetCount(at))
         END
       END
@@ -2118,7 +2140,12 @@ PROCEDURE LowerExprFull (n: AST.Node; VAR t: SymTab.TypeIndex;
         END;
         rop := SymTab.OpEq; folded := RelSym(op, rop);
         IF op = AST.OpIn THEN
-          QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2), SymTab.SetCount(t2), qt);
+          IF SymTab.IsPackedSet(t2) THEN
+            QbeGen.PackedInSet(q, q2, SymTab.SetBaseLo(t2),
+              SymTab.SetCount(t2), t2, qt)
+          ELSE QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2),
+                 SymTab.SetCount(t2), qt)
+          END;
           t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
         ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
            OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
@@ -2126,7 +2153,11 @@ PROCEDURE LowerExprFull (n: AST.Node; VAR t: SymTab.TypeIndex;
           t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
         ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
            OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
-          QbeGen.CmpSet(rop, q, q2, SymTab.SetWords(t), SymTab.SetWords(t2), qt);
+          IF SymTab.IsPackedSet(t) OR SymTab.IsPackedSet(t2) THEN
+            QbeGen.PackedCmpSet(rop, q, t, q2, t2, qt)
+          ELSE QbeGen.CmpSet(rop, q, q2, SymTab.SetWords(t),
+                 SymTab.SetWords(t2), qt)
+          END;
           t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
         ELSIF SymTab.StrCompat(t, t2) THEN
           QbeGen.StrEq(rop, q, q2, qt);
@@ -2194,8 +2225,14 @@ PROCEDURE LowerExprFull (n: AST.Node; VAR t: SymTab.TypeIndex;
           ELSIF op = AST.OpMul THEN idx := 1
           ELSE idx := 3
           END;
-          QbeGen.SetBinOp(idx, q, q2, lw, rw, qt);
-          t := SymTab.NewSet(SymTab.NewSubR(0, VAL(INTEGER, mw) * 32 - 1));
+          IF SymTab.IsPackedSet(t) OR SymTab.IsPackedSet(t2) THEN
+            QbeGen.PackedSetBinOp(idx, q, t, q2, t2, qt);
+            t := SymTab.NewSet(SymTab.NewSubR(0, 31))
+          ELSE
+            QbeGen.SetBinOp(idx, q, q2, lw, rw, qt);
+            t := SymTab.NewSet(SymTab.NewSubR(0,
+              VAL(INTEGER, mw) * 32 - 1))
+          END;
           QbeGen.CopyOp(qt, q)
         ELSIF (op = AST.OpAdd)
            AND (SymTab.StrCompat(t, t2)
@@ -2327,7 +2364,7 @@ PROCEDURE LowerStmt (seq: AST.Node);
           ELSE QbeGen.CopyArray(qd, qe, dt)
           END
         ELSIF SymTab.ClassOf(dt) = SymTab.ClSet THEN
-          QbeGen.CopySet(qd, qe, SymTab.SetWords(dt), SymTab.SetWords(et))
+          QbeGen.CopySetVal(qd, dt, qe, et)
         ELSIF SymTab.ClassOf(dt) = SymTab.ClRecord THEN
           QbeGen.CopyRecord(qd, qe, dt)
         ELSIF SymTab.IsLongFamily(dt) THEN
@@ -2345,7 +2382,7 @@ PROCEDURE LowerStmt (seq: AST.Node);
           ELSE QbeGen.CopyArray(qd, qe, dt)
           END
         ELSIF SymTab.ClassOf(dt) = SymTab.ClSet THEN
-          QbeGen.CopySet(qd, qe, SymTab.SetWords(dt), SymTab.SetWords(et))
+          QbeGen.CopySetVal(qd, dt, qe, et)
         ELSIF SymTab.ClassOf(dt) = SymTab.ClRecord THEN
           QbeGen.CopyRecord(qd, qe, dt)
         ELSIF SymTab.IsSmallInt(dt) THEN

+ 44 - 1
compiler/src/M2.atg

@@ -1268,6 +1268,7 @@ PRODUCTIONS
     | Enum<t>
     | ArrayType<t, allowOpen>
     | SetType<t>
+    | PackSetType<t>
     | RecordType<t>
     | PointerType<t>
     | ProcType<t> .
@@ -1495,6 +1496,47 @@ PRODUCTIONS
                                              ELSE t := SymTab.NewSet(base)
                                              END
                                            END; .) .
+  (* PACKEDSET: same base rules as SET, but 1/2/4-byte storage.  V3
+     limits the span to 32 bits (SetBytes 1..4); wider packed sets are
+     an implementation limit (230). *)
+  PackSetType<VAR t: SymTab.TypeIndex>  (. VAR base: SymTab.TypeIndex;
+                                             blo, bhi, bspan: INTEGER;
+                                             bcls: INTEGER; .)
+    = "PACKEDSET"                       (. allowFwdType := FALSE; .)
+      "OF" Type<base, FALSE>
+                                        (. IF base = SymTab.InvalidType THEN
+                                             t := SymTab.InvalidType
+                                           ELSIF SymTab.Unresolved(base) THEN
+                                             t := SymTab.NewPackSet(base)
+                                           ELSE bcls :=
+                                                  SymTab.ClassOf(base);
+                                             IF SymTab.SubBounds(base,
+                                                     blo, bhi) THEN
+                                               bspan := bhi - blo + 1
+                                             ELSIF bcls = SymTab.ClBool THEN
+                                               blo := 0; bspan := 2
+                                             ELSIF bcls = SymTab.ClChar THEN
+                                               blo := 0; bspan := 256
+                                             ELSIF bcls = SymTab.ClByte THEN
+                                               blo := 0; bspan := 256
+                                             ELSIF bcls = SymTab.ClSByte THEN
+                                               blo := -128; bspan := 256
+                                             ELSIF bcls = SymTab.ClWord16 THEN
+                                               blo := 0; bspan := 65536
+                                             ELSIF bcls = SymTab.ClSWord16 THEN
+                                               blo := -32768; bspan := 65536
+                                             ELSIF bcls = SymTab.ClEnum THEN
+                                               blo := 0;
+                                               bspan := VAL(INTEGER,
+                                                 SymTab.EnumCount(base))
+                                             ELSE bspan := 0 END;
+                                             IF (bspan <= 0)
+                                                OR (bspan > 32) THEN
+                                               SemError(230);
+                                               t := SymTab.InvalidType
+                                             ELSE t := SymTab.NewPackSet(base)
+                                             END
+                                           END; .) .
   (* Records: flat blobs; array fields are pointers to static
      descriptors (locked amendment), nested records inline. Field
      offsets static and declaration-ordered. *)
@@ -3994,7 +4036,8 @@ PRODUCTIONS
                                                    SymTab.ClBool)
  AND (SymTab.ClassOf(et) #
                                                    SymTab.ClEnum)
- AND NOT SymTab.IsIntFamily(et) THEN
+ AND NOT SymTab.IsIntFamily(et)
+ AND NOT SymTab.IsPackedSet(et) THEN
                                                SemError(211) END
                                            END;
                                            t := SymTab.IntType(); .)

+ 3214 - 3171
compiler/src/M2.lst

@@ -1292,3188 +1292,3231 @@ Listing:
  1268      | Enum<t>
  1269      | ArrayType<t, allowOpen>
  1270      | SetType<t>
- 1271      | RecordType<t>
- 1272      | PointerType<t>
- 1273      | ProcType<t> .
- 1274    PointerType<VAR t: SymTab.TypeIndex>  (. VAR base: SymTab.TypeIndex; .)
- 1275      = "POINTER" "TO"                    (. allowFwdType := TRUE; .)
- 1276        Type<base, FALSE>                 (. allowFwdType := FALSE;
- 1277                                             t := SymTab.NewPtr(base); .) .
- 1278    (* Procedure types (step 8.5): PROCEDURE (params): result. Values
- 1279       are code pointers; params are collected into the descriptor. *)
- 1280    ProcType<VAR t: SymTab.TypeIndex>     (. VAR res, pt: SymTab.TypeIndex;
- 1281                                               isV: BOOLEAN; .)
- 1282      = ( "PROCEDURE" | "PROC" )         (. allowFwdType := FALSE;
- 1283                                             res := SymTab.InvalidType;
- 1284                                             t := SymTab.NewProcType(res); .)
- 1285        [ "(" [ ProcTypeSection<t>
- 1286                 { (";" | ",") ProcTypeSection<t> } ] ")" ]
- 1287        [ ":" ( TypeIdent<res>            (. SymTab.SetProcTypeRes(t, res); .)
- 1288              | "PROC"                    (. (* PROC as a result type: the
- 1289                                                pervasive procedure value
- 1290                                                type (ISO/PIM) *)
- 1291                                             SymTab.SetProcTypeRes(t,
- 1292                                               SymTab.AddrType()); .) ) ] .
- 1293    ProcTypeSection<t: SymTab.TypeIndex>  (. VAR pt: SymTab.TypeIndex;
- 1294                                               isV: BOOLEAN;
- 1295                                               cnt, k: CARDINAL;
- 1296                                               names: ARRAY [0 .. 15] OF SymTab.Name; .)
- 1297      =                                   (. isV := FALSE; cnt := 0; .)
- 1298        [ "VAR"                           (. isV := TRUE; .) ]
- 1299        ( GetIdent<names[cnt]>            (. INC(cnt); .)
- 1300          { "," ( GetIdent<names[cnt]>    (. INC(cnt); .)
- 1301                |                         (. (* a comma followed by a type
- 1302                                                (possibly VAR) ends the name
- 1303                                                list: the collected names
- 1304                                                were types, not names *)
- 1305                                             k := 0;
- 1306                                             WHILE k < cnt DO
- 1307                                               SymTab.ProcTypeAdd(t, isV,
- 1308                                                 SymTab.SymType(names[k]));
- 1309                                               INC(k)
- 1310                                             END;
- 1311                                             cnt := 0; .)
- 1312                  [ "VAR"                 (. isV := TRUE; .) ]
- 1313                  Type<pt, TRUE>          (. SymTab.ProcTypeAdd(t, isV, pt); .) ) }
- 1314          ( ":" Type<pt, TRUE>            (. k := 0;
- 1315                                             WHILE k < cnt DO
- 1316                                               SymTab.ProcTypeAdd(t, isV, pt);
- 1317                                               INC(k)
- 1318                                             END; .)
- 1319          |                               (. (* type-only parameter list:
- 1320                                                each collected name is a
- 1321                                                type (CHAR, a declared type,
- 1322                                                ... or the GNU shorthand) *)
- 1323                                             k := 0;
- 1324                                             WHILE k < cnt DO
- 1325                                               IF IsTypeName(names[k]) THEN
- 1326                                                 pt := SymTab.SymType(names[k])
- 1327                                               ELSE SemError(201);
- 1328                                                 pt := SymTab.InvalidType
- 1329                                               END;
- 1330                                               SymTab.ProcTypeAdd(t, isV, pt);
- 1331                                               INC(k)
- 1332                                             END; .) )
- 1333        | Type<pt, TRUE>                 (. (* unnamed parameter (PIM):
- 1334                                                e.g. PROCEDURE (VAR ARRAY OF REAL) *)
- 1335                                             SymTab.ProcTypeAdd(t, isV, pt); .) ) .
- 1336    (* Arrays: "OF" without bounds is an open formal (allowed only
- 1337       where allowOpen); "[lo..hi, ...]" nests bounded levels inside
- 1338       out.  The PIM/ISO multi-index form repeats the bracket group
- 1339       ("ARRAY [lo..hi], [lo..hi] OF T"); the bounds of every group
- 1340       nest in the same inside-out order as the comma list.  Bounds are
- 1341       folded literals (int/char); anything else 230.  Bare-type indices
- 1342       ("ARRAY Color OF") wait for enum ordinals. *)
- 1343    ArrayType<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
- 1344                                          (. VAR elem: SymTab.TypeIndex;
- 1345                                               eb: SymTab.Name;
- 1346                                               ok: BOOLEAN;
- 1347                                               bnds, bndh: ARRAY [0 .. 7] OF INTEGER;
- 1348                                               nb, k: CARDINAL;
- 1349                                               idx: SymTab.TypeIndex;
- 1350                                               ilo, ihi: INTEGER; .)
- 1351      = "ARRAY"                           (. allowFwdType := FALSE; .)
- 1352        ( "OF"
- 1353          Type<elem, FALSE>               (. LexName(eb); (* the element ident *)
- 1354                                             IF NOT allowOpen THEN
- 1355                                               SemError(230) END;
- 1356                                             t := SymTab.NewOpenArray(elem);
- 1357                                             IF SymTab.Equal(eb, "BYTE") THEN
- 1358                                               SymTab.MarkByteBuf(t) END; .)
- 1359        | TypeIdent<idx> [ Subrange<idx> ]
- 1360          "OF" Type<elem, FALSE>          (. (* index-type array: the index
- 1361                                                type's ordinal bounds give the
- 1362                                                [lo..hi] pair *)
- 1363                                             IF SymTab.TypeBounds(idx, ilo,
- 1364                                                ihi)
- 1365                                             THEN t := SymTab.NewArrayB(elem,
- 1366                                                    ilo, ihi)
- 1367                                             ELSE SemError(230);
- 1368                                               t := SymTab.InvalidType
- 1369                                             END; .)
- 1370        | "["                             (. SymTab.BoundBegin; ok := TRUE;
- 1371                                             nb := 0; .)
- 1372          BoundPair<ok>
- 1373          { "," BoundPair<ok> }
- 1374          "]"                             (. (* snapshot this bracket group
- 1375                                                before the element type, which
- 1376                                                reuses the bound buffer for a
- 1377                                                nested ARRAY *)
- 1378                                             IF nb + SymTab.BoundCount() >
- 1379                                                HIGH(bnds) + 1 THEN
- 1380                                               SemError(230); ok := FALSE
- 1381                                             ELSE
- 1382                                               k := 0;
- 1383                                               WHILE k < SymTab.BoundCount() DO
- 1384                                                 bnds[nb] := SymTab.BoundLo(k);
- 1385                                                 bndh[nb] := SymTab.BoundHi(k);
- 1386                                                 INC(k); INC(nb)
- 1387                                               END
- 1388                                             END; .)
- 1389          { "," "["                       (. SymTab.BoundBegin; .)
- 1390            BoundPair<ok>
- 1391            { "," BoundPair<ok> }
- 1392            "]"                           (. IF nb + SymTab.BoundCount() >
- 1393                                                HIGH(bnds) + 1 THEN
- 1394                                               SemError(230); ok := FALSE
- 1395                                             ELSE
- 1396                                               k := 0;
- 1397                                               WHILE k < SymTab.BoundCount() DO
- 1398                                                 bnds[nb] := SymTab.BoundLo(k);
- 1399                                                 bndh[nb] := SymTab.BoundHi(k);
- 1400                                                 INC(k); INC(nb)
- 1401                                               END
- 1402                                             END; .) }
- 1403          "OF" Type<elem, FALSE>
- 1404                                          (. IF ok THEN
- 1405                                               k := nb;
- 1406                                               WHILE k > 0 DO
- 1407                                                 DEC(k);
- 1408                                                 elem := SymTab.NewArrayB(
- 1409                                                   elem, bnds[k], bndh[k])
- 1410                                               END;
- 1411                                               t := elem
- 1412                                             ELSE t := SymTab.InvalidType
- 1413                                             END; .) ) .
- 1414    BoundPair<VAR ok: BOOLEAN>            (. VAR tlo, thi: SymTab.TypeIndex;
- 1415                                               qlo, qhi: QbeGen.QVal;
- 1416                                               lo, hi: INTEGER;
- 1417                                               cl, cl2: INTEGER; .)
- 1418      = Expr<tlo, qlo> ".." Expr<thi, qhi>
- 1419                                          (. IF (tlo = SymTab.InvalidType)
- 1420                                              OR (thi = SymTab.InvalidType) THEN
- 1421                                             ok := FALSE
- 1422                                           ELSE cl := SymTab.ClassOf(tlo);
- 1423                                             cl2 := SymTab.ClassOf(thi);
- 1424                                             IF ((cl # SymTab.ClInt)
- 1425   AND (cl # SymTab.ClChar)
- 1426   AND (cl # SymTab.ClBool)
- 1427   AND (cl # SymTab.ClEnum)
- 1428   AND (cl # SymTab.ClByte)
- 1429   AND (cl # SymTab.ClSByte)
- 1430   AND (cl # SymTab.ClWord16)
- 1431   AND (cl # SymTab.ClSWord16))
- 1432                                                OR ((cl2 # SymTab.ClInt)
- 1433   AND (cl2 # SymTab.ClChar)
- 1434   AND (cl2 # SymTab.ClBool)
- 1435   AND (cl2 # SymTab.ClEnum)
- 1436   AND (cl2 # SymTab.ClByte)
- 1437   AND (cl2 # SymTab.ClSByte)
- 1438   AND (cl2 # SymTab.ClWord16)
- 1439   AND (cl2 # SymTab.ClSWord16)) THEN
- 1440                                               SemError(230); ok := FALSE
- 1441                                             ELSIF NOT SymTab.ConstInt(qlo, lo)
- 1442                                                OR NOT SymTab.ConstInt(qhi, hi)
- 1443                                                OR (lo > hi) THEN
- 1444                                               SemError(230); ok := FALSE
- 1445                                              ELSIF NOT SymTab.BoundAdd(lo, hi) THEN
- 1446                                                SemError(230); ok := FALSE
- 1447                                              END;
- 1448                                            END; .) .
- 1449    (* Sets: multi-word masks over bases ≤ 256 values (bool, char,
- 1450       bounded subranges; enums wait for ordinals, INTEGER is
- 1451       unbounded). Literals are SET OF [0..255]; assignment and
- 1452       comparison across suitable bases are lenient (masks over min
- 1453       words + zero-check extras), out-of-span literals are 222. *)
- 1454    SetType<VAR t: SymTab.TypeIndex>      (. VAR base: SymTab.TypeIndex;
- 1455                                               blo, bhi, bspan: INTEGER;
- 1456                                               bcls: INTEGER; .)
- 1457      = "SET"                             (. allowFwdType := FALSE; .)
- 1458        "OF" Type<base, FALSE>
- 1459                                          (. IF base = SymTab.InvalidType THEN
- 1460                                               t := SymTab.InvalidType
- 1461                                             ELSIF SymTab.Unresolved(base) THEN
- 1462                                               (* an opaque/formal base: defer
- 1463                                                  the span check until the
- 1464                                                  base is completed *)
- 1465                                               t := SymTab.NewSet(base)
- 1466                                             ELSE bcls :=
- 1467                                                    SymTab.ClassOf(base);
- 1468                                               (* a subrange keeps its own
- 1469                                                  span even when its base is
- 1470                                                  CHAR/BOOLEAN/an enum *)
- 1471                                               IF SymTab.SubBounds(base,
- 1472                                                       blo, bhi) THEN
- 1473                                                 bspan := bhi - blo + 1
- 1474                                               ELSIF bcls = SymTab.ClBool THEN
- 1475                                                 blo := 0; bspan := 2
- 1476                                               ELSIF bcls = SymTab.ClChar THEN
- 1477                                                 blo := 0; bspan := 256
- 1478                                               ELSIF bcls = SymTab.ClByte THEN
- 1479                                                 blo := 0; bspan := 256
- 1480                                               ELSIF bcls = SymTab.ClSByte THEN
- 1481                                                 blo := -128; bspan := 256
- 1482                                               ELSIF bcls = SymTab.ClWord16 THEN
- 1483                                                 blo := 0; bspan := 65536
- 1484                                               ELSIF bcls = SymTab.ClSWord16 THEN
- 1485                                                 blo := -32768; bspan := 65536
- 1486                                               ELSIF bcls = SymTab.ClEnum THEN
- 1487                                                 blo := 0;
- 1488                                                 bspan := VAL(INTEGER,
- 1489                                                   SymTab.EnumCount(base))
- 1490                                               ELSE bspan := 0 END;
- 1491                                               IF (bspan <= 0)
- 1492                                                  OR (bspan > 65536) THEN
- 1493                                                 SemError(230);
- 1494                                                 t := SymTab.InvalidType
- 1495                                               ELSE t := SymTab.NewSet(base)
- 1496                                               END
- 1497                                             END; .) .
- 1498    (* Records: flat blobs; array fields are pointers to static
- 1499       descriptors (locked amendment), nested records inline. Field
- 1500       offsets static and declaration-ordered. *)
- 1501    (* Field list: plain fields and (optionally) one variant part.  The
- 1502       variant part is a `CASE ... END` item; because it starts with the
- 1503       CASE keyword it is unambiguously distinguishable from a field
- 1504       (which starts with an identifier). *)
- 1505    RecordType<VAR t: SymTab.TypeIndex>   (. VAR t2: SymTab.TypeIndex;
- 1506                                               tagOk: BOOLEAN; .)
- 1507      = "RECORD"                          (. allowFwdType := FALSE;
- 1508                                             t := SymTab.NewRecord(); .)
- 1509        [ RecItem<t> { ";" [ RecItem<t> ] } ]
- 1510        "END"                             (. SymTab.LayoutRecord(t); .) .
- 1511    RecItem<rec: SymTab.TypeIndex>        (. VAR tt: SymTab.TypeIndex; .)
- 1512      = RecField<rec>
- 1513      | CaseField<rec>                    (. SymTab.MarkVariant(rec); .) .
- 1514    (* A variant part: CASE [tag] : Type OF variants.  gm2 extensions:
- 1515       an untagged inner CASE (no tag field), empty arms and ELSE arms. *)
- 1516    CaseField<rec: SymTab.TypeIndex>      (. VAR tagT: SymTab.TypeIndex;
- 1517                                               tagN: SymTab.Name;
- 1518                                               tagged: BOOLEAN; .)
- 1519      = "CASE"                            (. SymTab.ResetFields(rec);
- 1520                                             tagged := FALSE; .)
- 1521        [ GetIdent<tagN>                  (. IF NOT SymTab.FieldPending(rec,
- 1522                                               tagN) THEN
- 1523                                               SemError(200) END;
- 1524                                             tagged := TRUE; .) ]
- 1525        ":" Type<tagT, FALSE>             (. IF (tagT # SymTab.InvalidType)
- 1526    AND NOT SymTab.IsOrdinal(tagT) THEN
- 1527                                               SemError(224)
- 1528                                             END;
- 1529                                             IF tagged THEN
- 1530                                               SymTab.FixPendingF(rec, tagT);
- 1531                                               SymTab.SetVariantTag(rec, tagN)
- 1532                                             END; .)
- 1533        "OF"
- 1534        RecFieldList<rec>
- 1535        { "|"                             (. SymTab.ResetFields(rec); .)
- 1536          RecFieldList<rec> }
- 1537        [ "ELSE" ]
- 1538        "END" .
- 1539    (* A variant branch: `labels : fields` (fields and their trailing ";"
- 1540       optional, gm2), `ELSE`, or empty (the extra "|" separators gm2
- 1541       tolerates).  A branch may itself contain a nested variant CASE. *)
- 1542    RecFieldList<rec: SymTab.TypeIndex>   (. VAR lt, lq: SymTab.TypeIndex;
- 1543                                               lv1, lv2: QbeGen.QVal; .)
- 1544      = [ ( VarLabel<lt, lv1> [ ".." VarLabel<lq, lv2> ]
- 1545            { "," VarLabel<lt, lv1> [ ".." VarLabel<lq, lv2> ] }
- 1546            ":"
- 1547            [ ArmField<rec> { ";" [ ArmField<rec> ] } ]
- 1548          | "ELSE" ) ] .
- 1549    ArmField<rec: SymTab.TypeIndex>
- 1550      = RecField<rec>
- 1551      | CaseField<rec>                    (. SymTab.MarkVariant(rec); .) .
- 1552    (* Variant case label: a constant (or a constant range).  Values are
- 1553       not interpreted (the layout overlays regardless). *)
- 1554    VarLabel<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1555                                          (. VAR lname: SymTab.Name; .)
- 1556      = ( ident                         (. LexName(lname);
- 1557                                             QbeGen.CopyOp("0", q);
- 1558                                             t := SymTab.IntType(); .)
- 1559        | integer                       (. LexString(lname);
- 1560                                             QbeGen.CopyOp("0", q);
- 1561                                             t := SymTab.IntType(); .)
- 1562        | charConst                     (. LexString(lname);
- 1563                                             QbeGen.CopyOp("0", q);
- 1564                                             t := SymTab.CharType(); .) ) .
- 1565    RecField<rec: SymTab.TypeIndex>       (. VAR n: SymTab.Name;
- 1566                                               t2: SymTab.TypeIndex; .)
- 1567      = RecIdents<rec> ":" Type<t2, FALSE>(. SymTab.FixPendingF(rec, t2); .) .
- 1568    RecIdents<rec: SymTab.TypeIndex>      (. VAR n: SymTab.Name; .)
- 1569      = GetIdent<n>                       (. IF NOT SymTab.FieldPending(rec,
- 1570                                               n) THEN
- 1571                                               SemError(200) END; .)
- 1572        { "," GetIdent<n>                 (. IF NOT SymTab.FieldPending(rec,
- 1573                                               n) THEN
- 1574                                               SemError(200) END; .) } .
- 1575    TypeIdent<VAR t: SymTab.TypeIndex>    (. VAR n, qid: SymTab.Name;
- 1576                                               k: INTEGER;
- 1577                                               dotted: BOOLEAN; .)
- 1578      = GetIdent<n>                       (. dotted := FALSE;
- 1579                                             IF NOT SymTab.Lookup(n) THEN
- 1580                                               (* declaration before use: an
- 1581                                                  undeclared type is 201,
- 1582                                                  except as a POINTER's base
- 1583                                                  (allowFwdType) *)
- 1584                                               k := -1;
- 1585                                               IF allowFwdType THEN
- 1586                                                 t := SymTab.ForwardType(n)
- 1587                                               ELSE t := SymTab.InvalidType
- 1588                                               END;
- 1589                                               IF t = SymTab.InvalidType THEN
- 1590                                                 SemError(201)
- 1591                                               END
- 1592                                             ELSE k := SymTab.SymKind(n);
- 1593                                               IF (k = SymTab.KindType)
- 1594                                                  OR (k = SymTab.KindPredef) THEN
- 1595                                                 t := SymTab.SymType(n)
- 1596                                               ELSE t := SymTab.InvalidType
- 1597                                               END
- 1598                                             END; .)
- 1599        [ "." GetIdent<qid>               (. dotted := TRUE;
- 1600                                             IF k = SymTab.KindModule THEN
- 1601                                               t := SymTab.QualType(n, qid);
- 1602                                               IF t = SymTab.InvalidType THEN
- 1603                                                 SemError(201)
- 1604                                               END
- 1605                                             ELSE SemError(221);
- 1606                                               t := SymTab.InvalidType
- 1607                                             END; .) ]
- 1608                                          (. IF NOT dotted THEN
- 1609                                               IF (k = SymTab.KindModule)
- 1610                                                  OR ((k # SymTab.KindType)
- 1611    AND (k # SymTab.KindPredef)
- 1612    AND (k # SymTab.KindImport)
- 1613    AND (k # -1)) THEN
- 1614                                                 SemError(221)
- 1615                                               END
- 1616                                             END; .) .
- 1617    Subrange<VAR t: SymTab.TypeIndex>     (. VAR tlo, thi: SymTab.TypeIndex;
- 1618                                               qlo, qhi: QbeGen.QVal;
- 1619                                               lo, hi: INTEGER; .)
- 1620      = "[" Expr<tlo, qlo> ".." Expr<thi, qhi>
- 1621                                          (. IF (tlo = SymTab.InvalidType)
- 1622                                              OR (thi = SymTab.InvalidType) THEN
- 1623                                             t := SymTab.InvalidType
- 1624                                           ELSIF NOT SymTab.IsOrdinal(tlo)
- 1625                                              OR NOT SymTab.IsOrdinal(thi) THEN
- 1626                                             SemError(230);
- 1627                                             t := SymTab.InvalidType
- 1628                                           ELSIF NOT SymTab.ConstInt(qlo, lo)
- 1629                                              OR NOT SymTab.ConstInt(qhi, hi)
- 1630                                              OR (lo > hi) THEN
- 1631                                             SemError(230);
- 1632                                             t := SymTab.InvalidType
- 1633                                           ELSE IF SymTab.SameType(tlo, thi) THEN
- 1634                                             (* keep the base type: ['A'..'Z']
- 1635                                                is character, [red..blue]
- 1636                                                that enumeration *)
- 1637                                             t := SymTab.NewSubB(lo, hi, tlo)
- 1638                                           ELSE t := SymTab.NewSubR(lo, hi)
- 1639                                           END
- 1640                                           END; .)
- 1641        "]" .
- 1642    Enum<VAR t: SymTab.TypeIndex>         (. VAR n: SymTab.Name;
- 1643                                               ord: INTEGER;
- 1644                                               qv: QbeGen.QVal; .)
- 1645      = "("                               (. t := SymTab.NewEnum();
- 1646                                             ord := 0; .)
- 1647        GetIdent<n>                       (. IF NOT SymTab.Enter(n,
- 1648                                               SymTab.KindConst) THEN
- 1649                                               SemError(200) END;
- 1650                                             SymTab.SetSymType(n, t);
- 1651                                             QbeGen.IntStr(ord, qv);
- 1652                                             SymTab.SetSymVal(n, qv);
- 1653                                             SymTab.NoteEnumLit(t, n);
- 1654                                             Lower.NoteVar(n,
- 1655                                               SymTab.KindConst, t);
- 1656                                             Lower.NoteConstVal(qv);
- 1657                                             INC(ord); .)
- 1658        { "," GetIdent<n>                 (. IF NOT SymTab.Enter(n,
- 1659                                               SymTab.KindConst) THEN
- 1660                                               SemError(200) END;
- 1661                                             SymTab.SetSymType(n, t);
- 1662                                             QbeGen.IntStr(ord, qv);
- 1663                                             SymTab.SetSymVal(n, qv);
- 1664                                             SymTab.NoteEnumLit(t, n);
- 1665                                             Lower.NoteVar(n,
- 1666                                               SymTab.KindConst, t);
- 1667                                             Lower.NoteConstVal(qv);
- 1668                                             INC(ord); .) }
- 1669        ")"                               (. SymTab.SetEnumCount(t,
- 1670                                               VAL(CARDINAL, ord)); .) .
- 1671    (* Clarion-form classes (docs/OOP.txt): declaration + single
- 1672       inheritance + IMPLEMENTATION blocks. Scopes and member checks
- 1673       now; lowering (vtable, dispatch, THIS) later — one 230 per
- 1674       class/impl block. Methods end with ";" per the Table example
- 1675       (not "," as in the sketch). No underscores in identifiers. *)
- 1676    (* Single CLASS item in both loops: separating declaration from
- 1677       IMPLEMENTATION at the loop level needs 2-token lookahead
- 1678       (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
- 1679       The second token decides after CLASS is consumed. A misplaced
- 1680       CLASS IMPLEMENTATION inside TYPE still parses (harmless: the
- 1681       whole unit ends 230 until lowering). *)
- 1682    ClassItem
- 1683      = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
- 1684    ClassRest                             (. VAR cn, m2, pn: SymTab.Name;
- 1685                                               ct: SymTab.TypeIndex; .)
- 1686      = GetIdent<cn>                      (. IF NOT SymTab.Enter(cn,
- 1687                                               SymTab.KindType) THEN
- 1688                                               SemError(200) END;
- 1689                                             ct := SymTab.NewClass();
- 1690                                             SymTab.SetSymType(cn, ct);
- 1691                                             SymTab.PushClassScope(ct);
- 1692                                             astCls := AST.MakeNode(AST.NkClassDecl);
- 1693                                             AST.SetChild(astCls, 0,
- 1694                                               AST.MakeLeaf(AST.NkIdent, cn));
- 1695                                             astClsP := AST.NoNode;
- 1696                                             astClsPTail := AST.NoNode;
- 1697                                             astClsF := AST.NoNode;
- 1698                                             astClsFTail := AST.NoNode;
- 1699                                             astClsM := AST.NoNode;
- 1700                                             astClsMTail := AST.NoNode; .)
- 1701        [ Parents<ct> ]
- 1702        ";"
- 1703        { ClassField<ct> ";" }
- 1704        { MethodHeading<pn, SymTab.InvalidType> ";"
- 1705                                          (. Lower.ScopeLeave;
- 1706                                             SymTab.CloseProc;
- 1707                                             QbeGen.AbortFunc; .) }
- 1708        "END"
- 1709        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
- 1710                                               SemError(202) END;
- 1711                                             SymTab.LayoutClass(ct);
- 1712                                             SymTab.PopScope;
- 1713                                             AST.SetChild(astCls, 1, astClsP);
- 1714                                             AST.SetChild(astCls, 2, astClsF);
- 1715                                             AST.SetChild(astCls, 3, astClsM);
- 1716                                             astDecl := astCls; .) .
- 1717    Parents<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name; .)
- 1718      = "(" Parent1<ct>
- 1719        { "," GetIdent<p>                 (. SemError(230); .) }
- 1720        ")" .
- 1721    Parent1<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name;
- 1722                                               pt: SymTab.TypeIndex; .)
- 1723      = GetIdent<p>                       (. IF NOT SymTab.Lookup(p) THEN
- 1724                                               SemError(201)
- 1725                                             ELSE pt := SymTab.SymType(p);
- 1726                                               IF SymTab.ClassOf(pt) #
- 1727                                                  SymTab.ClClass THEN
- 1728                                                 SemError(230)
- 1729                                               ELSE SymTab.SetParent(ct, pt)
- 1730                                               END
- 1731                                             END;
- 1732                                             AstAppend(AST.NkFieldDecl,
- 1733                                               astClsP, astClsPTail,
- 1734                                               AST.MakeLeaf(AST.NkIdent, p)); .) .
- 1735    ClassField<ct: SymTab.TypeIndex>      (. VAR n, rhs: SymTab.Name;
- 1736                                               t: SymTab.TypeIndex;
- 1737                                               astNode: AST.Node; .)
- 1738      = GetIdent<n>
- 1739        ( "=" GetIdent<rhs>               (. IF NOT SymTab.Enter(n,
- 1740                                               SymTab.KindConst) THEN
- 1741                                               SemError(200) END;
- 1742                                             astNode := AST.MakeNode(AST.NkConstDecl);
- 1743                                             AST.SetChild(astNode, 0,
- 1744                                               AST.MakeLeaf(AST.NkIdent, n));
- 1745                                             AST.SetChild(astNode, 1,
- 1746                                               AST.MakeLeaf(AST.NkIdent, rhs));
- 1747                                             AstAppend(AST.NkFieldDecl,
- 1748                                               astClsF, astClsFTail, astNode);
- 1749                                             IF SymTab.Lookup(rhs) THEN
- 1750                                               SymTab.SetSymType(n,
- 1751                                                 SymTab.SymType(rhs))
- 1752                                             END; .)
- 1753        |                                 (. IF NOT SymTab.FieldPending(ct,
- 1754                                               n) THEN
- 1755                                               SemError(200) END;
- 1756                                             astNode := AST.MakeNode(AST.NkVarDecl);
- 1757                                             AST.SetChild(astNode, 0,
- 1758                                               AST.MakeLeaf(AST.NkIdent, n)); .)
- 1759          { "," GetIdent<n>               (. IF NOT SymTab.FieldPending(ct,
- 1760                                               n) THEN
- 1761                                               SemError(200) END;
- 1762                                             AST.SetChild(astNode,
- 1763                                               AST.NChild(astNode),
- 1764                                               AST.MakeLeaf(AST.NkIdent, n)); .) }
- 1765          ":" Type<t, FALSE>              (. SymTab.FixPendingF(ct, t);
- 1766                                             AST.SetTy(astNode, t);
- 1767                                             AstAppend(AST.NkFieldDecl,
- 1768                                               astClsF, astClsFTail, astNode); .) ) .
- 1769    MethodHeading<VAR pn: SymTab.Name; ct: SymTab.TypeIndex>
- 1770                                          (. VAR wantVirt: BOOLEAN; .)
- 1771      =                                   (. wantVirt := FALSE; .)
- 1772        [ "VIRTUAL"                       (. wantVirt := TRUE; .) ]
- 1773        ProcHeading<pn, ct>               (. IF wantVirt THEN
- 1774                                               SymTab.MarkVirtual END;
- 1775                                             astMethod := AST.MakeNode(AST.NkProcDecl);
- 1776                                             AST.SetChild(astMethod, 0,
- 1777                                               AST.MakeLeaf(AST.NkIdent, pn));
- 1778                                             IF wantVirt THEN
- 1779                                               AST.SetOp(astMethod, 3)
- 1780                                             ELSE AST.SetOp(astMethod, 0)
- 1781                                             END;
- 1782                                             AstAppend(AST.NkFieldDecl,
- 1783                                               astClsM, astClsMTail, astMethod); .) .
- 1784    ClassImplRest                         (. VAR cn, m2: SymTab.Name;
- 1785                                               ct: SymTab.TypeIndex; .)
- 1786      = GetIdent<cn>                      (. IF NOT SymTab.Lookup(cn) THEN
- 1787                                               SemError(201);
- 1788                                               ct := SymTab.InvalidType
- 1789                                             ELSE ct := SymTab.SymType(cn);
- 1790                                               IF SymTab.ClassOf(ct) #
- 1791                                                  SymTab.ClClass THEN
- 1792                                                 SemError(230);
- 1793                                                 ct := SymTab.InvalidType
- 1794                                               END
- 1795                                             END;
- 1796                                             astCls := AST.MakeNode(AST.NkClassDecl);
- 1797                                             AST.SetOp(astCls, 1);
- 1798                                             AST.SetChild(astCls, 0,
- 1799                                               AST.MakeLeaf(AST.NkIdent, cn));
- 1800                                             astClsM := AST.NoNode;
- 1801                                             astClsMTail := AST.NoNode;
- 1802                                             astStmt := AST.NoNode;
- 1803                                             IF ct #
- 1804                                                SymTab.InvalidType THEN
- 1805                                               IF NOT SymTab.PushClassMembers(
- 1806                                                      ct) THEN
- 1807                                                 SemError(230) END;
- 1808                                               SymTab.PushImplClass(ct)
- 1809                                             END; .)
- 1810        ";" { MethodImpl<ct> ";" }
- 1811                                          (. astStmt := AST.NoNode; .)
- 1812        [ "BEGIN"                         (. astStmt := AST.MakeNode(AST.NkBlock);
- 1813                                             .)
- 1814          [ StatSeq ] ]
- 1815        "END"
- 1816        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
- 1817                                               SemError(202) END;
- 1818                                             SymTab.PopImplClass;
- 1819                                             SymTab.PopScope;
- 1820                                             AST.SetChild(astCls, 1, AST.NoNode);
- 1821                                             AST.SetChild(astCls, 2, astStmt);
- 1822                                             AST.SetChild(astCls, 3, astClsM);
- 1823                                             astDecl := astCls; .) .
- 1824    MethodImpl<ct: SymTab.TypeIndex>      (. VAR pn: SymTab.Name;
- 1825                                               thisQ: QbeGen.QVal;
- 1826                                               methRes: SymTab.TypeIndex; .)
- 1827      = MethodHeading<pn, ct> ";"
- 1828                                          (. IF (ct #
- 1829                                                SymTab.InvalidType)
- 1830   AND NOT SymTab.MethodExists(ct,
- 1831                                                    pn) THEN
- 1832                                               SemError(201) END; .)
- 1833        ( "FORWARD"                       (. AST.SetOp(astMethod, 1);
- 1834                                             SymTab.MarkFwd;
- 1835                                             QbeGen.AbortFunc;
- 1836                                             Lower.ScopeLeave;
- 1837                                             SymTab.CloseProc; .)
- 1838        |                                 (.
- 1839                                             (* bind the receiver: bare
- 1840                                                field names resolve
- 1841                                                against THIS *)
- 1842                                              QbeGen.CopyOp("@", thisQ);
- 1843                                             QbeGen.PushWith(thisQ); .)
- 1844          Block<pn>                       (. AST.SetChild(astMethod, 1, astStmt);
- 1845                                             AST.SetChild(astMethod, 2, astBlkDecls);
- 1846                                             QbeGen.PopWith;
- 1847                                             methRes := SymTab.CurRes();
- 1848                                             Lower.ScopeLeave;
- 1849                                             SymTab.CloseProc;
- 1850                                             QbeGen.EndFunc(methRes); .) ) .
- 1851    ConstBlock                            (. VAR astSeq, astTail: AST.Node; .)
- 1852      = "CONST"                           (. astSeq := AST.NoNode;
- 1853                                             astTail := AST.NoNode; .)
- 1854        { ConstDecl ";"                   (. AstAppend(AST.NkDeclSeq,
- 1855                                               astSeq, astTail, astDecl); .) }
- 1856                                          (. astDecl := astSeq; .) .
- 1857    ConstDecl                             (. VAR n: SymTab.Name;
- 1858                                               t: SymTab.TypeIndex;
- 1859                                               qv: QbeGen.QVal;
- 1860                                               cls: INTEGER;
- 1861                                               mk: ARRAY [0 .. 15] OF CARDINAL;
- 1862                                               mw: CARDINAL;
- 1863                                               mlo: INTEGER;
- 1864                                               astNode: AST.Node; .)
- 1865      = GetIdent<n>                       (. IF NOT SymTab.Enter(n,
- 1866                                               SymTab.KindConst) THEN
- 1867                                               SemError(200) END; .)
- 1868        "="
- 1869        Expr<t, qv> (. astNode := AST.MakeNode(AST.NkConstDecl);
- 1870                                             AST.SetChild(astNode, 0,
- 1871                                               AST.MakeLeaf(AST.NkIdent, n));
- 1872                                             AST.SetChild(astNode, 1, astCur);
- 1873                                             AST.SetTy(astNode, t);
- 1874                                             astDecl := astNode;
- 1875                                             Lower.NoteVar(n, SymTab.KindConst, t);
- 1876                                             Lower.NoteConstVal(qv);
- 1877                                             SymTab.SetSymType(n, t);
- 1878                                             cls := SymTab.ClassOf(t);
- 1879                                             IF cls = SymTab.ClSet THEN
- 1880                                               (* a SET CONST needs static
- 1881                                                  data: fold its mask now
- 1882                                                  (the grammar sees the
- 1883                                                  element values) and let
- 1884                                                  Lower re-emit it *)
- 1885                                               IF Lower.SetConstMaskOf(
- 1886                                                    AST.Child(astNode, 1),
- 1887                                                    mk, mw, mlo) THEN
- 1888                                                 Lower.NoteSetMask(n, mk, mw,
- 1889                                                   mlo);
- 1890                                                 SymTab.SetSymVal(n, qv)
- 1891                                               ELSE
- 1892                                                 SemError(230)
- 1893                                               END
- 1894                                             ELSIF (cls = SymTab.ClArray)
- 1895                                                OR (cls = SymTab.ClRecord)
- 1896                                                OR (cls = SymTab.ClClass)
- 1897                                                OR (cls = SymTab.ClStr)
- 1898                                                OR (cls = SymTab.ClUStr) THEN
- 1899                                               (* an aggregate/string
- 1900                                                  constant: qv is its
- 1901                                                  descriptor address; no
- 1902                                                  scalar data *)
- 1903                                               SymTab.SetSymVal(n, qv)
- 1904                                             ELSIF NOT QbeGen.IsImm(qv) THEN
- 1905                                               SemError(230)
- 1906                                             ELSE
- 1907                                               SymTab.SetSymVal(n, qv);
- 1908                                             END; .) .
- 1909    VarBlock                              (. VAR astSeq, astTail: AST.Node; .)
- 1910      = "VAR"                             (. astSeq := AST.NoNode;
- 1911                                             astTail := AST.NoNode; .)
- 1912        { VarDecl ";"                     (. AstAppend(AST.NkDeclSeq,
- 1913                                               astSeq, astTail, astDecl); .) }
- 1914                                          (. astDecl := astSeq; .) .
- 1915    VarDecl                               (. VAR nm: SymTab.Name;
- 1916                                               t: SymTab.TypeIndex;
- 1917                                               i: CARDINAL;
- 1918                                               cls: INTEGER;
- 1919                                               astNode, astTail: AST.Node; .)
- 1920      = VarIdents ":"
- 1921        Type<t, FALSE> (. astNode := AST.MakeNode(AST.NkVarDecl);
- 1922                                             astTail := astNode;
- 1923                                             i := 0;
- 1924                                             WHILE i < SymTab.PendCount() DO
- 1925                                               SymTab.PendName(i, nm);
- 1926                                               Lower.NoteVar(nm, SymTab.KindVar, t);
- 1927                                               (* chunked: a VAR list can
- 1928                                                  exceed AST.MaxChild *)
- 1929                                               AstAppend(AST.NkBlock,
- 1930                                                 astNode, astTail,
- 1931                                                 AST.MakeLeaf(AST.NkIdent, nm));
- 1932                                               INC(i)
- 1933                                             END;
- 1934                                             AST.SetTy(astNode, t);
- 1935                                             astDecl := astNode;
- 1936                                             cls := SymTab.ClassOf(t);
- 1937                                             IF (t # SymTab.InvalidType)
- 1938   AND NOT SymTab.IsUnresolved(t)
- 1939   AND (cls # SymTab.ClInt)
- 1940   AND (cls # SymTab.ClBool)
- 1941   AND (cls # SymTab.ClChar)
- 1942   AND (cls # SymTab.ClReal)
- 1943   AND (cls # SymTab.ClArray)
- 1944   AND (cls # SymTab.ClSet)
- 1945   AND (cls # SymTab.ClRecord)
- 1946   AND (cls # SymTab.ClPtr)
- 1947   AND (cls # SymTab.ClLong)
- 1948   AND (cls # SymTab.ClProc)
- 1949   AND (cls # SymTab.ClUChar)
- 1950   AND (cls # SymTab.ClUStr)
- 1951   AND (cls # SymTab.ClEnum)
- 1952   AND (cls # SymTab.ClByte)
- 1953   AND (cls # SymTab.ClSByte)
- 1954   AND (cls # SymTab.ClWord16)
- 1955   AND (cls # SymTab.ClSWord16)
- 1956   AND (cls # SymTab.ClClass) THEN
- 1957                                               SemError(230) END;
- 1958                                             IF QbeGen.LocFull() THEN
- 1959                                               SemError(233) END;
- 1960                                             i := 0;
- 1961                                             IF SymTab.IsUnresolved(t)
- 1962                                                AND NOT SymTab.InProc() THEN
- 1963                                               (* a forward-typed global:
- 1964                                                  defer emission until the
- 1965                                                  TYPE block completes *)
- 1966                                               AST.SetOp(astNode, 1);
- 1967                                               WHILE i < SymTab.PendCount() DO
- 1968                                                 SymTab.PendName(i, nm);
- 1969                                                 IF nPendVar <=
- 1970                                                    HIGH(pendVarName) THEN
- 1971                                                   pendVarName[nPendVar] := nm;
- 1972                                                   pendVarT[nPendVar] := t;
- 1973                                                   INC(nPendVar)
- 1974                                                 END;
- 1975                                                 INC(i)
- 1976                                               END
- 1977                                             ELSE
- 1978                                               WHILE i < SymTab.PendCount() DO
- 1979                                                 SymTab.PendName(i, nm);
- 1980                                                 INC(i)
- 1981                                               END
- 1982                                             END;
- 1983                                             (* a plain VAR list, not a
- 1984                                                heading: the signature
- 1985                                                result is discarded *)
- 1986                                             IF NOT SymTab.FixPending(t) THEN
- 1987                                             END; .) .
- 1988    VarIdents                             (. VAR n: SymTab.Name; .)
- 1989      = GetIdent<n>                       (. IF NOT SymTab.EnterPending(n,
- 1990                                               SymTab.KindVar) THEN
- 1991                                               SemError(200) END; .)
- 1992        { ","
- 1993          GetIdent<n>                     (. IF NOT SymTab.EnterPending(n,
- 1994                                               SymTab.KindVar) THEN
- 1995                                               SemError(200) END; .) } .
- 1996    ParIdents<isV: BOOLEAN>               (. VAR n: SymTab.Name; .)
- 1997      = GetIdent<n>                       (. IF NOT SymTab.EnterParam(n, isV) THEN
- 1998                                               SemError(200) END; .)
- 1999        { "," GetIdent<n>                 (. IF NOT SymTab.EnterParam(n, isV) THEN
- 2000                                               SemError(200) END; .) } .
- 2001    (* Procedure headings enter scopes/params/result and buffer the
- 2002       QBE header; bodies lower to functions (4.1, module level only).
- 2003       FORWARD marks; the body heading re-enters (signature compare
- 2004       deferred). Nested procedures parse + check, lowering = 4.2. *)
- 2005    (* gm2 declaration pragmas: __BUILTIN__ (definition module) and
- 2006       __ATTRIBUTE__ __BUILTIN__ (( name )) (implementation).  They
- 2007       annotate C built-ins; V3 parses and ignores them. *)
- 2008    ProcPragma
- 2009      = "__BUILTIN__"
- 2010      | "__ATTRIBUTE__" [ "__BUILTIN__" ] [ "(" "(" ident ")" ")" ] .
- 2011  
- 2012    ProcHeading<VAR pn: SymTab.Name; methCls: SymTab.TypeIndex>
- 2013                                          (. VAR t: SymTab.TypeIndex;
- 2014                                               mg: QbeGen.QVal; .)
- 2015      = "PROCEDURE"
- 2016        [ ProcPragma ]
- 2017        GetIdent<pn>                      (. IF methCls #
- 2018                                                SymTab.InvalidType THEN
- 2019                                             (* a method: resume the
- 2020                                                declared symbol (reuse
- 2021                                                its uid) *)
- 2022                                             IF NOT SymTab.ResumeMethod(
- 2023                                                  methCls, pn) THEN
- 2024                                               SemError(200) END
- 2025                                             ELSIF NOT SymTab.EnterProc(pn) THEN
- 2026                                             IF NOT SymTab.ReenterProc(pn) THEN
- 2027                                               IF NOT SymTab.ResumeProc(pn) THEN
- 2028                                                 SemError(200) END
- 2029                                               END
- 2030                                             END;
- 2031                                             Lower.ScopeEnter;
- 2032                                             Lower.NoteProc(pn,
- 2033                                               SymTab.ProcUid(pn),
- 2034                                               SymTab.InvalidType,
- 2035                                               SymTab.ProcDepthOf(pn),
- 2036                                               FALSE);
- 2037                                             QbeGen.BeginFunc("");
- 2038                                             IF methCls #
- 2039                                                SymTab.InvalidType THEN
- 2040                                               (* hidden THIS receiver:
- 2041                                                  a VAR param of the
- 2042                                                  class type, pushed as
- 2043                                                  the WITH base *)
- 2044                                               IF NOT SymTab.EnterThisParam(
- 2045                                                    methCls) THEN
- 2046                                                 SemError(200) END;
- 2047                                               IF NOT QbeGen.FuncParam(
- 2048                                                    "THIS", TRUE,
- 2049                                                    methCls) THEN
- 2050                                                 SemError(233) END
- 2051                                             END; .)
- 2052        [ FormalParams ]
- 2053        [ ":" ( TypeIdent<t>              (. IF NOT SymTab.SetProcRes(t) THEN
- 2054                                               SemError(235) END;
- 2055                                             Lower.SetProcRes(t); .)
- 2056              | "PROC"                    (. (* PROC result: the procedure
- 2057                                                value type *)
- 2058                                             IF NOT SymTab.SetProcRes(
- 2059                                                SymTab.AddrType()) THEN
- 2060                                               SemError(235) END;
- 2061                                             Lower.SetProcRes(
- 2062                                               SymTab.AddrType()); .) ) ] .
- 2063    FormalParams
- 2064      = "(" [ ParamSection { ";" ParamSection } ] ")" .
- 2065    ParamSection                          (. VAR t: SymTab.TypeIndex;
- 2066                                               nm: SymTab.Name;
- 2067                                               i: CARDINAL;
- 2068                                               isV: BOOLEAN; .)
- 2069      =                                   (. isV := FALSE; .)
- 2070        [ "VAR"                           (. isV := TRUE; .) ]
- 2071        ParIdents<isV> ":" Type<t, TRUE>  (. i := 0;
- 2072                                             WHILE i < SymTab.PendCount() DO
- 2073                                               SymTab.PendName(i, nm);
- 2074                                               Lower.NoteParam(nm, t, isV);
- 2075                                               Lower.NoteVar(nm, SymTab.KindParam, t);
- 2076                                               (* value open arrays are
- 2077                                                  passed as descriptor
- 2078                                                  addresses (no copy):
- 2079                                                  same representation as
- 2080                                                  VAR formals *)
- 2081                                               IF NOT QbeGen.FuncParam(nm,
- 2082                                                    isV
- 2083                                                    OR SymTab.IsOpenArray(t),
- 2084                                                    t) THEN
- 2085                                                 SemError(233) END;
- 2086                                               INC(i)
- 2087                                             END;
- 2088                                             IF NOT SymTab.FixPending(t) THEN
- 2089                                               SemError(235) END; .) .
- 2090    (* Nested procedures lower like top-level ones (4.2): the
- 2091       static link gives them their parent's frame. Methods keep
- 2092       parse-now/230-later. *)
- 2093    ProcDecl                              (. VAR pn: SymTab.Name;
- 2094                                               saveFun: SymTab.Name;
- 2095                                               astNode: AST.Node; .)
- 2096      = ProcHeading<pn, SymTab.InvalidType> ";"
- 2097                                          (. astNode := AST.MakeNode(AST.NkProcDecl);
- 2098                                             AST.SetOp(astNode, 0);
- 2099                                             AST.SetChild(astNode, 0,
- 2100                                               AST.MakeLeaf(AST.NkIdent, pn));
- 2101                                             Lower.NoteProcNode(astNode); .)
- 2102        ( "FORWARD"                       (. AST.SetOp(astNode, 1);
- 2103                                             astDecl := astNode;
- 2104                                             Lower.ScopeLeave;
- 2105                                             SymTab.MarkFwd;
- 2106                                             SymTab.CloseProc;
- 2107                                             QbeGen.AbortFunc; .)
- 2108        | "EXTERNAL"                      (. AST.SetOp(astNode, 2);
- 2109                                             astDecl := astNode;
- 2110                                             Lower.MarkProcExternal;
- 2111                                             Lower.ScopeLeave;
- 2112                                             SymTab.MarkExternal("");
- 2113                                             SymTab.CloseProc;
- 2114                                             QbeGen.AbortFunc; .)
- 2115        |                                 
- 2116          (. allowDefer := TRUE; deferredBody := FALSE;
- 2117                                             curProcNode := astNode;
- 2118                                             saveFun := curFun;
- 2119                                             curFun := pn; .)
- 2120          Block<pn>                       (. curFun := saveFun;
- 2121                                             IF deferredBody THEN
- 2122                                               (* body skipped: close like
- 2123                                                  FORWARD (no body node) *)
- 2124                                               astDecl := astNode;
- 2125                                               Lower.ScopeLeave;
- 2126                                               SymTab.CloseProc;
- 2127                                               QbeGen.AbortFunc
- 2128                                             ELSE
- 2129                                               AST.SetChild(astNode, 1, astStmt);
- 2130                                               AST.SetChild(astNode, 2, astBlkDecls);
- 2131                                               astDecl := astNode;
- 2132                                               Lower.ScopeLeave;
- 2133                                               SymTab.CloseProc;
- 2134                                               QbeGen.EndFunc(
- 2135                                                 SymTab.ProcRes(pn))
- 2136                                             END; .) ) .
- 2137    Block<pn: SymTab.Name>                (. VAR m2: SymTab.Name; dfr: BOOLEAN; .)
- 2138      =                                   (. dfr := FALSE;
- 2139                                             IF allowDefer AND twoPhaseParse
- 2140                                                AND NOT repassing THEN
- 2141                                               dfr := DeferSkip(pn)
- 2142                                             END;
- 2143                                             allowDefer := FALSE;
- 2144                                             .)
- 2145        DeclSeq                           (. astBlkDecls := astDecl;
- 2146                                             astStmt := AST.NoNode;
- 2147                                             nLab := 0; nGot := 0; .)
- 2148        [ "BEGIN"                         (. (* an empty body is still a
- 2149                                               body: mark it so Lower
- 2150                                               does not read it as a
- 2151                                               definition heading *)
- 2152                                             IF NOT dfr THEN
- 2153                                               IF astStmt = AST.NoNode THEN
- 2154                                                 astStmt :=
- 2155                                                   AST.MakeNode(AST.NkBlock)
- 2156                                               END
- 2157                                             END; .)
- 2158          [ StatSeq ] ]
- 2159        "END"
- 2160        GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
- 2161                                               SemError(202) END;
- 2162                                             CheckGotos; .) .
- 2163    (* Two-phase, phase 2 (milestone 2c): re-parse every deferred module-
- 2164       level body once the unit's declarations are complete.  Inlined at
- 2165       both call sites because a stand-alone epsilon production is
- 2166       "unreachable" to Coco/R (referenced only from actions). *)
- 2167    StatSeq                               (. VAR astSeq, astTail: AST.Node; .)
- 2168      =                                   (. astSeq := AST.NoNode;
- 2169                                             astTail := AST.NoNode; .)
- 2170        Statement                         (. AstAppend(AST.NkBlock,
- 2171                                               astSeq, astTail, astStmt); .)
- 2172        { ";" [ Statement                 (. AstAppend(AST.NkBlock,
- 2173                                               astSeq, astTail, astStmt); .) ] }
- 2174                                          (. astStmt := astSeq; .) .
- 2175    (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
- 2176       are accepted: the statement after ';' is optional. *)
- 2177    Statement                             (. VAR lx: QbeGen.QVal; lxnm: SymTab.Name; .)
- 2178      = (. astStmt := AST.NoNode; .)
- 2179        ( AssOrCall
- 2180      | IfStat
- 2181      | WhileStat
- 2182      | RepeatStat
- 2183      | LoopStat
- 2184      | ForStat
- 2185      | CaseStat
- 2186      | WithStat
- 2187      | ReturnStat
- 2188      | HaltStat
- 2189      | NewStat
- 2190      | DisposeStat
- 2191      | IncDecStat
- 2192      | InclExclStat
- 2193      | "EXIT"                            (. IF NOT QbeGen.TopLoop(lx) THEN
- 2194                                               SemError(230) END;
- 2195                                             astStmt := AST.MakeNode(AST.NkExit); .)
- 2196      | "GOTO" GetIdent<lxnm>             (. NoteGoto(lxnm);
- 2197                                             astStmt := AST.MakeNode(AST.NkGoto);
- 2198                                             AST.SetChild(astStmt, 0,
- 2199                                               AST.MakeLeaf(AST.NkIdent, lxnm)); .) ) .
- 2200    (* INCL(set, elem) / EXCL(set, elem): PIM set-element builtins. *)
- 2201    InclExclStat                          (. VAR at, et2: SymTab.TypeIndex;
- 2202                                               dk: INTEGER;
- 2203                                               qd, qe: QbeGen.QVal;
- 2204                                               qn: SymTab.Name;
- 2205                                               sfx, isInc: BOOLEAN;
- 2206                                               astNode, astD: AST.Node; .)
- 2207      = ( "INCL"                          (. isInc := TRUE; .)
- 2208        | "EXCL"                          (. isInc := FALSE; .) )
- 2209        "(" Design<at, dk, qd, qn, sfx> (. astD := astCur; .) ","
- 2210        Expr<et2, qe> ")"
- 2211                                          (. astNode := AST.MakeNode(AST.NkCall);
- 2212                                             IF isInc THEN
- 2213                                               AST.SetChild(astNode, 0,
- 2214                                                 AST.MakeLeaf(AST.NkIdent, "INCL"))
- 2215                                             ELSE AST.SetChild(astNode, 0,
- 2216                                                 AST.MakeLeaf(AST.NkIdent, "EXCL"))
- 2217                                             END;
- 2218                                             IF astD # AST.NoNode THEN
- 2219                                               AST.SetChild(astNode, 1, astD) END;
- 2220                                             IF astCur # AST.NoNode THEN
- 2221                                               AST.SetChild(astNode, 2, astCur) END;
- 2222                                             astStmt := astNode; .)
- 2223                                          (. IF (at # SymTab.InvalidType)
- 2224    AND (SymTab.ClassOf(at) # SymTab.ClSet) THEN
- 2225                                               SemError(222)
- 2226                                             END; .) .
- 2227    (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an
- 2228       integer designator. *)
- 2229    IncDecStat                            (. VAR dt, et2: SymTab.TypeIndex;
- 2230                                               dk: INTEGER;
- 2231                                               qd, qv, qn2, qstep:
- 2232                                                 QbeGen.QVal;
- 2233                                               qn: SymTab.Name;
- 2234                                               sfx, isInc: BOOLEAN;
- 2235                                               astNode, astD, astStep:
- 2236                                                 AST.Node; .)
- 2237      =                                   (. isInc := TRUE; .)
- 2238        ( "INC"                           (. isInc := TRUE; .)
- 2239        | "DEC"                           (. isInc := FALSE; .) )
- 2240        "("                               (. astStep := AST.NoNode; .)
- 2241        Design<dt, dk, qd, qn, sfx> (. astD := astCur; .)
- 2242        [ "," Expr<et2, qstep> (. astStep := astCur; .) ]
- 2243        ")"                               (. astNode := AST.MakeNode(AST.NkCall);
- 2244                                             IF isInc THEN
- 2245                                               AST.SetChild(astNode, 0,
- 2246                                                 AST.MakeLeaf(AST.NkIdent, "INC"))
- 2247                                             ELSE AST.SetChild(astNode, 0,
- 2248                                                 AST.MakeLeaf(AST.NkIdent, "DEC"))
- 2249                                             END;
- 2250                                             IF astD # AST.NoNode THEN
- 2251                                               AST.SetChild(astNode, 1, astD) END;
- 2252                                             IF astStep # AST.NoNode THEN
- 2253                                               AST.SetChild(astNode, 2, astStep) END;
- 2254                                             astStmt := astNode; .)                               (. IF dt = SymTab.InvalidType THEN
- 2255                                             ELSIF (dk # SymTab.KindVar)
- 2256   AND (dk # SymTab.KindParam)
- 2257   AND (dk # SymTab.KindField) THEN
- 2258                                               SemError(210)
- 2259                                             ELSIF NOT SymTab.IsOrdinal(dt) THEN
- 2260                                               SemError(211)
- 2261                                             END; .) .
- 2262    (* NEW/DISPOSE as builtin statements (no call syntax until step 4).
- 2263       Targets are pointer designators; DISPOSE nils afterwards (safer
- 2264       than Wirth-undefined; documented). DISPOSE is shallow. *)
- 2265    NewStat                               (. VAR dt: SymTab.TypeIndex;
- 2266                                               dk: INTEGER;
- 2267                                               qd, qm: QbeGen.QVal;
- 2268                                               qn: SymTab.Name;
- 2269                                               sfx: BOOLEAN;
- 2270                                               bt: SymTab.TypeIndex;
- 2271                                               astNode, astD: AST.Node; .)
- 2272      = "NEW" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
- 2273                                          (. astNode := AST.MakeNode(AST.NkCall);
- 2274                                             AST.SetChild(astNode, 0,
- 2275                                               AST.MakeLeaf(AST.NkIdent, "NEW"));
- 2276                                             IF astD # AST.NoNode THEN
- 2277                                               AST.SetChild(astNode, 1, astD) END;
- 2278                                             astStmt := astNode; .)
- 2279                                           (. IF dt = SymTab.InvalidType THEN
- 2280                                              ELSIF (dk # SymTab.KindVar)
- 2281    AND (dk # SymTab.KindParam)
- 2282    AND (dk # SymTab.KindField) THEN
- 2283                                                SemError(210)
- 2284                                              ELSIF SymTab.ClassOf(dt) #
- 2285                                                    SymTab.ClPtr THEN
- 2286                                                SemError(219)
- 2287                                              END; .) .
- 2288    DisposeStat                           (. VAR dt: SymTab.TypeIndex;
- 2289                                               dk: INTEGER;
- 2290                                               qd, qv: QbeGen.QVal;
- 2291                                               qn: SymTab.Name;
- 2292                                               sfx: BOOLEAN;
- 2293                                               astNode, astD: AST.Node; .)
- 2294      = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
- 2295                                          (. astNode := AST.MakeNode(AST.NkCall);
- 2296                                             AST.SetChild(astNode, 0,
- 2297                                               AST.MakeLeaf(AST.NkIdent, "DISPOSE"));
- 2298                                             IF astD # AST.NoNode THEN
- 2299                                               AST.SetChild(astNode, 1, astD) END;
- 2300                                             astStmt := astNode; .)
- 2301                                           (. IF dt = SymTab.InvalidType THEN
- 2302                                              ELSIF (dk # SymTab.KindVar)
- 2303    AND (dk # SymTab.KindParam)
- 2304    AND (dk # SymTab.KindField) THEN
- 2305                                                SemError(210)
- 2306                                              ELSIF SymTab.ClassOf(dt) #
- 2307                                                    SymTab.ClPtr THEN
- 2308                                                SemError(219)
- 2309                                              END; .) .
- 2310    (* WITH pushes each record's fields (inner wins) plus its base
- 2311       address; field designators resolve through both stacks. *)
- 2312    WithStat                              (. VAR nW: CARDINAL;
- 2313                                               astNode: AST.Node; .)
- 2314      = "WITH"                            (. nW := 0;
- 2315                                             astNode := AST.MakeNode(AST.NkWith); .)
- 2316        WithItem<nW, astNode> { "," WithItem<nW, astNode> }
- 2317        "DO"                              (. astStmt := AST.NoNode; .)
- 2318        [ StatSeq ] "END"                 (. AST.SetChild(astNode,
- 2319                                             AST.NChild(astNode), astStmt);
- 2320                                             astStmt := astNode;
- 2321                                             WHILE nW > 0 DO
- 2322                                               SymTab.PopScope;
- 2323                                               QbeGen.PopWith;
- 2324                                               DEC(nW)
- 2325                                             END; .) .
- 2326    WithItem<VAR nW: CARDINAL; wnode: AST.Node>
- 2327                                          (. VAR dt: SymTab.TypeIndex;
- 2328                                               dk: INTEGER;
- 2329                                               qd, qe: QbeGen.QVal;
- 2330                                               qn: SymTab.Name;
- 2331                                               sfx: BOOLEAN; .)
- 2332      = Design<dt, dk, qd, qn, sfx>
- 2333                                          (. IF astCur # AST.NoNode THEN
- 2334                                               AST.SetChild(wnode,
- 2335                                                 AST.NChild(wnode), astCur) END;
- 2336                                             IF dt = SymTab.InvalidType THEN
- 2337                                             ELSIF (SymTab.ClassOf(dt) #
- 2338                                                    SymTab.ClRecord)
- 2339   AND (SymTab.ClassOf(dt) #
- 2340                                                   SymTab.ClClass) THEN
- 2341                                               SemError(215)
- 2342                                             ELSIF SymTab.PushRecord(dt) THEN
- 2343                                               QbeGen.PushWith(qd);
- 2344                                               INC(nW)
- 2345                                             END; .) .
- 2346    (* Assignment or procedure-statement call (4.1, module level).
- 2347       Bare `P;` is a syntax error; function-as-statement is 233. *)
- 2348    AssOrCall                             (. VAR dt, et: SymTab.TypeIndex;
- 2349                                               dk: INTEGER;
- 2350                                               qd, qe, qt, ql: QbeGen.QVal;
- 2351                                               qn: SymTab.Name;
- 2352                                               ct2, res0: SymTab.TypeIndex;
- 2353                                               q2, mg0: QbeGen.QVal;
- 2354                                               isR, conv, wconv: BOOLEAN;
- 2355                                               called, sfx: BOOLEAN;
- 2356                                               astLhs, astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN;
- 2357                                               n: SymTab.Name; astLab, astNode: AST.Node; .)
- 2358      = GetIdent<n>
- 2359        ( ":"                             (. NoteLabel(n);
- 2360                                             astNode := AST.MakeNode(AST.NkLabel);
- 2361                                             AST.SetChild(astNode, 0,
- 2362                                               AST.MakeLeaf(AST.NkIdent, n));
- 2363                                             astLab := AST.MakeNode(AST.NkBlock);
- 2364                                             AST.SetChild(astLab, 0, astNode); .)
- 2365          Statement                       (. IF astStmt # AST.NoNode THEN
- 2366                                               AST.SetChild(astLab, 1, astStmt) END;
- 2367                                             astStmt := astLab; .)
- 2368        | DesignTail<n, dt, dk, qd, qn, sfx>
- 2369        (. astLhs := astCur; astNArgs := 0; .)
- 2370        ( ":="
- 2371          Expr<et, qe>                    (. astStmt := AST.MakeBin(
- 2372                                               AST.NkAssign, 0, astLhs, astCur);
- 2373                                             IF (dt # SymTab.InvalidType)
- 2374   AND (dk # SymTab.KindVar)
- 2375   AND (dk # SymTab.KindParam)
- 2376   AND (dk # SymTab.KindField) THEN
- 2377                                             SemError(210)
- 2378                                           ELSIF NOT SymTab.Assignable(et,
- 2379                                                    dt) THEN
- 2380                                             SemError(210)
- 2381                                           ELSIF (dt # SymTab.InvalidType)
- 2382   AND (SymTab.ClassOf(dt) =
- 2383                                                 SymTab.ClClass) THEN
- 2384                                             SemError(230) END;
- 2385                                           isR := (dt #
- 2386                                                   SymTab.InvalidType)
- 2387   AND (SymTab.ClassOf(dt)
- 2388                                                     = SymTab.ClReal);
- 2389                                           conv := isR
- 2390   AND SymTab.IsIntFamily(et);
- 2391                                           wconv := (dt #
- 2392                                                     SymTab.InvalidType)
- 2393   AND SymTab.IsLongFamily(dt)
- 2394   AND SymTab.IsIntFamily(et);
- 2395                                           IF ((dk = SymTab.KindVar)
- 2396                                               OR (dk = SymTab.KindParam)
- 2397                                               OR (dk = SymTab.KindField))
- 2398   AND (dt # SymTab.InvalidType)
- 2399   AND (et # SymTab.InvalidType)
- 2400   AND (SymTab.ClassOf(dt) #
- 2401                                                 SymTab.ClClass) THEN
- 2402                                           END; .)
- 2403        | ArgList<qn, dt, qd, TRUE, TRUE, methCls, ct2, q2, called>
- 2404                                          (. astRes := AstCallNode(astLhs);
- 2405                                             sfx := FALSE; .)
- 2406          ( { ResultComp<ct2, q2, sfx, astRes, mname, methCls, isM> }
- 2407            ":=" Expr<et, qe>             (. astStmt := AST.MakeBin(
- 2408                                               AST.NkAssign, 0, astRes, astCur);
- 2409                                             IF NOT sfx THEN
- 2410                                               SemError(233)
- 2411                                             ELSIF (ct2 # SymTab.InvalidType)
- 2412    AND NOT SymTab.Assignable(et, ct2) THEN
- 2413                                               SemError(210)
- 2414                                             END; .)
- 2415          |                               (. (* discarding the result of a
- 2416                                               foreign C varargs call
- 2417                                               (printf/snprintf) is accepted;
- 2418                                               an ordinary Modula-2 function
- 2419                                               used as a statement stays 233 *)
- 2420                                             IF (ct2 # SymTab.InvalidType)
- 2421                                                AND NOT SymTab.Varargs(qn) THEN
- 2422                                               SemError(233) END;
- 2423                                             astStmt := astRes; .) )
- 2424        |                                 (* bare `P;`: proper parameterless
- 2425                                              procedure call; anything else
- 2426                                              here is 233 (was a bare syntax
- 2427                                              error before 4.2) *)
- 2428                                          (. astStmt := AstCallNode(astLhs);
- 2429                                              IF (dk = SymTab.KindProc)
- 2430   AND NOT sfx THEN
- 2431                                               res0 := SymTab.ProcRes(qn);
- 2432                                               IF res0 #
- 2433                                                  SymTab.InvalidType THEN
- 2434                                                 SemError(233)
- 2435                                               ELSIF SymTab.ProcNPar(qn) #
- 2436                                                       0 THEN
- 2437                                                 SemError(233)
- 2438                                               END
- 2439                                             ELSIF (dt # SymTab.InvalidType)
- 2440    AND (SymTab.ClassOf(dt) = SymTab.ClProc) THEN
- 2441                                               IF SymTab.ProcTypeRes(dt) #
- 2442                                                  SymTab.InvalidType THEN
- 2443                                                 SemError(233)
- 2444                                               ELSIF SymTab.ProcTypeNPar(dt) #
- 2445                                                       0 THEN
- 2446                                                 SemError(233)
- 2447                                               END
- 2448                                             ELSE SemError(233)
- 2449                                              END; .) ) ) .
- 2450    (* Actual-parameter list shared by statement and expression calls.
- 2451       want selects CallEnd's result handling; t/q carry the call
- 2452       value (statement calls discard). Arity/type failures are 233;
- 2453       evaluation code still emits so the .ssa stays assembleable. *)
- 2454    ArgList<pn: SymTab.Name; pt: SymTab.TypeIndex; callee: QbeGen.QVal;
- 2455            want: BOOLEAN; soft: BOOLEAN; methCls: SymTab.TypeIndex;
- 2456            VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
- 2457            VAR called: BOOLEAN>          (. VAR i, np: CARDINAL;
- 2458                                               vs: INTEGER;
- 2459                                               res: SymTab.TypeIndex;
- 2460                                               mg: QbeGen.QVal;
- 2461                                               ok, ind, isMeth, va, isConv: BOOLEAN; .)
- 2462      = "("                               (. called := TRUE;
- 2463                                             ok := TRUE;
- 2464                                             ind := FALSE;
- 2465                                             isConv := FALSE;
- 2466                                             isMeth := methCls #
- 2467                                               SymTab.InvalidType;
- 2468                                             IF isMeth THEN
- 2469                                               res := SymTab.ClassMethodRes(methCls, pn)
- 2470                                             ELSIF SymTab.SymKind(pn) = SymTab.KindProc THEN
- 2471                                               res := SymTab.ProcRes(pn)
- 2472                                             ELSIF (SymTab.SymKind(pn) = SymTab.KindType)
- 2473    OR (SymTab.SymKind(pn) = SymTab.KindPredef) THEN
- 2474                                               (* ISO type conversion T(x):
- 2475                                                  one value, result is T *)
- 2476                                               isConv := TRUE;
- 2477                                               res := SymTab.SymType(pn)
- 2478                                             ELSIF (pt # SymTab.InvalidType)
- 2479    AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN
- 2480                                               ind := TRUE;
- 2481                                               res := SymTab.ProcTypeRes(pt)
- 2482                                             ELSE SemError(233);
- 2483                                               ok := FALSE;
- 2484                                               res := SymTab.InvalidType
- 2485                                             END;
- 2486                                             i := 0; .)
- 2487        [ ActParam<pn, pt, ind, methCls, i>        (. INC(i); .)
- 2488          { "," ActParam<pn, pt, ind, methCls, i>  (. INC(i); .) } ]
- 2489        ")"                               (. IF ok THEN
- 2490                                               IF isConv THEN
- 2491                                                 (* a conversion takes
- 2492                                                    exactly one value *)
- 2493                                                 IF i # 1 THEN
- 2494                                                   SemError(233); ok := FALSE
- 2495                                                 END
- 2496                                               ELSE
- 2497                                                 IF isMeth THEN
- 2498                                                   np := SymTab.ClassMethodNPar(
- 2499                                                     methCls, pn)
- 2500                                                 ELSIF ind THEN
- 2501                                                   np := SymTab.ProcTypeNPar(pt)
- 2502                                                 ELSE np := SymTab.ProcNPar(pn)
- 2503                                                 END;
- 2504                                                 va := (NOT isMeth) AND (NOT ind)
- 2505                                                   AND (SymTab.SymKind(pn) =
- 2506                                                        SymTab.KindProc)
- 2507                                                   AND SymTab.Varargs(pn);
- 2508                                                 IF (i # np) AND NOT va THEN
- 2509                                                   SemError(233); ok := FALSE
- 2510                                                 END
- 2511                                               END
- 2512                                             END;
- 2513                                             IF NOT ok THEN
- 2514                                               t := SymTab.InvalidType;
- 2515                                               QbeGen.CopyOp("0", q)
- 2516                                             ELSIF want THEN
- 2517                                               IF res =
- 2518                                                  SymTab.InvalidType THEN
- 2519                                                 IF NOT soft THEN SemError(233) END;
- 2520                                                 t := SymTab.InvalidType;
- 2521                                                 QbeGen.CopyOp("0", q)
- 2522                                               ELSE t := res;
- 2523                                                  QbeGen.CopyOp("@", q)
- 2524                                               END
- 2525                                             ELSE
- 2526                                               (* a function call used as
- 2527                                                  a statement: allowed for
- 2528                                                  a foreign C varargs proc
- 2529                                                  (printf/snprintf), whose
- 2530                                                  result is conventionally
- 2531                                                  discarded; ordinary
- 2532                                                  Modula-2 functions keep
- 2533                                                  the 233 diagnostic *)
- 2534                                               IF (res # SymTab.InvalidType)
- 2535                                                  AND NOT va THEN
- 2536                                                 SemError(233)
- 2537                                               END;
- 2538                                               t := SymTab.InvalidType;
- 2539                                               QbeGen.CopyOp("0", q);
- 2540                                             END; .) .
- 2541    (* One actual: VAR formals take recorded designator addresses
- 2542       (233 otherwise); value formals take converted expressions. *)
- 2543    ActParam<pn: SymTab.Name; pt: SymTab.TypeIndex; ind: BOOLEAN;
- 2544             methCls: SymTab.TypeIndex; i: CARDINAL>
- 2545                                          (. VAR at, ft: SymTab.TypeIndex;
- 2546                                               qe, qa, qt: QbeGen.QVal;
- 2547                                               isV, conv, va: BOOLEAN;
- 2548                                               cl: CHAR;
- 2549                                               savedN, aj: CARDINAL;
- 2550                                               savedArgs: ARRAY [0 .. 31]
- 2551                                                 OF AST.Node;
- 2552                                               astActual: AST.Node; .)
- 2553      =                                   (. (* Parsing the actual can clobber
- 2554                                               the enclosing call's argument
- 2555                                               list (Factor resets astNArgs),
- 2556                                               so save/restore it. *)
- 2557                                             savedN := astNArgs; aj := 0;
- 2558                                             WHILE aj <= HIGH(astArgs) DO
- 2559                                               savedArgs[aj] := astArgs[aj];
- 2560                                               INC(aj)
- 2561                                             END; .)
- 2562        Expr<at, qe>                      (. QbeGen.CopyOp(qe, convQ); convT := at;
- 2563                                             astActual := astCur;
- 2564                                             astNArgs := savedN; aj := 0;
- 2565                                             WHILE aj <= HIGH(astArgs) DO
- 2566                                               astArgs[aj] := savedArgs[aj];
- 2567                                               INC(aj)
- 2568                                             END;
- 2569                                             IF astNArgs <= HIGH(astArgs) THEN
- 2570                                               astArgs[astNArgs] := astCur;
- 2571                                               INC(astNArgs)
- 2572                                             ELSE SemError(230)
- 2573                                               (* > 32 actuals: impl limit *)
- 2574                                             END;
- 2575                                             va := (NOT ind)
- 2576                                               AND (methCls =
- 2577                                                  SymTab.InvalidType)
- 2578                                               AND (SymTab.SymKind(pn) =
- 2579                                                  SymTab.KindProc)
- 2580                                               AND SymTab.Varargs(pn);
- 2581                                             IF ind THEN
- 2582                                               ft :=
- 2583                                                 SymTab.ProcTypeParamType(pt,
- 2584                                                   i);
- 2585                                               isV :=
- 2586                                                 SymTab.ProcTypeParamIsVar(pt,
- 2587                                                   i)
- 2588                                             ELSIF methCls #
- 2589                                                SymTab.InvalidType THEN
- 2590                                               ft :=
- 2591                                                 SymTab.ClassMethodParamType(
- 2592                                                 methCls, pn, i);
- 2593                                               isV :=
- 2594                                                 SymTab.ClassMethodParamIsVar(
- 2595                                                 methCls, pn, i)
- 2596                                             ELSE
- 2597                                               ft := SymTab.ParamType(pn, i);
- 2598                                               isV := SymTab.ParamIsVar(pn, i)
- 2599                                             END;
- 2600                                             IF (at = SymTab.InvalidType) THEN
- 2601                                             ELSIF ft = SymTab.InvalidType THEN
- 2602                                             ELSIF isV THEN
- 2603                                               IF (SymTab.ClassOf(at) = SymTab.ClChar)
- 2604    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
- 2605    AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar)
- 2606    AND QbeGen.IsImm(qe) THEN
- 2607                                               ELSIF (AST.Kind(astActual) #
- 2608                                                      AST.NkDesignator)
- 2609    AND (AST.Kind(astActual) # AST.NkStrLit) THEN
- 2610                                                 SemError(233)
- 2611                                               ELSIF NOT SymTab.VarParamOk(at, ft)
- 2612     AND NOT SymTab.ByteBufOk(at, ft) THEN
- 2613                                                 SemError(233)
- 2614                                               END
- 2615                                             ELSE
- 2616                                               IF (SymTab.ClassOf(at) = SymTab.ClChar)
- 2617    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
- 2618    AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar)
- 2619    AND QbeGen.IsImm(qe) THEN
- 2620                                               ELSIF NOT SymTab.Assignable(at, ft)
- 2621     AND NOT SymTab.ByteBufOk(at, ft) THEN
- 2622                                                 SemError(233)
- 2623                                               END
- 2624                                             END; .) .
- 2625    IfStat                                (. VAR t: SymTab.TypeIndex;
- 2626                                               q: QbeGen.QVal;
- 2627                                               hasElse: BOOLEAN;
- 2628                                               astCond, astIf, astLast,
- 2629                                               astNode: AST.Node; .)
- 2630      = "IF" (. hasElse := FALSE; .)
- 2631        Expr<t, q> (. astCond := astCur; astStmt := AST.NoNode;
- 2632                                             IF NOT SymTab.BoolCheck(t) THEN
- 2633                                               SemError(214) END; .)
- 2634        "THEN" [ StatSeq ]                (. astNode := AST.MakeNode(AST.NkIf);
- 2635                                             AST.SetChild(astNode, 0, astCond);
- 2636                                             AST.SetChild(astNode, 1, astStmt);
- 2637                                             astIf := astNode;
- 2638                                             astLast := astNode; .)
- 2639        { "ELSIF"
- 2640          Expr<t, q> (. astCond := astCur; astStmt := AST.NoNode;
- 2641                                             IF NOT SymTab.BoolCheck(t) THEN
- 2642                                               SemError(214) END; .)
- 2643          "THEN" [ StatSeq ]              (. astNode := AST.MakeNode(AST.NkIf);
- 2644                                             AST.SetChild(astNode, 0, astCond);
- 2645                                             AST.SetChild(astNode, 1, astStmt);
- 2646                                             AST.SetChild(astLast, 2, astNode);
- 2647                                             astLast := astNode; .) }
- 2648        [ "ELSE"                          (. hasElse := TRUE;
- 2649                                             astStmt := AST.NoNode; .)
- 2650          [ StatSeq ] (. AST.SetChild(astLast, 2, astStmt); .) ]
- 2651        "END" (. astStmt := astIf; .) .
- 2652    WhileStat                             (. VAR t: SymTab.TypeIndex;
- 2653                                               q: QbeGen.QVal;
- 2654                                               astCond, astNode: AST.Node; .)
- 2655      = "WHILE" (. astStmt := AST.NoNode; .)
- 2656        Expr<t, q> (. astCond := astCur;
- 2657                                             IF NOT SymTab.BoolCheck(t) THEN
- 2658                                               SemError(214) END; .)
- 2659        "DO" [ StatSeq ]                  (. astNode := AST.MakeNode(AST.NkWhile);
- 2660                                             AST.SetChild(astNode, 0, astCond);
- 2661                                             AST.SetChild(astNode, 1, astStmt);
- 2662                                             astStmt := astNode; .)
- 2663        "END" .
- 2664    RepeatStat                            (. VAR t: SymTab.TypeIndex;
- 2665                                               q: QbeGen.QVal;
- 2666                                               astCond, astBody, astNode:
- 2667                                                 AST.Node; .)
- 2668      = "REPEAT" (. astStmt := AST.NoNode; .)
- 2669        [ StatSeq ] (. astBody := astStmt; .)
- 2670        "UNTIL" Expr<t, q> (. astCond := astCur;
- 2671                                             astNode := AST.MakeNode(AST.NkRepeat);
- 2672                                             AST.SetChild(astNode, 0, astBody);
- 2673                                             AST.SetChild(astNode, 1, astCond);
- 2674                                             astStmt := astNode;
- 2675                                             IF NOT SymTab.BoolCheck(t) THEN
- 2676                                               SemError(214) END; .) .
- 2677    LoopStat                              (. VAR lEnd: QbeGen.QVal; astNode: AST.Node; .)
- 2678      = "LOOP"                            (. astStmt := AST.NoNode;
- 2679                                             QbeGen.NewLabel(lEnd);
- 2680                                             QbeGen.PushLoop(lEnd); .)
- 2681        [ StatSeq ]
- 2682        "END"                             (. astNode := AST.MakeNode(AST.NkLoop);
- 2683                                             AST.SetChild(astNode, 0, astStmt);
- 2684                                             astStmt := astNode;
- 2685                                             QbeGen.PopLoop; .) .
- 2686    (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
- 2687       Runtime direction would need a compare-select; the literal
- 2688       sign picks cslew/csegew at "DO" time. *)
- 2689    ForStat                               (. VAR lv: SymTab.Name;
- 2690                                               tlo, thi, tby:
- 2691                                                 SymTab.TypeIndex;
- 2692                                               qlo, qhi, qby, qt, qk, qb:
- 2693                                                 QbeGen.QVal;
- 2694                                               lTop, lBody, lEnd:
- 2695                                                 QbeGen.QVal;
- 2696                                               by: INTEGER;
- 2697                                               ok: BOOLEAN;
- 2698                                               astVar, astLo, astHi, astBy,
- 2699                                               astNode: AST.Node; .)
- 2700      = "FOR"                             (. by := 1; .)
- 2701        GetIdent<lv> (. astVar := AST.MakeLeaf(AST.NkIdent, lv);
- 2702                                             astStmt := AST.NoNode;
- 2703                                             astBy := AST.NoNode;
- 2704                                             ok := SymTab.Lookup(lv);
- 2705                                             IF NOT ok THEN
- 2706                                               SemError(201)
- 2707                                             ELSIF (SymTab.SymKind(lv) #
- 2708                                                    SymTab.KindVar)
- 2709   AND (SymTab.SymKind(lv) #
- 2710                                                   SymTab.KindParam) THEN
- 2711                                               SemError(220); ok := FALSE
- 2712                                             ELSIF NOT SymTab.IsOrdinal(
- 2713                                                     SymTab.SymType(lv)) THEN
- 2714                                               SemError(220); ok := FALSE
- 2715                                             END; .)
- 2716        ":=" Expr<tlo, qlo> (. astLo := astCur;
- 2717                                             IF NOT SymTab.Assignable(tlo,
- 2718                                                  SymTab.SymType(lv)) THEN
- 2719                                               SemError(220); ok := FALSE
- 2720                                             END; .)
- 2721        "TO" Expr<thi, qhi> (. astHi := astCur;
- 2722                                             IF NOT SymTab.Assignable(thi,
- 2723                                                  SymTab.SymType(lv)) THEN
- 2724                                               SemError(220); ok := FALSE
- 2725                                             END; .)
- 2726        [ "BY" Expr<tby, qby> (. astBy := astCur;
- 2727                                             IF (tby #
- 2728                                               SymTab.InvalidType)
- 2729   AND NOT SymTab.IsIntFamily(tby) THEN
- 2730                                               SemError(220); ok := FALSE
- 2731                                             END;
- 2732                                             IF NOT SymTab.ConstInt(qby, by) THEN
- 2733                                               SemError(230); by := 1
- 2734                                             ELSIF by = 0 THEN
- 2735                                               SemError(220); by := 1
- 2736                                             END; .) ]
- 2737        "DO"
- 2738        [ StatSeq ]
- 2739        "END" (. astNode := AST.MakeNode(AST.NkFor);
- 2740                                             AST.SetChild(astNode, 0, astVar);
- 2741                                             AST.SetChild(astNode, 1, astLo);
- 2742                                             AST.SetChild(astNode, 2, astHi);
- 2743                                             AST.SetChild(astNode, 3, astBy);
- 2744                                             AST.SetChild(astNode, 4, astStmt);
- 2745                                             astStmt := astNode;
- 2746                                             .) .
- 2747    CaseStat                              (. VAR tsel: SymTab.TypeIndex;
- 2748                                               qsel, lEnd: QbeGen.QVal;
- 2749                                               arm, astNode, astArms,
- 2750                                               astArmsTail: AST.Node; .)
- 2751      = "CASE" Expr<tsel, qsel>           (. astNode := AST.MakeNode(AST.NkCase);
- 2752                                             AST.SetChild(astNode, 0, astCur);
- 2753                                             astArms := AST.NoNode;
- 2754                                             astArmsTail := AST.NoNode;
- 2755                                             .)
- 2756        "OF" [ "|" ] CaseAlt<tsel, qsel, lEnd, astArms, astArmsTail>
- 2757        { "|" CaseAlt<tsel, qsel, lEnd, astArms, astArmsTail> }
- 2758        [ "ELSE"                          (. astStmt := AST.NoNode; .)
- 2759          [ StatSeq ]                     (. arm := AST.MakeNode(AST.NkCaseArm);
- 2760                                             AST.SetOp(arm, 1);
- 2761                                             AST.SetChild(arm, 0, astStmt);
- 2762                                             AstAppend(AST.NkBlock,
- 2763                                               astArms, astArmsTail, arm); .) ]
- 2764        "END"                             (. AST.SetChild(astNode, 1, astArms);
- 2765                                             astStmt := astNode;
- 2766                                             .) .
- 2767    (* Compare-chain lowering: each alternative ends its match-tests
- 2768       with "jmp lAfter", so the no-match fallthrough skips the body:
- 2769       "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
- 2770       lAfter:". Falls into the next alternative, ELSE, or END. *)
- 2771    CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
- 2772            lEnd: QbeGen.QVal; VAR arms, armsTail: AST.Node>
- 2773                                          (. VAR arm: AST.Node; .)
- 2774      =                                   (. arm := AST.MakeNode(AST.NkCaseArm); .)
- 2775        CaseLabel<tsel, qsel, arm>
- 2776        { "," CaseLabel<tsel, qsel, arm> }
- 2777        ":"                               (. astStmt := AST.NoNode; .)
- 2778        [ StatSeq ]                       (. AST.SetChild(arm, AST.NChild(arm),
- 2779                                             astStmt);
- 2780                                             AstAppend(AST.NkBlock,
- 2781                                               arms, armsTail, arm);
- 2782                                             .) .
- 2783    CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
- 2784              arm: AST.Node>
- 2785                                          (. VAR t2, t3: SymTab.TypeIndex;
- 2786                                               q2, q3, qc, qd, qe:
- 2787                                                 QbeGen.QVal;
- 2788                                               astLab: AST.Node;
- 2789                                               lNext: QbeGen.QVal; .)
- 2790      = Expr<t2, q2> (. astLab := astCur;
- 2791                                             IF SymTab.IsEmptyStr(t2)
- 2792                                                AND (SymTab.ClassOf(tsel) =
- 2793                                                     SymTab.ClChar) THEN
- 2794                                               (* ISO: '' as a CASE label
- 2795                                                  is the terminator *)
- 2796                                               QbeGen.CopyOp("0", q2);
- 2797                                               t2 := SymTab.CharType()
- 2798                                             END;
- 2799                                             IF (t2 #
- 2800                                               SymTab.InvalidType)
- 2801   AND (tsel #
- 2802                                                 SymTab.InvalidType)
- 2803   AND NOT SymTab.EqCheck(t2,
- 2804                                                   tsel) THEN
- 2805                                               SemError(213) END;
- 2806                                             (* set labels are not immediates:
- 2807                                                the CASE chain uses CmpSet *)
- 2808                                             IF (SymTab.ClassOf(t2) # SymTab.ClSet)
- 2809   AND NOT QbeGen.IsImm(q2) THEN
- 2810                                               SemError(230)
- 2811                                             END; .)
- 2812        [ ".." Expr<t3, q3>               (. astLab := AST.MakeBin(
- 2813                                               AST.NkSubrange, 0, astLab, astCur);
- 2814                                             IF SymTab.IsEmptyStr(t3)
- 2815                                                AND (SymTab.ClassOf(tsel) =
- 2816                                                     SymTab.ClChar) THEN
- 2817                                               QbeGen.CopyOp("0", q3);
- 2818                                               t3 := SymTab.CharType()
- 2819                                             END;
- 2820                                             IF (t3 #
- 2821                                               SymTab.InvalidType)
- 2822   AND (tsel #
- 2823                                                 SymTab.InvalidType)
- 2824   AND NOT SymTab.EqCheck(t3,
- 2825                                                   tsel) THEN
- 2826                                               SemError(213) END;
- 2827                                                 IF (SymTab.ClassOf(t3) # SymTab.ClSet)
- 2828   AND NOT QbeGen.IsImm(q3) THEN
- 2829                                                   SemError(230)
- 2830                                                 END; .) ]
- 2831                                          (. AST.SetChild(arm,
- 2832                                               AST.NChild(arm), astLab); .) .
- 2833    ReturnStat                            (. VAR t: SymTab.TypeIndex;
- 2834                                               q, qt: QbeGen.QVal;
- 2835                                               res: SymTab.TypeIndex;
- 2836                                               hadE, conv: BOOLEAN;
- 2837                                               astVal, astNode: AST.Node; .)
- 2838      = "RETURN"                          (. hadE := FALSE; astStmt := AST.NoNode; .)
- 2839        [ Expr<t, q> (. hadE := TRUE; astVal := astCur; .) ]
- 2840                                          (. astNode := AST.MakeNode(AST.NkReturn);
- 2841                                             IF hadE THEN
- 2842                                               AST.SetChild(astNode, 0, astVal)
- 2843                                             END;
- 2844                                             astStmt := astNode;
- 2845                                             conv := FALSE;
- 2846                                             IF NOT SymTab.InProc() THEN
- 2847                                               SemError(232)
- 2848                                             ELSE res := SymTab.CurRes();
- 2849                                               IF NOT hadE THEN
- 2850                                                 IF res #
- 2851                                                    SymTab.InvalidType THEN
- 2852                                                   SemError(232)
- 2853                                                 END
- 2854                                               ELSIF (res =
- 2855                                                      SymTab.InvalidType)
- 2856                                                  OR (t #
- 2857                                                      SymTab.InvalidType)
- 2858   AND NOT SymTab.Assignable(t,
- 2859                                                       res) THEN
- 2860                                                 SemError(232)
- 2861                                             END
- 2862                                             END; .) .
- 2863    HaltStat                              (. VAR t: SymTab.TypeIndex;
- 2864                                               q: QbeGen.QVal;
- 2865                                               astVal, astNode: AST.Node; .)
- 2866      = "HALT" (. astVal := AST.NoNode; .)
- 2867        [ "(" Expr<t, q> (. astVal := astCur; .) ")" ]
- 2868                                          (. astNode := AST.MakeNode(AST.NkHalt);
- 2869                                             IF astVal # AST.NoNode THEN
- 2870                                               AST.SetChild(astNode, 0, astVal)
- 2871                                             END;
- 2872                                             astStmt := astNode;
- 2873                                             .) .
- 2874    (* Designator: scalar loads, array addresses, and index suffixes.
- 2875       Each index descends one level (bounds-checked, trap on breach);
- 2876       nested levels reload the inner descriptor address. q ends as the
- 2877       value (scalars), the descriptor address (plain arrays), or the
- 2878       element address (indexed); sfx marks the indexed form. *)
- 2879    Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
- 2880           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
- 2881                                          (. VAR n: SymTab.Name; .)
- 2882      = GetIdent<n> DesignTail<n, t, k, q, qn, sfx> .
- 2883    (* The part of Design after the identifier: resolve it and walk the
- 2884       selectors.  Split out so a statement can decide between a label
- 2885       (`ident :`) and a designator (`ident := ...`) with one token. *)
- 2886    DesignTail<VAR n: SymTab.Name; VAR t: SymTab.TypeIndex; VAR k: INTEGER;
- 2887           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
- 2888                                          (. VAR fn, mal: SymTab.Name;
- 2889                                               cls: INTEGER;
- 2890                                               ic: SymTab.TypeIndex;
- 2891                                               curT, it, eT, bt:
- 2892                                                 SymTab.TypeIndex;
- 2893                                               iq, ql, qlo, qhi, qe:
- 2894                                                 QbeGen.QVal;
- 2895                                               lo, hi: INTEGER;
- 2896                                               fo: INTEGER;
- 2897                                               isOpen: BOOLEAN;
- 2898                                               qb, cv: QbeGen.QVal;
- 2899                                               r: BOOLEAN;
- 2900                                                astDes, astSel: AST.Node; .)
- 2901      =                                   (. methCls := SymTab.InvalidType;
- 2902                                             QbeGen.CopyOp(n, qn);
- 2903                                             sfx := FALSE;
- 2904                                             IF NOT SymTab.Lookup(n) THEN
- 2905                                               (* a bare method name inside
- 2906                                                  a CLASS IMPLEMENTATION
- 2907                                                  is a sibling call on
- 2908                                                  THIS *)
- 2909                                               ic := SymTab.CurImplClass();
- 2910                                               IF (ic #
- 2911                                                  SymTab.InvalidType)
- 2912    AND SymTab.MethodExists(ic, n) THEN
- 2913                                                 sfx := FALSE;
- 2914                                                  QbeGen.CopyOp("@", q);
- 2915                                                 methCls := ic;
- 2916                                                 k := SymTab.KindProc;
- 2917                                                 t := SymTab.InvalidType
- 2918                                               ELSIF SymTab.InProc() THEN
- 2919                                                 (* not declared anywhere
- 2920                                                    in scope: with bodies
- 2921                                                    parsed at unit end this
- 2922                                                    is a genuine 201 (a
- 2923                                                    nested-local forward is
- 2924                                                    no longer tolerated). *)
- 2925                                                 SemError(201);
- 2926                                                 t := SymTab.InvalidType;
- 2927                                                 k := -1;
- 2928                                                 QbeGen.CopyOp("0", q)
- 2929                                               ELSE
- 2930                                                 SemError(201);
- 2931                                                 t :=
- 2932                                                   SymTab.InvalidType;
- 2933                                                 k := -1;
- 2934                                                 QbeGen.CopyOp("0", q)
- 2935                                               END
- 2936                                             ELSE
- 2937                                               t := SymTab.SymType(n);
- 2938                                               k := SymTab.SymKind(n);
- 2939                                               IF k = SymTab.KindConst THEN
- 2940                                                 IF SymTab.Equal(n,
- 2941                                                    "TRUE") THEN
- 2942                                                   t := SymTab.BoolType();
- 2943                                                   QbeGen.CopyOp("1", q)
- 2944                                                 ELSIF SymTab.Equal(n,
- 2945                                                    "FALSE") THEN
- 2946                                                   t := SymTab.BoolType();
- 2947                                                   QbeGen.CopyOp("0", q)
- 2948                                                 ELSIF SymTab.Equal(n,
- 2949                                                    "NIL") THEN
- 2950                                                   QbeGen.CopyOp("0", q)
- 2951                                                 ELSE
- 2952                                                   cls :=
- 2953                                                     SymTab.ClassOf(t);
- 2954                                                   IF (t #
- 2955                                                       SymTab.InvalidType)
- 2956   AND ((cls = SymTab.ClInt)
- 2957                                                      OR (cls
- 2958                                                          = SymTab.ClChar)
- 2959                                                      OR (cls
- 2960                                                          = SymTab.ClEnum)
- 2961                                                      OR (cls
- 2962                                                          = SymTab.ClReal)
- 2963                                                      OR (cls
- 2964                                                          = SymTab.ClLong)
- 2965                                                      OR (cls
- 2966                                                          = SymTab.ClNil)
- 2967                                                      OR (cls = SymTab.ClByte)
- 2968                                                      OR (cls = SymTab.ClSByte)
- 2969                                                      OR (cls = SymTab.ClWord16)
- 2970                                                      OR (cls = SymTab.ClSWord16)
- 2971                                                       OR (cls = SymTab.ClBool)) THEN
- 2972                                                     IF cls = SymTab.ClNil THEN
- 2973                                                       QbeGen.CopyOp("0", q)
- 2974                                                     ELSIF ((cls
- 2975                                                         = SymTab.ClInt)
- 2976                                                       OR (cls
- 2977                                                         = SymTab.ClChar)
- 2978                                                       OR (cls
- 2979                                                         = SymTab.ClEnum)
- 2980                                                       OR (cls
- 2981                                                         = SymTab.ClLong)
- 2982                                                        OR (cls = SymTab.ClByte)
- 2983                                                        OR (cls = SymTab.ClSByte)
- 2984                                                        OR (cls = SymTab.ClWord16)
- 2985                                                        OR (cls = SymTab.ClSWord16)
- 2986                                                        OR (cls = SymTab.ClBool))
- 2987    AND SymTab.GetSymVal(n, cv)
- 2988    AND QbeGen.IsImm(cv) THEN
- 2989                                                       QbeGen.CopyOp(cv, q)
- 2990                                                     ELSE
- 2991                                                       QbeGen.LoadVar(n,
- 2992                                                         cls = SymTab.ClReal,
- 2993                                                         q)
- 2994                                                     END
- 2995                                                   ELSIF (cls = SymTab.ClArray)
- 2996                                                      OR (cls = SymTab.ClRecord)
- 2997                                                      OR (cls = SymTab.ClClass)
- 2998                                                      OR (cls = SymTab.ClStr)
- 2999                                                      OR (cls = SymTab.ClUStr)
- 3000                                                      OR (cls = SymTab.ClSet) THEN
- 3001                                                     (* aggregate constant:
- 3002                                                        its value IS the
- 3003                                                        descriptor address *)
- 3004                                                     IF SymTab.GetSymVal(n, cv) THEN
- 3005                                                       QbeGen.CopyOp(cv, q)
- 3006                                                     ELSE
- 3007                                                       QbeGen.CopyOp("0", q)
- 3008                                                     END
- 3009                                                   ELSE
- 3010                                                     IF t #
- 3011                                                        SymTab.InvalidType THEN
- 3012                                                       SemError(230)
- 3013                                                     END;
- 3014                                                     QbeGen.CopyOp("0", q)
- 3015                                                   END
- 3016                                                 END
- 3017                                               ELSIF (k = SymTab.KindVar)
- 3018                                                  OR (k = SymTab.KindParam) THEN
- 3019                                                 cls := SymTab.ClassOf(t);
- 3020                                                 IF (cls # SymTab.ClInt)
- 3021                                                    AND (cls # SymTab.ClBool)
- 3022                                                    AND (cls # SymTab.ClChar)
- 3023                                                    AND (cls # SymTab.ClUChar)
- 3024                                                    AND (cls # SymTab.ClEnum)
- 3025                                                    AND (cls # SymTab.ClReal)
- 3026                                                    AND (cls # SymTab.ClPtr)
- 3027                                                    AND (cls # SymTab.ClProc)
- 3028                                                    AND (cls # SymTab.ClLong)
- 3029                                                    AND (cls # SymTab.ClArray)
- 3030                                                    AND (cls # SymTab.ClSet)
- 3031                                                    AND (cls # SymTab.ClRecord)
- 3032                                                    AND (cls # SymTab.ClUStr)
- 3033                                                    AND (cls # SymTab.ClByte)
- 3034                                                    AND (cls # SymTab.ClSByte)
- 3035                                                    AND (cls # SymTab.ClWord16)
- 3036                                                    AND (cls # SymTab.ClSWord16)
- 3037                                                    AND (cls # SymTab.ClClass) THEN
- 3038                                                   SemError(230);
- 3039                                                   QbeGen.CopyOp("0", q)
- 3040                                                 ELSE QbeGen.CopyOp("@", q)
- 3041                                                 END
- 3042                                               ELSE QbeGen.CopyOp("0", q);
- 3043                                                 IF k = SymTab.KindImport THEN
- 3044                                                   SemError(230)
- 3045                                                 ELSIF k =
- 3046                                                    SymTab.KindProc THEN
- 3047                                                   (* bare procedure name:
- 3048                                                      a following ArgList
- 3049                                                      makes it a call;
- 3050                                                      otherwise Fact
- 3051                                                      reports 230 *)
- 3052                                                 ELSE
- 3053                                                    IF k = SymTab.KindField THEN
- 3054                                                      IF QbeGen.TopWith(qb) THEN
- 3055                                                        sfx := TRUE
- 3056                                                      ELSE SemError(230);
- 3057                                                        QbeGen.CopyOp("0", q)
- 3058                                                      END
- 3059                                                    END
- 3060                                                 END
- 3061                                               END
- 3062                                             END; .)
- 3063        (. astDes := AST.MakeNode(AST.NkDesignator);
- 3064           AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .)
- 3065        { "[" Expr<it, iq>
- 3066                                          (. AST.SetChild(astDes, AST.NChild(astDes),
- 3067               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
- 3068                                             ELSIF SymTab.ClassOf(t) #
- 3069                                                   SymTab.ClArray THEN
- 3070                                               SemError(217);
- 3071                                               t := SymTab.InvalidType
- 3072                                             ELSIF NOT SymTab.IsIntFamily(it)
- 3073   AND (SymTab.ClassOf(it) #
- 3074                                                   SymTab.ClChar)
- 3075   AND (SymTab.ClassOf(it) #
- 3076                                                   SymTab.ClEnum)
- 3077   AND (SymTab.ClassOf(it) #
- 3078                                                   SymTab.ClBool) THEN
- 3079                                               SemError(218);
- 3080                                               t := SymTab.InvalidType
- 3081                                              ELSE
- 3082                                                eT := SymTab.ArrayElem(t);
- 3083                                                t := eT; sfx := TRUE
- 3084                                              END; .)
- 3085          { "," Expr<it, iq>
- 3086                                          (. AST.SetChild(astDes, AST.NChild(astDes),
- 3087               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
- 3088                                             ELSIF SymTab.ClassOf(t) #
- 3089                                                   SymTab.ClArray THEN
- 3090                                               SemError(217);
- 3091                                               t := SymTab.InvalidType
- 3092                                             ELSIF NOT SymTab.IsIntFamily(it)
- 3093   AND (SymTab.ClassOf(it) #
- 3094                                                   SymTab.ClChar)
- 3095   AND (SymTab.ClassOf(it) #
- 3096                                                   SymTab.ClEnum)
- 3097   AND (SymTab.ClassOf(it) #
- 3098                                                   SymTab.ClBool) THEN
- 3099                                               SemError(218);
- 3100                                               t := SymTab.InvalidType
- 3101                                              ELSE
- 3102                                                eT := SymTab.ArrayElem(t);
- 3103                                                t := eT; sfx := TRUE
- 3104                                              END; .) }
- 3105          "]"
- 3106        | "." GetIdent<fn>
- 3107                                          (. astSel := AST.MakeNode(AST.NkSelector);
- 3108               AST.SetOp(astSel, AST.SelField);
- 3109               AST.SetChild(astSel, 0, AST.MakeLeaf(AST.NkIdent, fn));
- 3110               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF k = SymTab.KindModule THEN
- 3111                                               (* qualified L.x: materialize
- 3112                                                  the export, then load it *)
- 3113                                               IF NOT SymTab.MaterializeAlias(n,
- 3114                                                    fn, mal) THEN
- 3115                                                 SemError(201);
- 3116                                                 t := SymTab.InvalidType;
- 3117                                                 QbeGen.CopyOp("0", q)
- 3118                                               ELSE
- 3119                                                 QbeGen.CopyOp(mal, qn);
- 3120                                                 t := SymTab.SymType(mal);
- 3121                                                 k := SymTab.SymKind(mal);
- 3122                                                 sfx := FALSE;
- 3123                                                 IF k = SymTab.KindProc THEN
- 3124                                                   (* call: ArgList supplies
- 3125                                                      the value *)
- 3126                                                   QbeGen.CopyOp("0", q)
- 3127                                                 ELSIF k = SymTab.KindConst THEN
- 3128                                                   IF SymTab.GetSymVal(mal,
- 3129                                                      cv)
- 3130                                                   THEN QbeGen.CopyOp(cv, q)
- 3131                                                   ELSE QbeGen.CopyOp("0", q)
- 3132                                                   END
- 3133                                                  END
- 3134                                               END
- 3135                                             ELSIF t = SymTab.InvalidType THEN
- 3136                                             ELSIF (SymTab.ClassOf(t) #
- 3137                                                    SymTab.ClRecord)
- 3138   AND (SymTab.ClassOf(t) #
- 3139                                                   SymTab.ClClass) THEN
- 3140                                               SemError(215);
- 3141                                               t := SymTab.InvalidType
- 3142                                             ELSIF (SymTab.ClassOf(t) =
- 3143                                                    SymTab.ClClass)
- 3144    AND SymTab.MethodExists(t, fn) THEN
- 3145                                               (* obj.Method: bind the
- 3146                                                  method and pass obj as
- 3147                                                  the hidden receiver; q
- 3148                                                  already holds the
- 3149                                                  object's address *)
- 3150                                               QbeGen.CopyOp(fn, n);
- 3151                                               QbeGen.CopyOp(fn, qn);
- 3152                                               methCls := t;
- 3153                                               k := SymTab.KindProc;
- 3154                                               t := SymTab.InvalidType
- 3155                                             ELSIF NOT SymTab.FieldExists(t,
- 3156                                                      fn) THEN
- 3157                                               SemError(216);
- 3158                                               t := SymTab.InvalidType
- 3159                                              ELSE
- 3160                                                t := SymTab.FieldType(t, fn);
- 3161                                                sfx := TRUE
- 3162                                              END; .)
- 3163        | "^"
- 3164                                          (. astSel := AST.MakeNode(AST.NkSelector);
- 3165               AST.SetOp(astSel, AST.SelDeref);
- 3166               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF t = SymTab.InvalidType THEN
- 3167                                             ELSIF SymTab.ClassOf(t) #
- 3168                                                   SymTab.ClPtr THEN
- 3169                                               SemError(219);
- 3170                                               t := SymTab.InvalidType
- 3171                                             ELSE
- 3172                                               bt := SymTab.PtrBase(t);
- 3173                                               IF bt = SymTab.InvalidType THEN
- 3174                                               ELSE
- 3175                                                  t := bt;
- 3176                                                  sfx := TRUE
- 3177                                                END
- 3178                                             END; .) } (. astCur := astDes; .) .
- 3179    (* Result suffix (ISO component after a function call): `F()^`,
- 3180       `F()[i]`, `F().field`.  The call result is in t/q with sfx FALSE
- 3181       (a value, or a descriptor address for aggregates); each component
- 3182       descends one level exactly like the Design components. *)
- 3183    ResultComp<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
- 3184               VAR sfx: BOOLEAN; VAR node: AST.Node;
- 3185               VAR mname: SymTab.Name; VAR methCls: SymTab.TypeIndex;
- 3186               VAR isM: BOOLEAN>          (. VAR it, eT, bt: SymTab.TypeIndex;
- 3187                                               iq, ql, qlo, qhi, qe, qb:
- 3188                                                 QbeGen.QVal;
- 3189                                               lo, hi, fo: INTEGER;
- 3190                                               isOpen: BOOLEAN;
- 3191                                               fname: SymTab.Name;
- 3192                                               astWrap, astSel: AST.Node; .)
- 3193      = "[" Expr<it, iq>
- 3194                                          (. isM := FALSE;
- 3195                                             IF AST.Kind(node) # AST.NkDesignator THEN
- 3196                                               astWrap := AST.MakeNode(
- 3197                                                 AST.NkDesignator);
- 3198                                               AST.SetChild(astWrap, 0, node);
- 3199                                               node := astWrap
- 3200                                             END;
- 3201                                             AST.SetChild(node, AST.NChild(node),
- 3202                                               AST.MakeUn(AST.NkSelector,
- 3203                                                 AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
- 3204                                             ELSIF SymTab.ClassOf(t) #
- 3205                                                   SymTab.ClArray THEN
- 3206                                               SemError(217);
- 3207                                               t := SymTab.InvalidType
- 3208                                             ELSIF NOT SymTab.IsIntFamily(it)
- 3209    AND (SymTab.ClassOf(it) # SymTab.ClChar)
- 3210    AND (SymTab.ClassOf(it) # SymTab.ClEnum)
- 3211    AND (SymTab.ClassOf(it) # SymTab.ClBool) THEN
- 3212                                               SemError(218);
- 3213                                               t := SymTab.InvalidType
- 3214                                              ELSE
- 3215                                                eT := SymTab.ArrayElem(t);
- 3216                                                t := eT; sfx := TRUE
- 3217                                              END; .)
- 3218        "]"
- 3219      | "." GetIdent<fname>
- 3220                                          (. isM := FALSE;
- 3221                                             IF AST.Kind(node) # AST.NkDesignator THEN
- 3222                                               astWrap := AST.MakeNode(
- 3223                                                 AST.NkDesignator);
- 3224                                               AST.SetChild(astWrap, 0, node);
- 3225                                               node := astWrap
- 3226                                             END;
- 3227                                             AST.SetChild(node, AST.NChild(node),
- 3228                                               AST.MakeUn(AST.NkSelector,
- 3229                                                 AST.SelField,
- 3230                                                 AST.MakeLeaf(AST.NkIdent,
- 3231                                                   fname))); IF t = SymTab.InvalidType THEN
- 3232                                             ELSIF (SymTab.ClassOf(t) #
- 3233                                                    SymTab.ClRecord)
- 3234    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
- 3235                                               SemError(215);
- 3236                                               t := SymTab.InvalidType
- 3237                                              ELSIF (SymTab.ClassOf(t) =
- 3238                                                     SymTab.ClClass)
- 3239    AND SymTab.MethodExists(t, fname) THEN
- 3240                                                (* a method on the call result:
- 3241                                                   a following ArgList makes
- 3242                                                   the call *)
- 3243                                                mname := fname;
- 3244                                                methCls := t; isM := TRUE;
- 3245                                                t := SymTab.InvalidType
- 3246                                             ELSIF NOT SymTab.FieldExists(t,
- 3247                                                      fname) THEN
- 3248                                               SemError(216);
+ 1271      | PackSetType<t>
+ 1272      | RecordType<t>
+ 1273      | PointerType<t>
+ 1274      | ProcType<t> .
+ 1275    PointerType<VAR t: SymTab.TypeIndex>  (. VAR base: SymTab.TypeIndex; .)
+ 1276      = "POINTER" "TO"                    (. allowFwdType := TRUE; .)
+ 1277        Type<base, FALSE>                 (. allowFwdType := FALSE;
+ 1278                                             t := SymTab.NewPtr(base); .) .
+ 1279    (* Procedure types (step 8.5): PROCEDURE (params): result. Values
+ 1280       are code pointers; params are collected into the descriptor. *)
+ 1281    ProcType<VAR t: SymTab.TypeIndex>     (. VAR res, pt: SymTab.TypeIndex;
+ 1282                                               isV: BOOLEAN; .)
+ 1283      = ( "PROCEDURE" | "PROC" )         (. allowFwdType := FALSE;
+ 1284                                             res := SymTab.InvalidType;
+ 1285                                             t := SymTab.NewProcType(res); .)
+ 1286        [ "(" [ ProcTypeSection<t>
+ 1287                 { (";" | ",") ProcTypeSection<t> } ] ")" ]
+ 1288        [ ":" ( TypeIdent<res>            (. SymTab.SetProcTypeRes(t, res); .)
+ 1289              | "PROC"                    (. (* PROC as a result type: the
+ 1290                                                pervasive procedure value
+ 1291                                                type (ISO/PIM) *)
+ 1292                                             SymTab.SetProcTypeRes(t,
+ 1293                                               SymTab.AddrType()); .) ) ] .
+ 1294    ProcTypeSection<t: SymTab.TypeIndex>  (. VAR pt: SymTab.TypeIndex;
+ 1295                                               isV: BOOLEAN;
+ 1296                                               cnt, k: CARDINAL;
+ 1297                                               names: ARRAY [0 .. 15] OF SymTab.Name; .)
+ 1298      =                                   (. isV := FALSE; cnt := 0; .)
+ 1299        [ "VAR"                           (. isV := TRUE; .) ]
+ 1300        ( GetIdent<names[cnt]>            (. INC(cnt); .)
+ 1301          { "," ( GetIdent<names[cnt]>    (. INC(cnt); .)
+ 1302                |                         (. (* a comma followed by a type
+ 1303                                                (possibly VAR) ends the name
+ 1304                                                list: the collected names
+ 1305                                                were types, not names *)
+ 1306                                             k := 0;
+ 1307                                             WHILE k < cnt DO
+ 1308                                               SymTab.ProcTypeAdd(t, isV,
+ 1309                                                 SymTab.SymType(names[k]));
+ 1310                                               INC(k)
+ 1311                                             END;
+ 1312                                             cnt := 0; .)
+ 1313                  [ "VAR"                 (. isV := TRUE; .) ]
+ 1314                  Type<pt, TRUE>          (. SymTab.ProcTypeAdd(t, isV, pt); .) ) }
+ 1315          ( ":" Type<pt, TRUE>            (. k := 0;
+ 1316                                             WHILE k < cnt DO
+ 1317                                               SymTab.ProcTypeAdd(t, isV, pt);
+ 1318                                               INC(k)
+ 1319                                             END; .)
+ 1320          |                               (. (* type-only parameter list:
+ 1321                                                each collected name is a
+ 1322                                                type (CHAR, a declared type,
+ 1323                                                ... or the GNU shorthand) *)
+ 1324                                             k := 0;
+ 1325                                             WHILE k < cnt DO
+ 1326                                               IF IsTypeName(names[k]) THEN
+ 1327                                                 pt := SymTab.SymType(names[k])
+ 1328                                               ELSE SemError(201);
+ 1329                                                 pt := SymTab.InvalidType
+ 1330                                               END;
+ 1331                                               SymTab.ProcTypeAdd(t, isV, pt);
+ 1332                                               INC(k)
+ 1333                                             END; .) )
+ 1334        | Type<pt, TRUE>                 (. (* unnamed parameter (PIM):
+ 1335                                                e.g. PROCEDURE (VAR ARRAY OF REAL) *)
+ 1336                                             SymTab.ProcTypeAdd(t, isV, pt); .) ) .
+ 1337    (* Arrays: "OF" without bounds is an open formal (allowed only
+ 1338       where allowOpen); "[lo..hi, ...]" nests bounded levels inside
+ 1339       out.  The PIM/ISO multi-index form repeats the bracket group
+ 1340       ("ARRAY [lo..hi], [lo..hi] OF T"); the bounds of every group
+ 1341       nest in the same inside-out order as the comma list.  Bounds are
+ 1342       folded literals (int/char); anything else 230.  Bare-type indices
+ 1343       ("ARRAY Color OF") wait for enum ordinals. *)
+ 1344    ArrayType<VAR t: SymTab.TypeIndex; allowOpen: BOOLEAN>
+ 1345                                          (. VAR elem: SymTab.TypeIndex;
+ 1346                                               eb: SymTab.Name;
+ 1347                                               ok: BOOLEAN;
+ 1348                                               bnds, bndh: ARRAY [0 .. 7] OF INTEGER;
+ 1349                                               nb, k: CARDINAL;
+ 1350                                               idx: SymTab.TypeIndex;
+ 1351                                               ilo, ihi: INTEGER; .)
+ 1352      = "ARRAY"                           (. allowFwdType := FALSE; .)
+ 1353        ( "OF"
+ 1354          Type<elem, FALSE>               (. LexName(eb); (* the element ident *)
+ 1355                                             IF NOT allowOpen THEN
+ 1356                                               SemError(230) END;
+ 1357                                             t := SymTab.NewOpenArray(elem);
+ 1358                                             IF SymTab.Equal(eb, "BYTE") THEN
+ 1359                                               SymTab.MarkByteBuf(t) END; .)
+ 1360        | TypeIdent<idx> [ Subrange<idx> ]
+ 1361          "OF" Type<elem, FALSE>          (. (* index-type array: the index
+ 1362                                                type's ordinal bounds give the
+ 1363                                                [lo..hi] pair *)
+ 1364                                             IF SymTab.TypeBounds(idx, ilo,
+ 1365                                                ihi)
+ 1366                                             THEN t := SymTab.NewArrayB(elem,
+ 1367                                                    ilo, ihi)
+ 1368                                             ELSE SemError(230);
+ 1369                                               t := SymTab.InvalidType
+ 1370                                             END; .)
+ 1371        | "["                             (. SymTab.BoundBegin; ok := TRUE;
+ 1372                                             nb := 0; .)
+ 1373          BoundPair<ok>
+ 1374          { "," BoundPair<ok> }
+ 1375          "]"                             (. (* snapshot this bracket group
+ 1376                                                before the element type, which
+ 1377                                                reuses the bound buffer for a
+ 1378                                                nested ARRAY *)
+ 1379                                             IF nb + SymTab.BoundCount() >
+ 1380                                                HIGH(bnds) + 1 THEN
+ 1381                                               SemError(230); ok := FALSE
+ 1382                                             ELSE
+ 1383                                               k := 0;
+ 1384                                               WHILE k < SymTab.BoundCount() DO
+ 1385                                                 bnds[nb] := SymTab.BoundLo(k);
+ 1386                                                 bndh[nb] := SymTab.BoundHi(k);
+ 1387                                                 INC(k); INC(nb)
+ 1388                                               END
+ 1389                                             END; .)
+ 1390          { "," "["                       (. SymTab.BoundBegin; .)
+ 1391            BoundPair<ok>
+ 1392            { "," BoundPair<ok> }
+ 1393            "]"                           (. IF nb + SymTab.BoundCount() >
+ 1394                                                HIGH(bnds) + 1 THEN
+ 1395                                               SemError(230); ok := FALSE
+ 1396                                             ELSE
+ 1397                                               k := 0;
+ 1398                                               WHILE k < SymTab.BoundCount() DO
+ 1399                                                 bnds[nb] := SymTab.BoundLo(k);
+ 1400                                                 bndh[nb] := SymTab.BoundHi(k);
+ 1401                                                 INC(k); INC(nb)
+ 1402                                               END
+ 1403                                             END; .) }
+ 1404          "OF" Type<elem, FALSE>
+ 1405                                          (. IF ok THEN
+ 1406                                               k := nb;
+ 1407                                               WHILE k > 0 DO
+ 1408                                                 DEC(k);
+ 1409                                                 elem := SymTab.NewArrayB(
+ 1410                                                   elem, bnds[k], bndh[k])
+ 1411                                               END;
+ 1412                                               t := elem
+ 1413                                             ELSE t := SymTab.InvalidType
+ 1414                                             END; .) ) .
+ 1415    BoundPair<VAR ok: BOOLEAN>            (. VAR tlo, thi: SymTab.TypeIndex;
+ 1416                                               qlo, qhi: QbeGen.QVal;
+ 1417                                               lo, hi: INTEGER;
+ 1418                                               cl, cl2: INTEGER; .)
+ 1419      = Expr<tlo, qlo> ".." Expr<thi, qhi>
+ 1420                                          (. IF (tlo = SymTab.InvalidType)
+ 1421                                              OR (thi = SymTab.InvalidType) THEN
+ 1422                                             ok := FALSE
+ 1423                                           ELSE cl := SymTab.ClassOf(tlo);
+ 1424                                             cl2 := SymTab.ClassOf(thi);
+ 1425                                             IF ((cl # SymTab.ClInt)
+ 1426   AND (cl # SymTab.ClChar)
+ 1427   AND (cl # SymTab.ClBool)
+ 1428   AND (cl # SymTab.ClEnum)
+ 1429   AND (cl # SymTab.ClByte)
+ 1430   AND (cl # SymTab.ClSByte)
+ 1431   AND (cl # SymTab.ClWord16)
+ 1432   AND (cl # SymTab.ClSWord16))
+ 1433                                                OR ((cl2 # SymTab.ClInt)
+ 1434   AND (cl2 # SymTab.ClChar)
+ 1435   AND (cl2 # SymTab.ClBool)
+ 1436   AND (cl2 # SymTab.ClEnum)
+ 1437   AND (cl2 # SymTab.ClByte)
+ 1438   AND (cl2 # SymTab.ClSByte)
+ 1439   AND (cl2 # SymTab.ClWord16)
+ 1440   AND (cl2 # SymTab.ClSWord16)) THEN
+ 1441                                               SemError(230); ok := FALSE
+ 1442                                             ELSIF NOT SymTab.ConstInt(qlo, lo)
+ 1443                                                OR NOT SymTab.ConstInt(qhi, hi)
+ 1444                                                OR (lo > hi) THEN
+ 1445                                               SemError(230); ok := FALSE
+ 1446                                              ELSIF NOT SymTab.BoundAdd(lo, hi) THEN
+ 1447                                                SemError(230); ok := FALSE
+ 1448                                              END;
+ 1449                                            END; .) .
+ 1450    (* Sets: multi-word masks over bases ≤ 256 values (bool, char,
+ 1451       bounded subranges; enums wait for ordinals, INTEGER is
+ 1452       unbounded). Literals are SET OF [0..255]; assignment and
+ 1453       comparison across suitable bases are lenient (masks over min
+ 1454       words + zero-check extras), out-of-span literals are 222. *)
+ 1455    SetType<VAR t: SymTab.TypeIndex>      (. VAR base: SymTab.TypeIndex;
+ 1456                                               blo, bhi, bspan: INTEGER;
+ 1457                                               bcls: INTEGER; .)
+ 1458      = "SET"                             (. allowFwdType := FALSE; .)
+ 1459        "OF" Type<base, FALSE>
+ 1460                                          (. IF base = SymTab.InvalidType THEN
+ 1461                                               t := SymTab.InvalidType
+ 1462                                             ELSIF SymTab.Unresolved(base) THEN
+ 1463                                               (* an opaque/formal base: defer
+ 1464                                                  the span check until the
+ 1465                                                  base is completed *)
+ 1466                                               t := SymTab.NewSet(base)
+ 1467                                             ELSE bcls :=
+ 1468                                                    SymTab.ClassOf(base);
+ 1469                                               (* a subrange keeps its own
+ 1470                                                  span even when its base is
+ 1471                                                  CHAR/BOOLEAN/an enum *)
+ 1472                                               IF SymTab.SubBounds(base,
+ 1473                                                       blo, bhi) THEN
+ 1474                                                 bspan := bhi - blo + 1
+ 1475                                               ELSIF bcls = SymTab.ClBool THEN
+ 1476                                                 blo := 0; bspan := 2
+ 1477                                               ELSIF bcls = SymTab.ClChar THEN
+ 1478                                                 blo := 0; bspan := 256
+ 1479                                               ELSIF bcls = SymTab.ClByte THEN
+ 1480                                                 blo := 0; bspan := 256
+ 1481                                               ELSIF bcls = SymTab.ClSByte THEN
+ 1482                                                 blo := -128; bspan := 256
+ 1483                                               ELSIF bcls = SymTab.ClWord16 THEN
+ 1484                                                 blo := 0; bspan := 65536
+ 1485                                               ELSIF bcls = SymTab.ClSWord16 THEN
+ 1486                                                 blo := -32768; bspan := 65536
+ 1487                                               ELSIF bcls = SymTab.ClEnum THEN
+ 1488                                                 blo := 0;
+ 1489                                                 bspan := VAL(INTEGER,
+ 1490                                                   SymTab.EnumCount(base))
+ 1491                                               ELSE bspan := 0 END;
+ 1492                                               IF (bspan <= 0)
+ 1493                                                  OR (bspan > 65536) THEN
+ 1494                                                 SemError(230);
+ 1495                                                 t := SymTab.InvalidType
+ 1496                                               ELSE t := SymTab.NewSet(base)
+ 1497                                               END
+ 1498                                             END; .) .
+ 1499    (* PACKEDSET: same base rules as SET, but 1/2/4-byte storage.  V3
+ 1500       limits the span to 32 bits (SetBytes 1..4); wider packed sets are
+ 1501       an implementation limit (230). *)
+ 1502    PackSetType<VAR t: SymTab.TypeIndex>  (. VAR base: SymTab.TypeIndex;
+ 1503                                               blo, bhi, bspan: INTEGER;
+ 1504                                               bcls: INTEGER; .)
+ 1505      = "PACKEDSET"                       (. allowFwdType := FALSE; .)
+ 1506        "OF" Type<base, FALSE>
+ 1507                                          (. IF base = SymTab.InvalidType THEN
+ 1508                                               t := SymTab.InvalidType
+ 1509                                             ELSIF SymTab.Unresolved(base) THEN
+ 1510                                               t := SymTab.NewPackSet(base)
+ 1511                                             ELSE bcls :=
+ 1512                                                    SymTab.ClassOf(base);
+ 1513                                               IF SymTab.SubBounds(base,
+ 1514                                                       blo, bhi) THEN
+ 1515                                                 bspan := bhi - blo + 1
+ 1516                                               ELSIF bcls = SymTab.ClBool THEN
+ 1517                                                 blo := 0; bspan := 2
+ 1518                                               ELSIF bcls = SymTab.ClChar THEN
+ 1519                                                 blo := 0; bspan := 256
+ 1520                                               ELSIF bcls = SymTab.ClByte THEN
+ 1521                                                 blo := 0; bspan := 256
+ 1522                                               ELSIF bcls = SymTab.ClSByte THEN
+ 1523                                                 blo := -128; bspan := 256
+ 1524                                               ELSIF bcls = SymTab.ClWord16 THEN
+ 1525                                                 blo := 0; bspan := 65536
+ 1526                                               ELSIF bcls = SymTab.ClSWord16 THEN
+ 1527                                                 blo := -32768; bspan := 65536
+ 1528                                               ELSIF bcls = SymTab.ClEnum THEN
+ 1529                                                 blo := 0;
+ 1530                                                 bspan := VAL(INTEGER,
+ 1531                                                   SymTab.EnumCount(base))
+ 1532                                               ELSE bspan := 0 END;
+ 1533                                               IF (bspan <= 0)
+ 1534                                                  OR (bspan > 32) THEN
+ 1535                                                 SemError(230);
+ 1536                                                 t := SymTab.InvalidType
+ 1537                                               ELSE t := SymTab.NewPackSet(base)
+ 1538                                               END
+ 1539                                             END; .) .
+ 1540    (* Records: flat blobs; array fields are pointers to static
+ 1541       descriptors (locked amendment), nested records inline. Field
+ 1542       offsets static and declaration-ordered. *)
+ 1543    (* Field list: plain fields and (optionally) one variant part.  The
+ 1544       variant part is a `CASE ... END` item; because it starts with the
+ 1545       CASE keyword it is unambiguously distinguishable from a field
+ 1546       (which starts with an identifier). *)
+ 1547    RecordType<VAR t: SymTab.TypeIndex>   (. VAR t2: SymTab.TypeIndex;
+ 1548                                               tagOk: BOOLEAN; .)
+ 1549      = "RECORD"                          (. allowFwdType := FALSE;
+ 1550                                             t := SymTab.NewRecord(); .)
+ 1551        [ RecItem<t> { ";" [ RecItem<t> ] } ]
+ 1552        "END"                             (. SymTab.LayoutRecord(t); .) .
+ 1553    RecItem<rec: SymTab.TypeIndex>        (. VAR tt: SymTab.TypeIndex; .)
+ 1554      = RecField<rec>
+ 1555      | CaseField<rec>                    (. SymTab.MarkVariant(rec); .) .
+ 1556    (* A variant part: CASE [tag] : Type OF variants.  gm2 extensions:
+ 1557       an untagged inner CASE (no tag field), empty arms and ELSE arms. *)
+ 1558    CaseField<rec: SymTab.TypeIndex>      (. VAR tagT: SymTab.TypeIndex;
+ 1559                                               tagN: SymTab.Name;
+ 1560                                               tagged: BOOLEAN; .)
+ 1561      = "CASE"                            (. SymTab.ResetFields(rec);
+ 1562                                             tagged := FALSE; .)
+ 1563        [ GetIdent<tagN>                  (. IF NOT SymTab.FieldPending(rec,
+ 1564                                               tagN) THEN
+ 1565                                               SemError(200) END;
+ 1566                                             tagged := TRUE; .) ]
+ 1567        ":" Type<tagT, FALSE>             (. IF (tagT # SymTab.InvalidType)
+ 1568    AND NOT SymTab.IsOrdinal(tagT) THEN
+ 1569                                               SemError(224)
+ 1570                                             END;
+ 1571                                             IF tagged THEN
+ 1572                                               SymTab.FixPendingF(rec, tagT);
+ 1573                                               SymTab.SetVariantTag(rec, tagN)
+ 1574                                             END; .)
+ 1575        "OF"
+ 1576        RecFieldList<rec>
+ 1577        { "|"                             (. SymTab.ResetFields(rec); .)
+ 1578          RecFieldList<rec> }
+ 1579        [ "ELSE" ]
+ 1580        "END" .
+ 1581    (* A variant branch: `labels : fields` (fields and their trailing ";"
+ 1582       optional, gm2), `ELSE`, or empty (the extra "|" separators gm2
+ 1583       tolerates).  A branch may itself contain a nested variant CASE. *)
+ 1584    RecFieldList<rec: SymTab.TypeIndex>   (. VAR lt, lq: SymTab.TypeIndex;
+ 1585                                               lv1, lv2: QbeGen.QVal; .)
+ 1586      = [ ( VarLabel<lt, lv1> [ ".." VarLabel<lq, lv2> ]
+ 1587            { "," VarLabel<lt, lv1> [ ".." VarLabel<lq, lv2> ] }
+ 1588            ":"
+ 1589            [ ArmField<rec> { ";" [ ArmField<rec> ] } ]
+ 1590          | "ELSE" ) ] .
+ 1591    ArmField<rec: SymTab.TypeIndex>
+ 1592      = RecField<rec>
+ 1593      | CaseField<rec>                    (. SymTab.MarkVariant(rec); .) .
+ 1594    (* Variant case label: a constant (or a constant range).  Values are
+ 1595       not interpreted (the layout overlays regardless). *)
+ 1596    VarLabel<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1597                                          (. VAR lname: SymTab.Name; .)
+ 1598      = ( ident                         (. LexName(lname);
+ 1599                                             QbeGen.CopyOp("0", q);
+ 1600                                             t := SymTab.IntType(); .)
+ 1601        | integer                       (. LexString(lname);
+ 1602                                             QbeGen.CopyOp("0", q);
+ 1603                                             t := SymTab.IntType(); .)
+ 1604        | charConst                     (. LexString(lname);
+ 1605                                             QbeGen.CopyOp("0", q);
+ 1606                                             t := SymTab.CharType(); .) ) .
+ 1607    RecField<rec: SymTab.TypeIndex>       (. VAR n: SymTab.Name;
+ 1608                                               t2: SymTab.TypeIndex; .)
+ 1609      = RecIdents<rec> ":" Type<t2, FALSE>(. SymTab.FixPendingF(rec, t2); .) .
+ 1610    RecIdents<rec: SymTab.TypeIndex>      (. VAR n: SymTab.Name; .)
+ 1611      = GetIdent<n>                       (. IF NOT SymTab.FieldPending(rec,
+ 1612                                               n) THEN
+ 1613                                               SemError(200) END; .)
+ 1614        { "," GetIdent<n>                 (. IF NOT SymTab.FieldPending(rec,
+ 1615                                               n) THEN
+ 1616                                               SemError(200) END; .) } .
+ 1617    TypeIdent<VAR t: SymTab.TypeIndex>    (. VAR n, qid: SymTab.Name;
+ 1618                                               k: INTEGER;
+ 1619                                               dotted: BOOLEAN; .)
+ 1620      = GetIdent<n>                       (. dotted := FALSE;
+ 1621                                             IF NOT SymTab.Lookup(n) THEN
+ 1622                                               (* declaration before use: an
+ 1623                                                  undeclared type is 201,
+ 1624                                                  except as a POINTER's base
+ 1625                                                  (allowFwdType) *)
+ 1626                                               k := -1;
+ 1627                                               IF allowFwdType THEN
+ 1628                                                 t := SymTab.ForwardType(n)
+ 1629                                               ELSE t := SymTab.InvalidType
+ 1630                                               END;
+ 1631                                               IF t = SymTab.InvalidType THEN
+ 1632                                                 SemError(201)
+ 1633                                               END
+ 1634                                             ELSE k := SymTab.SymKind(n);
+ 1635                                               IF (k = SymTab.KindType)
+ 1636                                                  OR (k = SymTab.KindPredef) THEN
+ 1637                                                 t := SymTab.SymType(n)
+ 1638                                               ELSE t := SymTab.InvalidType
+ 1639                                               END
+ 1640                                             END; .)
+ 1641        [ "." GetIdent<qid>               (. dotted := TRUE;
+ 1642                                             IF k = SymTab.KindModule THEN
+ 1643                                               t := SymTab.QualType(n, qid);
+ 1644                                               IF t = SymTab.InvalidType THEN
+ 1645                                                 SemError(201)
+ 1646                                               END
+ 1647                                             ELSE SemError(221);
+ 1648                                               t := SymTab.InvalidType
+ 1649                                             END; .) ]
+ 1650                                          (. IF NOT dotted THEN
+ 1651                                               IF (k = SymTab.KindModule)
+ 1652                                                  OR ((k # SymTab.KindType)
+ 1653    AND (k # SymTab.KindPredef)
+ 1654    AND (k # SymTab.KindImport)
+ 1655    AND (k # -1)) THEN
+ 1656                                                 SemError(221)
+ 1657                                               END
+ 1658                                             END; .) .
+ 1659    Subrange<VAR t: SymTab.TypeIndex>     (. VAR tlo, thi: SymTab.TypeIndex;
+ 1660                                               qlo, qhi: QbeGen.QVal;
+ 1661                                               lo, hi: INTEGER; .)
+ 1662      = "[" Expr<tlo, qlo> ".." Expr<thi, qhi>
+ 1663                                          (. IF (tlo = SymTab.InvalidType)
+ 1664                                              OR (thi = SymTab.InvalidType) THEN
+ 1665                                             t := SymTab.InvalidType
+ 1666                                           ELSIF NOT SymTab.IsOrdinal(tlo)
+ 1667                                              OR NOT SymTab.IsOrdinal(thi) THEN
+ 1668                                             SemError(230);
+ 1669                                             t := SymTab.InvalidType
+ 1670                                           ELSIF NOT SymTab.ConstInt(qlo, lo)
+ 1671                                              OR NOT SymTab.ConstInt(qhi, hi)
+ 1672                                              OR (lo > hi) THEN
+ 1673                                             SemError(230);
+ 1674                                             t := SymTab.InvalidType
+ 1675                                           ELSE IF SymTab.SameType(tlo, thi) THEN
+ 1676                                             (* keep the base type: ['A'..'Z']
+ 1677                                                is character, [red..blue]
+ 1678                                                that enumeration *)
+ 1679                                             t := SymTab.NewSubB(lo, hi, tlo)
+ 1680                                           ELSE t := SymTab.NewSubR(lo, hi)
+ 1681                                           END
+ 1682                                           END; .)
+ 1683        "]" .
+ 1684    Enum<VAR t: SymTab.TypeIndex>         (. VAR n: SymTab.Name;
+ 1685                                               ord: INTEGER;
+ 1686                                               qv: QbeGen.QVal; .)
+ 1687      = "("                               (. t := SymTab.NewEnum();
+ 1688                                             ord := 0; .)
+ 1689        GetIdent<n>                       (. IF NOT SymTab.Enter(n,
+ 1690                                               SymTab.KindConst) THEN
+ 1691                                               SemError(200) END;
+ 1692                                             SymTab.SetSymType(n, t);
+ 1693                                             QbeGen.IntStr(ord, qv);
+ 1694                                             SymTab.SetSymVal(n, qv);
+ 1695                                             SymTab.NoteEnumLit(t, n);
+ 1696                                             Lower.NoteVar(n,
+ 1697                                               SymTab.KindConst, t);
+ 1698                                             Lower.NoteConstVal(qv);
+ 1699                                             INC(ord); .)
+ 1700        { "," GetIdent<n>                 (. IF NOT SymTab.Enter(n,
+ 1701                                               SymTab.KindConst) THEN
+ 1702                                               SemError(200) END;
+ 1703                                             SymTab.SetSymType(n, t);
+ 1704                                             QbeGen.IntStr(ord, qv);
+ 1705                                             SymTab.SetSymVal(n, qv);
+ 1706                                             SymTab.NoteEnumLit(t, n);
+ 1707                                             Lower.NoteVar(n,
+ 1708                                               SymTab.KindConst, t);
+ 1709                                             Lower.NoteConstVal(qv);
+ 1710                                             INC(ord); .) }
+ 1711        ")"                               (. SymTab.SetEnumCount(t,
+ 1712                                               VAL(CARDINAL, ord)); .) .
+ 1713    (* Clarion-form classes (docs/OOP.txt): declaration + single
+ 1714       inheritance + IMPLEMENTATION blocks. Scopes and member checks
+ 1715       now; lowering (vtable, dispatch, THIS) later — one 230 per
+ 1716       class/impl block. Methods end with ";" per the Table example
+ 1717       (not "," as in the sketch). No underscores in identifiers. *)
+ 1718    (* Single CLASS item in both loops: separating declaration from
+ 1719       IMPLEMENTATION at the loop level needs 2-token lookahead
+ 1720       (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
+ 1721       The second token decides after CLASS is consumed. A misplaced
+ 1722       CLASS IMPLEMENTATION inside TYPE still parses (harmless: the
+ 1723       whole unit ends 230 until lowering). *)
+ 1724    ClassItem
+ 1725      = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
+ 1726    ClassRest                             (. VAR cn, m2, pn: SymTab.Name;
+ 1727                                               ct: SymTab.TypeIndex; .)
+ 1728      = GetIdent<cn>                      (. IF NOT SymTab.Enter(cn,
+ 1729                                               SymTab.KindType) THEN
+ 1730                                               SemError(200) END;
+ 1731                                             ct := SymTab.NewClass();
+ 1732                                             SymTab.SetSymType(cn, ct);
+ 1733                                             SymTab.PushClassScope(ct);
+ 1734                                             astCls := AST.MakeNode(AST.NkClassDecl);
+ 1735                                             AST.SetChild(astCls, 0,
+ 1736                                               AST.MakeLeaf(AST.NkIdent, cn));
+ 1737                                             astClsP := AST.NoNode;
+ 1738                                             astClsPTail := AST.NoNode;
+ 1739                                             astClsF := AST.NoNode;
+ 1740                                             astClsFTail := AST.NoNode;
+ 1741                                             astClsM := AST.NoNode;
+ 1742                                             astClsMTail := AST.NoNode; .)
+ 1743        [ Parents<ct> ]
+ 1744        ";"
+ 1745        { ClassField<ct> ";" }
+ 1746        { MethodHeading<pn, SymTab.InvalidType> ";"
+ 1747                                          (. Lower.ScopeLeave;
+ 1748                                             SymTab.CloseProc;
+ 1749                                             QbeGen.AbortFunc; .) }
+ 1750        "END"
+ 1751        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
+ 1752                                               SemError(202) END;
+ 1753                                             SymTab.LayoutClass(ct);
+ 1754                                             SymTab.PopScope;
+ 1755                                             AST.SetChild(astCls, 1, astClsP);
+ 1756                                             AST.SetChild(astCls, 2, astClsF);
+ 1757                                             AST.SetChild(astCls, 3, astClsM);
+ 1758                                             astDecl := astCls; .) .
+ 1759    Parents<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name; .)
+ 1760      = "(" Parent1<ct>
+ 1761        { "," GetIdent<p>                 (. SemError(230); .) }
+ 1762        ")" .
+ 1763    Parent1<ct: SymTab.TypeIndex>         (. VAR p: SymTab.Name;
+ 1764                                               pt: SymTab.TypeIndex; .)
+ 1765      = GetIdent<p>                       (. IF NOT SymTab.Lookup(p) THEN
+ 1766                                               SemError(201)
+ 1767                                             ELSE pt := SymTab.SymType(p);
+ 1768                                               IF SymTab.ClassOf(pt) #
+ 1769                                                  SymTab.ClClass THEN
+ 1770                                                 SemError(230)
+ 1771                                               ELSE SymTab.SetParent(ct, pt)
+ 1772                                               END
+ 1773                                             END;
+ 1774                                             AstAppend(AST.NkFieldDecl,
+ 1775                                               astClsP, astClsPTail,
+ 1776                                               AST.MakeLeaf(AST.NkIdent, p)); .) .
+ 1777    ClassField<ct: SymTab.TypeIndex>      (. VAR n, rhs: SymTab.Name;
+ 1778                                               t: SymTab.TypeIndex;
+ 1779                                               astNode: AST.Node; .)
+ 1780      = GetIdent<n>
+ 1781        ( "=" GetIdent<rhs>               (. IF NOT SymTab.Enter(n,
+ 1782                                               SymTab.KindConst) THEN
+ 1783                                               SemError(200) END;
+ 1784                                             astNode := AST.MakeNode(AST.NkConstDecl);
+ 1785                                             AST.SetChild(astNode, 0,
+ 1786                                               AST.MakeLeaf(AST.NkIdent, n));
+ 1787                                             AST.SetChild(astNode, 1,
+ 1788                                               AST.MakeLeaf(AST.NkIdent, rhs));
+ 1789                                             AstAppend(AST.NkFieldDecl,
+ 1790                                               astClsF, astClsFTail, astNode);
+ 1791                                             IF SymTab.Lookup(rhs) THEN
+ 1792                                               SymTab.SetSymType(n,
+ 1793                                                 SymTab.SymType(rhs))
+ 1794                                             END; .)
+ 1795        |                                 (. IF NOT SymTab.FieldPending(ct,
+ 1796                                               n) THEN
+ 1797                                               SemError(200) END;
+ 1798                                             astNode := AST.MakeNode(AST.NkVarDecl);
+ 1799                                             AST.SetChild(astNode, 0,
+ 1800                                               AST.MakeLeaf(AST.NkIdent, n)); .)
+ 1801          { "," GetIdent<n>               (. IF NOT SymTab.FieldPending(ct,
+ 1802                                               n) THEN
+ 1803                                               SemError(200) END;
+ 1804                                             AST.SetChild(astNode,
+ 1805                                               AST.NChild(astNode),
+ 1806                                               AST.MakeLeaf(AST.NkIdent, n)); .) }
+ 1807          ":" Type<t, FALSE>              (. SymTab.FixPendingF(ct, t);
+ 1808                                             AST.SetTy(astNode, t);
+ 1809                                             AstAppend(AST.NkFieldDecl,
+ 1810                                               astClsF, astClsFTail, astNode); .) ) .
+ 1811    MethodHeading<VAR pn: SymTab.Name; ct: SymTab.TypeIndex>
+ 1812                                          (. VAR wantVirt: BOOLEAN; .)
+ 1813      =                                   (. wantVirt := FALSE; .)
+ 1814        [ "VIRTUAL"                       (. wantVirt := TRUE; .) ]
+ 1815        ProcHeading<pn, ct>               (. IF wantVirt THEN
+ 1816                                               SymTab.MarkVirtual END;
+ 1817                                             astMethod := AST.MakeNode(AST.NkProcDecl);
+ 1818                                             AST.SetChild(astMethod, 0,
+ 1819                                               AST.MakeLeaf(AST.NkIdent, pn));
+ 1820                                             IF wantVirt THEN
+ 1821                                               AST.SetOp(astMethod, 3)
+ 1822                                             ELSE AST.SetOp(astMethod, 0)
+ 1823                                             END;
+ 1824                                             AstAppend(AST.NkFieldDecl,
+ 1825                                               astClsM, astClsMTail, astMethod); .) .
+ 1826    ClassImplRest                         (. VAR cn, m2: SymTab.Name;
+ 1827                                               ct: SymTab.TypeIndex; .)
+ 1828      = GetIdent<cn>                      (. IF NOT SymTab.Lookup(cn) THEN
+ 1829                                               SemError(201);
+ 1830                                               ct := SymTab.InvalidType
+ 1831                                             ELSE ct := SymTab.SymType(cn);
+ 1832                                               IF SymTab.ClassOf(ct) #
+ 1833                                                  SymTab.ClClass THEN
+ 1834                                                 SemError(230);
+ 1835                                                 ct := SymTab.InvalidType
+ 1836                                               END
+ 1837                                             END;
+ 1838                                             astCls := AST.MakeNode(AST.NkClassDecl);
+ 1839                                             AST.SetOp(astCls, 1);
+ 1840                                             AST.SetChild(astCls, 0,
+ 1841                                               AST.MakeLeaf(AST.NkIdent, cn));
+ 1842                                             astClsM := AST.NoNode;
+ 1843                                             astClsMTail := AST.NoNode;
+ 1844                                             astStmt := AST.NoNode;
+ 1845                                             IF ct #
+ 1846                                                SymTab.InvalidType THEN
+ 1847                                               IF NOT SymTab.PushClassMembers(
+ 1848                                                      ct) THEN
+ 1849                                                 SemError(230) END;
+ 1850                                               SymTab.PushImplClass(ct)
+ 1851                                             END; .)
+ 1852        ";" { MethodImpl<ct> ";" }
+ 1853                                          (. astStmt := AST.NoNode; .)
+ 1854        [ "BEGIN"                         (. astStmt := AST.MakeNode(AST.NkBlock);
+ 1855                                             .)
+ 1856          [ StatSeq ] ]
+ 1857        "END"
+ 1858        GetIdent<m2>                      (. IF NOT SymTab.Equal(cn, m2) THEN
+ 1859                                               SemError(202) END;
+ 1860                                             SymTab.PopImplClass;
+ 1861                                             SymTab.PopScope;
+ 1862                                             AST.SetChild(astCls, 1, AST.NoNode);
+ 1863                                             AST.SetChild(astCls, 2, astStmt);
+ 1864                                             AST.SetChild(astCls, 3, astClsM);
+ 1865                                             astDecl := astCls; .) .
+ 1866    MethodImpl<ct: SymTab.TypeIndex>      (. VAR pn: SymTab.Name;
+ 1867                                               thisQ: QbeGen.QVal;
+ 1868                                               methRes: SymTab.TypeIndex; .)
+ 1869      = MethodHeading<pn, ct> ";"
+ 1870                                          (. IF (ct #
+ 1871                                                SymTab.InvalidType)
+ 1872   AND NOT SymTab.MethodExists(ct,
+ 1873                                                    pn) THEN
+ 1874                                               SemError(201) END; .)
+ 1875        ( "FORWARD"                       (. AST.SetOp(astMethod, 1);
+ 1876                                             SymTab.MarkFwd;
+ 1877                                             QbeGen.AbortFunc;
+ 1878                                             Lower.ScopeLeave;
+ 1879                                             SymTab.CloseProc; .)
+ 1880        |                                 (.
+ 1881                                             (* bind the receiver: bare
+ 1882                                                field names resolve
+ 1883                                                against THIS *)
+ 1884                                              QbeGen.CopyOp("@", thisQ);
+ 1885                                             QbeGen.PushWith(thisQ); .)
+ 1886          Block<pn>                       (. AST.SetChild(astMethod, 1, astStmt);
+ 1887                                             AST.SetChild(astMethod, 2, astBlkDecls);
+ 1888                                             QbeGen.PopWith;
+ 1889                                             methRes := SymTab.CurRes();
+ 1890                                             Lower.ScopeLeave;
+ 1891                                             SymTab.CloseProc;
+ 1892                                             QbeGen.EndFunc(methRes); .) ) .
+ 1893    ConstBlock                            (. VAR astSeq, astTail: AST.Node; .)
+ 1894      = "CONST"                           (. astSeq := AST.NoNode;
+ 1895                                             astTail := AST.NoNode; .)
+ 1896        { ConstDecl ";"                   (. AstAppend(AST.NkDeclSeq,
+ 1897                                               astSeq, astTail, astDecl); .) }
+ 1898                                          (. astDecl := astSeq; .) .
+ 1899    ConstDecl                             (. VAR n: SymTab.Name;
+ 1900                                               t: SymTab.TypeIndex;
+ 1901                                               qv: QbeGen.QVal;
+ 1902                                               cls: INTEGER;
+ 1903                                               mk: ARRAY [0 .. 15] OF CARDINAL;
+ 1904                                               mw: CARDINAL;
+ 1905                                               mlo: INTEGER;
+ 1906                                               astNode: AST.Node; .)
+ 1907      = GetIdent<n>                       (. IF NOT SymTab.Enter(n,
+ 1908                                               SymTab.KindConst) THEN
+ 1909                                               SemError(200) END; .)
+ 1910        "="
+ 1911        Expr<t, qv> (. astNode := AST.MakeNode(AST.NkConstDecl);
+ 1912                                             AST.SetChild(astNode, 0,
+ 1913                                               AST.MakeLeaf(AST.NkIdent, n));
+ 1914                                             AST.SetChild(astNode, 1, astCur);
+ 1915                                             AST.SetTy(astNode, t);
+ 1916                                             astDecl := astNode;
+ 1917                                             Lower.NoteVar(n, SymTab.KindConst, t);
+ 1918                                             Lower.NoteConstVal(qv);
+ 1919                                             SymTab.SetSymType(n, t);
+ 1920                                             cls := SymTab.ClassOf(t);
+ 1921                                             IF cls = SymTab.ClSet THEN
+ 1922                                               (* a SET CONST needs static
+ 1923                                                  data: fold its mask now
+ 1924                                                  (the grammar sees the
+ 1925                                                  element values) and let
+ 1926                                                  Lower re-emit it *)
+ 1927                                               IF Lower.SetConstMaskOf(
+ 1928                                                    AST.Child(astNode, 1),
+ 1929                                                    mk, mw, mlo) THEN
+ 1930                                                 Lower.NoteSetMask(n, mk, mw,
+ 1931                                                   mlo);
+ 1932                                                 SymTab.SetSymVal(n, qv)
+ 1933                                               ELSE
+ 1934                                                 SemError(230)
+ 1935                                               END
+ 1936                                             ELSIF (cls = SymTab.ClArray)
+ 1937                                                OR (cls = SymTab.ClRecord)
+ 1938                                                OR (cls = SymTab.ClClass)
+ 1939                                                OR (cls = SymTab.ClStr)
+ 1940                                                OR (cls = SymTab.ClUStr) THEN
+ 1941                                               (* an aggregate/string
+ 1942                                                  constant: qv is its
+ 1943                                                  descriptor address; no
+ 1944                                                  scalar data *)
+ 1945                                               SymTab.SetSymVal(n, qv)
+ 1946                                             ELSIF NOT QbeGen.IsImm(qv) THEN
+ 1947                                               SemError(230)
+ 1948                                             ELSE
+ 1949                                               SymTab.SetSymVal(n, qv);
+ 1950                                             END; .) .
+ 1951    VarBlock                              (. VAR astSeq, astTail: AST.Node; .)
+ 1952      = "VAR"                             (. astSeq := AST.NoNode;
+ 1953                                             astTail := AST.NoNode; .)
+ 1954        { VarDecl ";"                     (. AstAppend(AST.NkDeclSeq,
+ 1955                                               astSeq, astTail, astDecl); .) }
+ 1956                                          (. astDecl := astSeq; .) .
+ 1957    VarDecl                               (. VAR nm: SymTab.Name;
+ 1958                                               t: SymTab.TypeIndex;
+ 1959                                               i: CARDINAL;
+ 1960                                               cls: INTEGER;
+ 1961                                               astNode, astTail: AST.Node; .)
+ 1962      = VarIdents ":"
+ 1963        Type<t, FALSE> (. astNode := AST.MakeNode(AST.NkVarDecl);
+ 1964                                             astTail := astNode;
+ 1965                                             i := 0;
+ 1966                                             WHILE i < SymTab.PendCount() DO
+ 1967                                               SymTab.PendName(i, nm);
+ 1968                                               Lower.NoteVar(nm, SymTab.KindVar, t);
+ 1969                                               (* chunked: a VAR list can
+ 1970                                                  exceed AST.MaxChild *)
+ 1971                                               AstAppend(AST.NkBlock,
+ 1972                                                 astNode, astTail,
+ 1973                                                 AST.MakeLeaf(AST.NkIdent, nm));
+ 1974                                               INC(i)
+ 1975                                             END;
+ 1976                                             AST.SetTy(astNode, t);
+ 1977                                             astDecl := astNode;
+ 1978                                             cls := SymTab.ClassOf(t);
+ 1979                                             IF (t # SymTab.InvalidType)
+ 1980   AND NOT SymTab.IsUnresolved(t)
+ 1981   AND (cls # SymTab.ClInt)
+ 1982   AND (cls # SymTab.ClBool)
+ 1983   AND (cls # SymTab.ClChar)
+ 1984   AND (cls # SymTab.ClReal)
+ 1985   AND (cls # SymTab.ClArray)
+ 1986   AND (cls # SymTab.ClSet)
+ 1987   AND (cls # SymTab.ClRecord)
+ 1988   AND (cls # SymTab.ClPtr)
+ 1989   AND (cls # SymTab.ClLong)
+ 1990   AND (cls # SymTab.ClProc)
+ 1991   AND (cls # SymTab.ClUChar)
+ 1992   AND (cls # SymTab.ClUStr)
+ 1993   AND (cls # SymTab.ClEnum)
+ 1994   AND (cls # SymTab.ClByte)
+ 1995   AND (cls # SymTab.ClSByte)
+ 1996   AND (cls # SymTab.ClWord16)
+ 1997   AND (cls # SymTab.ClSWord16)
+ 1998   AND (cls # SymTab.ClClass) THEN
+ 1999                                               SemError(230) END;
+ 2000                                             IF QbeGen.LocFull() THEN
+ 2001                                               SemError(233) END;
+ 2002                                             i := 0;
+ 2003                                             IF SymTab.IsUnresolved(t)
+ 2004                                                AND NOT SymTab.InProc() THEN
+ 2005                                               (* a forward-typed global:
+ 2006                                                  defer emission until the
+ 2007                                                  TYPE block completes *)
+ 2008                                               AST.SetOp(astNode, 1);
+ 2009                                               WHILE i < SymTab.PendCount() DO
+ 2010                                                 SymTab.PendName(i, nm);
+ 2011                                                 IF nPendVar <=
+ 2012                                                    HIGH(pendVarName) THEN
+ 2013                                                   pendVarName[nPendVar] := nm;
+ 2014                                                   pendVarT[nPendVar] := t;
+ 2015                                                   INC(nPendVar)
+ 2016                                                 END;
+ 2017                                                 INC(i)
+ 2018                                               END
+ 2019                                             ELSE
+ 2020                                               WHILE i < SymTab.PendCount() DO
+ 2021                                                 SymTab.PendName(i, nm);
+ 2022                                                 INC(i)
+ 2023                                               END
+ 2024                                             END;
+ 2025                                             (* a plain VAR list, not a
+ 2026                                                heading: the signature
+ 2027                                                result is discarded *)
+ 2028                                             IF NOT SymTab.FixPending(t) THEN
+ 2029                                             END; .) .
+ 2030    VarIdents                             (. VAR n: SymTab.Name; .)
+ 2031      = GetIdent<n>                       (. IF NOT SymTab.EnterPending(n,
+ 2032                                               SymTab.KindVar) THEN
+ 2033                                               SemError(200) END; .)
+ 2034        { ","
+ 2035          GetIdent<n>                     (. IF NOT SymTab.EnterPending(n,
+ 2036                                               SymTab.KindVar) THEN
+ 2037                                               SemError(200) END; .) } .
+ 2038    ParIdents<isV: BOOLEAN>               (. VAR n: SymTab.Name; .)
+ 2039      = GetIdent<n>                       (. IF NOT SymTab.EnterParam(n, isV) THEN
+ 2040                                               SemError(200) END; .)
+ 2041        { "," GetIdent<n>                 (. IF NOT SymTab.EnterParam(n, isV) THEN
+ 2042                                               SemError(200) END; .) } .
+ 2043    (* Procedure headings enter scopes/params/result and buffer the
+ 2044       QBE header; bodies lower to functions (4.1, module level only).
+ 2045       FORWARD marks; the body heading re-enters (signature compare
+ 2046       deferred). Nested procedures parse + check, lowering = 4.2. *)
+ 2047    (* gm2 declaration pragmas: __BUILTIN__ (definition module) and
+ 2048       __ATTRIBUTE__ __BUILTIN__ (( name )) (implementation).  They
+ 2049       annotate C built-ins; V3 parses and ignores them. *)
+ 2050    ProcPragma
+ 2051      = "__BUILTIN__"
+ 2052      | "__ATTRIBUTE__" [ "__BUILTIN__" ] [ "(" "(" ident ")" ")" ] .
+ 2053  
+ 2054    ProcHeading<VAR pn: SymTab.Name; methCls: SymTab.TypeIndex>
+ 2055                                          (. VAR t: SymTab.TypeIndex;
+ 2056                                               mg: QbeGen.QVal; .)
+ 2057      = "PROCEDURE"
+ 2058        [ ProcPragma ]
+ 2059        GetIdent<pn>                      (. IF methCls #
+ 2060                                                SymTab.InvalidType THEN
+ 2061                                             (* a method: resume the
+ 2062                                                declared symbol (reuse
+ 2063                                                its uid) *)
+ 2064                                             IF NOT SymTab.ResumeMethod(
+ 2065                                                  methCls, pn) THEN
+ 2066                                               SemError(200) END
+ 2067                                             ELSIF NOT SymTab.EnterProc(pn) THEN
+ 2068                                             IF NOT SymTab.ReenterProc(pn) THEN
+ 2069                                               IF NOT SymTab.ResumeProc(pn) THEN
+ 2070                                                 SemError(200) END
+ 2071                                               END
+ 2072                                             END;
+ 2073                                             Lower.ScopeEnter;
+ 2074                                             Lower.NoteProc(pn,
+ 2075                                               SymTab.ProcUid(pn),
+ 2076                                               SymTab.InvalidType,
+ 2077                                               SymTab.ProcDepthOf(pn),
+ 2078                                               FALSE);
+ 2079                                             QbeGen.BeginFunc("");
+ 2080                                             IF methCls #
+ 2081                                                SymTab.InvalidType THEN
+ 2082                                               (* hidden THIS receiver:
+ 2083                                                  a VAR param of the
+ 2084                                                  class type, pushed as
+ 2085                                                  the WITH base *)
+ 2086                                               IF NOT SymTab.EnterThisParam(
+ 2087                                                    methCls) THEN
+ 2088                                                 SemError(200) END;
+ 2089                                               IF NOT QbeGen.FuncParam(
+ 2090                                                    "THIS", TRUE,
+ 2091                                                    methCls) THEN
+ 2092                                                 SemError(233) END
+ 2093                                             END; .)
+ 2094        [ FormalParams ]
+ 2095        [ ":" ( TypeIdent<t>              (. IF NOT SymTab.SetProcRes(t) THEN
+ 2096                                               SemError(235) END;
+ 2097                                             Lower.SetProcRes(t); .)
+ 2098              | "PROC"                    (. (* PROC result: the procedure
+ 2099                                                value type *)
+ 2100                                             IF NOT SymTab.SetProcRes(
+ 2101                                                SymTab.AddrType()) THEN
+ 2102                                               SemError(235) END;
+ 2103                                             Lower.SetProcRes(
+ 2104                                               SymTab.AddrType()); .) ) ] .
+ 2105    FormalParams
+ 2106      = "(" [ ParamSection { ";" ParamSection } ] ")" .
+ 2107    ParamSection                          (. VAR t: SymTab.TypeIndex;
+ 2108                                               nm: SymTab.Name;
+ 2109                                               i: CARDINAL;
+ 2110                                               isV: BOOLEAN; .)
+ 2111      =                                   (. isV := FALSE; .)
+ 2112        [ "VAR"                           (. isV := TRUE; .) ]
+ 2113        ParIdents<isV> ":" Type<t, TRUE>  (. i := 0;
+ 2114                                             WHILE i < SymTab.PendCount() DO
+ 2115                                               SymTab.PendName(i, nm);
+ 2116                                               Lower.NoteParam(nm, t, isV);
+ 2117                                               Lower.NoteVar(nm, SymTab.KindParam, t);
+ 2118                                               (* value open arrays are
+ 2119                                                  passed as descriptor
+ 2120                                                  addresses (no copy):
+ 2121                                                  same representation as
+ 2122                                                  VAR formals *)
+ 2123                                               IF NOT QbeGen.FuncParam(nm,
+ 2124                                                    isV
+ 2125                                                    OR SymTab.IsOpenArray(t),
+ 2126                                                    t) THEN
+ 2127                                                 SemError(233) END;
+ 2128                                               INC(i)
+ 2129                                             END;
+ 2130                                             IF NOT SymTab.FixPending(t) THEN
+ 2131                                               SemError(235) END; .) .
+ 2132    (* Nested procedures lower like top-level ones (4.2): the
+ 2133       static link gives them their parent's frame. Methods keep
+ 2134       parse-now/230-later. *)
+ 2135    ProcDecl                              (. VAR pn: SymTab.Name;
+ 2136                                               saveFun: SymTab.Name;
+ 2137                                               astNode: AST.Node; .)
+ 2138      = ProcHeading<pn, SymTab.InvalidType> ";"
+ 2139                                          (. astNode := AST.MakeNode(AST.NkProcDecl);
+ 2140                                             AST.SetOp(astNode, 0);
+ 2141                                             AST.SetChild(astNode, 0,
+ 2142                                               AST.MakeLeaf(AST.NkIdent, pn));
+ 2143                                             Lower.NoteProcNode(astNode); .)
+ 2144        ( "FORWARD"                       (. AST.SetOp(astNode, 1);
+ 2145                                             astDecl := astNode;
+ 2146                                             Lower.ScopeLeave;
+ 2147                                             SymTab.MarkFwd;
+ 2148                                             SymTab.CloseProc;
+ 2149                                             QbeGen.AbortFunc; .)
+ 2150        | "EXTERNAL"                      (. AST.SetOp(astNode, 2);
+ 2151                                             astDecl := astNode;
+ 2152                                             Lower.MarkProcExternal;
+ 2153                                             Lower.ScopeLeave;
+ 2154                                             SymTab.MarkExternal("");
+ 2155                                             SymTab.CloseProc;
+ 2156                                             QbeGen.AbortFunc; .)
+ 2157        |                                 
+ 2158          (. allowDefer := TRUE; deferredBody := FALSE;
+ 2159                                             curProcNode := astNode;
+ 2160                                             saveFun := curFun;
+ 2161                                             curFun := pn; .)
+ 2162          Block<pn>                       (. curFun := saveFun;
+ 2163                                             IF deferredBody THEN
+ 2164                                               (* body skipped: close like
+ 2165                                                  FORWARD (no body node) *)
+ 2166                                               astDecl := astNode;
+ 2167                                               Lower.ScopeLeave;
+ 2168                                               SymTab.CloseProc;
+ 2169                                               QbeGen.AbortFunc
+ 2170                                             ELSE
+ 2171                                               AST.SetChild(astNode, 1, astStmt);
+ 2172                                               AST.SetChild(astNode, 2, astBlkDecls);
+ 2173                                               astDecl := astNode;
+ 2174                                               Lower.ScopeLeave;
+ 2175                                               SymTab.CloseProc;
+ 2176                                               QbeGen.EndFunc(
+ 2177                                                 SymTab.ProcRes(pn))
+ 2178                                             END; .) ) .
+ 2179    Block<pn: SymTab.Name>                (. VAR m2: SymTab.Name; dfr: BOOLEAN; .)
+ 2180      =                                   (. dfr := FALSE;
+ 2181                                             IF allowDefer AND twoPhaseParse
+ 2182                                                AND NOT repassing THEN
+ 2183                                               dfr := DeferSkip(pn)
+ 2184                                             END;
+ 2185                                             allowDefer := FALSE;
+ 2186                                             .)
+ 2187        DeclSeq                           (. astBlkDecls := astDecl;
+ 2188                                             astStmt := AST.NoNode;
+ 2189                                             nLab := 0; nGot := 0; .)
+ 2190        [ "BEGIN"                         (. (* an empty body is still a
+ 2191                                               body: mark it so Lower
+ 2192                                               does not read it as a
+ 2193                                               definition heading *)
+ 2194                                             IF NOT dfr THEN
+ 2195                                               IF astStmt = AST.NoNode THEN
+ 2196                                                 astStmt :=
+ 2197                                                   AST.MakeNode(AST.NkBlock)
+ 2198                                               END
+ 2199                                             END; .)
+ 2200          [ StatSeq ] ]
+ 2201        "END"
+ 2202        GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
+ 2203                                               SemError(202) END;
+ 2204                                             CheckGotos; .) .
+ 2205    (* Two-phase, phase 2 (milestone 2c): re-parse every deferred module-
+ 2206       level body once the unit's declarations are complete.  Inlined at
+ 2207       both call sites because a stand-alone epsilon production is
+ 2208       "unreachable" to Coco/R (referenced only from actions). *)
+ 2209    StatSeq                               (. VAR astSeq, astTail: AST.Node; .)
+ 2210      =                                   (. astSeq := AST.NoNode;
+ 2211                                             astTail := AST.NoNode; .)
+ 2212        Statement                         (. AstAppend(AST.NkBlock,
+ 2213                                               astSeq, astTail, astStmt); .)
+ 2214        { ";" [ Statement                 (. AstAppend(AST.NkBlock,
+ 2215                                               astSeq, astTail, astStmt); .) ] }
+ 2216                                          (. astStmt := astSeq; .) .
+ 2217    (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
+ 2218       are accepted: the statement after ';' is optional. *)
+ 2219    Statement                             (. VAR lx: QbeGen.QVal; lxnm: SymTab.Name; .)
+ 2220      = (. astStmt := AST.NoNode; .)
+ 2221        ( AssOrCall
+ 2222      | IfStat
+ 2223      | WhileStat
+ 2224      | RepeatStat
+ 2225      | LoopStat
+ 2226      | ForStat
+ 2227      | CaseStat
+ 2228      | WithStat
+ 2229      | ReturnStat
+ 2230      | HaltStat
+ 2231      | NewStat
+ 2232      | DisposeStat
+ 2233      | IncDecStat
+ 2234      | InclExclStat
+ 2235      | "EXIT"                            (. IF NOT QbeGen.TopLoop(lx) THEN
+ 2236                                               SemError(230) END;
+ 2237                                             astStmt := AST.MakeNode(AST.NkExit); .)
+ 2238      | "GOTO" GetIdent<lxnm>             (. NoteGoto(lxnm);
+ 2239                                             astStmt := AST.MakeNode(AST.NkGoto);
+ 2240                                             AST.SetChild(astStmt, 0,
+ 2241                                               AST.MakeLeaf(AST.NkIdent, lxnm)); .) ) .
+ 2242    (* INCL(set, elem) / EXCL(set, elem): PIM set-element builtins. *)
+ 2243    InclExclStat                          (. VAR at, et2: SymTab.TypeIndex;
+ 2244                                               dk: INTEGER;
+ 2245                                               qd, qe: QbeGen.QVal;
+ 2246                                               qn: SymTab.Name;
+ 2247                                               sfx, isInc: BOOLEAN;
+ 2248                                               astNode, astD: AST.Node; .)
+ 2249      = ( "INCL"                          (. isInc := TRUE; .)
+ 2250        | "EXCL"                          (. isInc := FALSE; .) )
+ 2251        "(" Design<at, dk, qd, qn, sfx> (. astD := astCur; .) ","
+ 2252        Expr<et2, qe> ")"
+ 2253                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 2254                                             IF isInc THEN
+ 2255                                               AST.SetChild(astNode, 0,
+ 2256                                                 AST.MakeLeaf(AST.NkIdent, "INCL"))
+ 2257                                             ELSE AST.SetChild(astNode, 0,
+ 2258                                                 AST.MakeLeaf(AST.NkIdent, "EXCL"))
+ 2259                                             END;
+ 2260                                             IF astD # AST.NoNode THEN
+ 2261                                               AST.SetChild(astNode, 1, astD) END;
+ 2262                                             IF astCur # AST.NoNode THEN
+ 2263                                               AST.SetChild(astNode, 2, astCur) END;
+ 2264                                             astStmt := astNode; .)
+ 2265                                          (. IF (at # SymTab.InvalidType)
+ 2266    AND (SymTab.ClassOf(at) # SymTab.ClSet) THEN
+ 2267                                               SemError(222)
+ 2268                                             END; .) .
+ 2269    (* INC(v [,step]) / DEC(v [,step]) as builtin statements over an
+ 2270       integer designator. *)
+ 2271    IncDecStat                            (. VAR dt, et2: SymTab.TypeIndex;
+ 2272                                               dk: INTEGER;
+ 2273                                               qd, qv, qn2, qstep:
+ 2274                                                 QbeGen.QVal;
+ 2275                                               qn: SymTab.Name;
+ 2276                                               sfx, isInc: BOOLEAN;
+ 2277                                               astNode, astD, astStep:
+ 2278                                                 AST.Node; .)
+ 2279      =                                   (. isInc := TRUE; .)
+ 2280        ( "INC"                           (. isInc := TRUE; .)
+ 2281        | "DEC"                           (. isInc := FALSE; .) )
+ 2282        "("                               (. astStep := AST.NoNode; .)
+ 2283        Design<dt, dk, qd, qn, sfx> (. astD := astCur; .)
+ 2284        [ "," Expr<et2, qstep> (. astStep := astCur; .) ]
+ 2285        ")"                               (. astNode := AST.MakeNode(AST.NkCall);
+ 2286                                             IF isInc THEN
+ 2287                                               AST.SetChild(astNode, 0,
+ 2288                                                 AST.MakeLeaf(AST.NkIdent, "INC"))
+ 2289                                             ELSE AST.SetChild(astNode, 0,
+ 2290                                                 AST.MakeLeaf(AST.NkIdent, "DEC"))
+ 2291                                             END;
+ 2292                                             IF astD # AST.NoNode THEN
+ 2293                                               AST.SetChild(astNode, 1, astD) END;
+ 2294                                             IF astStep # AST.NoNode THEN
+ 2295                                               AST.SetChild(astNode, 2, astStep) END;
+ 2296                                             astStmt := astNode; .)                               (. IF dt = SymTab.InvalidType THEN
+ 2297                                             ELSIF (dk # SymTab.KindVar)
+ 2298   AND (dk # SymTab.KindParam)
+ 2299   AND (dk # SymTab.KindField) THEN
+ 2300                                               SemError(210)
+ 2301                                             ELSIF NOT SymTab.IsOrdinal(dt) THEN
+ 2302                                               SemError(211)
+ 2303                                             END; .) .
+ 2304    (* NEW/DISPOSE as builtin statements (no call syntax until step 4).
+ 2305       Targets are pointer designators; DISPOSE nils afterwards (safer
+ 2306       than Wirth-undefined; documented). DISPOSE is shallow. *)
+ 2307    NewStat                               (. VAR dt: SymTab.TypeIndex;
+ 2308                                               dk: INTEGER;
+ 2309                                               qd, qm: QbeGen.QVal;
+ 2310                                               qn: SymTab.Name;
+ 2311                                               sfx: BOOLEAN;
+ 2312                                               bt: SymTab.TypeIndex;
+ 2313                                               astNode, astD: AST.Node; .)
+ 2314      = "NEW" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
+ 2315                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 2316                                             AST.SetChild(astNode, 0,
+ 2317                                               AST.MakeLeaf(AST.NkIdent, "NEW"));
+ 2318                                             IF astD # AST.NoNode THEN
+ 2319                                               AST.SetChild(astNode, 1, astD) END;
+ 2320                                             astStmt := astNode; .)
+ 2321                                           (. IF dt = SymTab.InvalidType THEN
+ 2322                                              ELSIF (dk # SymTab.KindVar)
+ 2323    AND (dk # SymTab.KindParam)
+ 2324    AND (dk # SymTab.KindField) THEN
+ 2325                                                SemError(210)
+ 2326                                              ELSIF SymTab.ClassOf(dt) #
+ 2327                                                    SymTab.ClPtr THEN
+ 2328                                                SemError(219)
+ 2329                                              END; .) .
+ 2330    DisposeStat                           (. VAR dt: SymTab.TypeIndex;
+ 2331                                               dk: INTEGER;
+ 2332                                               qd, qv: QbeGen.QVal;
+ 2333                                               qn: SymTab.Name;
+ 2334                                               sfx: BOOLEAN;
+ 2335                                               astNode, astD: AST.Node; .)
+ 2336      = "DISPOSE" "(" Design<dt, dk, qd, qn, sfx> (. astD := astCur; .) ")"
+ 2337                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 2338                                             AST.SetChild(astNode, 0,
+ 2339                                               AST.MakeLeaf(AST.NkIdent, "DISPOSE"));
+ 2340                                             IF astD # AST.NoNode THEN
+ 2341                                               AST.SetChild(astNode, 1, astD) END;
+ 2342                                             astStmt := astNode; .)
+ 2343                                           (. IF dt = SymTab.InvalidType THEN
+ 2344                                              ELSIF (dk # SymTab.KindVar)
+ 2345    AND (dk # SymTab.KindParam)
+ 2346    AND (dk # SymTab.KindField) THEN
+ 2347                                                SemError(210)
+ 2348                                              ELSIF SymTab.ClassOf(dt) #
+ 2349                                                    SymTab.ClPtr THEN
+ 2350                                                SemError(219)
+ 2351                                              END; .) .
+ 2352    (* WITH pushes each record's fields (inner wins) plus its base
+ 2353       address; field designators resolve through both stacks. *)
+ 2354    WithStat                              (. VAR nW: CARDINAL;
+ 2355                                               astNode: AST.Node; .)
+ 2356      = "WITH"                            (. nW := 0;
+ 2357                                             astNode := AST.MakeNode(AST.NkWith); .)
+ 2358        WithItem<nW, astNode> { "," WithItem<nW, astNode> }
+ 2359        "DO"                              (. astStmt := AST.NoNode; .)
+ 2360        [ StatSeq ] "END"                 (. AST.SetChild(astNode,
+ 2361                                             AST.NChild(astNode), astStmt);
+ 2362                                             astStmt := astNode;
+ 2363                                             WHILE nW > 0 DO
+ 2364                                               SymTab.PopScope;
+ 2365                                               QbeGen.PopWith;
+ 2366                                               DEC(nW)
+ 2367                                             END; .) .
+ 2368    WithItem<VAR nW: CARDINAL; wnode: AST.Node>
+ 2369                                          (. VAR dt: SymTab.TypeIndex;
+ 2370                                               dk: INTEGER;
+ 2371                                               qd, qe: QbeGen.QVal;
+ 2372                                               qn: SymTab.Name;
+ 2373                                               sfx: BOOLEAN; .)
+ 2374      = Design<dt, dk, qd, qn, sfx>
+ 2375                                          (. IF astCur # AST.NoNode THEN
+ 2376                                               AST.SetChild(wnode,
+ 2377                                                 AST.NChild(wnode), astCur) END;
+ 2378                                             IF dt = SymTab.InvalidType THEN
+ 2379                                             ELSIF (SymTab.ClassOf(dt) #
+ 2380                                                    SymTab.ClRecord)
+ 2381   AND (SymTab.ClassOf(dt) #
+ 2382                                                   SymTab.ClClass) THEN
+ 2383                                               SemError(215)
+ 2384                                             ELSIF SymTab.PushRecord(dt) THEN
+ 2385                                               QbeGen.PushWith(qd);
+ 2386                                               INC(nW)
+ 2387                                             END; .) .
+ 2388    (* Assignment or procedure-statement call (4.1, module level).
+ 2389       Bare `P;` is a syntax error; function-as-statement is 233. *)
+ 2390    AssOrCall                             (. VAR dt, et: SymTab.TypeIndex;
+ 2391                                               dk: INTEGER;
+ 2392                                               qd, qe, qt, ql: QbeGen.QVal;
+ 2393                                               qn: SymTab.Name;
+ 2394                                               ct2, res0: SymTab.TypeIndex;
+ 2395                                               q2, mg0: QbeGen.QVal;
+ 2396                                               isR, conv, wconv: BOOLEAN;
+ 2397                                               called, sfx: BOOLEAN;
+ 2398                                               astLhs, astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN;
+ 2399                                               n: SymTab.Name; astLab, astNode: AST.Node; .)
+ 2400      = GetIdent<n>
+ 2401        ( ":"                             (. NoteLabel(n);
+ 2402                                             astNode := AST.MakeNode(AST.NkLabel);
+ 2403                                             AST.SetChild(astNode, 0,
+ 2404                                               AST.MakeLeaf(AST.NkIdent, n));
+ 2405                                             astLab := AST.MakeNode(AST.NkBlock);
+ 2406                                             AST.SetChild(astLab, 0, astNode); .)
+ 2407          Statement                       (. IF astStmt # AST.NoNode THEN
+ 2408                                               AST.SetChild(astLab, 1, astStmt) END;
+ 2409                                             astStmt := astLab; .)
+ 2410        | DesignTail<n, dt, dk, qd, qn, sfx>
+ 2411        (. astLhs := astCur; astNArgs := 0; .)
+ 2412        ( ":="
+ 2413          Expr<et, qe>                    (. astStmt := AST.MakeBin(
+ 2414                                               AST.NkAssign, 0, astLhs, astCur);
+ 2415                                             IF (dt # SymTab.InvalidType)
+ 2416   AND (dk # SymTab.KindVar)
+ 2417   AND (dk # SymTab.KindParam)
+ 2418   AND (dk # SymTab.KindField) THEN
+ 2419                                             SemError(210)
+ 2420                                           ELSIF NOT SymTab.Assignable(et,
+ 2421                                                    dt) THEN
+ 2422                                             SemError(210)
+ 2423                                           ELSIF (dt # SymTab.InvalidType)
+ 2424   AND (SymTab.ClassOf(dt) =
+ 2425                                                 SymTab.ClClass) THEN
+ 2426                                             SemError(230) END;
+ 2427                                           isR := (dt #
+ 2428                                                   SymTab.InvalidType)
+ 2429   AND (SymTab.ClassOf(dt)
+ 2430                                                     = SymTab.ClReal);
+ 2431                                           conv := isR
+ 2432   AND SymTab.IsIntFamily(et);
+ 2433                                           wconv := (dt #
+ 2434                                                     SymTab.InvalidType)
+ 2435   AND SymTab.IsLongFamily(dt)
+ 2436   AND SymTab.IsIntFamily(et);
+ 2437                                           IF ((dk = SymTab.KindVar)
+ 2438                                               OR (dk = SymTab.KindParam)
+ 2439                                               OR (dk = SymTab.KindField))
+ 2440   AND (dt # SymTab.InvalidType)
+ 2441   AND (et # SymTab.InvalidType)
+ 2442   AND (SymTab.ClassOf(dt) #
+ 2443                                                 SymTab.ClClass) THEN
+ 2444                                           END; .)
+ 2445        | ArgList<qn, dt, qd, TRUE, TRUE, methCls, ct2, q2, called>
+ 2446                                          (. astRes := AstCallNode(astLhs);
+ 2447                                             sfx := FALSE; .)
+ 2448          ( { ResultComp<ct2, q2, sfx, astRes, mname, methCls, isM> }
+ 2449            ":=" Expr<et, qe>             (. astStmt := AST.MakeBin(
+ 2450                                               AST.NkAssign, 0, astRes, astCur);
+ 2451                                             IF NOT sfx THEN
+ 2452                                               SemError(233)
+ 2453                                             ELSIF (ct2 # SymTab.InvalidType)
+ 2454    AND NOT SymTab.Assignable(et, ct2) THEN
+ 2455                                               SemError(210)
+ 2456                                             END; .)
+ 2457          |                               (. (* discarding the result of a
+ 2458                                               foreign C varargs call
+ 2459                                               (printf/snprintf) is accepted;
+ 2460                                               an ordinary Modula-2 function
+ 2461                                               used as a statement stays 233 *)
+ 2462                                             IF (ct2 # SymTab.InvalidType)
+ 2463                                                AND NOT SymTab.Varargs(qn) THEN
+ 2464                                               SemError(233) END;
+ 2465                                             astStmt := astRes; .) )
+ 2466        |                                 (* bare `P;`: proper parameterless
+ 2467                                              procedure call; anything else
+ 2468                                              here is 233 (was a bare syntax
+ 2469                                              error before 4.2) *)
+ 2470                                          (. astStmt := AstCallNode(astLhs);
+ 2471                                              IF (dk = SymTab.KindProc)
+ 2472   AND NOT sfx THEN
+ 2473                                               res0 := SymTab.ProcRes(qn);
+ 2474                                               IF res0 #
+ 2475                                                  SymTab.InvalidType THEN
+ 2476                                                 SemError(233)
+ 2477                                               ELSIF SymTab.ProcNPar(qn) #
+ 2478                                                       0 THEN
+ 2479                                                 SemError(233)
+ 2480                                               END
+ 2481                                             ELSIF (dt # SymTab.InvalidType)
+ 2482    AND (SymTab.ClassOf(dt) = SymTab.ClProc) THEN
+ 2483                                               IF SymTab.ProcTypeRes(dt) #
+ 2484                                                  SymTab.InvalidType THEN
+ 2485                                                 SemError(233)
+ 2486                                               ELSIF SymTab.ProcTypeNPar(dt) #
+ 2487                                                       0 THEN
+ 2488                                                 SemError(233)
+ 2489                                               END
+ 2490                                             ELSE SemError(233)
+ 2491                                              END; .) ) ) .
+ 2492    (* Actual-parameter list shared by statement and expression calls.
+ 2493       want selects CallEnd's result handling; t/q carry the call
+ 2494       value (statement calls discard). Arity/type failures are 233;
+ 2495       evaluation code still emits so the .ssa stays assembleable. *)
+ 2496    ArgList<pn: SymTab.Name; pt: SymTab.TypeIndex; callee: QbeGen.QVal;
+ 2497            want: BOOLEAN; soft: BOOLEAN; methCls: SymTab.TypeIndex;
+ 2498            VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
+ 2499            VAR called: BOOLEAN>          (. VAR i, np: CARDINAL;
+ 2500                                               vs: INTEGER;
+ 2501                                               res: SymTab.TypeIndex;
+ 2502                                               mg: QbeGen.QVal;
+ 2503                                               ok, ind, isMeth, va, isConv: BOOLEAN; .)
+ 2504      = "("                               (. called := TRUE;
+ 2505                                             ok := TRUE;
+ 2506                                             ind := FALSE;
+ 2507                                             isConv := FALSE;
+ 2508                                             isMeth := methCls #
+ 2509                                               SymTab.InvalidType;
+ 2510                                             IF isMeth THEN
+ 2511                                               res := SymTab.ClassMethodRes(methCls, pn)
+ 2512                                             ELSIF SymTab.SymKind(pn) = SymTab.KindProc THEN
+ 2513                                               res := SymTab.ProcRes(pn)
+ 2514                                             ELSIF (SymTab.SymKind(pn) = SymTab.KindType)
+ 2515    OR (SymTab.SymKind(pn) = SymTab.KindPredef) THEN
+ 2516                                               (* ISO type conversion T(x):
+ 2517                                                  one value, result is T *)
+ 2518                                               isConv := TRUE;
+ 2519                                               res := SymTab.SymType(pn)
+ 2520                                             ELSIF (pt # SymTab.InvalidType)
+ 2521    AND (SymTab.ClassOf(pt) = SymTab.ClProc) THEN
+ 2522                                               ind := TRUE;
+ 2523                                               res := SymTab.ProcTypeRes(pt)
+ 2524                                             ELSE SemError(233);
+ 2525                                               ok := FALSE;
+ 2526                                               res := SymTab.InvalidType
+ 2527                                             END;
+ 2528                                             i := 0; .)
+ 2529        [ ActParam<pn, pt, ind, methCls, i>        (. INC(i); .)
+ 2530          { "," ActParam<pn, pt, ind, methCls, i>  (. INC(i); .) } ]
+ 2531        ")"                               (. IF ok THEN
+ 2532                                               IF isConv THEN
+ 2533                                                 (* a conversion takes
+ 2534                                                    exactly one value *)
+ 2535                                                 IF i # 1 THEN
+ 2536                                                   SemError(233); ok := FALSE
+ 2537                                                 END
+ 2538                                               ELSE
+ 2539                                                 IF isMeth THEN
+ 2540                                                   np := SymTab.ClassMethodNPar(
+ 2541                                                     methCls, pn)
+ 2542                                                 ELSIF ind THEN
+ 2543                                                   np := SymTab.ProcTypeNPar(pt)
+ 2544                                                 ELSE np := SymTab.ProcNPar(pn)
+ 2545                                                 END;
+ 2546                                                 va := (NOT isMeth) AND (NOT ind)
+ 2547                                                   AND (SymTab.SymKind(pn) =
+ 2548                                                        SymTab.KindProc)
+ 2549                                                   AND SymTab.Varargs(pn);
+ 2550                                                 IF (i # np) AND NOT va THEN
+ 2551                                                   SemError(233); ok := FALSE
+ 2552                                                 END
+ 2553                                               END
+ 2554                                             END;
+ 2555                                             IF NOT ok THEN
+ 2556                                               t := SymTab.InvalidType;
+ 2557                                               QbeGen.CopyOp("0", q)
+ 2558                                             ELSIF want THEN
+ 2559                                               IF res =
+ 2560                                                  SymTab.InvalidType THEN
+ 2561                                                 IF NOT soft THEN SemError(233) END;
+ 2562                                                 t := SymTab.InvalidType;
+ 2563                                                 QbeGen.CopyOp("0", q)
+ 2564                                               ELSE t := res;
+ 2565                                                  QbeGen.CopyOp("@", q)
+ 2566                                               END
+ 2567                                             ELSE
+ 2568                                               (* a function call used as
+ 2569                                                  a statement: allowed for
+ 2570                                                  a foreign C varargs proc
+ 2571                                                  (printf/snprintf), whose
+ 2572                                                  result is conventionally
+ 2573                                                  discarded; ordinary
+ 2574                                                  Modula-2 functions keep
+ 2575                                                  the 233 diagnostic *)
+ 2576                                               IF (res # SymTab.InvalidType)
+ 2577                                                  AND NOT va THEN
+ 2578                                                 SemError(233)
+ 2579                                               END;
+ 2580                                               t := SymTab.InvalidType;
+ 2581                                               QbeGen.CopyOp("0", q);
+ 2582                                             END; .) .
+ 2583    (* One actual: VAR formals take recorded designator addresses
+ 2584       (233 otherwise); value formals take converted expressions. *)
+ 2585    ActParam<pn: SymTab.Name; pt: SymTab.TypeIndex; ind: BOOLEAN;
+ 2586             methCls: SymTab.TypeIndex; i: CARDINAL>
+ 2587                                          (. VAR at, ft: SymTab.TypeIndex;
+ 2588                                               qe, qa, qt: QbeGen.QVal;
+ 2589                                               isV, conv, va: BOOLEAN;
+ 2590                                               cl: CHAR;
+ 2591                                               savedN, aj: CARDINAL;
+ 2592                                               savedArgs: ARRAY [0 .. 31]
+ 2593                                                 OF AST.Node;
+ 2594                                               astActual: AST.Node; .)
+ 2595      =                                   (. (* Parsing the actual can clobber
+ 2596                                               the enclosing call's argument
+ 2597                                               list (Factor resets astNArgs),
+ 2598                                               so save/restore it. *)
+ 2599                                             savedN := astNArgs; aj := 0;
+ 2600                                             WHILE aj <= HIGH(astArgs) DO
+ 2601                                               savedArgs[aj] := astArgs[aj];
+ 2602                                               INC(aj)
+ 2603                                             END; .)
+ 2604        Expr<at, qe>                      (. QbeGen.CopyOp(qe, convQ); convT := at;
+ 2605                                             astActual := astCur;
+ 2606                                             astNArgs := savedN; aj := 0;
+ 2607                                             WHILE aj <= HIGH(astArgs) DO
+ 2608                                               astArgs[aj] := savedArgs[aj];
+ 2609                                               INC(aj)
+ 2610                                             END;
+ 2611                                             IF astNArgs <= HIGH(astArgs) THEN
+ 2612                                               astArgs[astNArgs] := astCur;
+ 2613                                               INC(astNArgs)
+ 2614                                             ELSE SemError(230)
+ 2615                                               (* > 32 actuals: impl limit *)
+ 2616                                             END;
+ 2617                                             va := (NOT ind)
+ 2618                                               AND (methCls =
+ 2619                                                  SymTab.InvalidType)
+ 2620                                               AND (SymTab.SymKind(pn) =
+ 2621                                                  SymTab.KindProc)
+ 2622                                               AND SymTab.Varargs(pn);
+ 2623                                             IF ind THEN
+ 2624                                               ft :=
+ 2625                                                 SymTab.ProcTypeParamType(pt,
+ 2626                                                   i);
+ 2627                                               isV :=
+ 2628                                                 SymTab.ProcTypeParamIsVar(pt,
+ 2629                                                   i)
+ 2630                                             ELSIF methCls #
+ 2631                                                SymTab.InvalidType THEN
+ 2632                                               ft :=
+ 2633                                                 SymTab.ClassMethodParamType(
+ 2634                                                 methCls, pn, i);
+ 2635                                               isV :=
+ 2636                                                 SymTab.ClassMethodParamIsVar(
+ 2637                                                 methCls, pn, i)
+ 2638                                             ELSE
+ 2639                                               ft := SymTab.ParamType(pn, i);
+ 2640                                               isV := SymTab.ParamIsVar(pn, i)
+ 2641                                             END;
+ 2642                                             IF (at = SymTab.InvalidType) THEN
+ 2643                                             ELSIF ft = SymTab.InvalidType THEN
+ 2644                                             ELSIF isV THEN
+ 2645                                               IF (SymTab.ClassOf(at) = SymTab.ClChar)
+ 2646    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
+ 2647    AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar)
+ 2648    AND QbeGen.IsImm(qe) THEN
+ 2649                                               ELSIF (AST.Kind(astActual) #
+ 2650                                                      AST.NkDesignator)
+ 2651    AND (AST.Kind(astActual) # AST.NkStrLit) THEN
+ 2652                                                 SemError(233)
+ 2653                                               ELSIF NOT SymTab.VarParamOk(at, ft)
+ 2654     AND NOT SymTab.ByteBufOk(at, ft) THEN
+ 2655                                                 SemError(233)
+ 2656                                               END
+ 2657                                             ELSE
+ 2658                                               IF (SymTab.ClassOf(at) = SymTab.ClChar)
+ 2659    AND (SymTab.ClassOf(ft) = SymTab.ClArray)
+ 2660    AND (SymTab.ClassOf(SymTab.ArrayElem(ft)) = SymTab.ClChar)
+ 2661    AND QbeGen.IsImm(qe) THEN
+ 2662                                               ELSIF NOT SymTab.Assignable(at, ft)
+ 2663     AND NOT SymTab.ByteBufOk(at, ft) THEN
+ 2664                                                 SemError(233)
+ 2665                                               END
+ 2666                                             END; .) .
+ 2667    IfStat                                (. VAR t: SymTab.TypeIndex;
+ 2668                                               q: QbeGen.QVal;
+ 2669                                               hasElse: BOOLEAN;
+ 2670                                               astCond, astIf, astLast,
+ 2671                                               astNode: AST.Node; .)
+ 2672      = "IF" (. hasElse := FALSE; .)
+ 2673        Expr<t, q> (. astCond := astCur; astStmt := AST.NoNode;
+ 2674                                             IF NOT SymTab.BoolCheck(t) THEN
+ 2675                                               SemError(214) END; .)
+ 2676        "THEN" [ StatSeq ]                (. astNode := AST.MakeNode(AST.NkIf);
+ 2677                                             AST.SetChild(astNode, 0, astCond);
+ 2678                                             AST.SetChild(astNode, 1, astStmt);
+ 2679                                             astIf := astNode;
+ 2680                                             astLast := astNode; .)
+ 2681        { "ELSIF"
+ 2682          Expr<t, q> (. astCond := astCur; astStmt := AST.NoNode;
+ 2683                                             IF NOT SymTab.BoolCheck(t) THEN
+ 2684                                               SemError(214) END; .)
+ 2685          "THEN" [ StatSeq ]              (. astNode := AST.MakeNode(AST.NkIf);
+ 2686                                             AST.SetChild(astNode, 0, astCond);
+ 2687                                             AST.SetChild(astNode, 1, astStmt);
+ 2688                                             AST.SetChild(astLast, 2, astNode);
+ 2689                                             astLast := astNode; .) }
+ 2690        [ "ELSE"                          (. hasElse := TRUE;
+ 2691                                             astStmt := AST.NoNode; .)
+ 2692          [ StatSeq ] (. AST.SetChild(astLast, 2, astStmt); .) ]
+ 2693        "END" (. astStmt := astIf; .) .
+ 2694    WhileStat                             (. VAR t: SymTab.TypeIndex;
+ 2695                                               q: QbeGen.QVal;
+ 2696                                               astCond, astNode: AST.Node; .)
+ 2697      = "WHILE" (. astStmt := AST.NoNode; .)
+ 2698        Expr<t, q> (. astCond := astCur;
+ 2699                                             IF NOT SymTab.BoolCheck(t) THEN
+ 2700                                               SemError(214) END; .)
+ 2701        "DO" [ StatSeq ]                  (. astNode := AST.MakeNode(AST.NkWhile);
+ 2702                                             AST.SetChild(astNode, 0, astCond);
+ 2703                                             AST.SetChild(astNode, 1, astStmt);
+ 2704                                             astStmt := astNode; .)
+ 2705        "END" .
+ 2706    RepeatStat                            (. VAR t: SymTab.TypeIndex;
+ 2707                                               q: QbeGen.QVal;
+ 2708                                               astCond, astBody, astNode:
+ 2709                                                 AST.Node; .)
+ 2710      = "REPEAT" (. astStmt := AST.NoNode; .)
+ 2711        [ StatSeq ] (. astBody := astStmt; .)
+ 2712        "UNTIL" Expr<t, q> (. astCond := astCur;
+ 2713                                             astNode := AST.MakeNode(AST.NkRepeat);
+ 2714                                             AST.SetChild(astNode, 0, astBody);
+ 2715                                             AST.SetChild(astNode, 1, astCond);
+ 2716                                             astStmt := astNode;
+ 2717                                             IF NOT SymTab.BoolCheck(t) THEN
+ 2718                                               SemError(214) END; .) .
+ 2719    LoopStat                              (. VAR lEnd: QbeGen.QVal; astNode: AST.Node; .)
+ 2720      = "LOOP"                            (. astStmt := AST.NoNode;
+ 2721                                             QbeGen.NewLabel(lEnd);
+ 2722                                             QbeGen.PushLoop(lEnd); .)
+ 2723        [ StatSeq ]
+ 2724        "END"                             (. astNode := AST.MakeNode(AST.NkLoop);
+ 2725                                             AST.SetChild(astNode, 0, astStmt);
+ 2726                                             astStmt := astNode;
+ 2727                                             QbeGen.PopLoop; .) .
+ 2728    (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
+ 2729       Runtime direction would need a compare-select; the literal
+ 2730       sign picks cslew/csegew at "DO" time. *)
+ 2731    ForStat                               (. VAR lv: SymTab.Name;
+ 2732                                               tlo, thi, tby:
+ 2733                                                 SymTab.TypeIndex;
+ 2734                                               qlo, qhi, qby, qt, qk, qb:
+ 2735                                                 QbeGen.QVal;
+ 2736                                               lTop, lBody, lEnd:
+ 2737                                                 QbeGen.QVal;
+ 2738                                               by: INTEGER;
+ 2739                                               ok: BOOLEAN;
+ 2740                                               astVar, astLo, astHi, astBy,
+ 2741                                               astNode: AST.Node; .)
+ 2742      = "FOR"                             (. by := 1; .)
+ 2743        GetIdent<lv> (. astVar := AST.MakeLeaf(AST.NkIdent, lv);
+ 2744                                             astStmt := AST.NoNode;
+ 2745                                             astBy := AST.NoNode;
+ 2746                                             ok := SymTab.Lookup(lv);
+ 2747                                             IF NOT ok THEN
+ 2748                                               SemError(201)
+ 2749                                             ELSIF (SymTab.SymKind(lv) #
+ 2750                                                    SymTab.KindVar)
+ 2751   AND (SymTab.SymKind(lv) #
+ 2752                                                   SymTab.KindParam) THEN
+ 2753                                               SemError(220); ok := FALSE
+ 2754                                             ELSIF NOT SymTab.IsOrdinal(
+ 2755                                                     SymTab.SymType(lv)) THEN
+ 2756                                               SemError(220); ok := FALSE
+ 2757                                             END; .)
+ 2758        ":=" Expr<tlo, qlo> (. astLo := astCur;
+ 2759                                             IF NOT SymTab.Assignable(tlo,
+ 2760                                                  SymTab.SymType(lv)) THEN
+ 2761                                               SemError(220); ok := FALSE
+ 2762                                             END; .)
+ 2763        "TO" Expr<thi, qhi> (. astHi := astCur;
+ 2764                                             IF NOT SymTab.Assignable(thi,
+ 2765                                                  SymTab.SymType(lv)) THEN
+ 2766                                               SemError(220); ok := FALSE
+ 2767                                             END; .)
+ 2768        [ "BY" Expr<tby, qby> (. astBy := astCur;
+ 2769                                             IF (tby #
+ 2770                                               SymTab.InvalidType)
+ 2771   AND NOT SymTab.IsIntFamily(tby) THEN
+ 2772                                               SemError(220); ok := FALSE
+ 2773                                             END;
+ 2774                                             IF NOT SymTab.ConstInt(qby, by) THEN
+ 2775                                               SemError(230); by := 1
+ 2776                                             ELSIF by = 0 THEN
+ 2777                                               SemError(220); by := 1
+ 2778                                             END; .) ]
+ 2779        "DO"
+ 2780        [ StatSeq ]
+ 2781        "END" (. astNode := AST.MakeNode(AST.NkFor);
+ 2782                                             AST.SetChild(astNode, 0, astVar);
+ 2783                                             AST.SetChild(astNode, 1, astLo);
+ 2784                                             AST.SetChild(astNode, 2, astHi);
+ 2785                                             AST.SetChild(astNode, 3, astBy);
+ 2786                                             AST.SetChild(astNode, 4, astStmt);
+ 2787                                             astStmt := astNode;
+ 2788                                             .) .
+ 2789    CaseStat                              (. VAR tsel: SymTab.TypeIndex;
+ 2790                                               qsel, lEnd: QbeGen.QVal;
+ 2791                                               arm, astNode, astArms,
+ 2792                                               astArmsTail: AST.Node; .)
+ 2793      = "CASE" Expr<tsel, qsel>           (. astNode := AST.MakeNode(AST.NkCase);
+ 2794                                             AST.SetChild(astNode, 0, astCur);
+ 2795                                             astArms := AST.NoNode;
+ 2796                                             astArmsTail := AST.NoNode;
+ 2797                                             .)
+ 2798        "OF" [ "|" ] CaseAlt<tsel, qsel, lEnd, astArms, astArmsTail>
+ 2799        { "|" CaseAlt<tsel, qsel, lEnd, astArms, astArmsTail> }
+ 2800        [ "ELSE"                          (. astStmt := AST.NoNode; .)
+ 2801          [ StatSeq ]                     (. arm := AST.MakeNode(AST.NkCaseArm);
+ 2802                                             AST.SetOp(arm, 1);
+ 2803                                             AST.SetChild(arm, 0, astStmt);
+ 2804                                             AstAppend(AST.NkBlock,
+ 2805                                               astArms, astArmsTail, arm); .) ]
+ 2806        "END"                             (. AST.SetChild(astNode, 1, astArms);
+ 2807                                             astStmt := astNode;
+ 2808                                             .) .
+ 2809    (* Compare-chain lowering: each alternative ends its match-tests
+ 2810       with "jmp lAfter", so the no-match fallthrough skips the body:
+ 2811       "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
+ 2812       lAfter:". Falls into the next alternative, ELSE, or END. *)
+ 2813    CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
+ 2814            lEnd: QbeGen.QVal; VAR arms, armsTail: AST.Node>
+ 2815                                          (. VAR arm: AST.Node; .)
+ 2816      =                                   (. arm := AST.MakeNode(AST.NkCaseArm); .)
+ 2817        CaseLabel<tsel, qsel, arm>
+ 2818        { "," CaseLabel<tsel, qsel, arm> }
+ 2819        ":"                               (. astStmt := AST.NoNode; .)
+ 2820        [ StatSeq ]                       (. AST.SetChild(arm, AST.NChild(arm),
+ 2821                                             astStmt);
+ 2822                                             AstAppend(AST.NkBlock,
+ 2823                                               arms, armsTail, arm);
+ 2824                                             .) .
+ 2825    CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
+ 2826              arm: AST.Node>
+ 2827                                          (. VAR t2, t3: SymTab.TypeIndex;
+ 2828                                               q2, q3, qc, qd, qe:
+ 2829                                                 QbeGen.QVal;
+ 2830                                               astLab: AST.Node;
+ 2831                                               lNext: QbeGen.QVal; .)
+ 2832      = Expr<t2, q2> (. astLab := astCur;
+ 2833                                             IF SymTab.IsEmptyStr(t2)
+ 2834                                                AND (SymTab.ClassOf(tsel) =
+ 2835                                                     SymTab.ClChar) THEN
+ 2836                                               (* ISO: '' as a CASE label
+ 2837                                                  is the terminator *)
+ 2838                                               QbeGen.CopyOp("0", q2);
+ 2839                                               t2 := SymTab.CharType()
+ 2840                                             END;
+ 2841                                             IF (t2 #
+ 2842                                               SymTab.InvalidType)
+ 2843   AND (tsel #
+ 2844                                                 SymTab.InvalidType)
+ 2845   AND NOT SymTab.EqCheck(t2,
+ 2846                                                   tsel) THEN
+ 2847                                               SemError(213) END;
+ 2848                                             (* set labels are not immediates:
+ 2849                                                the CASE chain uses CmpSet *)
+ 2850                                             IF (SymTab.ClassOf(t2) # SymTab.ClSet)
+ 2851   AND NOT QbeGen.IsImm(q2) THEN
+ 2852                                               SemError(230)
+ 2853                                             END; .)
+ 2854        [ ".." Expr<t3, q3>               (. astLab := AST.MakeBin(
+ 2855                                               AST.NkSubrange, 0, astLab, astCur);
+ 2856                                             IF SymTab.IsEmptyStr(t3)
+ 2857                                                AND (SymTab.ClassOf(tsel) =
+ 2858                                                     SymTab.ClChar) THEN
+ 2859                                               QbeGen.CopyOp("0", q3);
+ 2860                                               t3 := SymTab.CharType()
+ 2861                                             END;
+ 2862                                             IF (t3 #
+ 2863                                               SymTab.InvalidType)
+ 2864   AND (tsel #
+ 2865                                                 SymTab.InvalidType)
+ 2866   AND NOT SymTab.EqCheck(t3,
+ 2867                                                   tsel) THEN
+ 2868                                               SemError(213) END;
+ 2869                                                 IF (SymTab.ClassOf(t3) # SymTab.ClSet)
+ 2870   AND NOT QbeGen.IsImm(q3) THEN
+ 2871                                                   SemError(230)
+ 2872                                                 END; .) ]
+ 2873                                          (. AST.SetChild(arm,
+ 2874                                               AST.NChild(arm), astLab); .) .
+ 2875    ReturnStat                            (. VAR t: SymTab.TypeIndex;
+ 2876                                               q, qt: QbeGen.QVal;
+ 2877                                               res: SymTab.TypeIndex;
+ 2878                                               hadE, conv: BOOLEAN;
+ 2879                                               astVal, astNode: AST.Node; .)
+ 2880      = "RETURN"                          (. hadE := FALSE; astStmt := AST.NoNode; .)
+ 2881        [ Expr<t, q> (. hadE := TRUE; astVal := astCur; .) ]
+ 2882                                          (. astNode := AST.MakeNode(AST.NkReturn);
+ 2883                                             IF hadE THEN
+ 2884                                               AST.SetChild(astNode, 0, astVal)
+ 2885                                             END;
+ 2886                                             astStmt := astNode;
+ 2887                                             conv := FALSE;
+ 2888                                             IF NOT SymTab.InProc() THEN
+ 2889                                               SemError(232)
+ 2890                                             ELSE res := SymTab.CurRes();
+ 2891                                               IF NOT hadE THEN
+ 2892                                                 IF res #
+ 2893                                                    SymTab.InvalidType THEN
+ 2894                                                   SemError(232)
+ 2895                                                 END
+ 2896                                               ELSIF (res =
+ 2897                                                      SymTab.InvalidType)
+ 2898                                                  OR (t #
+ 2899                                                      SymTab.InvalidType)
+ 2900   AND NOT SymTab.Assignable(t,
+ 2901                                                       res) THEN
+ 2902                                                 SemError(232)
+ 2903                                             END
+ 2904                                             END; .) .
+ 2905    HaltStat                              (. VAR t: SymTab.TypeIndex;
+ 2906                                               q: QbeGen.QVal;
+ 2907                                               astVal, astNode: AST.Node; .)
+ 2908      = "HALT" (. astVal := AST.NoNode; .)
+ 2909        [ "(" Expr<t, q> (. astVal := astCur; .) ")" ]
+ 2910                                          (. astNode := AST.MakeNode(AST.NkHalt);
+ 2911                                             IF astVal # AST.NoNode THEN
+ 2912                                               AST.SetChild(astNode, 0, astVal)
+ 2913                                             END;
+ 2914                                             astStmt := astNode;
+ 2915                                             .) .
+ 2916    (* Designator: scalar loads, array addresses, and index suffixes.
+ 2917       Each index descends one level (bounds-checked, trap on breach);
+ 2918       nested levels reload the inner descriptor address. q ends as the
+ 2919       value (scalars), the descriptor address (plain arrays), or the
+ 2920       element address (indexed); sfx marks the indexed form. *)
+ 2921    Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
+ 2922           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
+ 2923                                          (. VAR n: SymTab.Name; .)
+ 2924      = GetIdent<n> DesignTail<n, t, k, q, qn, sfx> .
+ 2925    (* The part of Design after the identifier: resolve it and walk the
+ 2926       selectors.  Split out so a statement can decide between a label
+ 2927       (`ident :`) and a designator (`ident := ...`) with one token. *)
+ 2928    DesignTail<VAR n: SymTab.Name; VAR t: SymTab.TypeIndex; VAR k: INTEGER;
+ 2929           VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
+ 2930                                          (. VAR fn, mal: SymTab.Name;
+ 2931                                               cls: INTEGER;
+ 2932                                               ic: SymTab.TypeIndex;
+ 2933                                               curT, it, eT, bt:
+ 2934                                                 SymTab.TypeIndex;
+ 2935                                               iq, ql, qlo, qhi, qe:
+ 2936                                                 QbeGen.QVal;
+ 2937                                               lo, hi: INTEGER;
+ 2938                                               fo: INTEGER;
+ 2939                                               isOpen: BOOLEAN;
+ 2940                                               qb, cv: QbeGen.QVal;
+ 2941                                               r: BOOLEAN;
+ 2942                                                astDes, astSel: AST.Node; .)
+ 2943      =                                   (. methCls := SymTab.InvalidType;
+ 2944                                             QbeGen.CopyOp(n, qn);
+ 2945                                             sfx := FALSE;
+ 2946                                             IF NOT SymTab.Lookup(n) THEN
+ 2947                                               (* a bare method name inside
+ 2948                                                  a CLASS IMPLEMENTATION
+ 2949                                                  is a sibling call on
+ 2950                                                  THIS *)
+ 2951                                               ic := SymTab.CurImplClass();
+ 2952                                               IF (ic #
+ 2953                                                  SymTab.InvalidType)
+ 2954    AND SymTab.MethodExists(ic, n) THEN
+ 2955                                                 sfx := FALSE;
+ 2956                                                  QbeGen.CopyOp("@", q);
+ 2957                                                 methCls := ic;
+ 2958                                                 k := SymTab.KindProc;
+ 2959                                                 t := SymTab.InvalidType
+ 2960                                               ELSIF SymTab.InProc() THEN
+ 2961                                                 (* not declared anywhere
+ 2962                                                    in scope: with bodies
+ 2963                                                    parsed at unit end this
+ 2964                                                    is a genuine 201 (a
+ 2965                                                    nested-local forward is
+ 2966                                                    no longer tolerated). *)
+ 2967                                                 SemError(201);
+ 2968                                                 t := SymTab.InvalidType;
+ 2969                                                 k := -1;
+ 2970                                                 QbeGen.CopyOp("0", q)
+ 2971                                               ELSE
+ 2972                                                 SemError(201);
+ 2973                                                 t :=
+ 2974                                                   SymTab.InvalidType;
+ 2975                                                 k := -1;
+ 2976                                                 QbeGen.CopyOp("0", q)
+ 2977                                               END
+ 2978                                             ELSE
+ 2979                                               t := SymTab.SymType(n);
+ 2980                                               k := SymTab.SymKind(n);
+ 2981                                               IF k = SymTab.KindConst THEN
+ 2982                                                 IF SymTab.Equal(n,
+ 2983                                                    "TRUE") THEN
+ 2984                                                   t := SymTab.BoolType();
+ 2985                                                   QbeGen.CopyOp("1", q)
+ 2986                                                 ELSIF SymTab.Equal(n,
+ 2987                                                    "FALSE") THEN
+ 2988                                                   t := SymTab.BoolType();
+ 2989                                                   QbeGen.CopyOp("0", q)
+ 2990                                                 ELSIF SymTab.Equal(n,
+ 2991                                                    "NIL") THEN
+ 2992                                                   QbeGen.CopyOp("0", q)
+ 2993                                                 ELSE
+ 2994                                                   cls :=
+ 2995                                                     SymTab.ClassOf(t);
+ 2996                                                   IF (t #
+ 2997                                                       SymTab.InvalidType)
+ 2998   AND ((cls = SymTab.ClInt)
+ 2999                                                      OR (cls
+ 3000                                                          = SymTab.ClChar)
+ 3001                                                      OR (cls
+ 3002                                                          = SymTab.ClEnum)
+ 3003                                                      OR (cls
+ 3004                                                          = SymTab.ClReal)
+ 3005                                                      OR (cls
+ 3006                                                          = SymTab.ClLong)
+ 3007                                                      OR (cls
+ 3008                                                          = SymTab.ClNil)
+ 3009                                                      OR (cls = SymTab.ClByte)
+ 3010                                                      OR (cls = SymTab.ClSByte)
+ 3011                                                      OR (cls = SymTab.ClWord16)
+ 3012                                                      OR (cls = SymTab.ClSWord16)
+ 3013                                                       OR (cls = SymTab.ClBool)) THEN
+ 3014                                                     IF cls = SymTab.ClNil THEN
+ 3015                                                       QbeGen.CopyOp("0", q)
+ 3016                                                     ELSIF ((cls
+ 3017                                                         = SymTab.ClInt)
+ 3018                                                       OR (cls
+ 3019                                                         = SymTab.ClChar)
+ 3020                                                       OR (cls
+ 3021                                                         = SymTab.ClEnum)
+ 3022                                                       OR (cls
+ 3023                                                         = SymTab.ClLong)
+ 3024                                                        OR (cls = SymTab.ClByte)
+ 3025                                                        OR (cls = SymTab.ClSByte)
+ 3026                                                        OR (cls = SymTab.ClWord16)
+ 3027                                                        OR (cls = SymTab.ClSWord16)
+ 3028                                                        OR (cls = SymTab.ClBool))
+ 3029    AND SymTab.GetSymVal(n, cv)
+ 3030    AND QbeGen.IsImm(cv) THEN
+ 3031                                                       QbeGen.CopyOp(cv, q)
+ 3032                                                     ELSE
+ 3033                                                       QbeGen.LoadVar(n,
+ 3034                                                         cls = SymTab.ClReal,
+ 3035                                                         q)
+ 3036                                                     END
+ 3037                                                   ELSIF (cls = SymTab.ClArray)
+ 3038                                                      OR (cls = SymTab.ClRecord)
+ 3039                                                      OR (cls = SymTab.ClClass)
+ 3040                                                      OR (cls = SymTab.ClStr)
+ 3041                                                      OR (cls = SymTab.ClUStr)
+ 3042                                                      OR (cls = SymTab.ClSet) THEN
+ 3043                                                     (* aggregate constant:
+ 3044                                                        its value IS the
+ 3045                                                        descriptor address *)
+ 3046                                                     IF SymTab.GetSymVal(n, cv) THEN
+ 3047                                                       QbeGen.CopyOp(cv, q)
+ 3048                                                     ELSE
+ 3049                                                       QbeGen.CopyOp("0", q)
+ 3050                                                     END
+ 3051                                                   ELSE
+ 3052                                                     IF t #
+ 3053                                                        SymTab.InvalidType THEN
+ 3054                                                       SemError(230)
+ 3055                                                     END;
+ 3056                                                     QbeGen.CopyOp("0", q)
+ 3057                                                   END
+ 3058                                                 END
+ 3059                                               ELSIF (k = SymTab.KindVar)
+ 3060                                                  OR (k = SymTab.KindParam) THEN
+ 3061                                                 cls := SymTab.ClassOf(t);
+ 3062                                                 IF (cls # SymTab.ClInt)
+ 3063                                                    AND (cls # SymTab.ClBool)
+ 3064                                                    AND (cls # SymTab.ClChar)
+ 3065                                                    AND (cls # SymTab.ClUChar)
+ 3066                                                    AND (cls # SymTab.ClEnum)
+ 3067                                                    AND (cls # SymTab.ClReal)
+ 3068                                                    AND (cls # SymTab.ClPtr)
+ 3069                                                    AND (cls # SymTab.ClProc)
+ 3070                                                    AND (cls # SymTab.ClLong)
+ 3071                                                    AND (cls # SymTab.ClArray)
+ 3072                                                    AND (cls # SymTab.ClSet)
+ 3073                                                    AND (cls # SymTab.ClRecord)
+ 3074                                                    AND (cls # SymTab.ClUStr)
+ 3075                                                    AND (cls # SymTab.ClByte)
+ 3076                                                    AND (cls # SymTab.ClSByte)
+ 3077                                                    AND (cls # SymTab.ClWord16)
+ 3078                                                    AND (cls # SymTab.ClSWord16)
+ 3079                                                    AND (cls # SymTab.ClClass) THEN
+ 3080                                                   SemError(230);
+ 3081                                                   QbeGen.CopyOp("0", q)
+ 3082                                                 ELSE QbeGen.CopyOp("@", q)
+ 3083                                                 END
+ 3084                                               ELSE QbeGen.CopyOp("0", q);
+ 3085                                                 IF k = SymTab.KindImport THEN
+ 3086                                                   SemError(230)
+ 3087                                                 ELSIF k =
+ 3088                                                    SymTab.KindProc THEN
+ 3089                                                   (* bare procedure name:
+ 3090                                                      a following ArgList
+ 3091                                                      makes it a call;
+ 3092                                                      otherwise Fact
+ 3093                                                      reports 230 *)
+ 3094                                                 ELSE
+ 3095                                                    IF k = SymTab.KindField THEN
+ 3096                                                      IF QbeGen.TopWith(qb) THEN
+ 3097                                                        sfx := TRUE
+ 3098                                                      ELSE SemError(230);
+ 3099                                                        QbeGen.CopyOp("0", q)
+ 3100                                                      END
+ 3101                                                    END
+ 3102                                                 END
+ 3103                                               END
+ 3104                                             END; .)
+ 3105        (. astDes := AST.MakeNode(AST.NkDesignator);
+ 3106           AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n)); .)
+ 3107        { "[" Expr<it, iq>
+ 3108                                          (. AST.SetChild(astDes, AST.NChild(astDes),
+ 3109               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
+ 3110                                             ELSIF SymTab.ClassOf(t) #
+ 3111                                                   SymTab.ClArray THEN
+ 3112                                               SemError(217);
+ 3113                                               t := SymTab.InvalidType
+ 3114                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 3115   AND (SymTab.ClassOf(it) #
+ 3116                                                   SymTab.ClChar)
+ 3117   AND (SymTab.ClassOf(it) #
+ 3118                                                   SymTab.ClEnum)
+ 3119   AND (SymTab.ClassOf(it) #
+ 3120                                                   SymTab.ClBool) THEN
+ 3121                                               SemError(218);
+ 3122                                               t := SymTab.InvalidType
+ 3123                                              ELSE
+ 3124                                                eT := SymTab.ArrayElem(t);
+ 3125                                                t := eT; sfx := TRUE
+ 3126                                              END; .)
+ 3127          { "," Expr<it, iq>
+ 3128                                          (. AST.SetChild(astDes, AST.NChild(astDes),
+ 3129               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
+ 3130                                             ELSIF SymTab.ClassOf(t) #
+ 3131                                                   SymTab.ClArray THEN
+ 3132                                               SemError(217);
+ 3133                                               t := SymTab.InvalidType
+ 3134                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 3135   AND (SymTab.ClassOf(it) #
+ 3136                                                   SymTab.ClChar)
+ 3137   AND (SymTab.ClassOf(it) #
+ 3138                                                   SymTab.ClEnum)
+ 3139   AND (SymTab.ClassOf(it) #
+ 3140                                                   SymTab.ClBool) THEN
+ 3141                                               SemError(218);
+ 3142                                               t := SymTab.InvalidType
+ 3143                                              ELSE
+ 3144                                                eT := SymTab.ArrayElem(t);
+ 3145                                                t := eT; sfx := TRUE
+ 3146                                              END; .) }
+ 3147          "]"
+ 3148        | "." GetIdent<fn>
+ 3149                                          (. astSel := AST.MakeNode(AST.NkSelector);
+ 3150               AST.SetOp(astSel, AST.SelField);
+ 3151               AST.SetChild(astSel, 0, AST.MakeLeaf(AST.NkIdent, fn));
+ 3152               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF k = SymTab.KindModule THEN
+ 3153                                               (* qualified L.x: materialize
+ 3154                                                  the export, then load it *)
+ 3155                                               IF NOT SymTab.MaterializeAlias(n,
+ 3156                                                    fn, mal) THEN
+ 3157                                                 SemError(201);
+ 3158                                                 t := SymTab.InvalidType;
+ 3159                                                 QbeGen.CopyOp("0", q)
+ 3160                                               ELSE
+ 3161                                                 QbeGen.CopyOp(mal, qn);
+ 3162                                                 t := SymTab.SymType(mal);
+ 3163                                                 k := SymTab.SymKind(mal);
+ 3164                                                 sfx := FALSE;
+ 3165                                                 IF k = SymTab.KindProc THEN
+ 3166                                                   (* call: ArgList supplies
+ 3167                                                      the value *)
+ 3168                                                   QbeGen.CopyOp("0", q)
+ 3169                                                 ELSIF k = SymTab.KindConst THEN
+ 3170                                                   IF SymTab.GetSymVal(mal,
+ 3171                                                      cv)
+ 3172                                                   THEN QbeGen.CopyOp(cv, q)
+ 3173                                                   ELSE QbeGen.CopyOp("0", q)
+ 3174                                                   END
+ 3175                                                  END
+ 3176                                               END
+ 3177                                             ELSIF t = SymTab.InvalidType THEN
+ 3178                                             ELSIF (SymTab.ClassOf(t) #
+ 3179                                                    SymTab.ClRecord)
+ 3180   AND (SymTab.ClassOf(t) #
+ 3181                                                   SymTab.ClClass) THEN
+ 3182                                               SemError(215);
+ 3183                                               t := SymTab.InvalidType
+ 3184                                             ELSIF (SymTab.ClassOf(t) =
+ 3185                                                    SymTab.ClClass)
+ 3186    AND SymTab.MethodExists(t, fn) THEN
+ 3187                                               (* obj.Method: bind the
+ 3188                                                  method and pass obj as
+ 3189                                                  the hidden receiver; q
+ 3190                                                  already holds the
+ 3191                                                  object's address *)
+ 3192                                               QbeGen.CopyOp(fn, n);
+ 3193                                               QbeGen.CopyOp(fn, qn);
+ 3194                                               methCls := t;
+ 3195                                               k := SymTab.KindProc;
+ 3196                                               t := SymTab.InvalidType
+ 3197                                             ELSIF NOT SymTab.FieldExists(t,
+ 3198                                                      fn) THEN
+ 3199                                               SemError(216);
+ 3200                                               t := SymTab.InvalidType
+ 3201                                              ELSE
+ 3202                                                t := SymTab.FieldType(t, fn);
+ 3203                                                sfx := TRUE
+ 3204                                              END; .)
+ 3205        | "^"
+ 3206                                          (. astSel := AST.MakeNode(AST.NkSelector);
+ 3207               AST.SetOp(astSel, AST.SelDeref);
+ 3208               AST.SetChild(astDes, AST.NChild(astDes), astSel); IF t = SymTab.InvalidType THEN
+ 3209                                             ELSIF SymTab.ClassOf(t) #
+ 3210                                                   SymTab.ClPtr THEN
+ 3211                                               SemError(219);
+ 3212                                               t := SymTab.InvalidType
+ 3213                                             ELSE
+ 3214                                               bt := SymTab.PtrBase(t);
+ 3215                                               IF bt = SymTab.InvalidType THEN
+ 3216                                               ELSE
+ 3217                                                  t := bt;
+ 3218                                                  sfx := TRUE
+ 3219                                                END
+ 3220                                             END; .) } (. astCur := astDes; .) .
+ 3221    (* Result suffix (ISO component after a function call): `F()^`,
+ 3222       `F()[i]`, `F().field`.  The call result is in t/q with sfx FALSE
+ 3223       (a value, or a descriptor address for aggregates); each component
+ 3224       descends one level exactly like the Design components. *)
+ 3225    ResultComp<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
+ 3226               VAR sfx: BOOLEAN; VAR node: AST.Node;
+ 3227               VAR mname: SymTab.Name; VAR methCls: SymTab.TypeIndex;
+ 3228               VAR isM: BOOLEAN>          (. VAR it, eT, bt: SymTab.TypeIndex;
+ 3229                                               iq, ql, qlo, qhi, qe, qb:
+ 3230                                                 QbeGen.QVal;
+ 3231                                               lo, hi, fo: INTEGER;
+ 3232                                               isOpen: BOOLEAN;
+ 3233                                               fname: SymTab.Name;
+ 3234                                               astWrap, astSel: AST.Node; .)
+ 3235      = "[" Expr<it, iq>
+ 3236                                          (. isM := FALSE;
+ 3237                                             IF AST.Kind(node) # AST.NkDesignator THEN
+ 3238                                               astWrap := AST.MakeNode(
+ 3239                                                 AST.NkDesignator);
+ 3240                                               AST.SetChild(astWrap, 0, node);
+ 3241                                               node := astWrap
+ 3242                                             END;
+ 3243                                             AST.SetChild(node, AST.NChild(node),
+ 3244                                               AST.MakeUn(AST.NkSelector,
+ 3245                                                 AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
+ 3246                                             ELSIF SymTab.ClassOf(t) #
+ 3247                                                   SymTab.ClArray THEN
+ 3248                                               SemError(217);
  3249                                               t := SymTab.InvalidType
- 3250                                              ELSE
- 3251                                                t := SymTab.FieldType(t, fname);
- 3252                                                sfx := TRUE
- 3253                                              END; .)
- 3254      | "^"                               (. isM := FALSE;
- 3255                                             IF AST.Kind(node) # AST.NkDesignator THEN
- 3256                                               astWrap := AST.MakeNode(
- 3257                                                 AST.NkDesignator);
- 3258                                               AST.SetChild(astWrap, 0, node);
- 3259                                               node := astWrap
- 3260                                             END;
- 3261                                             astSel := AST.MakeNode(AST.NkSelector);
- 3262                                             AST.SetOp(astSel, AST.SelDeref);
- 3263                                             AST.SetChild(node,
- 3264                                               AST.NChild(node), astSel); IF t = SymTab.InvalidType THEN
- 3265                                             ELSIF SymTab.ClassOf(t) #
- 3266                                                   SymTab.ClPtr THEN
- 3267                                               SemError(219);
- 3268                                               t := SymTab.InvalidType
- 3269                                             ELSE
- 3270                                               bt := SymTab.PtrBase(t);
- 3271                                               IF bt # SymTab.InvalidType THEN
- 3272                                                  t := bt; sfx := TRUE
- 3273                                               END
- 3274                                             END; .) .
- 3275    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3276                                          (. VAR t2: SymTab.TypeIndex;
- 3277                                               op: INTEGER;
- 3278                                               q2, qt, wl: QbeGen.QVal;
- 3279                                                astA, astB: AST.Node;
- 3280                                                astOp: INTEGER;
- 3281                                                astMade: BOOLEAN;
- 3282                                               isR: BOOLEAN;
- 3283                                               v1, v2: INTEGER;
- 3284                                               b: BOOLEAN; .)
- 3285      = SimExpr<t, q>                     (. astA := astCur; astMade := FALSE; .)
- 3286        [ Rel<op> SimExpr<t2, q2>
- 3287          (. astB := astCur; astMade := TRUE;
- 3288              astOp := AST.OpEq;
- 3289              IF op = SymTab.OpNeq1 THEN astOp := AST.OpNe
- 3290              ELSIF op = SymTab.OpNeq2 THEN astOp := AST.OpNe
- 3291              ELSIF op = SymTab.OpLt THEN astOp := AST.OpLt
- 3292              ELSIF op = SymTab.OpLe THEN astOp := AST.OpLe
- 3293              ELSIF op = SymTab.OpGt THEN astOp := AST.OpGt
- 3294              ELSIF op = SymTab.OpGe THEN astOp := AST.OpGe
- 3295              ELSIF op = SymTab.OpIn THEN astOp := AST.OpIn
- 3296              END;
- 3297              IF op = SymTab.OpIn THEN
- 3298               IF SymTab.InCheck(t, t2) THEN
- 3299                 IF (t = SymTab.InvalidType)
- 3300                    OR (t2 = SymTab.InvalidType) THEN
- 3301                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 3302                 ELSE
- 3303                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 3304                 END
- 3305               ELSE SemError(222); t := SymTab.InvalidType;
- 3306                 QbeGen.CopyOp("0", q)
- 3307               END
- 3308             ELSIF SymTab.RelCheck(t, t2, op) THEN
- 3309               IF (t = SymTab.InvalidType)
- 3310                  OR (t2 = SymTab.InvalidType) THEN
- 3311                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 3312               ELSIF SymTab.IsOrdinal(t) AND SymTab.IsOrdinal(t2)
- 3313                  AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2)
- 3314                  AND SymTab.ConstInt(q, v1)
- 3315                  AND SymTab.ConstInt(q2, v2) THEN
- 3316                 (* fold a relation of two ordinal constants (needed for
- 3317                    ORD(boolean) in a CONST initialiser) *)
- 3318                 IF op = SymTab.OpEq THEN b := v1 = v2
- 3319                 ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN
- 3320                   b := v1 # v2
- 3321                 ELSIF op = SymTab.OpLt THEN b := v1 < v2
- 3322                 ELSIF op = SymTab.OpLe THEN b := v1 <= v2
- 3323                 ELSIF op = SymTab.OpGt THEN b := v1 > v2
- 3324                 ELSE b := v1 >= v2
- 3325                 END;
- 3326                 t := SymTab.BoolType();
- 3327                 IF b THEN QbeGen.CopyOp("1", q)
- 3328                 ELSE QbeGen.CopyOp("0", q)
- 3329                 END
- 3330               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
- 3331                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
- 3332                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
- 3333   AND (op # SymTab.OpNeq2) THEN
- 3334                   SemError(213); t := SymTab.InvalidType;
- 3335                   QbeGen.CopyOp("0", q)
- 3336                  ELSE
- 3337                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 3338                  END
- 3339                ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
- 3340                   OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 3341                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 3342               ELSIF SymTab.StrCompat(t, t2) THEN
- 3343                 QbeGen.StrEq(op, q, q2, qt);
- 3344                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 3345               ELSIF SymTab.IsLongFamily(t)
- 3346                  OR SymTab.IsLongFamily(t2) THEN
- 3347                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
- 3348                ELSE
- 3349                  t := SymTab.BoolType();
- 3350                  QbeGen.CopyOp("@", q)
- 3351                END
- 3352             ELSE SemError(213); t := SymTab.InvalidType;
- 3353                QbeGen.CopyOp("0", q)
- 3354              END;
- 3355              astCur := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); .) ]
- 3356         (. IF NOT astMade THEN astCur := astA END; .)
- 3357             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 3358    Rel<VAR op: INTEGER>
- 3359      = "="                               (. op := SymTab.OpEq; .)
- 3360      | "#"                               (. op := SymTab.OpNeq1; .)
- 3361      | "<"                               (. op := SymTab.OpLt; .)
- 3362      | "<="                              (. op := SymTab.OpLe; .)
- 3363      | ">"                               (. op := SymTab.OpGt; .)
- 3364      | ">="                              (. op := SymTab.OpGe; .)
- 3365      | "IN"                              (. op := SymTab.OpIn; .) .
- 3366    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3367                                          (. VAR t2, res2, lt, rt:
- 3368                                                 SymTab.TypeIndex;
- 3369                                               op: INTEGER;
- 3370                                               q2, qt, wq, qf, q2a, q2b:
- 3371                                                 QbeGen.QVal;
- 3372                                               neg, isR, isL, folded:
- 3373                                                 BOOLEAN;
- 3374                                               fok: BOOLEAN;
- 3375                                               lw, rw, mw: CARDINAL;
- 3376                                               lTrue, lNext, lDone, qr, qs: QbeGen.QVal;
- 3377                                                astA, astB: AST.Node;
- 3378                                                astSign, astOp: INTEGER;
- 3379                                                v1, v2: INTEGER;
- 3380                                                s: ARRAY [0 .. 255] OF CHAR; .)
- 3381      =                                   (. neg := FALSE; astSign := 0; .)
- 3382        [ "+"                         (. neg := TRUE; astSign := 1; .)
- 3383        | "-"                         (. neg := TRUE; astSign := -1; .) ]
- 3384        Term<t, q> (. astA := astCur;
- 3385                                            IF neg AND QbeGen.IsImm(q) THEN
- 3386                                              QbeGen.NegFold(q, q)
- 3387                                            END;
- 3388                                           IF astSign < 0 THEN
- 3389                                             astCur := AST.MakeUn(
- 3390                                               AST.NkUnary, AST.OpSub, astA);
- 3391                                             astA := astCur
- 3392                                           END; .)
- 3393         { AddOp<op>
- 3394           Term<t2, q2> (. astB := astCur; .)
- 3395          (. astOp := AST.OpAdd;
- 3396             IF op = SymTab.OpSub THEN astOp := AST.OpSub
- 3397             ELSIF op = SymTab.OpOr THEN astOp := AST.OpOr END;
- 3398             astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
- 3399             astCur := astA;
- 3400             IF op = SymTab.OpOr THEN
- 3401               (* short-circuit: if q is true the RHS is skipped *)
- 3402               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 3403                 t := SymTab.BoolType()
- 3404               ELSE SemError(212); t := SymTab.InvalidType END;
- 3405                IF t # SymTab.InvalidType THEN
- 3406                  QbeGen.CopyOp("@", q)
- 3407                ELSE QbeGen.CopyOp("0", q)
- 3408                END
- 3409             ELSIF (op = SymTab.OpAdd)
- 3410               AND (SymTab.ClassOf(t) = SymTab.ClChar)
- 3411               AND (SymTab.ClassOf(t2) = SymTab.ClChar)
- 3412               AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 3413               (* "W" + "o": two one-character string literals concatenate
- 3414                  to a two-character string (they are CHAR-typed immediates) *)
- 3415               IF SymTab.ConstInt(q, v1) AND SymTab.ConstInt(q2, v2)
- 3416                  AND (v1 >= 0) AND (v1 <= 255)
- 3417                  AND (v2 >= 0) AND (v2 <= 255) THEN
- 3418                 s[0] := '"'; s[1] := CHR(v1); s[2] := CHR(v2);
- 3419                 s[3] := '"'; s[4] := CHR(0);
- 3420                 QbeGen.DeclStr(s, qt); QbeGen.CopyOp(qt, q);
- 3421                 t := SymTab.NewStr();
- 3422                 astA := AST.MakeLeaf(AST.NkStrLit, s);
- 3423                 astCur := astA
- 3424               ELSE SemError(211); t := SymTab.InvalidType;
- 3425                 QbeGen.CopyOp("0", q)
- 3426               END
- 3427             ELSIF (op = SymTab.OpAdd)
- 3428               AND (SymTab.UStrCompat(t, t2)
- 3429                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
- 3430                   AND (SymTab.ClassOf(t2) = SymTab.ClUStr))
- 3431                 OR ((SymTab.ClassOf(t) = SymTab.ClUStr)
- 3432                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))
- 3433                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
- 3434                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN
- 3435               (* UString concatenation: a UCHAR operand becomes a
- 3436                  1-codepoint UString; the result is a descriptor in the
- 3437                  shim's concat buffer.  Work on copies so neither
- 3438                  operand is clobbered. *)
- 3439                t := SymTab.NewUStr();
- 3440                QbeGen.CopyOp("@", q)
- 3441             ELSIF (op = SymTab.OpAdd)
- 3442               AND (SymTab.StrCompat(t, t2)
- 3443                 OR (SymTab.IsStrType(t)
- 3444                   AND (SymTab.ClassOf(t2) = SymTab.ClChar))
- 3445                 OR ((SymTab.ClassOf(t) = SymTab.ClChar)
- 3446                   AND SymTab.IsStrType(t2))) THEN
- 3447               (* string concatenation; a CHAR operand becomes a
- 3448                  1-character string literal.  When both operands are
- 3449                  constants, fold to a single string literal so a
- 3450                  constructor element stays compile-time. *)
- 3451                QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2),
- 3452                  qt, fok);
- 3453                IF fok THEN QbeGen.CopyOp(qt, q)
- 3454                ELSE QbeGen.CopyOp("@", q)
- 3455                END;
- 3456                t := SymTab.NewStr()
- 3457             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 3458   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 3459   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 3460                lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 3461                mw := lw;
- 3462                IF rw > mw THEN mw := rw END;
- 3463                t := SymTab.NewSet(
- 3464                       SymTab.NewSubR(0,
- 3465                         VAL(INTEGER, mw) * 32 - 1));
- 3466                QbeGen.CopyOp("@", q)
- 3467             ELSE
- 3468               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
- 3469                 lt := t; rt := t2; t := res2
- 3470               ELSE SemError(211); t := SymTab.InvalidType END;
- 3471               IF t # SymTab.InvalidType THEN
- 3472                 isL := SymTab.IsLongFamily(t);
- 3473                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 3474                 folded := FALSE;
- 3475                 IF (NOT isL) AND (NOT isR)
- 3476    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 3477                   IF op = SymTab.OpAdd THEN
- 3478                     folded := QbeGen.Fold2(0, q, q2, qf)
- 3479                   ELSE
- 3480                     folded := QbeGen.Fold2(1, q, q2, qf)
- 3481                   END
- 3482                 END;
- 3483                 IF folded THEN QbeGen.CopyOp(qf, q)
- 3484                  ELSE
- 3485                  QbeGen.CopyOp("@", q)
- 3486                  END
- 3487               ELSE QbeGen.CopyOp("0", q)
- 3488               END
- 3489             END; .) }
- 3490             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 3491    AddOp<VAR op: INTEGER>
- 3492      = "+"                               (. op := SymTab.OpAdd; .)
- 3493      | "-"                               (. op := SymTab.OpSub; .)
- 3494      | "OR"                              (. op := SymTab.OpOr; .) .
- 3495    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3496                                          (. VAR t2, res2, lt, rt:
- 3497                                                 SymTab.TypeIndex;
- 3498                                               op: INTEGER;
- 3499                                               q2, qt, wq, qf:
- 3500                                                 QbeGen.QVal;
- 3501                                               isR, isL, folded: BOOLEAN;
- 3502                                               lw, rw, mw: CARDINAL;
- 3503                                               lNext, lFalse, lDone, qr, qs: QbeGen.QVal;
- 3504                                                astA, astB: AST.Node;
- 3505                                                astOp: INTEGER; .)
- 3506      = Fact<t, q> (. astA := astCur; .) { MulOp<op>
- 3507          Fact<t2, q2> (. astB := astCur; .)
- 3508        (. astOp := AST.OpMul;
- 3509           IF op = SymTab.OpSlash THEN astOp := AST.OpDiv
- 3510           ELSIF op = SymTab.OpDiv THEN astOp := AST.OpDiv
- 3511           ELSIF op = SymTab.OpMod THEN astOp := AST.OpMod
- 3512           ELSIF op = SymTab.OpAnd THEN astOp := AST.OpAnd END;
- 3513           astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
- 3514           astCur := astA;
- 3515           IF op = SymTab.OpAnd THEN
- 3516             (* short-circuit: if q is false the RHS is skipped *)
- 3517             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 3518               t := SymTab.BoolType()
- 3519             ELSE SemError(212); t := SymTab.InvalidType END;
- 3520              IF t # SymTab.InvalidType THEN QbeGen.CopyOp("@", q)
- 3521              ELSE QbeGen.CopyOp("0", q)
- 3522              END
- 3523           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 3524   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 3525   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 3526              lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 3527              mw := lw;
- 3528              IF rw > mw THEN mw := rw END;
- 3529              t := SymTab.NewSet(
- 3530                     SymTab.NewSubR(0,
- 3531                       VAL(INTEGER, mw) * 32 - 1));
- 3532              QbeGen.CopyOp("@", q)
- 3533           ELSE
- 3534             IF SymTab.ArithCheck(t, t2,
- 3535                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
- 3536                  res2) THEN
- 3537               lt := t; rt := t2; t := res2
- 3538             ELSE SemError(211); t := SymTab.InvalidType END;
- 3539             IF t # SymTab.InvalidType THEN
- 3540               isL := SymTab.IsLongFamily(t);
- 3541               isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 3542               folded := FALSE;
- 3543               IF (NOT isL) AND (NOT isR)
- 3544    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 3545                 IF op = SymTab.OpTimes THEN
- 3546                   folded := QbeGen.Fold2(2, q, q2, qf)
- 3547                 ELSIF op = SymTab.OpDiv THEN
- 3548                   folded := QbeGen.Fold2(3, q, q2, qf)
- 3549                 ELSIF op = SymTab.OpMod THEN
- 3550                   folded := QbeGen.Fold2(4, q, q2, qf)
- 3551                 END
- 3552               END;
- 3553               IF folded THEN QbeGen.CopyOp(qf, q)
- 3554                ELSE
- 3555                QbeGen.CopyOp("@", q)
- 3556                END
- 3557             ELSE QbeGen.CopyOp("0", q)
- 3558             END
- 3559           END; .) }
- 3560             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 3561    MulOp<VAR op: INTEGER>
- 3562      = "*"                               (. op := SymTab.OpTimes; .)
- 3563      | "/"                               (. op := SymTab.OpSlash; .)
- 3564      | "DIV"                             (. op := SymTab.OpDiv; .)
- 3565      | "MOD"                             (. op := SymTab.OpMod; .)
- 3566      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
- 3567    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 3568                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
- 3569                                               et, dt, t2, st, ct2, et2:
- 3570                                                 SymTab.TypeIndex;
- 3571                                               dk: INTEGER;
- 3572                                               qd, q2, sq, qa, qm0, qr, qt:
- 3573                                                 QbeGen.QVal;
- 3574                                               qn, vn: SymTab.Name;
- 3575                                               vt: SymTab.TypeIndex;
- 3576                                               c1, c2: INTEGER;
- 3577                                               lo, hi: INTEGER;
- 3578                                               isMax: BOOLEAN;
- 3579                                               called, isHigh, sfx, isCh,
- 3580                                               isU, uok, isStr: BOOLEAN;
- 3581                                               ucp: INTEGER; astIsLit: BOOLEAN;
- 3582                                                astD: AST.Node;
- 3583                                                astCall: BOOLEAN;
- 3584                                                astNode, astNot: AST.Node;
- 3585                                                j: CARDINAL;
- 3586                                                astArg2: AST.Node;
- 3587                                                astBrace: AST.Node;
- 3588                                                astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN;
- 3589                                                isConvF: BOOLEAN;
- 3590                                                fi, fj: CARDINAL; .)
- 3591      = (. astIsLit := FALSE; .)
- 3592      ( "__LINE__"                        (. QbeGen.IntStr(M2S.line, q);
- 3593                                             astIsLit := TRUE;
- 3594                                             astCur := AST.MakeLeaf(
- 3595                                               AST.NkIntLit, q);
- 3596                                             t := SymTab.IntType(); .)
- 3597      | "__FUNCTION__"                    (. (* fold to the current procedure
- 3598                                                (module name at unit level) *)
- 3599                                             s[0] := '"'; fi := 1; fj := 0;
- 3600                                             IF curFun[0] = CHR(0) THEN
- 3601                                               WHILE (unitName[fj] # CHR(0))
- 3602                                                 AND (fi < HIGH(s)) DO
- 3603                                                 s[fi] := unitName[fj];
- 3604                                                 INC(fi); INC(fj)
- 3605                                               END
- 3606                                             ELSE
- 3607                                               WHILE (curFun[fj] # CHR(0))
- 3608                                                 AND (fi < HIGH(s)) DO
- 3609                                                 s[fi] := curFun[fj];
- 3610                                                 INC(fi); INC(fj)
- 3611                                               END
- 3612                                             END;
- 3613                                             s[fi] := '"';
- 3614                                             s[fi + 1] := CHR(0);
- 3615                                             astIsLit := TRUE;
- 3616                                             astCur := AST.MakeLeaf(
- 3617                                               AST.NkStrLit, s);
- 3618                                             t := SymTab.NewStr();
- 3619                                             QbeGen.DeclStr(s, q); .)
- 3620      | "__FILE__"                        (. (* fold to the quoted file name *)
- 3621                                             s[0] := '"'; fi := 1; fj := 0;
- 3622                                             WHILE (M2S.fileName[fj] # CHR(0))
- 3623                                               AND (fi < HIGH(s)) DO
- 3624                                               s[fi] := M2S.fileName[fj];
- 3625                                               INC(fi); INC(fj)
- 3626                                             END;
- 3627                                             s[fi] := '"';
- 3628                                             s[fi + 1] := CHR(0);
- 3629                                             astIsLit := TRUE;
- 3630                                             astCur := AST.MakeLeaf(
- 3631                                               AST.NkStrLit, s);
- 3632                                             t := SymTab.NewStr();
- 3633                                             QbeGen.DeclStr(s, q); .)
- 3634      | integer                           (. LexString(s);
- 3635                                             QbeGen.NormInt(s, q); astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s);
- 3636                                             t := SymTab.IntType(); .)
- 3637      | charConst                         (. LexString(s);
- 3638                                             QbeGen.NormLit(s, q, isCh);
- 3639                                             astIsLit := TRUE;
- 3640                                             astCur := AST.MakeLeaf(
- 3641                                               AST.NkCharLit, s);
- 3642                                             t := SymTab.CharType(); .)
- 3643      | real                              (. LexString(s);
- 3644                                             QbeGen.NormReal(s, q);
- 3645                                             astIsLit := TRUE;
- 3646                                             astCur := AST.MakeLeaf(
- 3647                                               AST.NkRealLit, s);
- 3648                                             t := SymTab.RealType(); .)
- 3649      | string                            (. LexString(s);
- 3650                                             astIsLit := TRUE;
- 3651                                             astCur := AST.MakeLeaf(
- 3652                                               AST.NkStrLit, s);
- 3653                                             IF SymTab.StrLen(s) = 3 THEN
- 3654                                               t := SymTab.CharType();
- 3655                                               QbeGen.IntStr(
- 3656                                                 QbeGen.CharVal(s), q)
- 3657                                             ELSIF SymTab.StrLen(s) = 2 THEN
- 3658                                               (* empty string: a string value
- 3659                                                  for arrays, 0 for CHAR *)
- 3660                                               t := SymTab.NewEmptyStr();
- 3661                                               QbeGen.DeclStr(s, q)
- 3662                                             ELSE t := SymTab.NewStr();
- 3663                                               QbeGen.DeclStr(s, q);
- 3664                                               (* a literal's value IS its
- 3665                                                  static descriptor address *)
- 3666                                             END; .)
- 3667      | ustring                           (. LexString(s);
- 3668                                             astIsLit := TRUE;
- 3669                                             astCur := AST.MakeLeaf(
- 3670                                               AST.NkStrLit, s);
- 3671                                             QbeGen.DeclUStr(s, q, isU, ucp,
- 3672                                               uok);
- 3673                                             IF NOT uok THEN
- 3674                                               SemError(234);
- 3675                                               t := SymTab.InvalidType
- 3676                                             ELSIF isU THEN
- 3677                                               t := SymTab.UCharType();
- 3678                                               QbeGen.IntStr(ucp, q)
- 3679                                             ELSE
- 3680                                               t := SymTab.NewUStr();
- 3681                                             END; .)
- 3682      | Design<dt, dk, qd, qn, sfx>       (. astD := astCur; astCall := FALSE; astBrace := AST.NoNode;
- 3683                                             astNArgs := 0; called := FALSE;
- 3684                                             t := dt;
- 3685                                             IF dk = SymTab.KindConst THEN
- 3686                                               QbeGen.CopyOp(qd, q)
- 3687                                             ELSE QbeGen.CopyOp("@", q)
- 3688                                             END; .)
- 3689        [ TypedBraceLit<dt, q>            (. t := dt; astCall := TRUE;
- 3690                                               astBrace := astCur; .) ]
- 3691        [ ArgList<qn, dt, qd, TRUE, FALSE, methCls, ct2, q2, called>
- 3692                                          (. astCall := TRUE;
- 3693                                             IF (SymTab.SymKind(qn) = SymTab.KindType)
- 3694    OR (SymTab.SymKind(qn) = SymTab.KindPredef) THEN
- 3695                                             (* T(x): emit as the VAL builtin so Lower's
- 3696                                                conversion rules apply unchanged *)
- 3697                                             astNode := AST.MakeNode(AST.NkCall);
- 3698                                             AST.SetChild(astNode, 0,
- 3699                                               AST.MakeLeaf(AST.NkIdent, "VAL"));
- 3700                                             AST.SetChild(astNode, 1,
- 3701                                               AST.MakeLeaf(AST.NkIdent, qn));
- 3702                                             IF astNArgs = 1 THEN
- 3703                                               AST.SetChild(astNode, 2, astArgs[0])
- 3704                                             END;
- 3705                                             isConvF := TRUE
- 3706                                             ELSE astNode := AstCallNode(astD)
- 3707                                             END;
- 3708                                             astRes := astNode;
- 3709                                             t := ct2;
- 3710                                             QbeGen.CopyOp(q2, q);
- 3711                                             IF isConvF AND QbeGen.IsImm(convQ)
- 3712                                                AND OrdClass(convT) AND OrdClass(ct2) THEN
- 3713                                               QbeGen.CopyOp(convQ, q)
- 3714                                             END;
- 3715                                             sfx := FALSE; .)
- 3716          { ResultComp<t, q, sfx, astRes, mname, methCls, isM>
- 3717            [ (. astNArgs := 0; .)
- 3718              ArgList<mname, t, q, TRUE, FALSE, methCls, ct2, q2, called>
- 3719                                          (. astNode := AstCallNode(astRes);
- 3720                                             astRes := astNode;
- 3721                                             t := ct2;
- 3722                                             QbeGen.CopyOp(q2, q);
- 3723                                             sfx := FALSE; .) ] }
- 3724                                          (. IF sfx THEN
- 3725                                               IF t = SymTab.InvalidType THEN
- 3726                                                 QbeGen.CopyOp("0", q)
- 3727                                               ELSIF (SymTab.ClassOf(t) #
- 3728                                                      SymTab.ClRecord)
- 3729    AND (SymTab.ClassOf(t) # SymTab.ClSet)
- 3730    AND (SymTab.ClassOf(t) # SymTab.ClArray)
- 3731    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
- 3732                                                  QbeGen.CopyOp("@", q)
- 3733                                               END
- 3734                                             END; .) ]
- 3735                                          (. IF called THEN
- 3736                                               astCur := astRes
- 3737                                             ELSIF astCall THEN
- 3738                                               astCur := astBrace
- 3739                                             ELSE astCur := astD
- 3740                                             END;
- 3741                                              astIsLit := TRUE;
- 3742                                              IF NOT called
- 3743   AND (dk = SymTab.KindProc) THEN
- 3744                                               (* bare zero-arg function
- 3745                                                  call (parentheses may be
- 3746                                                  omitted); a proper or
- 3747                                                  parameterised proc here
- 3748                                                  is 230 *)
- 3749                                                IF (SymTab.ProcNPar(qn) = 0)
- 3750   AND (SymTab.ProcRes(qn) # SymTab.InvalidType) THEN
- 3751                                                  t := SymTab.ProcRes(qn);
- 3752                                                  QbeGen.CopyOp("@", q);
- 3753                                                  astCur := AST.MakeNode(AST.NkCall);
- 3754                                                  AST.SetChild(astCur, 0, astD)
- 3755                                                ELSE
- 3756                                                  t := SymTab.ProcTypeOf(qn);
- 3757                                                  QbeGen.CopyOp("@", q)
- 3758                                                END
- 3759                                             END; .)
- 3760      | ( "HIGH"                          (. isHigh := TRUE; .)
- 3761        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
- 3762        "(" ( Design<dt, dk, qd, qn, sfx> (. isStr := FALSE;
- 3763                                              isU := FALSE; .)
- 3764            | string                       (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
- 3765                                              isStr := TRUE;
- 3766                                              isU := FALSE;
- 3767                                              IF SymTab.StrLen(s) = 3 THEN
- 3768                                                dt := SymTab.CharType();
- 3769                                                QbeGen.IntStr(QbeGen.CharVal(s),
- 3770                                                  qd)
- 3771                                              ELSE
- 3772                                                dt := SymTab.NewStr();
- 3773                                                QbeGen.DeclStr(s, qd);
- 3774                                              END;
- 3775                                              dk := -1;
- 3776                                              qn[0] := CHR(0); .)
- 3777            | ustring                      (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
- 3778                                              QbeGen.DeclUStr(s, qd, isU, ucp,
- 3779                                                uok);
- 3780                                              isStr := FALSE;
- 3781                                              IF NOT uok THEN
- 3782                                                SemError(234);
- 3783                                                dt := SymTab.InvalidType
- 3784                                              ELSIF isU THEN
- 3785                                                (* one codepoint: a UCHAR;
- 3786                                                   LEN is 1, HIGH is 0 *)
- 3787                                                dt := SymTab.UCharType();
- 3788                                                QbeGen.IntStr(ucp, qd)
- 3789                                              ELSE
- 3790                                                dt := SymTab.NewUStr();
- 3791                                              END;
- 3792                                              dk := -1;
- 3793                                              qn[0] := CHR(0); .) )
- 3794        ")"
- 3795                                          (. astNode := AST.MakeNode(AST.NkCall);
- 3796     IF isHigh THEN AST.SetChild(astNode, 0,
- 3797       AST.MakeLeaf(AST.NkIdent, "HIGH"))
- 3798     ELSE AST.SetChild(astNode, 0,
- 3799       AST.MakeLeaf(AST.NkIdent, "LEN")) END;
- 3800     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3801     astCur := astNode; astIsLit := TRUE;
- 3802                                             IF (dt # SymTab.InvalidType)
- 3803    AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN
- 3804                                               (* UString: the count is
- 3805                                                  the descriptor header *)
- 3806                                                t := SymTab.IntType();
- 3807                                                QbeGen.CopyOp("@", q)
- 3808                                             ELSIF (dt # SymTab.InvalidType)
- 3809    AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN
- 3810                                               (* single UCHAR codepoint *)
- 3811                                               IF isHigh THEN
- 3812                                                 QbeGen.CopyOp("0", qr)
- 3813                                               ELSE
- 3814                                                 QbeGen.CopyOp("1", qr)
- 3815                                               END;
- 3816                                               t := SymTab.IntType();
- 3817                                               QbeGen.CopyOp(qr, q)
- 3818                                             ELSIF isStr THEN
- 3819                                               (* fold: content length at
- 3820                                                  compile time *)
- 3821                                               IF SymTab.StrLen(s) = 3 THEN
- 3822                                                 c1 := 1
- 3823                                               ELSE
- 3824                                                 c1 :=
- 3825                                                   SymTab.StrLen(s) - 2
- 3826                                               END;
- 3827                                               IF isHigh THEN
- 3828                                                 DEC(c1)
- 3829                                               END;
- 3830                                               QbeGen.IntStr(c1, qr);
- 3831                                               t := SymTab.IntType();
- 3832                                               QbeGen.CopyOp(qr, q)
- 3833                                             ELSIF dt = SymTab.InvalidType THEN
- 3834                                               t := SymTab.InvalidType;
- 3835                                               QbeGen.CopyOp("0", q)
- 3836                                             ELSIF SymTab.ClassOf(dt) =
- 3837                                                   SymTab.ClStr THEN
- 3838                                               (* HIGH/LEN of a string
- 3839                                                  CONST: its pooled literal
- 3840                                                  knows its length *)
- 3841                                               IF QbeGen.StrLitLen(qd, c1) THEN
- 3842                                                 IF isHigh THEN DEC(c1) END;
- 3843                                                 QbeGen.IntStr(VAL(INTEGER, c1),
- 3844                                                   qr);
- 3845                                                 t := SymTab.IntType();
- 3846                                                 QbeGen.CopyOp(qr, q)
- 3847                                               ELSE SemError(217);
- 3848                                                 t := SymTab.InvalidType;
- 3849                                                 QbeGen.CopyOp("0", q)
- 3850                                               END
- 3851                                             ELSIF SymTab.ClassOf(dt) #
- 3852                                                   SymTab.ClArray THEN
- 3853                                               SemError(217);
- 3854                                               t := SymTab.InvalidType;
- 3855                                               QbeGen.CopyOp("0", q)
- 3856                                             ELSE
- 3857                                                IF SymTab.IsOpenArray(dt) THEN
- 3858                                                  t := SymTab.IntType();
- 3859                                                  QbeGen.CopyOp("@", q)
- 3860                                                ELSE
- 3861                                                  IF isHigh THEN
- 3862                                                    QbeGen.IntStr(
- 3863                                                      SymTab.ArrayHi(dt), qr)
- 3864                                                  ELSE
- 3865                                                    QbeGen.IntStr(VAL(
- 3866                                                      INTEGER,
- 3867                                                      SymTab.ArrayLen(dt)),
- 3868                                                      qr)
- 3869                                                  END;
- 3870                                                  t := SymTab.IntType();
- 3871                                                  QbeGen.CopyOp(qr, q)
- 3872                                                END
- 3873                                              END; .)
- 3874      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
- 3875      (. astNode := AST.MakeNode(AST.NkCall);
- 3876     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "SIZE"));
- 3877     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3878     astCur := astNode; astIsLit := TRUE; .)
- 3879                                          (. IF dt = SymTab.InvalidType THEN
- 3880                                               t := SymTab.InvalidType;
- 3881                                               QbeGen.CopyOp("0", q)
- 3882                                             ELSE
- 3883                                               QbeGen.IntStr(VAL(INTEGER,
- 3884                                                 SymTab.ObjectSize(dt)), q);
- 3885                                               t := SymTab.IntType()
- 3886                                             END; .)
- 3887      | ( "SHIFT"                         (. isMax := FALSE; .)
- 3888        | "ROTATE"                        (. isMax := TRUE; .) )
- 3889        "(" Expr<et, q> (. astArg2 := astCur; .) "," Expr<et2, q2> ")"
- 3890                                          (. astNode := AST.MakeNode(AST.NkCall);
- 3891     IF isMax THEN AST.SetChild(astNode, 0,
- 3892       AST.MakeLeaf(AST.NkIdent, "ROTATE"))
- 3893     ELSE AST.SetChild(astNode, 0,
- 3894       AST.MakeLeaf(AST.NkIdent, "SHIFT")) END;
- 3895     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
- 3896     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
- 3897     astCur := astNode; astIsLit := TRUE;
- 3898                                             (* set shift/rotate: isMax
- 3899                                                doubles as "rotate" *)
- 3900                                             IF (et # SymTab.InvalidType)
- 3901                                                AND (SymTab.ClassOf(et) =
- 3902                                                   SymTab.ClSet) THEN
- 3903                                                t := et;
- 3904                                                QbeGen.CopyOp("@", q)
- 3905                                             ELSE SemError(230);
- 3906                                               t := SymTab.InvalidType;
- 3907                                               QbeGen.CopyOp("0", q)
- 3908                                             END; .)
- 3909      | ( "MIN"                           (. isMax := FALSE; .)
- 3910        | "MAX"                           (. isMax := TRUE; .) )
- 3911        "(" Design<dt, dk, qd, qn, sfx> ")"
- 3912                                          (. astNode := AST.MakeNode(AST.NkCall);
- 3913     IF isMax THEN AST.SetChild(astNode, 0,
- 3914       AST.MakeLeaf(AST.NkIdent, "MAX"))
- 3915     ELSE AST.SetChild(astNode, 0,
- 3916       AST.MakeLeaf(AST.NkIdent, "MIN")) END;
- 3917     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3918     astCur := astNode; astIsLit := TRUE;
- 3919                                             IF (dt # SymTab.InvalidType)
- 3920   AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN
- 3921                                               (* REAL/LONGREAL: the
- 3922                                                  implementation bounds *)
- 3923                                               IF isMax THEN
- 3924                                                 QbeGen.NormReal(
- 3925                                                   "3.402823e38", q)
- 3926                                               ELSE QbeGen.NormReal(
- 3927                                                   "-3.402823e38", q)
- 3928                                               END;
- 3929                                               t := SymTab.RealType()
- 3930                                             ELSIF (dt #
- 3931                                                SymTab.InvalidType)
- 3932   AND (SymTab.ClassOf(dt) =
- 3933                                                   SymTab.ClLong) THEN
- 3934                                               IF isMax THEN
- 3935                                                 QbeGen.CopyOp(
- 3936                                                   "9223372036854775807", q)
- 3937                                               ELSE QbeGen.CopyOp(
- 3938                                                   "-9223372036854775808", q)
- 3939                                               END;
- 3940                                               t := SymTab.LongType()
- 3941                                             ELSIF SymTab.TypeBounds(dt, lo,
- 3942                                                      hi) THEN
- 3943                                               IF isMax THEN
- 3944                                                 QbeGen.IntStr(hi, q)
- 3945                                               ELSE QbeGen.IntStr(lo, q)
- 3946                                               END;
- 3947                                               (* a set's bounds are those
- 3948                                                  of its base type *)
- 3949                                               IF SymTab.ClassOf(dt) =
- 3950                                                  SymTab.ClSet THEN
- 3951                                                 t := SymTab.SetBase(dt)
- 3952                                               ELSE t := SymTab.IntType()
- 3953                                               END
- 3954                                             ELSE SemError(230);
- 3955                                               t := SymTab.InvalidType;
- 3956                                               QbeGen.CopyOp("0", q)
- 3957                                             END; .)
- 3958      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
- 3959      (. astNode := AST.MakeNode(AST.NkCall);
- 3960     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ADR"));
- 3961     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3962     astCur := astNode; astIsLit := TRUE; .)
- 3963                                          (. IF dt = SymTab.InvalidType THEN
- 3964                                               t := SymTab.InvalidType;
- 3965                                               QbeGen.CopyOp("0", q)
- 3966                                             ELSE
- 3967                                                IF sfx
- 3968                                                   OR (dk = SymTab.KindVar)
- 3969                                                   OR (dk = SymTab.KindParam) THEN
- 3970                                                  QbeGen.CopyOp("@", q)
- 3971                                                ELSE SemError(230);
- 3972                                                  QbeGen.CopyOp("0", q)
- 3973                                                END;
- 3974                                               t := SymTab.AddrType()
- 3975                                             END; .)
- 3976      | "CHR" "(" Expr<et, q> ")"
- 3977      (. astNode := AST.MakeNode(AST.NkCall);
- 3978     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR"));
- 3979     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3980     astCur := astNode; astIsLit := TRUE; .)
- 3981                                          (. IF (et # SymTab.InvalidType)
- 3982   AND NOT SymTab.IsIntFamily(et) THEN
- 3983                                               SemError(211) END;
- 3984                                             t := SymTab.CharType(); .)
- 3985      | "ORD" "(" Expr<et, q> ")"
- 3986      (. astNode := AST.MakeNode(AST.NkCall);
- 3987     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ORD"));
- 3988     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 3989     astCur := astNode; astIsLit := TRUE; .)
- 3990                                          (. IF et # SymTab.InvalidType THEN
- 3991                                               IF (SymTab.ClassOf(et) #
- 3992                                                   SymTab.ClChar)
- 3993   AND (SymTab.ClassOf(et) #
- 3994                                                     SymTab.ClBool)
- 3995   AND (SymTab.ClassOf(et) #
- 3996                                                     SymTab.ClEnum)
- 3997   AND NOT SymTab.IsIntFamily(et) THEN
- 3998                                                 SemError(211) END
- 3999                                             END;
- 4000                                             t := SymTab.IntType(); .)
- 4001      | "CAP" "(" Expr<et, q> ")"
- 4002      (. astNode := AST.MakeNode(AST.NkCall);
- 4003     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CAP"));
- 4004     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 4005     astCur := astNode; astIsLit := TRUE; .)
- 4006                                           (. IF QbeGen.IsImm(q)
- 4007    AND SymTab.ConstInt(q, lo) THEN
- 4008       IF (lo >= VAL(INTEGER, ORD("a"))) AND (lo <= VAL(INTEGER, ORD("z"))) THEN lo := lo - 32 END;
- 4009       QbeGen.IntStr(lo, q)
- 4010     ELSE QbeGen.CopyOp("@", q)
- 4011     END;
- 4012     t := SymTab.CharType(); .)
- 4013      | "UCHR" "(" Expr<et, q> ")"
- 4014      (. astNode := AST.MakeNode(AST.NkCall);
- 4015     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UCHR"));
- 4016     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 4017     astCur := astNode; astIsLit := TRUE; .)
- 4018                                          (. (* UCHR: the UCHAR constructor.
- 4019                                                CHAR -> UCHAR (identity);
- 4020                                                INTEGER familly -> UCHAR
- 4021                                                (codepoint value). *)
- 4022                                             IF (et # SymTab.InvalidType)
- 4023    AND (SymTab.ClassOf(et) # SymTab.ClChar)
- 4024    AND NOT SymTab.IsIntFamily(et) THEN
+ 3250                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 3251    AND (SymTab.ClassOf(it) # SymTab.ClChar)
+ 3252    AND (SymTab.ClassOf(it) # SymTab.ClEnum)
+ 3253    AND (SymTab.ClassOf(it) # SymTab.ClBool) THEN
+ 3254                                               SemError(218);
+ 3255                                               t := SymTab.InvalidType
+ 3256                                              ELSE
+ 3257                                                eT := SymTab.ArrayElem(t);
+ 3258                                                t := eT; sfx := TRUE
+ 3259                                              END; .)
+ 3260        "]"
+ 3261      | "." GetIdent<fname>
+ 3262                                          (. isM := FALSE;
+ 3263                                             IF AST.Kind(node) # AST.NkDesignator THEN
+ 3264                                               astWrap := AST.MakeNode(
+ 3265                                                 AST.NkDesignator);
+ 3266                                               AST.SetChild(astWrap, 0, node);
+ 3267                                               node := astWrap
+ 3268                                             END;
+ 3269                                             AST.SetChild(node, AST.NChild(node),
+ 3270                                               AST.MakeUn(AST.NkSelector,
+ 3271                                                 AST.SelField,
+ 3272                                                 AST.MakeLeaf(AST.NkIdent,
+ 3273                                                   fname))); IF t = SymTab.InvalidType THEN
+ 3274                                             ELSIF (SymTab.ClassOf(t) #
+ 3275                                                    SymTab.ClRecord)
+ 3276    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
+ 3277                                               SemError(215);
+ 3278                                               t := SymTab.InvalidType
+ 3279                                              ELSIF (SymTab.ClassOf(t) =
+ 3280                                                     SymTab.ClClass)
+ 3281    AND SymTab.MethodExists(t, fname) THEN
+ 3282                                                (* a method on the call result:
+ 3283                                                   a following ArgList makes
+ 3284                                                   the call *)
+ 3285                                                mname := fname;
+ 3286                                                methCls := t; isM := TRUE;
+ 3287                                                t := SymTab.InvalidType
+ 3288                                             ELSIF NOT SymTab.FieldExists(t,
+ 3289                                                      fname) THEN
+ 3290                                               SemError(216);
+ 3291                                               t := SymTab.InvalidType
+ 3292                                              ELSE
+ 3293                                                t := SymTab.FieldType(t, fname);
+ 3294                                                sfx := TRUE
+ 3295                                              END; .)
+ 3296      | "^"                               (. isM := FALSE;
+ 3297                                             IF AST.Kind(node) # AST.NkDesignator THEN
+ 3298                                               astWrap := AST.MakeNode(
+ 3299                                                 AST.NkDesignator);
+ 3300                                               AST.SetChild(astWrap, 0, node);
+ 3301                                               node := astWrap
+ 3302                                             END;
+ 3303                                             astSel := AST.MakeNode(AST.NkSelector);
+ 3304                                             AST.SetOp(astSel, AST.SelDeref);
+ 3305                                             AST.SetChild(node,
+ 3306                                               AST.NChild(node), astSel); IF t = SymTab.InvalidType THEN
+ 3307                                             ELSIF SymTab.ClassOf(t) #
+ 3308                                                   SymTab.ClPtr THEN
+ 3309                                               SemError(219);
+ 3310                                               t := SymTab.InvalidType
+ 3311                                             ELSE
+ 3312                                               bt := SymTab.PtrBase(t);
+ 3313                                               IF bt # SymTab.InvalidType THEN
+ 3314                                                  t := bt; sfx := TRUE
+ 3315                                               END
+ 3316                                             END; .) .
+ 3317    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3318                                          (. VAR t2: SymTab.TypeIndex;
+ 3319                                               op: INTEGER;
+ 3320                                               q2, qt, wl: QbeGen.QVal;
+ 3321                                                astA, astB: AST.Node;
+ 3322                                                astOp: INTEGER;
+ 3323                                                astMade: BOOLEAN;
+ 3324                                               isR: BOOLEAN;
+ 3325                                               v1, v2: INTEGER;
+ 3326                                               b: BOOLEAN; .)
+ 3327      = SimExpr<t, q>                     (. astA := astCur; astMade := FALSE; .)
+ 3328        [ Rel<op> SimExpr<t2, q2>
+ 3329          (. astB := astCur; astMade := TRUE;
+ 3330              astOp := AST.OpEq;
+ 3331              IF op = SymTab.OpNeq1 THEN astOp := AST.OpNe
+ 3332              ELSIF op = SymTab.OpNeq2 THEN astOp := AST.OpNe
+ 3333              ELSIF op = SymTab.OpLt THEN astOp := AST.OpLt
+ 3334              ELSIF op = SymTab.OpLe THEN astOp := AST.OpLe
+ 3335              ELSIF op = SymTab.OpGt THEN astOp := AST.OpGt
+ 3336              ELSIF op = SymTab.OpGe THEN astOp := AST.OpGe
+ 3337              ELSIF op = SymTab.OpIn THEN astOp := AST.OpIn
+ 3338              END;
+ 3339              IF op = SymTab.OpIn THEN
+ 3340               IF SymTab.InCheck(t, t2) THEN
+ 3341                 IF (t = SymTab.InvalidType)
+ 3342                    OR (t2 = SymTab.InvalidType) THEN
+ 3343                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 3344                 ELSE
+ 3345                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 3346                 END
+ 3347               ELSE SemError(222); t := SymTab.InvalidType;
+ 3348                 QbeGen.CopyOp("0", q)
+ 3349               END
+ 3350             ELSIF SymTab.RelCheck(t, t2, op) THEN
+ 3351               IF (t = SymTab.InvalidType)
+ 3352                  OR (t2 = SymTab.InvalidType) THEN
+ 3353                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 3354               ELSIF SymTab.IsOrdinal(t) AND SymTab.IsOrdinal(t2)
+ 3355                  AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2)
+ 3356                  AND SymTab.ConstInt(q, v1)
+ 3357                  AND SymTab.ConstInt(q2, v2) THEN
+ 3358                 (* fold a relation of two ordinal constants (needed for
+ 3359                    ORD(boolean) in a CONST initialiser) *)
+ 3360                 IF op = SymTab.OpEq THEN b := v1 = v2
+ 3361                 ELSIF (op = SymTab.OpNeq1) OR (op = SymTab.OpNeq2) THEN
+ 3362                   b := v1 # v2
+ 3363                 ELSIF op = SymTab.OpLt THEN b := v1 < v2
+ 3364                 ELSIF op = SymTab.OpLe THEN b := v1 <= v2
+ 3365                 ELSIF op = SymTab.OpGt THEN b := v1 > v2
+ 3366                 ELSE b := v1 >= v2
+ 3367                 END;
+ 3368                 t := SymTab.BoolType();
+ 3369                 IF b THEN QbeGen.CopyOp("1", q)
+ 3370                 ELSE QbeGen.CopyOp("0", q)
+ 3371                 END
+ 3372               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
+ 3373                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
+ 3374                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
+ 3375   AND (op # SymTab.OpNeq2) THEN
+ 3376                   SemError(213); t := SymTab.InvalidType;
+ 3377                   QbeGen.CopyOp("0", q)
+ 3378                  ELSE
+ 3379                    t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 3380                  END
+ 3381                ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
+ 3382                   OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 3383                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 3384               ELSIF SymTab.StrCompat(t, t2) THEN
+ 3385                 QbeGen.StrEq(op, q, q2, qt);
+ 3386                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 3387               ELSIF SymTab.IsLongFamily(t)
+ 3388                  OR SymTab.IsLongFamily(t2) THEN
+ 3389                  t := SymTab.BoolType(); QbeGen.CopyOp("@", q)
+ 3390                ELSE
+ 3391                  t := SymTab.BoolType();
+ 3392                  QbeGen.CopyOp("@", q)
+ 3393                END
+ 3394             ELSE SemError(213); t := SymTab.InvalidType;
+ 3395                QbeGen.CopyOp("0", q)
+ 3396              END;
+ 3397              astCur := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB); .) ]
+ 3398         (. IF NOT astMade THEN astCur := astA END; .)
+ 3399             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 3400    Rel<VAR op: INTEGER>
+ 3401      = "="                               (. op := SymTab.OpEq; .)
+ 3402      | "#"                               (. op := SymTab.OpNeq1; .)
+ 3403      | "<"                               (. op := SymTab.OpLt; .)
+ 3404      | "<="                              (. op := SymTab.OpLe; .)
+ 3405      | ">"                               (. op := SymTab.OpGt; .)
+ 3406      | ">="                              (. op := SymTab.OpGe; .)
+ 3407      | "IN"                              (. op := SymTab.OpIn; .) .
+ 3408    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3409                                          (. VAR t2, res2, lt, rt:
+ 3410                                                 SymTab.TypeIndex;
+ 3411                                               op: INTEGER;
+ 3412                                               q2, qt, wq, qf, q2a, q2b:
+ 3413                                                 QbeGen.QVal;
+ 3414                                               neg, isR, isL, folded:
+ 3415                                                 BOOLEAN;
+ 3416                                               fok: BOOLEAN;
+ 3417                                               lw, rw, mw: CARDINAL;
+ 3418                                               lTrue, lNext, lDone, qr, qs: QbeGen.QVal;
+ 3419                                                astA, astB: AST.Node;
+ 3420                                                astSign, astOp: INTEGER;
+ 3421                                                v1, v2: INTEGER;
+ 3422                                                s: ARRAY [0 .. 255] OF CHAR; .)
+ 3423      =                                   (. neg := FALSE; astSign := 0; .)
+ 3424        [ "+"                         (. neg := TRUE; astSign := 1; .)
+ 3425        | "-"                         (. neg := TRUE; astSign := -1; .) ]
+ 3426        Term<t, q> (. astA := astCur;
+ 3427                                            IF neg AND QbeGen.IsImm(q) THEN
+ 3428                                              QbeGen.NegFold(q, q)
+ 3429                                            END;
+ 3430                                           IF astSign < 0 THEN
+ 3431                                             astCur := AST.MakeUn(
+ 3432                                               AST.NkUnary, AST.OpSub, astA);
+ 3433                                             astA := astCur
+ 3434                                           END; .)
+ 3435         { AddOp<op>
+ 3436           Term<t2, q2> (. astB := astCur; .)
+ 3437          (. astOp := AST.OpAdd;
+ 3438             IF op = SymTab.OpSub THEN astOp := AST.OpSub
+ 3439             ELSIF op = SymTab.OpOr THEN astOp := AST.OpOr END;
+ 3440             astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
+ 3441             astCur := astA;
+ 3442             IF op = SymTab.OpOr THEN
+ 3443               (* short-circuit: if q is true the RHS is skipped *)
+ 3444               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 3445                 t := SymTab.BoolType()
+ 3446               ELSE SemError(212); t := SymTab.InvalidType END;
+ 3447                IF t # SymTab.InvalidType THEN
+ 3448                  QbeGen.CopyOp("@", q)
+ 3449                ELSE QbeGen.CopyOp("0", q)
+ 3450                END
+ 3451             ELSIF (op = SymTab.OpAdd)
+ 3452               AND (SymTab.ClassOf(t) = SymTab.ClChar)
+ 3453               AND (SymTab.ClassOf(t2) = SymTab.ClChar)
+ 3454               AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 3455               (* "W" + "o": two one-character string literals concatenate
+ 3456                  to a two-character string (they are CHAR-typed immediates) *)
+ 3457               IF SymTab.ConstInt(q, v1) AND SymTab.ConstInt(q2, v2)
+ 3458                  AND (v1 >= 0) AND (v1 <= 255)
+ 3459                  AND (v2 >= 0) AND (v2 <= 255) THEN
+ 3460                 s[0] := '"'; s[1] := CHR(v1); s[2] := CHR(v2);
+ 3461                 s[3] := '"'; s[4] := CHR(0);
+ 3462                 QbeGen.DeclStr(s, qt); QbeGen.CopyOp(qt, q);
+ 3463                 t := SymTab.NewStr();
+ 3464                 astA := AST.MakeLeaf(AST.NkStrLit, s);
+ 3465                 astCur := astA
+ 3466               ELSE SemError(211); t := SymTab.InvalidType;
+ 3467                 QbeGen.CopyOp("0", q)
+ 3468               END
+ 3469             ELSIF (op = SymTab.OpAdd)
+ 3470               AND (SymTab.UStrCompat(t, t2)
+ 3471                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
+ 3472                   AND (SymTab.ClassOf(t2) = SymTab.ClUStr))
+ 3473                 OR ((SymTab.ClassOf(t) = SymTab.ClUStr)
+ 3474                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))
+ 3475                 OR ((SymTab.ClassOf(t) = SymTab.ClUChar)
+ 3476                   AND (SymTab.ClassOf(t2) = SymTab.ClUChar))) THEN
+ 3477               (* UString concatenation: a UCHAR operand becomes a
+ 3478                  1-codepoint UString; the result is a descriptor in the
+ 3479                  shim's concat buffer.  Work on copies so neither
+ 3480                  operand is clobbered. *)
+ 3481                t := SymTab.NewUStr();
+ 3482                QbeGen.CopyOp("@", q)
+ 3483             ELSIF (op = SymTab.OpAdd)
+ 3484               AND (SymTab.StrCompat(t, t2)
+ 3485                 OR (SymTab.IsStrType(t)
+ 3486                   AND (SymTab.ClassOf(t2) = SymTab.ClChar))
+ 3487                 OR ((SymTab.ClassOf(t) = SymTab.ClChar)
+ 3488                   AND SymTab.IsStrType(t2))) THEN
+ 3489               (* string concatenation; a CHAR operand becomes a
+ 3490                  1-character string literal.  When both operands are
+ 3491                  constants, fold to a single string literal so a
+ 3492                  constructor element stays compile-time. *)
+ 3493                QbeGen.StrFold(q, q2, SymTab.ClassOf(t), SymTab.ClassOf(t2),
+ 3494                  qt, fok);
+ 3495                IF fok THEN QbeGen.CopyOp(qt, q)
+ 3496                ELSE QbeGen.CopyOp("@", q)
+ 3497                END;
+ 3498                t := SymTab.NewStr()
+ 3499             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 3500   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 3501   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 3502                lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 3503                mw := lw;
+ 3504                IF rw > mw THEN mw := rw END;
+ 3505                t := SymTab.NewSet(
+ 3506                       SymTab.NewSubR(0,
+ 3507                         VAL(INTEGER, mw) * 32 - 1));
+ 3508                QbeGen.CopyOp("@", q)
+ 3509             ELSE
+ 3510               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
+ 3511                 lt := t; rt := t2; t := res2
+ 3512               ELSE SemError(211); t := SymTab.InvalidType END;
+ 3513               IF t # SymTab.InvalidType THEN
+ 3514                 isL := SymTab.IsLongFamily(t);
+ 3515                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 3516                 folded := FALSE;
+ 3517                 IF (NOT isL) AND (NOT isR)
+ 3518    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 3519                   IF op = SymTab.OpAdd THEN
+ 3520                     folded := QbeGen.Fold2(0, q, q2, qf)
+ 3521                   ELSE
+ 3522                     folded := QbeGen.Fold2(1, q, q2, qf)
+ 3523                   END
+ 3524                 END;
+ 3525                 IF folded THEN QbeGen.CopyOp(qf, q)
+ 3526                  ELSE
+ 3527                  QbeGen.CopyOp("@", q)
+ 3528                  END
+ 3529               ELSE QbeGen.CopyOp("0", q)
+ 3530               END
+ 3531             END; .) }
+ 3532             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 3533    AddOp<VAR op: INTEGER>
+ 3534      = "+"                               (. op := SymTab.OpAdd; .)
+ 3535      | "-"                               (. op := SymTab.OpSub; .)
+ 3536      | "OR"                              (. op := SymTab.OpOr; .) .
+ 3537    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3538                                          (. VAR t2, res2, lt, rt:
+ 3539                                                 SymTab.TypeIndex;
+ 3540                                               op: INTEGER;
+ 3541                                               q2, qt, wq, qf:
+ 3542                                                 QbeGen.QVal;
+ 3543                                               isR, isL, folded: BOOLEAN;
+ 3544                                               lw, rw, mw: CARDINAL;
+ 3545                                               lNext, lFalse, lDone, qr, qs: QbeGen.QVal;
+ 3546                                                astA, astB: AST.Node;
+ 3547                                                astOp: INTEGER; .)
+ 3548      = Fact<t, q> (. astA := astCur; .) { MulOp<op>
+ 3549          Fact<t2, q2> (. astB := astCur; .)
+ 3550        (. astOp := AST.OpMul;
+ 3551           IF op = SymTab.OpSlash THEN astOp := AST.OpDiv
+ 3552           ELSIF op = SymTab.OpDiv THEN astOp := AST.OpDiv
+ 3553           ELSIF op = SymTab.OpMod THEN astOp := AST.OpMod
+ 3554           ELSIF op = SymTab.OpAnd THEN astOp := AST.OpAnd END;
+ 3555           astA := AST.MakeBin(AST.NkBinExpr, astOp, astA, astB);
+ 3556           astCur := astA;
+ 3557           IF op = SymTab.OpAnd THEN
+ 3558             (* short-circuit: if q is false the RHS is skipped *)
+ 3559             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 3560               t := SymTab.BoolType()
+ 3561             ELSE SemError(212); t := SymTab.InvalidType END;
+ 3562              IF t # SymTab.InvalidType THEN QbeGen.CopyOp("@", q)
+ 3563              ELSE QbeGen.CopyOp("0", q)
+ 3564              END
+ 3565           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 3566   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 3567   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 3568              lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 3569              mw := lw;
+ 3570              IF rw > mw THEN mw := rw END;
+ 3571              t := SymTab.NewSet(
+ 3572                     SymTab.NewSubR(0,
+ 3573                       VAL(INTEGER, mw) * 32 - 1));
+ 3574              QbeGen.CopyOp("@", q)
+ 3575           ELSE
+ 3576             IF SymTab.ArithCheck(t, t2,
+ 3577                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
+ 3578                  res2) THEN
+ 3579               lt := t; rt := t2; t := res2
+ 3580             ELSE SemError(211); t := SymTab.InvalidType END;
+ 3581             IF t # SymTab.InvalidType THEN
+ 3582               isL := SymTab.IsLongFamily(t);
+ 3583               isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 3584               folded := FALSE;
+ 3585               IF (NOT isL) AND (NOT isR)
+ 3586    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 3587                 IF op = SymTab.OpTimes THEN
+ 3588                   folded := QbeGen.Fold2(2, q, q2, qf)
+ 3589                 ELSIF op = SymTab.OpDiv THEN
+ 3590                   folded := QbeGen.Fold2(3, q, q2, qf)
+ 3591                 ELSIF op = SymTab.OpMod THEN
+ 3592                   folded := QbeGen.Fold2(4, q, q2, qf)
+ 3593                 END
+ 3594               END;
+ 3595               IF folded THEN QbeGen.CopyOp(qf, q)
+ 3596                ELSE
+ 3597                QbeGen.CopyOp("@", q)
+ 3598                END
+ 3599             ELSE QbeGen.CopyOp("0", q)
+ 3600             END
+ 3601           END; .) }
+ 3602             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 3603    MulOp<VAR op: INTEGER>
+ 3604      = "*"                               (. op := SymTab.OpTimes; .)
+ 3605      | "/"                               (. op := SymTab.OpSlash; .)
+ 3606      | "DIV"                             (. op := SymTab.OpDiv; .)
+ 3607      | "MOD"                             (. op := SymTab.OpMod; .)
+ 3608      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
+ 3609    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 3610                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
+ 3611                                               et, dt, t2, st, ct2, et2:
+ 3612                                                 SymTab.TypeIndex;
+ 3613                                               dk: INTEGER;
+ 3614                                               qd, q2, sq, qa, qm0, qr, qt:
+ 3615                                                 QbeGen.QVal;
+ 3616                                               qn, vn: SymTab.Name;
+ 3617                                               vt: SymTab.TypeIndex;
+ 3618                                               c1, c2: INTEGER;
+ 3619                                               lo, hi: INTEGER;
+ 3620                                               isMax: BOOLEAN;
+ 3621                                               called, isHigh, sfx, isCh,
+ 3622                                               isU, uok, isStr: BOOLEAN;
+ 3623                                               ucp: INTEGER; astIsLit: BOOLEAN;
+ 3624                                                astD: AST.Node;
+ 3625                                                astCall: BOOLEAN;
+ 3626                                                astNode, astNot: AST.Node;
+ 3627                                                j: CARDINAL;
+ 3628                                                astArg2: AST.Node;
+ 3629                                                astBrace: AST.Node;
+ 3630                                                astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN;
+ 3631                                                isConvF: BOOLEAN;
+ 3632                                                fi, fj: CARDINAL; .)
+ 3633      = (. astIsLit := FALSE; .)
+ 3634      ( "__LINE__"                        (. QbeGen.IntStr(M2S.line, q);
+ 3635                                             astIsLit := TRUE;
+ 3636                                             astCur := AST.MakeLeaf(
+ 3637                                               AST.NkIntLit, q);
+ 3638                                             t := SymTab.IntType(); .)
+ 3639      | "__FUNCTION__"                    (. (* fold to the current procedure
+ 3640                                                (module name at unit level) *)
+ 3641                                             s[0] := '"'; fi := 1; fj := 0;
+ 3642                                             IF curFun[0] = CHR(0) THEN
+ 3643                                               WHILE (unitName[fj] # CHR(0))
+ 3644                                                 AND (fi < HIGH(s)) DO
+ 3645                                                 s[fi] := unitName[fj];
+ 3646                                                 INC(fi); INC(fj)
+ 3647                                               END
+ 3648                                             ELSE
+ 3649                                               WHILE (curFun[fj] # CHR(0))
+ 3650                                                 AND (fi < HIGH(s)) DO
+ 3651                                                 s[fi] := curFun[fj];
+ 3652                                                 INC(fi); INC(fj)
+ 3653                                               END
+ 3654                                             END;
+ 3655                                             s[fi] := '"';
+ 3656                                             s[fi + 1] := CHR(0);
+ 3657                                             astIsLit := TRUE;
+ 3658                                             astCur := AST.MakeLeaf(
+ 3659                                               AST.NkStrLit, s);
+ 3660                                             t := SymTab.NewStr();
+ 3661                                             QbeGen.DeclStr(s, q); .)
+ 3662      | "__FILE__"                        (. (* fold to the quoted file name *)
+ 3663                                             s[0] := '"'; fi := 1; fj := 0;
+ 3664                                             WHILE (M2S.fileName[fj] # CHR(0))
+ 3665                                               AND (fi < HIGH(s)) DO
+ 3666                                               s[fi] := M2S.fileName[fj];
+ 3667                                               INC(fi); INC(fj)
+ 3668                                             END;
+ 3669                                             s[fi] := '"';
+ 3670                                             s[fi + 1] := CHR(0);
+ 3671                                             astIsLit := TRUE;
+ 3672                                             astCur := AST.MakeLeaf(
+ 3673                                               AST.NkStrLit, s);
+ 3674                                             t := SymTab.NewStr();
+ 3675                                             QbeGen.DeclStr(s, q); .)
+ 3676      | integer                           (. LexString(s);
+ 3677                                             QbeGen.NormInt(s, q); astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s);
+ 3678                                             t := SymTab.IntType(); .)
+ 3679      | charConst                         (. LexString(s);
+ 3680                                             QbeGen.NormLit(s, q, isCh);
+ 3681                                             astIsLit := TRUE;
+ 3682                                             astCur := AST.MakeLeaf(
+ 3683                                               AST.NkCharLit, s);
+ 3684                                             t := SymTab.CharType(); .)
+ 3685      | real                              (. LexString(s);
+ 3686                                             QbeGen.NormReal(s, q);
+ 3687                                             astIsLit := TRUE;
+ 3688                                             astCur := AST.MakeLeaf(
+ 3689                                               AST.NkRealLit, s);
+ 3690                                             t := SymTab.RealType(); .)
+ 3691      | string                            (. LexString(s);
+ 3692                                             astIsLit := TRUE;
+ 3693                                             astCur := AST.MakeLeaf(
+ 3694                                               AST.NkStrLit, s);
+ 3695                                             IF SymTab.StrLen(s) = 3 THEN
+ 3696                                               t := SymTab.CharType();
+ 3697                                               QbeGen.IntStr(
+ 3698                                                 QbeGen.CharVal(s), q)
+ 3699                                             ELSIF SymTab.StrLen(s) = 2 THEN
+ 3700                                               (* empty string: a string value
+ 3701                                                  for arrays, 0 for CHAR *)
+ 3702                                               t := SymTab.NewEmptyStr();
+ 3703                                               QbeGen.DeclStr(s, q)
+ 3704                                             ELSE t := SymTab.NewStr();
+ 3705                                               QbeGen.DeclStr(s, q);
+ 3706                                               (* a literal's value IS its
+ 3707                                                  static descriptor address *)
+ 3708                                             END; .)
+ 3709      | ustring                           (. LexString(s);
+ 3710                                             astIsLit := TRUE;
+ 3711                                             astCur := AST.MakeLeaf(
+ 3712                                               AST.NkStrLit, s);
+ 3713                                             QbeGen.DeclUStr(s, q, isU, ucp,
+ 3714                                               uok);
+ 3715                                             IF NOT uok THEN
+ 3716                                               SemError(234);
+ 3717                                               t := SymTab.InvalidType
+ 3718                                             ELSIF isU THEN
+ 3719                                               t := SymTab.UCharType();
+ 3720                                               QbeGen.IntStr(ucp, q)
+ 3721                                             ELSE
+ 3722                                               t := SymTab.NewUStr();
+ 3723                                             END; .)
+ 3724      | Design<dt, dk, qd, qn, sfx>       (. astD := astCur; astCall := FALSE; astBrace := AST.NoNode;
+ 3725                                             astNArgs := 0; called := FALSE;
+ 3726                                             t := dt;
+ 3727                                             IF dk = SymTab.KindConst THEN
+ 3728                                               QbeGen.CopyOp(qd, q)
+ 3729                                             ELSE QbeGen.CopyOp("@", q)
+ 3730                                             END; .)
+ 3731        [ TypedBraceLit<dt, q>            (. t := dt; astCall := TRUE;
+ 3732                                               astBrace := astCur; .) ]
+ 3733        [ ArgList<qn, dt, qd, TRUE, FALSE, methCls, ct2, q2, called>
+ 3734                                          (. astCall := TRUE;
+ 3735                                             IF (SymTab.SymKind(qn) = SymTab.KindType)
+ 3736    OR (SymTab.SymKind(qn) = SymTab.KindPredef) THEN
+ 3737                                             (* T(x): emit as the VAL builtin so Lower's
+ 3738                                                conversion rules apply unchanged *)
+ 3739                                             astNode := AST.MakeNode(AST.NkCall);
+ 3740                                             AST.SetChild(astNode, 0,
+ 3741                                               AST.MakeLeaf(AST.NkIdent, "VAL"));
+ 3742                                             AST.SetChild(astNode, 1,
+ 3743                                               AST.MakeLeaf(AST.NkIdent, qn));
+ 3744                                             IF astNArgs = 1 THEN
+ 3745                                               AST.SetChild(astNode, 2, astArgs[0])
+ 3746                                             END;
+ 3747                                             isConvF := TRUE
+ 3748                                             ELSE astNode := AstCallNode(astD)
+ 3749                                             END;
+ 3750                                             astRes := astNode;
+ 3751                                             t := ct2;
+ 3752                                             QbeGen.CopyOp(q2, q);
+ 3753                                             IF isConvF AND QbeGen.IsImm(convQ)
+ 3754                                                AND OrdClass(convT) AND OrdClass(ct2) THEN
+ 3755                                               QbeGen.CopyOp(convQ, q)
+ 3756                                             END;
+ 3757                                             sfx := FALSE; .)
+ 3758          { ResultComp<t, q, sfx, astRes, mname, methCls, isM>
+ 3759            [ (. astNArgs := 0; .)
+ 3760              ArgList<mname, t, q, TRUE, FALSE, methCls, ct2, q2, called>
+ 3761                                          (. astNode := AstCallNode(astRes);
+ 3762                                             astRes := astNode;
+ 3763                                             t := ct2;
+ 3764                                             QbeGen.CopyOp(q2, q);
+ 3765                                             sfx := FALSE; .) ] }
+ 3766                                          (. IF sfx THEN
+ 3767                                               IF t = SymTab.InvalidType THEN
+ 3768                                                 QbeGen.CopyOp("0", q)
+ 3769                                               ELSIF (SymTab.ClassOf(t) #
+ 3770                                                      SymTab.ClRecord)
+ 3771    AND (SymTab.ClassOf(t) # SymTab.ClSet)
+ 3772    AND (SymTab.ClassOf(t) # SymTab.ClArray)
+ 3773    AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
+ 3774                                                  QbeGen.CopyOp("@", q)
+ 3775                                               END
+ 3776                                             END; .) ]
+ 3777                                          (. IF called THEN
+ 3778                                               astCur := astRes
+ 3779                                             ELSIF astCall THEN
+ 3780                                               astCur := astBrace
+ 3781                                             ELSE astCur := astD
+ 3782                                             END;
+ 3783                                              astIsLit := TRUE;
+ 3784                                              IF NOT called
+ 3785   AND (dk = SymTab.KindProc) THEN
+ 3786                                               (* bare zero-arg function
+ 3787                                                  call (parentheses may be
+ 3788                                                  omitted); a proper or
+ 3789                                                  parameterised proc here
+ 3790                                                  is 230 *)
+ 3791                                                IF (SymTab.ProcNPar(qn) = 0)
+ 3792   AND (SymTab.ProcRes(qn) # SymTab.InvalidType) THEN
+ 3793                                                  t := SymTab.ProcRes(qn);
+ 3794                                                  QbeGen.CopyOp("@", q);
+ 3795                                                  astCur := AST.MakeNode(AST.NkCall);
+ 3796                                                  AST.SetChild(astCur, 0, astD)
+ 3797                                                ELSE
+ 3798                                                  t := SymTab.ProcTypeOf(qn);
+ 3799                                                  QbeGen.CopyOp("@", q)
+ 3800                                                END
+ 3801                                             END; .)
+ 3802      | ( "HIGH"                          (. isHigh := TRUE; .)
+ 3803        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
+ 3804        "(" ( Design<dt, dk, qd, qn, sfx> (. isStr := FALSE;
+ 3805                                              isU := FALSE; .)
+ 3806            | string                       (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
+ 3807                                              isStr := TRUE;
+ 3808                                              isU := FALSE;
+ 3809                                              IF SymTab.StrLen(s) = 3 THEN
+ 3810                                                dt := SymTab.CharType();
+ 3811                                                QbeGen.IntStr(QbeGen.CharVal(s),
+ 3812                                                  qd)
+ 3813                                              ELSE
+ 3814                                                dt := SymTab.NewStr();
+ 3815                                                QbeGen.DeclStr(s, qd);
+ 3816                                              END;
+ 3817                                              dk := -1;
+ 3818                                              qn[0] := CHR(0); .)
+ 3819            | ustring                      (. LexString(s); astCur := AST.MakeLeaf(AST.NkStrLit, s);
+ 3820                                              QbeGen.DeclUStr(s, qd, isU, ucp,
+ 3821                                                uok);
+ 3822                                              isStr := FALSE;
+ 3823                                              IF NOT uok THEN
+ 3824                                                SemError(234);
+ 3825                                                dt := SymTab.InvalidType
+ 3826                                              ELSIF isU THEN
+ 3827                                                (* one codepoint: a UCHAR;
+ 3828                                                   LEN is 1, HIGH is 0 *)
+ 3829                                                dt := SymTab.UCharType();
+ 3830                                                QbeGen.IntStr(ucp, qd)
+ 3831                                              ELSE
+ 3832                                                dt := SymTab.NewUStr();
+ 3833                                              END;
+ 3834                                              dk := -1;
+ 3835                                              qn[0] := CHR(0); .) )
+ 3836        ")"
+ 3837                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 3838     IF isHigh THEN AST.SetChild(astNode, 0,
+ 3839       AST.MakeLeaf(AST.NkIdent, "HIGH"))
+ 3840     ELSE AST.SetChild(astNode, 0,
+ 3841       AST.MakeLeaf(AST.NkIdent, "LEN")) END;
+ 3842     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3843     astCur := astNode; astIsLit := TRUE;
+ 3844                                             IF (dt # SymTab.InvalidType)
+ 3845    AND (SymTab.ClassOf(dt) = SymTab.ClUStr) THEN
+ 3846                                               (* UString: the count is
+ 3847                                                  the descriptor header *)
+ 3848                                                t := SymTab.IntType();
+ 3849                                                QbeGen.CopyOp("@", q)
+ 3850                                             ELSIF (dt # SymTab.InvalidType)
+ 3851    AND (SymTab.ClassOf(dt) = SymTab.ClUChar) THEN
+ 3852                                               (* single UCHAR codepoint *)
+ 3853                                               IF isHigh THEN
+ 3854                                                 QbeGen.CopyOp("0", qr)
+ 3855                                               ELSE
+ 3856                                                 QbeGen.CopyOp("1", qr)
+ 3857                                               END;
+ 3858                                               t := SymTab.IntType();
+ 3859                                               QbeGen.CopyOp(qr, q)
+ 3860                                             ELSIF isStr THEN
+ 3861                                               (* fold: content length at
+ 3862                                                  compile time *)
+ 3863                                               IF SymTab.StrLen(s) = 3 THEN
+ 3864                                                 c1 := 1
+ 3865                                               ELSE
+ 3866                                                 c1 :=
+ 3867                                                   SymTab.StrLen(s) - 2
+ 3868                                               END;
+ 3869                                               IF isHigh THEN
+ 3870                                                 DEC(c1)
+ 3871                                               END;
+ 3872                                               QbeGen.IntStr(c1, qr);
+ 3873                                               t := SymTab.IntType();
+ 3874                                               QbeGen.CopyOp(qr, q)
+ 3875                                             ELSIF dt = SymTab.InvalidType THEN
+ 3876                                               t := SymTab.InvalidType;
+ 3877                                               QbeGen.CopyOp("0", q)
+ 3878                                             ELSIF SymTab.ClassOf(dt) =
+ 3879                                                   SymTab.ClStr THEN
+ 3880                                               (* HIGH/LEN of a string
+ 3881                                                  CONST: its pooled literal
+ 3882                                                  knows its length *)
+ 3883                                               IF QbeGen.StrLitLen(qd, c1) THEN
+ 3884                                                 IF isHigh THEN DEC(c1) END;
+ 3885                                                 QbeGen.IntStr(VAL(INTEGER, c1),
+ 3886                                                   qr);
+ 3887                                                 t := SymTab.IntType();
+ 3888                                                 QbeGen.CopyOp(qr, q)
+ 3889                                               ELSE SemError(217);
+ 3890                                                 t := SymTab.InvalidType;
+ 3891                                                 QbeGen.CopyOp("0", q)
+ 3892                                               END
+ 3893                                             ELSIF SymTab.ClassOf(dt) #
+ 3894                                                   SymTab.ClArray THEN
+ 3895                                               SemError(217);
+ 3896                                               t := SymTab.InvalidType;
+ 3897                                               QbeGen.CopyOp("0", q)
+ 3898                                             ELSE
+ 3899                                                IF SymTab.IsOpenArray(dt) THEN
+ 3900                                                  t := SymTab.IntType();
+ 3901                                                  QbeGen.CopyOp("@", q)
+ 3902                                                ELSE
+ 3903                                                  IF isHigh THEN
+ 3904                                                    QbeGen.IntStr(
+ 3905                                                      SymTab.ArrayHi(dt), qr)
+ 3906                                                  ELSE
+ 3907                                                    QbeGen.IntStr(VAL(
+ 3908                                                      INTEGER,
+ 3909                                                      SymTab.ArrayLen(dt)),
+ 3910                                                      qr)
+ 3911                                                  END;
+ 3912                                                  t := SymTab.IntType();
+ 3913                                                  QbeGen.CopyOp(qr, q)
+ 3914                                                END
+ 3915                                              END; .)
+ 3916      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
+ 3917      (. astNode := AST.MakeNode(AST.NkCall);
+ 3918     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "SIZE"));
+ 3919     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3920     astCur := astNode; astIsLit := TRUE; .)
+ 3921                                          (. IF dt = SymTab.InvalidType THEN
+ 3922                                               t := SymTab.InvalidType;
+ 3923                                               QbeGen.CopyOp("0", q)
+ 3924                                             ELSE
+ 3925                                               QbeGen.IntStr(VAL(INTEGER,
+ 3926                                                 SymTab.ObjectSize(dt)), q);
+ 3927                                               t := SymTab.IntType()
+ 3928                                             END; .)
+ 3929      | ( "SHIFT"                         (. isMax := FALSE; .)
+ 3930        | "ROTATE"                        (. isMax := TRUE; .) )
+ 3931        "(" Expr<et, q> (. astArg2 := astCur; .) "," Expr<et2, q2> ")"
+ 3932                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 3933     IF isMax THEN AST.SetChild(astNode, 0,
+ 3934       AST.MakeLeaf(AST.NkIdent, "ROTATE"))
+ 3935     ELSE AST.SetChild(astNode, 0,
+ 3936       AST.MakeLeaf(AST.NkIdent, "SHIFT")) END;
+ 3937     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
+ 3938     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
+ 3939     astCur := astNode; astIsLit := TRUE;
+ 3940                                             (* set shift/rotate: isMax
+ 3941                                                doubles as "rotate" *)
+ 3942                                             IF (et # SymTab.InvalidType)
+ 3943                                                AND (SymTab.ClassOf(et) =
+ 3944                                                   SymTab.ClSet) THEN
+ 3945                                                t := et;
+ 3946                                                QbeGen.CopyOp("@", q)
+ 3947                                             ELSE SemError(230);
+ 3948                                               t := SymTab.InvalidType;
+ 3949                                               QbeGen.CopyOp("0", q)
+ 3950                                             END; .)
+ 3951      | ( "MIN"                           (. isMax := FALSE; .)
+ 3952        | "MAX"                           (. isMax := TRUE; .) )
+ 3953        "(" Design<dt, dk, qd, qn, sfx> ")"
+ 3954                                          (. astNode := AST.MakeNode(AST.NkCall);
+ 3955     IF isMax THEN AST.SetChild(astNode, 0,
+ 3956       AST.MakeLeaf(AST.NkIdent, "MAX"))
+ 3957     ELSE AST.SetChild(astNode, 0,
+ 3958       AST.MakeLeaf(AST.NkIdent, "MIN")) END;
+ 3959     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 3960     astCur := astNode; astIsLit := TRUE;
+ 3961                                             IF (dt # SymTab.InvalidType)
+ 3962   AND (SymTab.ClassOf(dt) = SymTab.ClReal) THEN
+ 3963                                               (* REAL/LONGREAL: the
+ 3964                                                  implementation bounds *)
+ 3965                                               IF isMax THEN
+ 3966                                                 QbeGen.NormReal(
+ 3967                                                   "3.402823e38", q)
+ 3968                                               ELSE QbeGen.NormReal(
+ 3969                                                   "-3.402823e38", q)
+ 3970                                               END;
+ 3971                                               t := SymTab.RealType()
+ 3972                                             ELSIF (dt #
+ 3973                                                SymTab.InvalidType)
+ 3974   AND (SymTab.ClassOf(dt) =
+ 3975                                                   SymTab.ClLong) THEN
+ 3976                                               IF isMax THEN
+ 3977                                                 QbeGen.CopyOp(
+ 3978                                                   "9223372036854775807", q)
+ 3979                                               ELSE QbeGen.CopyOp(
+ 3980                                                   "-9223372036854775808", q)
+ 3981                                               END;
+ 3982                                               t := SymTab.LongType()
+ 3983                                             ELSIF SymTab.TypeBounds(dt, lo,
+ 3984                                                      hi) THEN
+ 3985                                               IF isMax THEN
+ 3986                                                 QbeGen.IntStr(hi, q)
+ 3987                                               ELSE QbeGen.IntStr(lo, q)
+ 3988                                               END;
+ 3989                                               (* a set's bounds are those
+ 3990                                                  of its base type *)
+ 3991                                               IF SymTab.ClassOf(dt) =
+ 3992                                                  SymTab.ClSet THEN
+ 3993                                                 t := SymTab.SetBase(dt)
+ 3994                                               ELSE t := SymTab.IntType()
+ 3995                                               END
+ 3996                                             ELSE SemError(230);
+ 3997                                               t := SymTab.InvalidType;
+ 3998                                               QbeGen.CopyOp("0", q)
+ 3999                                             END; .)
+ 4000      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 4001      (. astNode := AST.MakeNode(AST.NkCall);
+ 4002     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ADR"));
+ 4003     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 4004     astCur := astNode; astIsLit := TRUE; .)
+ 4005                                          (. IF dt = SymTab.InvalidType THEN
+ 4006                                               t := SymTab.InvalidType;
+ 4007                                               QbeGen.CopyOp("0", q)
+ 4008                                             ELSE
+ 4009                                                IF sfx
+ 4010                                                   OR (dk = SymTab.KindVar)
+ 4011                                                   OR (dk = SymTab.KindParam) THEN
+ 4012                                                  QbeGen.CopyOp("@", q)
+ 4013                                                ELSE SemError(230);
+ 4014                                                  QbeGen.CopyOp("0", q)
+ 4015                                                END;
+ 4016                                               t := SymTab.AddrType()
+ 4017                                             END; .)
+ 4018      | "CHR" "(" Expr<et, q> ")"
+ 4019      (. astNode := AST.MakeNode(AST.NkCall);
+ 4020     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR"));
+ 4021     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 4022     astCur := astNode; astIsLit := TRUE; .)
+ 4023                                          (. IF (et # SymTab.InvalidType)
+ 4024   AND NOT SymTab.IsIntFamily(et) THEN
  4025                                               SemError(211) END;
- 4026                                             t := SymTab.UCharType(); .)
- 4027      | "CHR8" "(" Expr<et, q> ")"
+ 4026                                             t := SymTab.CharType(); .)
+ 4027      | "ORD" "(" Expr<et, q> ")"
  4028      (. astNode := AST.MakeNode(AST.NkCall);
- 4029     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR8"));
+ 4029     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ORD"));
  4030     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
  4031     astCur := astNode; astIsLit := TRUE; .)
- 4032                                          (. IF (et # SymTab.InvalidType)
- 4033    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
- 4034                                               SemError(211) END;
- 4035                                             t := SymTab.CharType(); .)
- 4036      | "UORD" "(" Expr<et, q> ")"
- 4037      (. astNode := AST.MakeNode(AST.NkCall);
- 4038     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UORD"));
- 4039     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 4040     astCur := astNode; astIsLit := TRUE; .)
- 4041                                          (. (* UORD(u): the codepoint as a
- 4042                                                32-bit ordinal (INTEGER),
- 4043                                                cf. ORD for CHAR. *)
- 4044                                             IF (et # SymTab.InvalidType)
- 4045    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
- 4046                                               SemError(211) END;
- 4047                                             t := SymTab.IntType(); .)
- 4048      | "ABS" "(" Expr<et, q> ")"
- 4049      (. astNode := AST.MakeNode(AST.NkCall);
- 4050     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ABS"));
- 4051     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 4052     astCur := astNode; astIsLit := TRUE; .)
- 4053                                          (. IF (et # SymTab.InvalidType)
- 4054   AND NOT SymTab.IsIntFamily(et)
- 4055   AND (SymTab.ClassOf(et) #
- 4056                                                  SymTab.ClReal) THEN
- 4057                                               SemError(211)
- 4058                                              ELSIF QbeGen.IsImm(q)
- 4059    AND SymTab.ConstInt(q, lo) THEN
- 4060                                                IF lo < 0 THEN lo := -lo END;
- 4061                                                QbeGen.IntStr(lo, q)
- 4062                                              ELSE QbeGen.CopyOp("@", q)
- 4063                                             END;
- 4064                                             t := et; .)
- 4065      | "ODD" "(" Expr<et, q> ")"
- 4066      (. astNode := AST.MakeNode(AST.NkCall);
- 4067     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ODD"));
- 4068     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
- 4069     astCur := astNode; astIsLit := TRUE; .)
- 4070                                          (. IF (et # SymTab.InvalidType)
- 4071   AND NOT SymTab.IsIntFamily(et) THEN
- 4072                                               SemError(211) END;
- 4073                                             t := SymTab.BoolType();
- 4074                                             IF QbeGen.IsImm(q)
- 4075    AND SymTab.ConstInt(q, lo) THEN
- 4076                                               IF (lo MOD 2) # 0 THEN
- 4077                                                 QbeGen.CopyOp("1", q)
- 4078                                               ELSE QbeGen.CopyOp("0", q)
- 4079                                               END
- 4080                                             ELSE QbeGen.CopyOp("@", q)
- 4081                                             END; .)
- 4082      | "TRUNC" "(" Expr<et, q> ")"
- 4083      (. (* TRUNC(x): real -> INTEGER, as the VAL builtin *)
- 4084     astNode := AST.MakeNode(AST.NkCall);
- 4085     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
- 4086     AST.SetChild(astNode, 1, AST.MakeLeaf(AST.NkIdent, "INTEGER"));
- 4087     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
- 4088     astCur := astNode; astIsLit := TRUE; .)
- 4089                                          (. t := SymTab.IntType();
- 4090                                             QbeGen.CopyOp("@", q); .)
- 4091      | "FLOAT" "(" Expr<et, q> ")"
- 4092      (. (* FLOAT(i): integer -> REAL, as the VAL builtin *)
- 4093     astNode := AST.MakeNode(AST.NkCall);
- 4094     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
- 4095     AST.SetChild(astNode, 1, AST.MakeLeaf(AST.NkIdent, "REAL"));
- 4096     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
- 4097     astCur := astNode; astIsLit := TRUE; .)
- 4098                                          (. t := SymTab.RealType();
- 4099     IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa); QbeGen.CopyOp(qa, q)
- 4100     ELSE QbeGen.CopyOp("@", q) END; .)
- 4101      | ( "VAL" | "CONVERT" | "CAST" ) "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
- 4102      (. astNode := AST.MakeNode(AST.NkCall);
- 4103     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
- 4104     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
- 4105     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
- 4106     astCur := astNode; astIsLit := TRUE; .)
- 4107                                          (. IF NOT SymTab.Lookup(vn) THEN
- 4108                                               SemError(201);
- 4109                                               t := SymTab.InvalidType
- 4110                                             ELSE vt := SymTab.SymType(vn);
- 4111                                               IF vt = SymTab.InvalidType THEN
- 4112                                                 t := SymTab.InvalidType
- 4113                                               ELSIF et =
- 4114                                                  SymTab.InvalidType THEN
- 4115                                                 t := vt
- 4116                                               ELSE
- 4117                                                 c1 := SymTab.ClassOf(et);
- 4118                                                 c2 := SymTab.ClassOf(vt);
- 4119                                                 IF ((c1 = SymTab.ClInt)
- 4120      OR (c1 = SymTab.ClByte) OR (c1 = SymTab.ClSByte)
- 4121      OR (c1 = SymTab.ClWord16) OR (c1 = SymTab.ClSWord16))
- 4122    AND (c2 = SymTab.ClLong) THEN
- 4123                                                   IF NOT QbeGen.IsImm(q) THEN QbeGen.WidenLong(q, qa); QbeGen.CopyOp(qa, q) END;
- 4124                                                   t := vt
- 4125                                                 ELSIF (c1 = SymTab.ClLong)
- 4126    AND ((c2 = SymTab.ClInt) OR (c2 = SymTab.ClByte)
- 4127      OR (c2 = SymTab.ClSByte) OR (c2 = SymTab.ClWord16)
- 4128      OR (c2 = SymTab.ClSWord16)) THEN
- 4129                                                   IF NOT (QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo)) THEN QbeGen.NarrowLong(q, qa); QbeGen.CopyOp(qa, q) END;
- 4130                                                   t := vt
- 4131                                                 ELSIF ((c1 = SymTab.ClInt)
- 4132      OR (c1 = SymTab.ClByte) OR (c1 = SymTab.ClSByte)
- 4133      OR (c1 = SymTab.ClWord16) OR (c1 = SymTab.ClSWord16))
- 4134    AND (c2 = SymTab.ClReal) THEN
- 4135                                                   IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa) ELSE QbeGen.ConvIR(q, qa) END;
- 4136                                                   QbeGen.CopyOp(qa, q);
- 4137                                                   t := vt
- 4138                                                 ELSIF (c1 = SymTab.ClLong)
- 4139    AND (c2 = SymTab.ClReal) THEN
- 4140                                                   IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa) ELSE QbeGen.ConvLR(q, qa) END;
- 4141                                                   QbeGen.CopyOp(qa, q);
- 4142                                                   t := vt
- 4143                                                 ELSIF (c1 = SymTab.ClReal)
- 4144    AND ((c2 = SymTab.ClInt) OR (c2 = SymTab.ClByte)
- 4145      OR (c2 = SymTab.ClSByte) OR (c2 = SymTab.ClWord16)
- 4146      OR (c2 = SymTab.ClSWord16)) THEN
- 4147                                                   QbeGen.ConvRI(q, qa);
- 4148                                                   QbeGen.CopyOp(qa, q);
- 4149                                                   t := vt
- 4150                                                 ELSIF (c1 = SymTab.ClReal)
- 4151    AND (c2 = SymTab.ClLong) THEN
- 4152                                                   QbeGen.ConvRL(q, qa);
- 4153                                                   QbeGen.CopyOp(qa, q);
- 4154                                                   t := vt
- 4155                                                 ELSIF (c1 = SymTab.ClLong)
- 4156    AND (c2 = SymTab.ClLong) THEN
- 4157                                                   t := vt
- 4158                                                 ELSIF ((c1 = SymTab.ClInt)
- 4159                                                     OR (c1 =
- 4160                                                        SymTab.ClChar)
- 4161                                                     OR (c1 =
- 4162                                                        SymTab.ClBool)
- 4163                                                     OR (c1 =
- 4164                                                        SymTab.ClByte)
- 4165                                                     OR (c1 =
- 4166                                                        SymTab.ClSByte)
- 4167                                                     OR (c1 =
- 4168                                                        SymTab.ClWord16)
- 4169                                                     OR (c1 =
- 4170                                                        SymTab.ClSWord16)
- 4171                                                     OR (c1 =
- 4172                                                        SymTab.ClEnum))
- 4173   AND ((c2 = SymTab.ClInt)
- 4174                                                     OR (c2 =
- 4175                                                        SymTab.ClChar)
- 4176                                                     OR (c2 =
- 4177                                                        SymTab.ClBool)
- 4178                                                     OR (c2 =
- 4179                                                        SymTab.ClByte)
- 4180                                                     OR (c2 =
- 4181                                                        SymTab.ClSByte)
- 4182                                                     OR (c2 =
- 4183                                                        SymTab.ClWord16)
- 4184                                                     OR (c2 =
- 4185                                                        SymTab.ClSWord16)
- 4186                                                     OR (c2 =
- 4187                                                        SymTab.ClEnum)) THEN
- 4188                                                   t := vt
- 4189                                                 ELSIF (c1 = SymTab.ClPtr)
- 4190    AND (c2 = SymTab.ClPtr) THEN
- 4191                                                   t := vt
- 4192                                                 ELSIF ((c1 = SymTab.ClProc)
- 4193    AND (c2 = SymTab.ClProc))
- 4194    OR ((c1 = SymTab.ClProc) AND (c2 = SymTab.ClPtr))
- 4195    OR ((c1 = SymTab.ClPtr) AND (c2 = SymTab.ClProc)) THEN
- 4196                                                   t := vt
- 4197                                                 ELSIF (c1 = SymTab.ClReal)
- 4198   AND (c2 = SymTab.ClReal) THEN
- 4199                                                   t := vt
- 4200                                                 ELSIF ((c1 = SymTab.ClSet) AND (c2 = SymTab.ClInt))
- 4201    OR ((c1 = SymTab.ClInt) AND (c2 = SymTab.ClSet)) THEN
- 4202                                                   (* a set <-> its machine word (BITSET) *)
- 4203                                                   t := vt
- 4204                                                 ELSE SemError(230);
- 4205                                                   t := SymTab.InvalidType
- 4206                                                 END
- 4207                                               END
- 4208                                             END; .)
- 4209      | "(" Expr<et, q> ")"               (. t := et; astIsLit := TRUE; .)
- 4210      | SetLit<st, sq>                    (. astIsLit := TRUE; t := st;
- 4211                                             QbeGen.CopyOp(sq, q); .)
- 4212      | ( "NOT" | "~" ) Fact<t2, q2>      (. astNot := astCur;
- 4213                                             IF SymTab.BoolCheck(t2) THEN
- 4214                                               t := SymTab.BoolType()
- 4215                                             ELSE SemError(212);
- 4216                                               t := SymTab.InvalidType END;
- 4217                                             IF t # SymTab.InvalidType THEN
- 4218                                                QbeGen.CopyOp("@", q)
- 4219                                             ELSE QbeGen.CopyOp("0", q)
- 4220                                             END;
- 4221                                             astIsLit := TRUE;
- 4222                                             astCur := AST.MakeUn(
- 4223                                               AST.NkUnary, AST.OpNot, astNot); .)
- 4224      )
- 4225      (. IF NOT astIsLit THEN astCur := AST.NoNode END; .)
- 4226             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
- 4227    (* Set literals are SET OF [0..255] (8 words); elements validated
- 4228       0..255 statically when foldable (222 otherwise), runtime trap
- 4229       for computed elements. Ranges always lower via SetRange. *)
- 4230    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 4231                                          (. VAR astNode: AST.Node; .)
- 4232      = "{"                               (. t := SymTab.NewSet(
- 4233                                               SymTab.NewSubR(0, 255));
- 4234                                             astNode := AST.MakeNode(AST.NkSetLit);
- 4235                                             QbeGen.NewSetTemp(8, q);
- 4236                                             QbeGen.SetZero(q, 8); .)
- 4237        [ SetElem<t, q, astNode> { "," SetElem<t, q, astNode> } ]
- 4238        "}"                               (. astCur := astNode; .) .
- 4239    (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set)
- 4240       or ArrayName{...} (an array constructor, GNU Modula-2).  The
- 4241       declared type sets the width (set) or element type (array). *)
- 4242    TypedBraceLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 4243                                          (. VAR nw: CARDINAL;
- 4244                                               astNode, astTail: AST.Node;
- 4245                                               savedCls: INTEGER; .)
- 4246      = "{"                               (. savedCls := braceCls;
- 4247                                             astNode := AST.MakeNode(AST.NkBraceLit);
- 4248                                             AST.SetTy(astNode, vt);
- 4249                                             astTail := astNode;
- 4250                                             IF vt = SymTab.InvalidType THEN
- 4251                                               braceCls := -1
- 4252                                             ELSE braceCls :=
- 4253                                                    SymTab.ClassOf(vt)
- 4254                                             END;
- 4255                                             IF braceCls = SymTab.ClSet THEN
- 4256                                               IF vt = SymTab.InvalidType THEN
- 4257                                                 nw := 8
- 4258                                               ELSE nw := SymTab.SetWords(vt);
- 4259                                                 IF nw = 0 THEN nw := 8 END
- 4260                                               END;
- 4261                                               QbeGen.NewSetTemp(nw, q);
- 4262                                               QbeGen.SetZero(q, nw)
- 4263                                             ELSIF (braceCls =
- 4264                                                    SymTab.ClArray)
- 4265                                                OR (braceCls =
- 4266                                                    SymTab.ClRecord)
- 4267                                                OR (braceCls =
- 4268                                                    SymTab.ClClass) THEN
- 4269                                               QbeGen.CtorBegin(vt)
- 4270                                             ELSE
- 4271                                               IF vt # SymTab.InvalidType THEN
- 4272                                                 SemError(230) END;
- 4273                                               braceCls := -1
- 4274                                             END; .)
- 4275        [ BraceElem<vt, q, astNode, astTail>
- 4276          { "," BraceElem<vt, q, astNode, astTail> } ]
- 4277        "}"                               (. IF (braceCls = SymTab.ClArray)
- 4278                                                OR (braceCls =
- 4279                                                   SymTab.ClRecord)
- 4280                                                OR (braceCls =
- 4281                                                   SymTab.ClClass) THEN
- 4282                                               QbeGen.CtorEnd(q)
- 4283                                             ELSIF braceCls # SymTab.ClSet THEN
- 4284                                               QbeGen.CopyOp("0", q)
- 4285                                             END;
- 4286                                             braceCls := savedCls; .)
- 4287                                          (. astCur := astNode; .) .
- 4288    BraceElem<vt: SymTab.TypeIndex; VAR sq: QbeGen.QVal;
- 4289              VAR node, tail: AST.Node>
- 4290                                          (. VAR et, et2: SymTab.TypeIndex;
- 4291                                               qe, q2: QbeGen.QVal;
- 4292                                               v, v2, reps, k: INTEGER;
- 4293                                               elem: SymTab.TypeIndex;
- 4294                                               lo: INTEGER;
- 4295                                               span: CARDINAL;
- 4296                                               cl, cl2: INTEGER;
- 4297                                               hasR, hasB: BOOLEAN;
- 4298                                               astEl: AST.Node; .)
- 4299      =                                   (. hasR := FALSE; hasB := FALSE;
- 4300                                             reps := 1; .)
- 4301        Expr<et, qe> (. astEl := astCur; .)
- 4302        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
- 4303                                               AST.NkSubrange, 0, astEl, astCur);
- 4304                                             hasR := TRUE; .) ]
- 4305        [ "BY" Expr<et2, q2>              (. hasB := TRUE; .) ]
- 4306                                          (. IF braceCls = SymTab.ClSet THEN
- 4307                                               IF hasB THEN SemError(230) END;
- 4308                                               lo := SymTab.SetBaseLo(vt);
- 4309                                               span := SymTab.SetCount(vt);
- 4310                                               IF (et = SymTab.InvalidType)
- 4311                                                  OR (hasR AND (et2 =
- 4312                                                     SymTab.InvalidType)) THEN
- 4313                                               ELSE cl :=
- 4314                                                      SymTab.ClassOf(et);
- 4315                                                 IF hasR THEN
- 4316                                                   cl2 :=
- 4317                                                     SymTab.ClassOf(et2)
- 4318                                                 ELSE cl2 := SymTab.ClInt
- 4319                                                 END;
- 4320                                                 IF NOT SymTab.SetElemClassOk(cl)
- 4321                                                    OR (hasR AND NOT
- 4322                                                       SymTab.SetElemClassOk(cl2))
- 4323                                                 THEN
- 4324                                                   SemError(222)
- 4325                                                 ELSIF hasR
- 4326   AND SymTab.ConstInt(qe, v)
- 4327   AND SymTab.ConstInt(q2,
- 4328                                                       v2)
- 4329   AND ((v < lo)
- 4330                                                       OR (v2 < lo)
- 4331                                                       OR (v >= lo +
- 4332                                                          VAL(INTEGER, span))
- 4333                                                       OR (v2 >= lo +
- 4334                                                          VAL(INTEGER, span))
- 4335                                                       OR (v > v2)) THEN
- 4336                                                   SemError(222)
- 4337                                                  ELSIF hasR THEN
- 4338                                                    QbeGen.SetRange(sq, qe, q2,
- 4339                                                      lo, span)
- 4340                                                  ELSIF SymTab.ConstInt(qe,
- 4341                                                          v)
- 4342   AND ((v < lo)
- 4343                                                        OR (v >= lo +
- 4344                                                           VAL(INTEGER,
- 4345                                                             span))) THEN
- 4346                                                    SemError(222)
- 4347                                                  ELSE QbeGen.SetBit(sq, qe,
- 4348                                                    lo, span)
- 4349                                                 END
- 4350                                               END
- 4351                                             ELSIF (braceCls = SymTab.ClArray)
- 4352                                                OR (braceCls =
- 4353                                                   SymTab.ClRecord)
- 4354                                                OR (braceCls =
- 4355                                                   SymTab.ClClass) THEN
- 4356                                               IF hasR THEN SemError(230) END;
- 4357                                               reps := 1;
- 4358                                               IF hasB THEN
- 4359                                                 IF SymTab.ConstInt(q2, v2)
- 4360   AND (v2 >= 1) THEN
- 4361                                                   reps := v2
- 4362                                                 ELSE SemError(230)
- 4363                                                 END
- 4364                                               END;
- 4365                                               k := 0;
- 4366                                               WHILE k < reps DO
- 4367                                                 QbeGen.CtorElem(qe);
- 4368                                                 INC(k)
- 4369                                               END
- 4370                                             END; .)
- 4371                                          (. (* the BY form repeats the
- 4372                                               element; keep the AST in
- 4373                                               step with CtorElem *)
- 4374                                             k := 0;
- 4375                                             WHILE k < reps DO
- 4376                                               AstAppend(AST.NkBlock,
- 4377                                                 node, tail, astEl);
- 4378                                               INC(k)
- 4379                                             END; .) .
- 4380    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal; node: AST.Node>         (. VAR et, et2: SymTab.TypeIndex;
- 4381                                               qe, q2: QbeGen.QVal;
- 4382                                               v, v2: INTEGER;
- 4383                                               lo: INTEGER;
- 4384                                               span: CARDINAL;
- 4385                                               cl, cl2: INTEGER;
- 4386                                               hasR: BOOLEAN;
- 4387                                               astEl: AST.Node; .)
- 4388      =                                   (. hasR := FALSE; .)
- 4389        Expr<et, qe> (. astEl := astCur; .)
- 4390        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
- 4391                                               AST.NkSubrange, 0, astEl, astCur);
- 4392                                             hasR := TRUE; .) ]
- 4393                                          (. lo := SymTab.SetBaseLo(st);
- 4394                                             span := SymTab.SetCount(st);
- 4395                                             IF (et = SymTab.InvalidType)
- 4396                                                OR (hasR AND (et2 =
- 4397                                                   SymTab.InvalidType)) THEN
- 4398                                             ELSE cl :=
- 4399                                                    SymTab.ClassOf(et);
- 4400                                               IF hasR THEN
- 4401                                                 cl2 :=
- 4402                                                   SymTab.ClassOf(et2)
- 4403                                               ELSE cl2 := SymTab.ClInt
- 4404                                               END;
- 4405                                               IF NOT SymTab.SetElemClassOk(cl)
- 4406                                                  OR (hasR AND NOT
- 4407                                                     SymTab.SetElemClassOk(cl2))
- 4408                                               THEN
- 4409                                                 SemError(222)
- 4410                                               ELSIF hasR
- 4411   AND SymTab.ConstInt(qe, v)
- 4412   AND SymTab.ConstInt(q2,
- 4413                                                     v2)
- 4414   AND ((v < lo)
- 4415                                                     OR (v2 < lo)
- 4416                                                     OR (v >= lo +
- 4417                                                        VAL(INTEGER, span))
- 4418                                                     OR (v2 >= lo +
- 4419                                                        VAL(INTEGER, span))
- 4420                                                     OR (v > v2)) THEN
- 4421                                                 SemError(222)
- 4422                                                ELSIF hasR THEN
- 4423                                                  QbeGen.SetRange(sq, qe, q2,
- 4424                                                    lo, span)
- 4425                                                ELSIF SymTab.ConstInt(qe,
- 4426                                                        v)
- 4427   AND ((v < lo)
- 4428                                                      OR (v >= lo +
- 4429                                                         VAL(INTEGER,
- 4430                                                           span))) THEN
- 4431                                                  SemError(222)
- 4432                                                ELSE QbeGen.SetBit(sq, qe,
- 4433                                                  lo, span)
- 4434                                               END
- 4435                                             END; .)
- 4436                                          (. AST.SetChild(node,
- 4437                                               AST.NChild(node), astEl); .) .
- 4438    GetIdent<VAR n: SymTab.Name>
- 4439      = ident                             (. LexName(n); .) .
- 4440  
- 4441  END M2.
+ 4032                                          (. IF et # SymTab.InvalidType THEN
+ 4033                                               IF (SymTab.ClassOf(et) #
+ 4034                                                   SymTab.ClChar)
+ 4035   AND (SymTab.ClassOf(et) #
+ 4036                                                     SymTab.ClBool)
+ 4037   AND (SymTab.ClassOf(et) #
+ 4038                                                     SymTab.ClEnum)
+ 4039   AND NOT SymTab.IsIntFamily(et)
+ 4040   AND NOT SymTab.IsPackedSet(et) THEN
+ 4041                                                 SemError(211) END
+ 4042                                             END;
+ 4043                                             t := SymTab.IntType(); .)
+ 4044      | "CAP" "(" Expr<et, q> ")"
+ 4045      (. astNode := AST.MakeNode(AST.NkCall);
+ 4046     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CAP"));
+ 4047     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 4048     astCur := astNode; astIsLit := TRUE; .)
+ 4049                                           (. IF QbeGen.IsImm(q)
+ 4050    AND SymTab.ConstInt(q, lo) THEN
+ 4051       IF (lo >= VAL(INTEGER, ORD("a"))) AND (lo <= VAL(INTEGER, ORD("z"))) THEN lo := lo - 32 END;
+ 4052       QbeGen.IntStr(lo, q)
+ 4053     ELSE QbeGen.CopyOp("@", q)
+ 4054     END;
+ 4055     t := SymTab.CharType(); .)
+ 4056      | "UCHR" "(" Expr<et, q> ")"
+ 4057      (. astNode := AST.MakeNode(AST.NkCall);
+ 4058     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UCHR"));
+ 4059     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 4060     astCur := astNode; astIsLit := TRUE; .)
+ 4061                                          (. (* UCHR: the UCHAR constructor.
+ 4062                                                CHAR -> UCHAR (identity);
+ 4063                                                INTEGER familly -> UCHAR
+ 4064                                                (codepoint value). *)
+ 4065                                             IF (et # SymTab.InvalidType)
+ 4066    AND (SymTab.ClassOf(et) # SymTab.ClChar)
+ 4067    AND NOT SymTab.IsIntFamily(et) THEN
+ 4068                                               SemError(211) END;
+ 4069                                             t := SymTab.UCharType(); .)
+ 4070      | "CHR8" "(" Expr<et, q> ")"
+ 4071      (. astNode := AST.MakeNode(AST.NkCall);
+ 4072     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "CHR8"));
+ 4073     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 4074     astCur := astNode; astIsLit := TRUE; .)
+ 4075                                          (. IF (et # SymTab.InvalidType)
+ 4076    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
+ 4077                                               SemError(211) END;
+ 4078                                             t := SymTab.CharType(); .)
+ 4079      | "UORD" "(" Expr<et, q> ")"
+ 4080      (. astNode := AST.MakeNode(AST.NkCall);
+ 4081     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "UORD"));
+ 4082     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 4083     astCur := astNode; astIsLit := TRUE; .)
+ 4084                                          (. (* UORD(u): the codepoint as a
+ 4085                                                32-bit ordinal (INTEGER),
+ 4086                                                cf. ORD for CHAR. *)
+ 4087                                             IF (et # SymTab.InvalidType)
+ 4088    AND (SymTab.ClassOf(et) # SymTab.ClUChar) THEN
+ 4089                                               SemError(211) END;
+ 4090                                             t := SymTab.IntType(); .)
+ 4091      | "ABS" "(" Expr<et, q> ")"
+ 4092      (. astNode := AST.MakeNode(AST.NkCall);
+ 4093     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ABS"));
+ 4094     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 4095     astCur := astNode; astIsLit := TRUE; .)
+ 4096                                          (. IF (et # SymTab.InvalidType)
+ 4097   AND NOT SymTab.IsIntFamily(et)
+ 4098   AND (SymTab.ClassOf(et) #
+ 4099                                                  SymTab.ClReal) THEN
+ 4100                                               SemError(211)
+ 4101                                              ELSIF QbeGen.IsImm(q)
+ 4102    AND SymTab.ConstInt(q, lo) THEN
+ 4103                                                IF lo < 0 THEN lo := -lo END;
+ 4104                                                QbeGen.IntStr(lo, q)
+ 4105                                              ELSE QbeGen.CopyOp("@", q)
+ 4106                                             END;
+ 4107                                             t := et; .)
+ 4108      | "ODD" "(" Expr<et, q> ")"
+ 4109      (. astNode := AST.MakeNode(AST.NkCall);
+ 4110     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "ODD"));
+ 4111     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 1, astCur) END;
+ 4112     astCur := astNode; astIsLit := TRUE; .)
+ 4113                                          (. IF (et # SymTab.InvalidType)
+ 4114   AND NOT SymTab.IsIntFamily(et) THEN
+ 4115                                               SemError(211) END;
+ 4116                                             t := SymTab.BoolType();
+ 4117                                             IF QbeGen.IsImm(q)
+ 4118    AND SymTab.ConstInt(q, lo) THEN
+ 4119                                               IF (lo MOD 2) # 0 THEN
+ 4120                                                 QbeGen.CopyOp("1", q)
+ 4121                                               ELSE QbeGen.CopyOp("0", q)
+ 4122                                               END
+ 4123                                             ELSE QbeGen.CopyOp("@", q)
+ 4124                                             END; .)
+ 4125      | "TRUNC" "(" Expr<et, q> ")"
+ 4126      (. (* TRUNC(x): real -> INTEGER, as the VAL builtin *)
+ 4127     astNode := AST.MakeNode(AST.NkCall);
+ 4128     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
+ 4129     AST.SetChild(astNode, 1, AST.MakeLeaf(AST.NkIdent, "INTEGER"));
+ 4130     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
+ 4131     astCur := astNode; astIsLit := TRUE; .)
+ 4132                                          (. t := SymTab.IntType();
+ 4133                                             QbeGen.CopyOp("@", q); .)
+ 4134      | "FLOAT" "(" Expr<et, q> ")"
+ 4135      (. (* FLOAT(i): integer -> REAL, as the VAL builtin *)
+ 4136     astNode := AST.MakeNode(AST.NkCall);
+ 4137     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
+ 4138     AST.SetChild(astNode, 1, AST.MakeLeaf(AST.NkIdent, "REAL"));
+ 4139     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
+ 4140     astCur := astNode; astIsLit := TRUE; .)
+ 4141                                          (. t := SymTab.RealType();
+ 4142     IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa); QbeGen.CopyOp(qa, q)
+ 4143     ELSE QbeGen.CopyOp("@", q) END; .)
+ 4144      | ( "VAL" | "CONVERT" | "CAST" ) "(" GetIdent<vn> (. astArg2 := AST.MakeLeaf(AST.NkIdent, vn); .) "," Expr<et, q> ")"
+ 4145      (. astNode := AST.MakeNode(AST.NkCall);
+ 4146     AST.SetChild(astNode, 0, AST.MakeLeaf(AST.NkIdent, "VAL"));
+ 4147     IF astArg2 # AST.NoNode THEN AST.SetChild(astNode, 1, astArg2) END;
+ 4148     IF astCur # AST.NoNode THEN AST.SetChild(astNode, 2, astCur) END;
+ 4149     astCur := astNode; astIsLit := TRUE; .)
+ 4150                                          (. IF NOT SymTab.Lookup(vn) THEN
+ 4151                                               SemError(201);
+ 4152                                               t := SymTab.InvalidType
+ 4153                                             ELSE vt := SymTab.SymType(vn);
+ 4154                                               IF vt = SymTab.InvalidType THEN
+ 4155                                                 t := SymTab.InvalidType
+ 4156                                               ELSIF et =
+ 4157                                                  SymTab.InvalidType THEN
+ 4158                                                 t := vt
+ 4159                                               ELSE
+ 4160                                                 c1 := SymTab.ClassOf(et);
+ 4161                                                 c2 := SymTab.ClassOf(vt);
+ 4162                                                 IF ((c1 = SymTab.ClInt)
+ 4163      OR (c1 = SymTab.ClByte) OR (c1 = SymTab.ClSByte)
+ 4164      OR (c1 = SymTab.ClWord16) OR (c1 = SymTab.ClSWord16))
+ 4165    AND (c2 = SymTab.ClLong) THEN
+ 4166                                                   IF NOT QbeGen.IsImm(q) THEN QbeGen.WidenLong(q, qa); QbeGen.CopyOp(qa, q) END;
+ 4167                                                   t := vt
+ 4168                                                 ELSIF (c1 = SymTab.ClLong)
+ 4169    AND ((c2 = SymTab.ClInt) OR (c2 = SymTab.ClByte)
+ 4170      OR (c2 = SymTab.ClSByte) OR (c2 = SymTab.ClWord16)
+ 4171      OR (c2 = SymTab.ClSWord16)) THEN
+ 4172                                                   IF NOT (QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo)) THEN QbeGen.NarrowLong(q, qa); QbeGen.CopyOp(qa, q) END;
+ 4173                                                   t := vt
+ 4174                                                 ELSIF ((c1 = SymTab.ClInt)
+ 4175      OR (c1 = SymTab.ClByte) OR (c1 = SymTab.ClSByte)
+ 4176      OR (c1 = SymTab.ClWord16) OR (c1 = SymTab.ClSWord16))
+ 4177    AND (c2 = SymTab.ClReal) THEN
+ 4178                                                   IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa) ELSE QbeGen.ConvIR(q, qa) END;
+ 4179                                                   QbeGen.CopyOp(qa, q);
+ 4180                                                   t := vt
+ 4181                                                 ELSIF (c1 = SymTab.ClLong)
+ 4182    AND (c2 = SymTab.ClReal) THEN
+ 4183                                                   IF QbeGen.IsImm(q) AND SymTab.ConstInt(q, lo) THEN QbeGen.NormReal(q, qa) ELSE QbeGen.ConvLR(q, qa) END;
+ 4184                                                   QbeGen.CopyOp(qa, q);
+ 4185                                                   t := vt
+ 4186                                                 ELSIF (c1 = SymTab.ClReal)
+ 4187    AND ((c2 = SymTab.ClInt) OR (c2 = SymTab.ClByte)
+ 4188      OR (c2 = SymTab.ClSByte) OR (c2 = SymTab.ClWord16)
+ 4189      OR (c2 = SymTab.ClSWord16)) THEN
+ 4190                                                   QbeGen.ConvRI(q, qa);
+ 4191                                                   QbeGen.CopyOp(qa, q);
+ 4192                                                   t := vt
+ 4193                                                 ELSIF (c1 = SymTab.ClReal)
+ 4194    AND (c2 = SymTab.ClLong) THEN
+ 4195                                                   QbeGen.ConvRL(q, qa);
+ 4196                                                   QbeGen.CopyOp(qa, q);
+ 4197                                                   t := vt
+ 4198                                                 ELSIF (c1 = SymTab.ClLong)
+ 4199    AND (c2 = SymTab.ClLong) THEN
+ 4200                                                   t := vt
+ 4201                                                 ELSIF ((c1 = SymTab.ClInt)
+ 4202                                                     OR (c1 =
+ 4203                                                        SymTab.ClChar)
+ 4204                                                     OR (c1 =
+ 4205                                                        SymTab.ClBool)
+ 4206                                                     OR (c1 =
+ 4207                                                        SymTab.ClByte)
+ 4208                                                     OR (c1 =
+ 4209                                                        SymTab.ClSByte)
+ 4210                                                     OR (c1 =
+ 4211                                                        SymTab.ClWord16)
+ 4212                                                     OR (c1 =
+ 4213                                                        SymTab.ClSWord16)
+ 4214                                                     OR (c1 =
+ 4215                                                        SymTab.ClEnum))
+ 4216   AND ((c2 = SymTab.ClInt)
+ 4217                                                     OR (c2 =
+ 4218                                                        SymTab.ClChar)
+ 4219                                                     OR (c2 =
+ 4220                                                        SymTab.ClBool)
+ 4221                                                     OR (c2 =
+ 4222                                                        SymTab.ClByte)
+ 4223                                                     OR (c2 =
+ 4224                                                        SymTab.ClSByte)
+ 4225                                                     OR (c2 =
+ 4226                                                        SymTab.ClWord16)
+ 4227                                                     OR (c2 =
+ 4228                                                        SymTab.ClSWord16)
+ 4229                                                     OR (c2 =
+ 4230                                                        SymTab.ClEnum)) THEN
+ 4231                                                   t := vt
+ 4232                                                 ELSIF (c1 = SymTab.ClPtr)
+ 4233    AND (c2 = SymTab.ClPtr) THEN
+ 4234                                                   t := vt
+ 4235                                                 ELSIF ((c1 = SymTab.ClProc)
+ 4236    AND (c2 = SymTab.ClProc))
+ 4237    OR ((c1 = SymTab.ClProc) AND (c2 = SymTab.ClPtr))
+ 4238    OR ((c1 = SymTab.ClPtr) AND (c2 = SymTab.ClProc)) THEN
+ 4239                                                   t := vt
+ 4240                                                 ELSIF (c1 = SymTab.ClReal)
+ 4241   AND (c2 = SymTab.ClReal) THEN
+ 4242                                                   t := vt
+ 4243                                                 ELSIF ((c1 = SymTab.ClSet) AND (c2 = SymTab.ClInt))
+ 4244    OR ((c1 = SymTab.ClInt) AND (c2 = SymTab.ClSet)) THEN
+ 4245                                                   (* a set <-> its machine word (BITSET) *)
+ 4246                                                   t := vt
+ 4247                                                 ELSE SemError(230);
+ 4248                                                   t := SymTab.InvalidType
+ 4249                                                 END
+ 4250                                               END
+ 4251                                             END; .)
+ 4252      | "(" Expr<et, q> ")"               (. t := et; astIsLit := TRUE; .)
+ 4253      | SetLit<st, sq>                    (. astIsLit := TRUE; t := st;
+ 4254                                             QbeGen.CopyOp(sq, q); .)
+ 4255      | ( "NOT" | "~" ) Fact<t2, q2>      (. astNot := astCur;
+ 4256                                             IF SymTab.BoolCheck(t2) THEN
+ 4257                                               t := SymTab.BoolType()
+ 4258                                             ELSE SemError(212);
+ 4259                                               t := SymTab.InvalidType END;
+ 4260                                             IF t # SymTab.InvalidType THEN
+ 4261                                                QbeGen.CopyOp("@", q)
+ 4262                                             ELSE QbeGen.CopyOp("0", q)
+ 4263                                             END;
+ 4264                                             astIsLit := TRUE;
+ 4265                                             astCur := AST.MakeUn(
+ 4266                                               AST.NkUnary, AST.OpNot, astNot); .)
+ 4267      )
+ 4268      (. IF NOT astIsLit THEN astCur := AST.NoNode END; .)
+ 4269             (. IF astCur # AST.NoNode THEN AST.SetTy(astCur, t) END; .) .
+ 4270    (* Set literals are SET OF [0..255] (8 words); elements validated
+ 4271       0..255 statically when foldable (222 otherwise), runtime trap
+ 4272       for computed elements. Ranges always lower via SetRange. *)
+ 4273    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 4274                                          (. VAR astNode: AST.Node; .)
+ 4275      = "{"                               (. t := SymTab.NewSet(
+ 4276                                               SymTab.NewSubR(0, 255));
+ 4277                                             astNode := AST.MakeNode(AST.NkSetLit);
+ 4278                                             QbeGen.NewSetTemp(8, q);
+ 4279                                             QbeGen.SetZero(q, 8); .)
+ 4280        [ SetElem<t, q, astNode> { "," SetElem<t, q, astNode> } ]
+ 4281        "}"                               (. astCur := astNode; .) .
+ 4282    (* Typed brace constructor: TypeName{ elems } — BITSET{0} (a set)
+ 4283       or ArrayName{...} (an array constructor, GNU Modula-2).  The
+ 4284       declared type sets the width (set) or element type (array). *)
+ 4285    TypedBraceLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 4286                                          (. VAR nw: CARDINAL;
+ 4287                                               astNode, astTail: AST.Node;
+ 4288                                               savedCls: INTEGER; .)
+ 4289      = "{"                               (. savedCls := braceCls;
+ 4290                                             astNode := AST.MakeNode(AST.NkBraceLit);
+ 4291                                             AST.SetTy(astNode, vt);
+ 4292                                             astTail := astNode;
+ 4293                                             IF vt = SymTab.InvalidType THEN
+ 4294                                               braceCls := -1
+ 4295                                             ELSE braceCls :=
+ 4296                                                    SymTab.ClassOf(vt)
+ 4297                                             END;
+ 4298                                             IF braceCls = SymTab.ClSet THEN
+ 4299                                               IF vt = SymTab.InvalidType THEN
+ 4300                                                 nw := 8
+ 4301                                               ELSE nw := SymTab.SetWords(vt);
+ 4302                                                 IF nw = 0 THEN nw := 8 END
+ 4303                                               END;
+ 4304                                               QbeGen.NewSetTemp(nw, q);
+ 4305                                               QbeGen.SetZero(q, nw)
+ 4306                                             ELSIF (braceCls =
+ 4307                                                    SymTab.ClArray)
+ 4308                                                OR (braceCls =
+ 4309                                                    SymTab.ClRecord)
+ 4310                                                OR (braceCls =
+ 4311                                                    SymTab.ClClass) THEN
+ 4312                                               QbeGen.CtorBegin(vt)
+ 4313                                             ELSE
+ 4314                                               IF vt # SymTab.InvalidType THEN
+ 4315                                                 SemError(230) END;
+ 4316                                               braceCls := -1
+ 4317                                             END; .)
+ 4318        [ BraceElem<vt, q, astNode, astTail>
+ 4319          { "," BraceElem<vt, q, astNode, astTail> } ]
+ 4320        "}"                               (. IF (braceCls = SymTab.ClArray)
+ 4321                                                OR (braceCls =
+ 4322                                                   SymTab.ClRecord)
+ 4323                                                OR (braceCls =
+ 4324                                                   SymTab.ClClass) THEN
+ 4325                                               QbeGen.CtorEnd(q)
+ 4326                                             ELSIF braceCls # SymTab.ClSet THEN
+ 4327                                               QbeGen.CopyOp("0", q)
+ 4328                                             END;
+ 4329                                             braceCls := savedCls; .)
+ 4330                                          (. astCur := astNode; .) .
+ 4331    BraceElem<vt: SymTab.TypeIndex; VAR sq: QbeGen.QVal;
+ 4332              VAR node, tail: AST.Node>
+ 4333                                          (. VAR et, et2: SymTab.TypeIndex;
+ 4334                                               qe, q2: QbeGen.QVal;
+ 4335                                               v, v2, reps, k: INTEGER;
+ 4336                                               elem: SymTab.TypeIndex;
+ 4337                                               lo: INTEGER;
+ 4338                                               span: CARDINAL;
+ 4339                                               cl, cl2: INTEGER;
+ 4340                                               hasR, hasB: BOOLEAN;
+ 4341                                               astEl: AST.Node; .)
+ 4342      =                                   (. hasR := FALSE; hasB := FALSE;
+ 4343                                             reps := 1; .)
+ 4344        Expr<et, qe> (. astEl := astCur; .)
+ 4345        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
+ 4346                                               AST.NkSubrange, 0, astEl, astCur);
+ 4347                                             hasR := TRUE; .) ]
+ 4348        [ "BY" Expr<et2, q2>              (. hasB := TRUE; .) ]
+ 4349                                          (. IF braceCls = SymTab.ClSet THEN
+ 4350                                               IF hasB THEN SemError(230) END;
+ 4351                                               lo := SymTab.SetBaseLo(vt);
+ 4352                                               span := SymTab.SetCount(vt);
+ 4353                                               IF (et = SymTab.InvalidType)
+ 4354                                                  OR (hasR AND (et2 =
+ 4355                                                     SymTab.InvalidType)) THEN
+ 4356                                               ELSE cl :=
+ 4357                                                      SymTab.ClassOf(et);
+ 4358                                                 IF hasR THEN
+ 4359                                                   cl2 :=
+ 4360                                                     SymTab.ClassOf(et2)
+ 4361                                                 ELSE cl2 := SymTab.ClInt
+ 4362                                                 END;
+ 4363                                                 IF NOT SymTab.SetElemClassOk(cl)
+ 4364                                                    OR (hasR AND NOT
+ 4365                                                       SymTab.SetElemClassOk(cl2))
+ 4366                                                 THEN
+ 4367                                                   SemError(222)
+ 4368                                                 ELSIF hasR
+ 4369   AND SymTab.ConstInt(qe, v)
+ 4370   AND SymTab.ConstInt(q2,
+ 4371                                                       v2)
+ 4372   AND ((v < lo)
+ 4373                                                       OR (v2 < lo)
+ 4374                                                       OR (v >= lo +
+ 4375                                                          VAL(INTEGER, span))
+ 4376                                                       OR (v2 >= lo +
+ 4377                                                          VAL(INTEGER, span))
+ 4378                                                       OR (v > v2)) THEN
+ 4379                                                   SemError(222)
+ 4380                                                  ELSIF hasR THEN
+ 4381                                                    QbeGen.SetRange(sq, qe, q2,
+ 4382                                                      lo, span)
+ 4383                                                  ELSIF SymTab.ConstInt(qe,
+ 4384                                                          v)
+ 4385   AND ((v < lo)
+ 4386                                                        OR (v >= lo +
+ 4387                                                           VAL(INTEGER,
+ 4388                                                             span))) THEN
+ 4389                                                    SemError(222)
+ 4390                                                  ELSE QbeGen.SetBit(sq, qe,
+ 4391                                                    lo, span)
+ 4392                                                 END
+ 4393                                               END
+ 4394                                             ELSIF (braceCls = SymTab.ClArray)
+ 4395                                                OR (braceCls =
+ 4396                                                   SymTab.ClRecord)
+ 4397                                                OR (braceCls =
+ 4398                                                   SymTab.ClClass) THEN
+ 4399                                               IF hasR THEN SemError(230) END;
+ 4400                                               reps := 1;
+ 4401                                               IF hasB THEN
+ 4402                                                 IF SymTab.ConstInt(q2, v2)
+ 4403   AND (v2 >= 1) THEN
+ 4404                                                   reps := v2
+ 4405                                                 ELSE SemError(230)
+ 4406                                                 END
+ 4407                                               END;
+ 4408                                               k := 0;
+ 4409                                               WHILE k < reps DO
+ 4410                                                 QbeGen.CtorElem(qe);
+ 4411                                                 INC(k)
+ 4412                                               END
+ 4413                                             END; .)
+ 4414                                          (. (* the BY form repeats the
+ 4415                                               element; keep the AST in
+ 4416                                               step with CtorElem *)
+ 4417                                             k := 0;
+ 4418                                             WHILE k < reps DO
+ 4419                                               AstAppend(AST.NkBlock,
+ 4420                                                 node, tail, astEl);
+ 4421                                               INC(k)
+ 4422                                             END; .) .
+ 4423    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal; node: AST.Node>         (. VAR et, et2: SymTab.TypeIndex;
+ 4424                                               qe, q2: QbeGen.QVal;
+ 4425                                               v, v2: INTEGER;
+ 4426                                               lo: INTEGER;
+ 4427                                               span: CARDINAL;
+ 4428                                               cl, cl2: INTEGER;
+ 4429                                               hasR: BOOLEAN;
+ 4430                                               astEl: AST.Node; .)
+ 4431      =                                   (. hasR := FALSE; .)
+ 4432        Expr<et, qe> (. astEl := astCur; .)
+ 4433        [ ".." Expr<et2, q2>              (. astEl := AST.MakeBin(
+ 4434                                               AST.NkSubrange, 0, astEl, astCur);
+ 4435                                             hasR := TRUE; .) ]
+ 4436                                          (. lo := SymTab.SetBaseLo(st);
+ 4437                                             span := SymTab.SetCount(st);
+ 4438                                             IF (et = SymTab.InvalidType)
+ 4439                                                OR (hasR AND (et2 =
+ 4440                                                   SymTab.InvalidType)) THEN
+ 4441                                             ELSE cl :=
+ 4442                                                    SymTab.ClassOf(et);
+ 4443                                               IF hasR THEN
+ 4444                                                 cl2 :=
+ 4445                                                   SymTab.ClassOf(et2)
+ 4446                                               ELSE cl2 := SymTab.ClInt
+ 4447                                               END;
+ 4448                                               IF NOT SymTab.SetElemClassOk(cl)
+ 4449                                                  OR (hasR AND NOT
+ 4450                                                     SymTab.SetElemClassOk(cl2))
+ 4451                                               THEN
+ 4452                                                 SemError(222)
+ 4453                                               ELSIF hasR
+ 4454   AND SymTab.ConstInt(qe, v)
+ 4455   AND SymTab.ConstInt(q2,
+ 4456                                                     v2)
+ 4457   AND ((v < lo)
+ 4458                                                     OR (v2 < lo)
+ 4459                                                     OR (v >= lo +
+ 4460                                                        VAL(INTEGER, span))
+ 4461                                                     OR (v2 >= lo +
+ 4462                                                        VAL(INTEGER, span))
+ 4463                                                     OR (v > v2)) THEN
+ 4464                                                 SemError(222)
+ 4465                                                ELSIF hasR THEN
+ 4466                                                  QbeGen.SetRange(sq, qe, q2,
+ 4467                                                    lo, span)
+ 4468                                                ELSIF SymTab.ConstInt(qe,
+ 4469                                                        v)
+ 4470   AND ((v < lo)
+ 4471                                                      OR (v >= lo +
+ 4472                                                         VAL(INTEGER,
+ 4473                                                           span))) THEN
+ 4474                                                  SemError(222)
+ 4475                                                ELSE QbeGen.SetBit(sq, qe,
+ 4476                                                  lo, span)
+ 4477                                               END
+ 4478                                             END; .)
+ 4479                                          (. AST.SetChild(node,
+ 4480                                               AST.NChild(node), astEl); .) .
+ 4481    GetIdent<VAR n: SymTab.Name>
+ 4482      = ident                             (. LexName(n); .) .
+ 4483  
+ 4484  END M2.
 
     0 errors
 
 
 Statistics:
 
-  nr of terminals:       118 (limit   400)
-  nr of non-terminals:    92 (limit   210)
-  nr of pragmas:           0 (limit   382)
-  nr of symbolnodes:     210 (limit   500)
-  nr of graphnodes:     1366 (limit  1500)
+  nr of terminals:       119 (limit   400)
+  nr of non-terminals:    93 (limit   210)
+  nr of pragmas:           0 (limit   381)
+  nr of symbolnodes:     212 (limit   500)
+  nr of graphnodes:     1373 (limit  1500)
   nr of conditionsets:    12 (limit   100)
   nr of charactersets:    17 (limit   250)
 

+ 17 - 0
compiler/src/QbeGen.def

@@ -447,6 +447,23 @@ PROCEDURE CmpSet (op: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
 (* =/# over min words plus zero-checks on the larger side's extras;
    q is fresh w 0/1. op is a SymTab.OpEq/Neq code. *)
 
+PROCEDURE LoadPacked (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
+(* Load a PACKEDSET value (1/2/4 bytes, zero-extended) into w. *)
+PROCEDURE CopySetVal (dst: ARRAY OF CHAR; dt: INTEGER;
+                      src: ARRAY OF CHAR; et: INTEGER);
+(* Set assignment/copy across SET/PACKEDSET representations. *)
+PROCEDURE PackedSetBit (addr: ARRAY OF CHAR; t: INTEGER;
+                        val: ARRAY OF CHAR; lo: INTEGER; span: CARDINAL);
+PROCEDURE PackedSetClearBit (addr: ARRAY OF CHAR; t: INTEGER;
+                             val: ARRAY OF CHAR; lo: INTEGER;
+                             span: CARDINAL);
+PROCEDURE PackedInSet (x: ARRAY OF CHAR; s: ARRAY OF CHAR;
+                       lo: INTEGER; span: CARDINAL; t: INTEGER;
+                       VAR q: QVal);
+PROCEDURE PackedCmpSet (op: INTEGER; l: ARRAY OF CHAR; lt: INTEGER;
+                        r: ARRAY OF CHAR; rt: INTEGER; VAR q: QVal);
+PROCEDURE PackedSetBinOp (sel: INTEGER; l: ARRAY OF CHAR; lt: INTEGER;
+                          r: ARRAY OF CHAR; rt: INTEGER; VAR q: QVal);
 PROCEDURE CopySet (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
                     dw, sw: CARDINAL);
 (* Copies min words via memcpy, zero-fills dst extras. *)

+ 168 - 2
compiler/src/QbeGen.mod

@@ -634,6 +634,21 @@ PROCEDURE DataLineH (name: ARRAY OF CHAR; init: ARRAY OF CHAR);
     WL(" }")
   END DataLineH;
 
+PROCEDURE DataLinePacked (name: ARRAY OF CHAR; t: INTEGER);
+(* A PACKEDSET global: 1/2/4 bytes, zero-initialised. *)
+  VAR nb: CARDINAL;
+  BEGIN
+    IF NOT opened THEN RETURN END;
+    nb := SymTab.SetBytes(t);
+    W("data $"); W(name);
+    W(" = { ");
+    IF nb = 1 THEN W("b 0")
+    ELSIF nb = 2 THEN W("h 0")
+    ELSE W("w 0")
+    END;
+    WL(" }")
+  END DataLinePacked;
+
 PROCEDURE DataLineL (name: ARRAY OF CHAR; init: ARRAY OF CHAR);
   BEGIN
     IF NOT opened THEN RETURN END;
@@ -661,6 +676,7 @@ PROCEDURE DeclVar (name: ARRAY OF CHAR; t: INTEGER);
     ELSIF SymTab.IsByteType(t) THEN DataLineB(g, "0")
     ELSIF SymTab.IsWord16Type(t) THEN DataLineH(g, "0")
     ELSIF SymTab.ClassOf(t) = SymTab.ClArray THEN DeclArr(g, t)
+    ELSIF SymTab.IsPackedSet(t) THEN DataLinePacked(g, t)
     ELSIF SymTab.ClassOf(t) = SymTab.ClSet THEN DeclSet(g, t)
     ELSIF (SymTab.ClassOf(t) = SymTab.ClRecord)
        OR (SymTab.ClassOf(t) = SymTab.ClClass) THEN
@@ -1015,6 +1031,12 @@ PROCEDURE AllocLocal (t: INTEGER; VAR slot: QVal);
       IntStr(VAL(INTEGER, SymTab.TypeSize(t)), nb);
       W(" =l alloc8 "); WL(nb);
       InitStack(slot, t)
+    ELSIF SymTab.IsPackedSet(t) THEN
+      W(" =l alloc4 4"); WL("");
+      IF SymTab.SetBytes(t) = 1 THEN W("  storeb 0, "); WL(slot)
+      ELSIF SymTab.SetBytes(t) = 2 THEN W("  storeh 0, "); WL(slot)
+      ELSE W("  storew 0, "); WL(slot)
+      END
     ELSIF cls = SymTab.ClSet THEN
       IntStr(VAL(INTEGER, SymTab.SetWords(t) * 4), nb);
       W(" =l alloc8 "); WL(nb);
@@ -1165,8 +1187,7 @@ PROCEDURE EndFuncHeader;
         IF cls = SymTab.ClArray THEN
           CopyArray(slot, parTmp[i], parTyp[i])
         ELSIF cls = SymTab.ClSet THEN
-          CopySet(slot, parTmp[i],
-            SymTab.SetWords(parTyp[i]), SymTab.SetWords(parTyp[i]))
+          CopySetVal(slot, parTyp[i], parTmp[i], parTyp[i])
         ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
           CopyRecord(slot, parTmp[i], parTyp[i])
         ELSIF cls = SymTab.ClReal THEN
@@ -2852,6 +2873,137 @@ PROCEDURE CmpSet (op: INTEGER; l: ARRAY OF CHAR; r: ARRAY OF CHAR;
     END
   END CmpSet;
 
+PROCEDURE LoadPacked (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
+  VAR nb: CARDINAL;
+  BEGIN
+    nb := SymTab.SetBytes(t);
+    NewTemp(q);
+    Revive;
+    W("  "); W(q);
+    IF nb = 1 THEN W(" =w loadub ")
+    ELSIF nb = 2 THEN W(" =w loaduh ")
+    ELSE W(" =w loadw ")
+    END;
+    WL(addr)
+  END LoadPacked;
+
+PROCEDURE StorePacked (addr: ARRAY OF CHAR; t: INTEGER;
+                       v: ARRAY OF CHAR);
+  VAR nb: CARDINAL;
+  BEGIN
+    nb := SymTab.SetBytes(t);
+    Revive;
+    IF nb = 1 THEN W("  storeb ")
+    ELSIF nb = 2 THEN W("  storeh ")
+    ELSE W("  storew ")
+    END;
+    W(v); W(", "); WL(addr)
+  END StorePacked;
+
+PROCEDURE CopySetVal (dst: ARRAY OF CHAR; dt: INTEGER;
+                      src: ARRAY OF CHAR; et: INTEGER);
+  VAR q: QVal;
+  BEGIN
+    IF SymTab.IsPackedSet(dt) THEN
+      IF SymTab.IsPackedSet(et) THEN LoadPacked(src, et, q)
+      ELSE LoadW(src, q)
+      END;
+      StorePacked(dst, dt, q)
+    ELSIF SymTab.IsPackedSet(et) THEN
+      SetZero(dst, SymTab.SetWords(dt));
+      LoadPacked(src, et, q);
+      StoreW(dst, q)
+    ELSE CopySet(dst, src, SymTab.SetWords(dt), SymTab.SetWords(et))
+    END
+  END CopySetVal;
+
+PROCEDURE PackedSetBit (addr: ARRAY OF CHAR; t: INTEGER;
+                        val: ARRAY OF CHAR; lo: INTEGER; span: CARDINAL);
+  VAR off, offL, hiS, loS, m, old, nv: QVal;
+  BEGIN
+    NewTemp(off);
+    IntStr(lo, loS);
+    Op3("sub", off, val, loS, FALSE);
+    WidenIndex(off, offL);
+    IntStr(VAL(INTEGER, span) - 1, hiS);
+    CheckRange(offL, "0", hiS);
+    NewTemp(m);
+    Op3("shl", m, "1", off, FALSE);
+    LoadPacked(addr, t, old);
+    NewTemp(nv);
+    Op3("or", nv, old, m, FALSE);
+    StorePacked(addr, t, nv)
+  END PackedSetBit;
+
+PROCEDURE PackedSetClearBit (addr: ARRAY OF CHAR; t: INTEGER;
+                             val: ARRAY OF CHAR; lo: INTEGER;
+                             span: CARDINAL);
+  VAR off, offL, hiS, loS, m, nm, old, nv: QVal;
+  BEGIN
+    NewTemp(off);
+    IntStr(lo, loS);
+    Op3("sub", off, val, loS, FALSE);
+    WidenIndex(off, offL);
+    IntStr(VAL(INTEGER, span) - 1, hiS);
+    CheckRange(offL, "0", hiS);
+    NewTemp(m);
+    Op3("shl", m, "1", off, FALSE);
+    NewTemp(nm);
+    Op3("xor", nm, m, "-1", FALSE);
+    LoadPacked(addr, t, old);
+    NewTemp(nv);
+    Op3("and", nv, old, nm, FALSE);
+    StorePacked(addr, t, nv)
+  END PackedSetClearBit;
+
+PROCEDURE PackedInSet (x: ARRAY OF CHAR; s: ARRAY OF CHAR;
+                       lo: INTEGER; span: CARDINAL; t: INTEGER;
+                       VAR q: QVal);
+  VAR off, offL, hiS, loS, word, sh, bit: QVal;
+  BEGIN
+    NewTemp(off);
+    IntStr(lo, loS);
+    Op3("sub", off, x, loS, FALSE);
+    WidenIndex(off, offL);
+    IntStr(VAL(INTEGER, span) - 1, hiS);
+    CheckRange(offL, "0", hiS);
+    LoadPacked(s, t, word);
+    NewTemp(sh);
+    Op3("shr", sh, word, off, FALSE);
+    NewTemp(bit);
+    Op3("and", bit, sh, "1", FALSE);
+    Cmp(SymTab.OpNeq1, bit, "0", q, FALSE)
+  END PackedInSet;
+
+PROCEDURE PackedCmpSet (op: INTEGER; l: ARRAY OF CHAR; lt: INTEGER;
+                        r: ARRAY OF CHAR; rt: INTEGER; VAR q: QVal);
+  VAR q1, q2: QVal;
+  BEGIN
+    IF SymTab.IsPackedSet(lt) THEN LoadPacked(l, lt, q1)
+    ELSE LoadW(l, q1)
+    END;
+    IF SymTab.IsPackedSet(rt) THEN LoadPacked(r, rt, q2)
+    ELSE LoadW(r, q2)
+    END;
+    Cmp(op, q1, q2, q, FALSE)
+  END PackedCmpSet;
+
+PROCEDURE PackedSetBinOp (sel: INTEGER; l: ARRAY OF CHAR; lt: INTEGER;
+                          r: ARRAY OF CHAR; rt: INTEGER; VAR q: QVal);
+  VAR tl, tr, w: QVal;
+  BEGIN
+    NewSetTemp(1, tl); NewSetTemp(1, tr);
+    IF SymTab.IsPackedSet(lt) THEN LoadPacked(l, lt, w)
+    ELSE LoadW(l, w)
+    END;
+    StoreW(tl, w);
+    IF SymTab.IsPackedSet(rt) THEN LoadPacked(r, rt, w)
+    ELSE LoadW(r, w)
+    END;
+    StoreW(tr, w);
+    SetBinOp(sel, tl, tr, 1, 1, q)
+  END PackedSetBinOp;
+
 PROCEDURE CopySet (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
                     dw, sw: CARDINAL);
 (* Copies min words via memcpy, zero-fills dst extras. Src extras
@@ -3024,6 +3176,13 @@ PROCEDURE ElemLoad (addr: ARRAY OF CHAR; t: INTEGER; VAR q: QVal);
        OR (cls = SymTab.ClClass) THEN
       W(" =l loadl ")
     ELSIF cls = SymTab.ClChar THEN W(" =w loadub ")
+    ELSIF cls = SymTab.ClSet THEN
+      IF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 1) THEN
+        W(" =w loadub ")
+      ELSIF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 2) THEN
+        W(" =w loaduh ")
+      ELSE W(" =w loadw ")
+      END
     ELSIF cls = SymTab.ClByte THEN W(" =w loadub ")
     ELSIF cls = SymTab.ClSByte THEN W(" =w loadsb ")
     ELSIF cls = SymTab.ClWord16 THEN W(" =w loaduh ")
@@ -3044,6 +3203,13 @@ PROCEDURE ElemStore (addr, v: ARRAY OF CHAR; t: INTEGER);
        OR (cls = SymTab.ClClass) THEN
       W("  storel ")
     ELSIF cls = SymTab.ClChar THEN W("  storeb ")
+    ELSIF cls = SymTab.ClSet THEN
+      IF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 1) THEN
+        W("  storeb ")
+      ELSIF SymTab.IsPackedSet(t) AND (SymTab.SetBytes(t) = 2) THEN
+        W("  storeh ")
+      ELSE W("  storew ")
+      END
     ELSIF (cls = SymTab.ClByte) OR (cls = SymTab.ClSByte) THEN W("  storeb ")
     ELSIF (cls = SymTab.ClWord16) OR (cls = SymTab.ClSWord16) THEN W("  storeh ")
     ELSE W("  storew ")

+ 6 - 0
compiler/src/SymTab.def

@@ -440,6 +440,9 @@ PROCEDURE MarkVariant (rec: TypeIndex);
 PROCEDURE IsVariant (rec: TypeIndex): BOOLEAN;
 (* TRUE when rec has a variant part. *)
 PROCEDURE NewSet (base: TypeIndex): TypeIndex;
+PROCEDURE NewPackSet (base: TypeIndex): TypeIndex;
+(* ISO PACKEDSET: same base/span as SET but 1/2/4-byte storage
+   (spans up to 32 bits in V3). *)
 PROCEDURE NewPtr (base: TypeIndex): TypeIndex;
 PROCEDURE NewStr (): TypeIndex;
 PROCEDURE NewEmptyStr (): TypeIndex;
@@ -578,6 +581,9 @@ PROCEDURE SubBounds (t: TypeIndex; VAR lo, hi: INTEGER): BOOLEAN;
 PROCEDURE SetBase (t: TypeIndex): TypeIndex;
 (* Base type of a set descriptor (InvalidType if none). *)
 PROCEDURE SetWords (t: TypeIndex): CARDINAL;
+PROCEDURE SetBytes (t: TypeIndex): CARDINAL;
+(* Storage bytes: SET = SetWords*4, PACKEDSET = ceil(count/8) (1..4). *)
+PROCEDURE IsPackedSet (t: TypeIndex): BOOLEAN;
 (* Mask words for a set type from its base span (bool 1, char 8,
    subrange by bounds); 0 when the base is unsuitable. *)
 PROCEDURE SetBaseLo (t: TypeIndex): INTEGER;

+ 32 - 5
compiler/src/SymTab.mod

@@ -18,7 +18,7 @@ CONST
   FInt = 9; FReal = 10; FChar = 11; FBool = 12;
   FClass = 13; FOpenArr = 14; FNil = 15; FLong = 16; FProc = 17;
   FUChar = 18; FUStr = 19; FByte = 20; FSByte = 21;
-  FWord16 = 22; FSWord16 = 23;
+  FWord16 = 22; FSWord16 = 23; FPackSet = 24;
 
   (* signatures compared by the strict 231 check are bounded to this many
      formals (self-hosting uses far fewer). *)
@@ -940,6 +940,11 @@ PROCEDURE NewSet (base: TypeIndex): TypeIndex;
     RETURN NewDesc(FSet, base)
   END NewSet;
 
+PROCEDURE NewPackSet (base: TypeIndex): TypeIndex;
+  BEGIN
+    RETURN NewDesc(FPackSet, base)
+  END NewPackSet;
+
 PROCEDURE NewPtr (base: TypeIndex): TypeIndex;
   BEGIN
     RETURN NewDesc(FPtr, base)
@@ -1122,7 +1127,7 @@ PROCEDURE ClassOf (t: TypeIndex): INTEGER;
     | FArray : RETURN ClArray
     | FOpenArr : RETURN ClArray
     | FRecord : RETURN ClRecord
-    | FSet : RETURN ClSet
+    | FSet, FPackSet : RETURN ClSet
     | FPtr : RETURN ClPtr
     | FStr : RETURN ClStr
     | FClass : RETURN ClClass
@@ -1329,7 +1334,8 @@ PROCEDURE SetBase (t: TypeIndex): TypeIndex;
   VAR r: TypeIndex;
   BEGIN
     r := Resolve(t);
-    IF (r = InvalidType) OR (tform[r] # FSet) THEN
+    IF (r = InvalidType) OR ((tform[r] # FSet)
+       AND (tform[r] # FPackSet)) THEN
       RETURN InvalidType
     END;
     RETURN tref[r]
@@ -1370,6 +1376,23 @@ PROCEDURE SetWords (t: TypeIndex): CARDINAL;
     RETURN VAL(CARDINAL, (n + 31) DIV 32)
   END SetWords;
 
+PROCEDURE SetBytes (t: TypeIndex): CARDINAL;
+  VAR lo, n: INTEGER;
+  BEGIN
+    IF NOT SetSpan(t, lo, n) THEN RETURN 0 END;
+    IF IsPackedSet(t) THEN
+      RETURN VAL(CARDINAL, (n + 7) DIV 8)
+    END;
+    RETURN VAL(CARDINAL, (n + 31) DIV 32) * 4
+  END SetBytes;
+
+PROCEDURE IsPackedSet (t: TypeIndex): BOOLEAN;
+  VAR r: TypeIndex;
+  BEGIN
+    r := Resolve(t);
+    RETURN (r # InvalidType) AND (tform[r] = FPackSet)
+  END IsPackedSet;
+
 PROCEDURE SetBaseLo (t: TypeIndex): INTEGER;
   VAR lo, n: INTEGER;
   BEGIN
@@ -1536,6 +1559,7 @@ PROCEDURE ElemBytes (t: TypeIndex): CARDINAL;
     IF (cls = ClWord16) OR (cls = ClSWord16) THEN
       RETURN 2
     END;
+    IF cls = ClSet THEN RETURN TypeSize(ArrayElem(t)) END;
     IF cls = ClReal THEN RETURN 8 END;
     IF (cls = ClArray) OR (cls = ClPtr) OR (cls = ClRecord)
        OR (cls = ClClass) OR (cls = ClProc) THEN
@@ -1577,6 +1601,7 @@ PROCEDURE TypeSizeD (t: TypeIndex; depth: CARDINAL): CARDINAL;
     | FReal : RETURN 8
     | FEnum, FSub : RETURN 4
     | FSet : RETURN SetWords(t) * 4
+    | FPackSet : RETURN SetBytes(t)
     | FPtr, FOpenArr, FArray, FProc, FUStr : RETURN 8
     | FRecord, FClass :
         n := 0;
@@ -3208,7 +3233,8 @@ PROCEDURE Assignable (src, dst: TypeIndex): BOOLEAN;
     rs := Resolve(src); rd := Resolve(dst);
     IF rs = rd THEN RETURN TRUE END;
     IF (rs = InvalidType) OR (rd = InvalidType) THEN RETURN TRUE END;
-    IF (tform[rs] = FSet) AND (tform[rd] = FSet) THEN
+    IF ((tform[rs] = FSet) OR (tform[rs] = FPackSet))
+       AND ((tform[rd] = FSet) OR (tform[rd] = FPackSet)) THEN
       RETURN SetBasesOk(tref[rs], tref[rd])
     END;
     IF (tform[rs] = FProc) AND (tform[rd] = FProc) THEN
@@ -3451,7 +3477,8 @@ PROCEDURE InCheck (l, set: TypeIndex): BOOLEAN;
   BEGIN
     IF (Resolve(l) = InvalidType) OR (Resolve(set) = InvalidType) THEN RETURN TRUE END;
     rs := Resolve(set);
-    IF (rs = InvalidType) OR (tform[rs] # FSet) THEN RETURN FALSE END;
+    IF (rs = InvalidType) OR ((tform[rs] # FSet)
+       AND (tform[rs] # FPackSet)) THEN RETURN FALSE END;
     b := tref[rs];
     IF SameType(l, b) THEN RETURN TRUE END;
     IF IsIntFamily(l) AND IsIntFamily(b) THEN RETURN TRUE END;

+ 77 - 0
compiler/tests/t_packedset.mod

@@ -0,0 +1,77 @@
+MODULE TPackedSet;
+// ISO PACKEDSET: 1/2/4-byte storage, INCL/EXCL/IN, ORD, elements in
+// records/arrays, value and VAR parameters, set operations. Exit 42.
+TYPE
+  Small  = PACKEDSET OF [0..7];
+  Wide2  = PACKEDSET OF [0..15];
+  Wide4  = PACKEDSET OF [0..31];
+  Colour = (red, blue, green, yellow, cyan, purple, black);
+  CS     = PACKEDSET OF Colour;
+  Rec    = RECORD
+             s  : Small;
+             tag: CARDINAL;
+           END;
+  Arr    = ARRAY [0..3] OF Small;
+  Set8   = SET OF [0..7];
+CONST SC = Small{1, 2};
+VAR ExitCode : INTEGER;
+VAR s, t : Small;
+VAR w2 : Wide2;
+VAR w4 : Wide4;
+VAR c : CS;
+VAR r : Rec;
+VAR a, b : Arr;
+VAR n : Set8;
+VAR i : INTEGER;
+PROCEDURE Take (x: Small) : CARDINAL;
+BEGIN
+  RETURN ORD(x)
+END Take;
+PROCEDURE AddTo (VAR x: Small; v: CARDINAL);
+BEGIN
+  INCL(x, v)
+END AddTo;
+PROCEDURE Has2 (x: Set8) : BOOLEAN;
+BEGIN
+  RETURN 2 IN x
+END Has2;
+PROCEDURE TakePacked (x: Small) : CARDINAL;
+BEGIN
+  RETURN ORD(x)
+END TakePacked;
+BEGIN
+  i := 0;
+  s := Small{};
+  t := Small{1, 2};
+  AddTo(s, 3);
+  EXCL(t, 1);
+  IF (3 IN s) AND NOT (2 IN s) AND NOT (1 IN s) THEN i := i + 1 END;
+  IF (2 IN t) AND NOT (1 IN t) THEN i := i + 2 END;
+  c := CS{red, purple};
+  IF (red IN c) AND (purple IN c) AND NOT (blue IN c) THEN i := i + 4 END;
+  r.s := Small{7};
+  INCL(r.s, 6);
+  r.tag := 99;
+  IF (6 IN r.s) AND (7 IN r.s) AND (r.tag = 99) THEN i := i + 8 END;
+  a[0] := Small{1}; a[1] := Small{2}; a[2] := Small{3}; a[3] := Small{4};
+  a[2] := Small{};
+  IF (4 IN a[3]) AND NOT (3 IN a[2]) THEN i := i + 16 END;
+  IF (ORD(SC) = 6) AND (2 IN SC) THEN i := i + 3 END;
+  b := a;
+  IF (4 IN b[3]) AND NOT (3 IN b[2]) THEN i := i + 5 END;
+  s := t + Small{4};                 (* union, assigned back to packed *)
+  n := s;                            (* packed -> normal representation *)
+  IF (2 IN s) AND (4 IN s) AND (2 IN n) AND (4 IN n)
+     AND Has2(s) AND (TakePacked(Set8{2}) = 4) THEN i := i + 3 END;
+  w2 := Wide2{15};
+  w4 := Wide4{31};
+  IF (ORD(Small{2..5}) = 60)
+     AND (SIZE(Small) = 1) AND (SIZE(Wide2) = 2) AND (SIZE(Wide4) = 4)
+     AND (SIZE(s) = 1) AND (SIZE(w2) = 2) AND (SIZE(w4) = 4)
+     AND (15 IN w2) AND (31 IN w4)
+     AND (Take(s) = ORD(s)) THEN
+    ExitCode := i
+  ELSE
+    ExitCode := 1
+  END
+END TPackedSet.

+ 3 - 3
docs/INDEX.md

@@ -7,7 +7,7 @@ bisecting *why* a decision was made, not for reading end-to-end).
 ## Start here
 
 - **`handoff-2026-10-23-next.md`** — current next-session plan
-  (PACKEDSET representation, exceptions, multi-dim open arrays; gates).
+  (PACKEDSET done; exceptions, multi-dim open arrays; gates).
 - **`handoff-2026-10-22-next.md`** — previous stop-point plan (range
   checks, PACKEDSET inspection; kept for provenance).
 - **`handoff-2026-10-19-next.md`** — previous plan (P1–P5 status, the
@@ -20,7 +20,7 @@ bisecting *why* a decision was made, not for reading end-to-end).
 - **`features.md`** — the feature list.
 - **`comparison-PIM4-gm2-V3.md`** — PIM4 / GNU Modula-2 / **M2R10** /
   **TopSpeed V3** / V3 feature comparison (2026-10-23; V3 at
-  `v3-rangechecks`; filename kept for link stability).
+  `v3-packedset`; filename kept for link stability).
 - **`analysis_gaps.md`** — language gaps + corpus notes.
 - **`gaps/README.md`** — minimal reproducers, one per unsupported gap,
   and the gm2-extension policy.
@@ -45,7 +45,7 @@ bisecting *why* a decision was made, not for reading end-to-end).
 ## Recent session summaries (newest first)
 
 - **`summary_session-2026-10-23.md`** — continuation: runtime subrange
-  range checks (+3 trap tests); PACKEDSET inspected and parked.
+  range checks (+3 trap tests); `PACKEDSET` implemented (1/2/4 bytes).
 - **`summary_session-2026-10-22.md`** — corpus triage: PIM/ISO
   multi-index arrays, typed CHAR/enum subranges, ordinal `FOR`, ISO
   empty string, typed libc prototypes, ISO SYSTEM sized types,

+ 12 - 8
docs/STATUS.md

@@ -1,12 +1,12 @@
-# m2compiler-V3 — status (2026-10-22)
+# m2compiler-V3 — status (2026-10-23)
 
 This answers "where are we now?".
 
 ## Numbers
 
-- Suite **262/262** (`compiler/run_tests.sh`).
+- Suite **263/263** (`compiler/run_tests.sh`).
 - Self-hosting **FIXPOINT OK** — stage2 and stage3 images are
-  byte-identical (4,032,793 bytes).
+  byte-identical (4,075,853 bytes).
 - Corpus **511 / 612** sources compile with 0 errors, **0 crashes**
   (`tools/v3-corpus/corpus.sh` over the gm2 testsuite; the harness now
   resolves V3's own shipped libraries); the rest are genuine language
@@ -57,7 +57,11 @@ control variable (`FOR c := red TO blue`).  The ISO empty string
 literal (`""`/`''`) is compatible with `CHAR` (value 0) in assignment,
 comparison, `CASE` labels, `FOR` bounds, actuals and `RETURN`, while
 remaining a string for `ARRAY OF CHAR` (whole-array assignment and
-content comparison).  Runtime **subrange range checks** now trap on
+content comparison).  `PACKEDSET OF <ordinal>` is supported with
+1/2/4-byte storage (1/2/4/8/16/32-bit spans); `SIZE` and `ORD` follow
+the packed width, and `INCL`/`EXCL`/`IN`/set operations/assignment work
+on packed values.  Wider packed sets are a loud implementation limit
+(`230`).  Runtime **subrange range checks** now trap on
 assignment, value actuals, `RETURN` and `INC`/`DEC`
 (`QbeGen.CheckRange`); the post-increment of a `FOR` control variable is
 not checked (the final successor may legitimately exceed a full
@@ -167,9 +171,9 @@ declarations still work (`t_fwdproc`, `t_fwdok`).
    `INC`/`DEC`, leading CASE `|`, `__FUNCTION__`).  Corpus is **511/612**
    at the stop point.  The remaining `LANG` entries are mostly:
    **declaration order** cases V3 rejects by policy (`docs/gaps/`); ISO
-   exceptions/`PACKEDSET`; multi-dimensional open arrays
-   (representation, see `handoff-2026-10-22-next.md`); and gm2-only
-   extensions.  See `docs/analysis_gaps.md`.
+   exceptions; multi-dimensional open arrays (representation, see
+   `docs/handoff-2026-10-23-next.md`); and gm2-only extensions.  See
+   `docs/analysis_gaps.md`.
 2. ~~**The size-sensitive V3 miscompile**~~ — **root-caused and fixed**
    (2026-10-19; see `docs/summary_l3_selfhost_fix.md`).  It was never
    size-sensitive: the fixpoint gate matched the literal string
@@ -210,7 +214,7 @@ declarations still work (`t_fwdproc`, `t_fwdok`).
 ```sh
 cd compiler
 ./build.sh          # M2.atg -> scanner/parser/driver -> ./M2
-./run_tests.sh      # 262/262
+./run_tests.sh      # 263/263
 cd ..
 ./bootstrap/fixpoint.sh   # FIXPOINT OK (byte-identical stage2/stage3)
 ```

+ 11 - 9
docs/comparison-PIM4-gm2-V3.md

@@ -1,7 +1,7 @@
 # PIM4 vs GNU Modula-2 vs M2R10 vs TopSpeed V3 vs V3 — feature comparison
 
-**Date:** 2026-10-23 · **V3 state:** `v3-rangechecks` (suite
-262/262, self-hosting fixpoint OK 4,032,793 bytes, corpus 511/612,
+**Date:** 2026-10-23 · **V3 state:** `v3-packedset` (suite
+263/263, self-hosting fixpoint OK 4,075,853 bytes, corpus 511/612,
 0 crashes).
 
 **Scope and sources.**
@@ -72,7 +72,7 @@ change individual cells.
 | Subranges | ✅ | ✅ | ✅ (`[lo..hi] OF Base`) | ✅ | ✅ (typed CHAR/enum subranges) |
 | Enumerations | ✅ | ✅ | ✅ extensible | ✅ | ✅ |
 | Sets (`SET OF`) | ✅ any finite ordinal (impl. limit) | ✅ | 🔄 `SET OF <enumType>` only | ✅ range/base/enum bases | 🔄 bool/char/byte/16-bit/enum/small-int; span ≤ 65536; no `SET OF CARDINAL` |
-| `PACKEDSET` | ❌ (ISO) | ✅ | ❌ | ❌ | ❌ |
+| `PACKEDSET` | ❌ (ISO) | ✅ | ❌ | ❌ | ✅ (1/2/4 bytes, span ≤ 32) |
 | Fixed / multi-dimensional arrays | ✅ `[a], [b] OF` | ✅ | ✅ `ARRAY count, count OF` (zero-based) | ✅ | ✅ both `[a], [b]` and `[a, b]` |
 | Open arrays (1-D) | ✅ | ✅ | ✅ (`BARE ARRAY OF`) | ✅ | ✅ |
 | Multi-dimensional open arrays | ❌ (ISO addition) | ✅ | 🔄 one-dimensional `BARE` arrays | ❌ | ❌ (descriptor-per-level representation) |
@@ -153,9 +153,9 @@ change individual cells.
   scalar→`ARRAY OF BYTE`, same-size `VAR`, bare proc values, variant
   extensions, set `CASE` labels, libc prototypes).  Its hard gaps are
   the large ISO features (**exceptions, complex arithmetic,
-  `PACKEDSET`, finalization/protection, multi-dimensional open arrays,
-  ISO OO**) and parts of the **word model** (`SHORTREAL`, `REAL` width),
-  plus a **65536-bit set span limit**.
+  finalization/protection, multi-dimensional open arrays, ISO OO**) and
+  parts of the **word model** (`SHORTREAL`, `REAL` width), plus a
+  **65536-bit `SET` span limit** and a **32-bit `PACKEDSET` limit**.
 
 ## V3-specific deviations and limits
 
@@ -168,7 +168,9 @@ change individual cells.
   are 32-bit; `LONGINT`/`LONGCARD` are 64-bit; every `REAL`/`SHORTREAL`
   is 8 bytes; `COMPLEX*` is a placeholder.
 - **Sets:** bases limited to bool/char/byte/16-bit/enum/small subranges;
-  total span ≤ 65536; no `SET OF CARDINAL`.
+  `SET` total span ≤ 65536; no `SET OF CARDINAL`.  `PACKEDSET` uses
+  1/2/4-byte storage with a 32-bit span limit (wider spans are a loud
+  `230`).
 - **Runtime range checks** are emitted for subrange assignment, value
   actuals, `RETURN` and `INC`/`DEC` (`QbeGen.CheckRange`, abort trap).
   The post-increment of a `FOR` control variable is not checked: the
@@ -185,8 +187,8 @@ change individual cells.
 ## Sources
 
 - V3: `docs/STATUS.md`, `docs/features.md`, `docs/gaps/README.md`,
-  `docs/analysis_gaps.md`, `docs/summary_session-2026-10-22.md`; the
-  gates in this document were run at `v3-smallfix`.
+  `docs/analysis_gaps.md`, `docs/summary_session-2026-10-23.md`; the
+  gates in this document were run at `v3-packedset`.
 - gm2: the GCC Modula-2 testsuite and `gm2-libs`/`gm2-libs-iso`
   definition modules in the sibling `gcc-git` tree.
 - M2R10: the published R10 grammar (m2r10-grammar.gll) and

+ 4 - 0
docs/features.md

@@ -78,6 +78,10 @@ Legend: ✅ done · 🔄 partial · ⏸ not started / deferred.
   including variant records (`RECORD … ; CASE tag : T OF … END`): plain
   fields pack before the tag, each branch's fields overlay after it.
 - ✅ `SET OF` bool/char/subrange (multi-word masks).
+- ✅ `PACKEDSET OF <ordinal>`: 1/2/4-byte storage for spans up to 32
+  bits (`SIZE` = width, `ORD` = mask, `INCL`/`EXCL`/`IN`, assignment,
+  set operations, packed array/record elements and parameters).
+  Wider packed sets are a loud `230` implementation limit.
 - ✅ `POINTER TO`, `NIL` as a real type, `ADDRESS` ↔ any pointer
   assignment (`p := ADR(x)`).
 - ✅ `UCHAR` (32-bit codepoint) + `U'a'`/`U"…"` literals (strict

+ 9 - 7
docs/gaps/README.md

@@ -231,13 +231,15 @@ compatibility (they do not relax any conforming rule).
   so the sized family is now 8/16/32 at its nominal widths.  `WORD`/
   `WORD32` remain 32-bit.  Regression `t_word16` (SIZE, wrapping, signed
   fields, arrays, `SET OF WORD16`/`INTEGER16`, conversions).
-- **`PACKEDSET` — inspected, not implemented** (2026-10-23): ISO
-  `PACKEDSET OF <ordinal>` is `SIZE`- and `ORD`-sensitive (`onebyte*`
-  assert `SIZE(PACKEDSET) = SIZE(BYTE) = 1` and `ORD(set)` values), so
-  aliasing it to `SET` would compile but be semantically wrong.  A
-  faithful implementation needs a 1/2/4-byte packed representation and
-  packed set operations; parked until that is scheduled.  Corpus:
-  `onebyte`, `onebyte2`, `onebyte3`.
+- **`PACKEDSET` — implemented for spans ≤ 32 bits** (2026-10-23):
+  `PACKEDSET OF <ordinal>` uses 1/2/4-byte storage; `SIZE` is the packed
+  width, `ORD` is the mask, and `INCL`/`EXCL`/`IN`, assignment, set
+  operations, packed array/record elements and parameters work.
+  Wider packed sets are a loud `230` implementation limit.  Regression
+  `t_packedset`.  The corpus files `onebyte`, `onebyte2`, `onebyte3`
+  still fail **earlier**: they use the module variable `r` in `assert`
+  before its declaration (declaration order, rejected by policy), not
+  because of `PACKEDSET`.
 - **`gap10` scalar `VAR` actual, same size — accepted** (2026-10-19).
   `VarParamOk` accepts a scalar VAR actual of a *different* type when
   `ObjectSize` matches (e.g. `INTEGER` for `VAR WORD`).  `testparam3`

+ 18 - 30
docs/handoff-2026-10-23-next.md

@@ -1,7 +1,7 @@
 # Next session — plan (from 2026-10-23)
 
-**Branch:** `master`.  **Feature state:** `v3-rangechecks`.
-**Gates:** suite **262/262**, fixpoint **OK (4,032,793 bytes)**,
+**Branch:** `master`.  **Feature state:** `v3-packedset`.
+**Gates:** suite **263/263**, fixpoint **OK (4,075,853 bytes)**,
 corpus **511/612, 0 crashes**.
 
 Read first: `docs/STATUS.md`, `docs/features.md`,
@@ -13,29 +13,18 @@ V3 follows **PIM/ISO Modula-2**, not gm2 leniencies.  Declaration before
 use is required for data; only a `POINTER`'s base may forward-reference.
 gm2 compatibility is accepted only where documented in `docs/gaps/`.
 
-## 1. `PACKEDSET` — 3 files (`onebyte`, `onebyte2`, `onebyte3`)
+## 1. `PACKEDSET` — done (spans ≤ 32 bits)
 
-Inspected 2026-10-23; **not** a safe alias to `SET`:
+Implemented 2026-10-23: 1/2/4-byte storage, `SIZE`/`ORD`, `INCL`/`EXCL`/
+`IN`, assignment, set operations, packed arrays/records/parameters.
+Wider packed sets are a loud `230` implementation limit.  Regression
+`t_packedset`.
 
-- `SIZE(PACKEDSET OF [0..7]) = SIZE(BYTE) = 1` (asserted);
-- `ORD(set)` is used (`ORD(si) = 2`, `ORD(se) = 32`);
-- arrays of packed sets (`onebyte3`) check neighbouring bytes.
-
-A faithful implementation needs:
-
-- a type form/class for packed sets with a **byte width**
-  (`ceil(span / 8)`; 1/2/4 bytes for the corpus, possibly an impl limit
-  beyond 32 bits);
-- `TypeSize`/`ElemBytes` = width; `SIZE` = width;
-- packed loads/stores (`loadub`/`loaduh`/`loadw` + `storeb`/`storeh`/
-  `storew`) for variables, fields, arrays and parameters;
-- set operations on packed masks: literal, assignment, `INCL`/`EXCL`,
-  `IN`, `=/#`, union/diff/intersection, `ORD` of a set;
-- range/mask checks consistent with the set span.
-
-Until then, the three corpus files stay `LANG` (documented in
-`docs/gaps/README.md`).  Do not map `PACKEDSET` to `SET` merely to raise
-the compile count.
+The corpus files `onebyte`, `onebyte2`, `onebyte3` still **do not
+compile**, but the blocker is earlier: they use the module variable `r`
+inside `assert` before its declaration (declaration order, rejected by
+policy).  With `r` moved before the procedure they compile and run.
+Do not relax declaration order for this corpus case.
 
 ## 2. ISO exceptions — 7 files (`except2/4/5/7/8/9`, `lazyunique`)
 
@@ -90,7 +79,7 @@ this feature.
 ## Gates for every step
 
 ```sh
-cd compiler && ./build.sh && ./run_tests.sh          # 262/262
+cd compiler && ./build.sh && ./run_tests.sh          # 263/263
 cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
 tools/v3-corpus/corpus.sh                            # 511 OK, 0 crash
 ```
@@ -103,13 +92,12 @@ session summary; commit with a `v3-*` tag.  Do not push without asking.
 ```sh
 cd .../m2compiler-V3
 git checkout master
-cd compiler && ./build.sh && ./run_tests.sh          # 262/262
+cd compiler && ./build.sh && ./run_tests.sh          # 263/263
 cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
 tools/v3-corpus/corpus.sh                            # 511 OK, 0 crash
 ```
 
-**Recommendation:** implement `PACKEDSET` properly (it is the only
-small, self-contained language feature left in the current handoff), or
-take the ISO exceptions design if you want a larger block.  Leave
-multi-dimensional open arrays and library/separate-compilation work for
-their own sessions.
+**Recommendation:** start the **ISO exceptions** design (the largest
+remaining language feature), or take the multi-dimensional-open-array
+ABI decision if you prefer an ABI task.  Library folders and separate
+compilation remain deferred (`docs/plan-separate-compilation.md`).

+ 22 - 21
docs/summary_session-2026-10-23.md

@@ -1,4 +1,4 @@
-# Session 2026-10-23 — continuation: range checks; PACKEDSET inspection
+# Session 2026-10-23 — range checks + PACKEDSET
 
 Branch **`master`**.  Continues `summary_session-2026-10-22.md` from the
 2026-10-22 stop point (`v3-smallfix`).
@@ -7,12 +7,26 @@ Branch **`master`**.  Continues `summary_session-2026-10-22.md` from the
 
 | gate | start | end |
 | --- | --- | --- |
-| suite (`compiler/run_tests.sh`) | 259/259 | **262/262** |
-| fixpoint (`bootstrap/fixpoint.sh`) | OK (4,028,447 B) | **OK (4,032,793 B)** |
+| suite (`compiler/run_tests.sh`) | 259/259 | **263/263** |
+| fixpoint (`bootstrap/fixpoint.sh`) | OK (4,028,447 B) | **OK (4,075,853 B)** |
 | corpus (`tools/v3-corpus/corpus.sh`) | 511/612 | **511/612, 0 crashes** |
 
 ## What landed
 
+### `PACKEDSET` — `SymTab` + `QbeGen` + `Lower` + grammar
+
+ISO `PACKEDSET OF <ordinal>` is implemented for spans up to 32 bits:
+1/2/4-byte storage (`SIZE` is the packed width), `ORD` is the mask,
+and `INCL`/`EXCL`/`IN`, assignment, set operations, packed array/record
+elements and value/VAR parameters all work.  Wider spans are a loud
+`230` implementation limit.  Regression `t_packedset`.
+
+The corpus files `onebyte`, `onebyte2`, `onebyte3` still do not
+compile, but the blocker is earlier: they use the module variable `r`
+inside `assert` before its declaration (declaration order, rejected by
+policy).  With `r` moved before the procedure they compile and run
+correctly.  Corpus stays 511.
+
 ### Runtime subrange range checks — `Lower` + `QbeGen.CheckRange`
 
 V3 accepted base-typed values into CHAR/enum subranges but emitted no
@@ -32,29 +46,16 @@ subranges are not checked yet.
 Regressions: `t_trap_range` (assignment), `t_trap_range_arg` (actual),
 `t_trap_range_ret` (`RETURN`); `t_subrange` remains the in-range case.
 
-### PACKEDSET — inspected, parked
-
-The handoff suggested starting with `PACKEDSET`.  Inspection of
-`onebyte*` shows it is **not** safe to alias to `SET`:
-
-- `SIZE(PACKEDSET) = SIZE(BYTE) = 1` is asserted;
-- `ORD(set)` is asserted (e.g. `ORD(si) = 2`, `ORD(se) = 32`);
-- `onebyte3` uses an `ARRAY OF PACKEDSET` and checks neighbouring bytes.
-
-A faithful implementation needs a 1/2/4-byte packed representation and
-packed set operations, not just a parser alias.  It is parked in
-`docs/handoff-2026-10-23-next.md` / `docs/gaps/README.md`.  Corpus
-stays at 511.
-
 ## Commits
 
 | commit | tag | work |
 | --- | --- | --- |
 | `54d84b9` | `v3-rangechecks` | runtime subrange range checks (+3 trap tests) |
+| `pending` | `v3-packedset` | PACKEDSET 1/2/4-byte storage |
 
 ## Remaining
 
-See `docs/handoff-2026-10-23-next.md`.  The next candidates are
-`PACKEDSET` (with a real representation), ISO exceptions (dedicated
-session), multi-dimensional open arrays (ABI decision), and the
-library-folder / separate-compilation plans (both deferred).
+See `docs/handoff-2026-10-23-next.md`.  The next candidates are ISO
+exceptions (dedicated session), multi-dimensional open arrays (ABI
+decision), and the library-folder / separate-compilation plans (both
+deferred).