Przeglądaj źródła

language: defer a forward type used as an array index

TYPE a = ARRAY idx OF T ; idx = [-2..2] (and an array field inside a
record/pointer, record7/complextypes) was a 230: the index type alias is
unresolved when the array is built.

Mark aliases created by ForwardType (tFwd) and, when an array's index is
such an alias, build it with placeholder bounds and record a deferred
fix-up (SymTab.DeferArrayIdx).  EndTypeBlock patches every pending
array's [lo..hi] (FixupArrayIdxs) once its index resolves.  Generic type
formals are not marked, so their array indices are unaffected.

Corpus 391 -> 393, 0 crashes.  Suite 229/229 (t_arrfwd).  Fixpoint OK,
3,839,005 bytes.
Eric Streit 1 dzień temu
rodzic
commit
9f4c7a474a

+ 2 - 2
README.md

@@ -47,8 +47,8 @@ docs/              STATUS.md, plan.md, plan-*.md, analysis_*.md, summary_*.md
 
 ## Status (2026-10-18)
 
-- Suite **228/228**; self-hosting **fixpoint OK** (byte-identical
-  stage2/stage3, 3,829,455 bytes); corpus **391/612 compile-OK,
+- Suite **229/229**; self-hosting **fixpoint OK** (byte-identical
+  stage2/stage3, 3,839,005 bytes); corpus **393/612 compile-OK,
   0 crashes** (`tools/v3-corpus`).
 - Active branch **`resolve-check`** (holds the AST/`Lower`/parse
   refactors and generics).

+ 1 - 0
compiler/run_tests.sh

@@ -99,6 +99,7 @@ expect_run t_setconst.mod 42
 expect_run t_constbuiltin.mod 42
 expect_run t_constreal.mod 42
 expect_run t_constlong.mod 42
+expect_run t_arrfwd.mod 42
 expect_run t_unicode.mod 31
 expect_run t_charbounds.mod 3
 expect_run t_record.mod 160

+ 8 - 0
compiler/src/M2.atg

@@ -1276,6 +1276,14 @@ PRODUCTIONS
                                               ihi)
                                            THEN t := SymTab.NewArrayB(elem,
                                                   ilo, ihi)
+                                           ELSIF SymTab.IsForwardType(idx)
+                                           THEN
+                                             (* forward index type: build
+                                                with placeholder bounds,
+                                                patched at EndTypeBlock *)
+                                             t := SymTab.NewArrayB(elem,
+                                                  0, 0);
+                                             SymTab.DeferArrayIdx(t, idx)
                                            ELSE SemError(230);
                                              t := SymTab.InvalidType
                                            END; .)

+ 2785 - 2777
compiler/src/M2.lst

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

+ 8 - 0
compiler/src/SymTab.def

@@ -401,6 +401,14 @@ PROCEDURE NewOpenArray (elem: TypeIndex): TypeIndex;
 (* Open ARRAY OF formal: 0-based, runtime count in the header.
    Only legal for formal parameters (grammar enforces). *)
 
+PROCEDURE DeferArrayIdx (arr, idx: TypeIndex);
+(* arr was built with placeholder bounds because its index type idx is a
+   forward reference; its [lo..hi] is patched when idx completes (at the
+   enclosing TYPE block's end, or the module-level TYPE block). *)
+PROCEDURE IsForwardType (t: TypeIndex): BOOLEAN;
+(* TRUE for an alias a forward reference created (to distinguish a
+   deferrable placeholder from a generic type formal). *)
+
 PROCEDURE BoundBegin;
 PROCEDURE BoundAdd (lo, hi: INTEGER): BOOLEAN;
 (* Accumulates one index bound pair for the enclosing ArrayType

+ 41 - 1
compiler/src/SymTab.mod

@@ -82,6 +82,12 @@ VAR
   nPend : CARDINAL;
   pendF : ARRAY [0 .. MaxPend - 1] OF FieldPtr;
   nPendF : CARDINAL;
+  (* forward-typed array indices awaiting completion: (array, index
+     alias).  Patched at EndTypeBlock once the alias resolves. *)
+  aPendN : CARDINAL;
+  aPendArr : ARRAY [0 .. MaxPend - 1] OF TypeIndex;
+  aPendIdx : ARRAY [0 .. MaxPend - 1] OF TypeIndex;
+  tFwd : ARRAY [0 .. MaxTypes - 1] OF BOOLEAN;  (* created by ForwardType *)
   tform : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
   tref : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
   tlo : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
@@ -2359,6 +2365,38 @@ PROCEDURE OpaqueBase (name: ARRAY OF CHAR): TypeIndex;
     RETURN InvalidType
   END OpaqueBase;
 
+PROCEDURE DeferArrayIdx (arr, idx: TypeIndex);
+  BEGIN
+    IF aPendN <= HIGH(aPendArr) THEN
+      aPendArr[aPendN] := arr; aPendIdx[aPendN] := idx; INC(aPendN)
+    END
+  END DeferArrayIdx;
+
+PROCEDURE IsForwardType (t: TypeIndex): BOOLEAN;
+  BEGIN
+    RETURN (t >= 0) AND (t < VAL(INTEGER, nTypes)) AND tFwd[t]
+  END IsForwardType;
+
+PROCEDURE FixupArrayIdxs;
+(* Patch every deferred array whose index alias now resolves. *)
+  VAR i: CARDINAL; lo, hi: INTEGER; arr, idx: TypeIndex;
+  BEGIN
+    i := 0;
+    WHILE i < aPendN DO
+      arr := aPendArr[i]; idx := aPendIdx[i];
+      IF TypeBounds(idx, lo, hi) THEN
+        IF (arr >= 0) AND (arr < VAL(INTEGER, nTypes))
+           AND (tform[arr] = FArray) THEN
+          alo[arr] := lo; ahi[arr] := hi
+        END;
+        DEC(aPendN);
+        aPendArr[i] := aPendArr[aPendN];
+        aPendIdx[i] := aPendIdx[aPendN]
+      ELSE INC(i)
+      END
+    END
+  END FixupArrayIdxs;
+
 PROCEDURE BeginTypeBlock;
   BEGIN
     INC(typeBlockDepth)
@@ -2366,7 +2404,8 @@ PROCEDURE BeginTypeBlock;
 
 PROCEDURE EndTypeBlock;
   BEGIN
-    IF typeBlockDepth > 0 THEN DEC(typeBlockDepth) END
+    IF typeBlockDepth > 0 THEN DEC(typeBlockDepth) END;
+    FixupArrayIdxs
   END EndTypeBlock;
 
 PROCEDURE IsUnresolved (t: TypeIndex): BOOLEAN;
@@ -2395,6 +2434,7 @@ PROCEDURE ForwardType (name: ARRAY OF CHAR): TypeIndex;
     END;
     IF NOT Enter(name, KindType) THEN RETURN InvalidType END;
     t := NewAlias();
+    IF (t >= 0) AND (t < VAL(INTEGER, nTypes)) THEN tFwd[t] := TRUE END;
     SetSymType(name, t);
     IF (typeBlockDepth = 0) AND (pfwdN <= HIGH(pfwdName)) THEN
       Assign(pfwdName[pfwdN], name);

+ 12 - 0
compiler/tests/t_arrfwd.mod

@@ -0,0 +1,12 @@
+MODULE TArrFwd;
+// An ARRAY whose index type is declared later (a forward type reference):
+// its bounds are patched when the TYPE block completes.  Exit 42.
+TYPE a = ARRAY idx OF INTEGER;
+     idx = [-2..2];
+VAR x : a;
+    ExitCode : INTEGER;
+BEGIN
+  x[0] := 5;
+  x[2] := 37;
+  IF x[0] + x[2] = 42 THEN ExitCode := 42 ELSE ExitCode := 1 END
+END TArrFwd.

+ 1 - 1
docs/INDEX.md

@@ -29,7 +29,7 @@ bisecting *why* a decision was made, not for reading end-to-end).
   bounds, set-of-enum, forward set); set-constant + folding findings.
 - `summary_set-constants-2026-10-18.md` — SET CONST (static masks,
   folded unions), builtin CONST folding (CAP/ABS/ODD, BOOLEAN consts),
-  and CONST representation conversions.
+  CONST representation conversions, and forward array-index types.
 - `summary_dlist-showcase-2026-10-16.md` — showcase23 + limitation fixes.
 - `summary_generics-limitations-fixed-2026-10-16.md` — the two
   template/proc-param limitations, fixed.

+ 7 - 6
docs/STATUS.md

@@ -4,10 +4,10 @@ This answers "where are we now?".
 
 ## Numbers
 
-- Suite **228/228** (`compiler/run_tests.sh`).
+- Suite **229/229** (`compiler/run_tests.sh`).
 - Self-hosting **FIXPOINT OK** — stage2 and stage3 images are
-  byte-identical (3,829,455 bytes).
-- Corpus **391 / 612** sources compile with 0 errors, **0 crashes**
+  byte-identical (3,839,005 bytes).
+- Corpus **393 / 612** sources compile with 0 errors, **0 crashes**
   (`tools/v3-corpus/corpus.sh` over the gm2 testsuite); the rest are
   genuine language gaps or unresolved imports.
 - Branch **`resolve-check`**; tree clean.
@@ -58,9 +58,10 @@ parameters, constraints, nested generics, generic classes.
 - **SET CONST** (static masks): a set constant (`CharSet{"0".."9"}`,
   a union of set constants) is folded to a mask at parse and re-emitted
   as a pooled `data $setN` descriptor.  **Builtin `CONST` folding**
-  (`CAP`/`ABS`/`ODD` over immediates), `BOOLEAN` `CONST`s, and
+  (`CAP`/`ABS`/`ODD` over immediates), `BOOLEAN` `CONST`s,
   representation-changing `CONST` conversions (`VAL(REAL, int)`,
-  `VAL(LONGINT, int)`, …) also landed: corpus 382 → 391.
+  `VAL(LONGINT, int)`, …), and **forward array-index types** (deferred,
+  patched at `EndTypeBlock`): corpus 382 → 393.
 - Clean `M2` exit codes (0 ok / 1 errors / 2 usage-IO).
 - Bug fixes: `PopPos` wiping repass diagnostics; global record data
   size (`w 0` → `l 0` for pointer/`LONGINT`/proc fields); template
@@ -88,7 +89,7 @@ parameters, constraints, nested generics, generic classes.
 ```sh
 cd compiler
 ./build.sh          # M2.atg -> scanner/parser/driver -> ./M2
-./run_tests.sh      # 228/228
+./run_tests.sh      # 229/229
 cd ..
 ./bootstrap/fixpoint.sh   # FIXPOINT OK (byte-identical stage2/stage3)
 ```

+ 10 - 4
docs/analysis_gaps.md

@@ -202,7 +202,13 @@ initialisers also landed **representation-changing conversions**:
 immediate.  Corpus **389 -> 391**; suite tests `t_constreal`,
 `t_constlong`.
 
-Next (recorded): forward *type* references in an array index / `CONST`
-conversion (`subrange4`/`7`/`11`, `record7`, `complextypes`,
-`setconst3`), and the `imp*` qualified-import family (partly a
-corpus-harness transitive-`.def` gap).
+Also landed **forward array-index types**: `TYPE a = ARRAY idx OF T;
+idx = [-2..2]` defers the array and patches its bounds at `EndTypeBlock`
+(`SymTab.DeferArrayIdx`/`FixupArrayIdxs`, `tFwd`).  `record7`/
+`complextypes` now pass; corpus **391 -> 393**; suite test `t_arrfwd`.
+
+Next (recorded): forward *type* references in a `CONST` conversion
+(`subrange4`/`7`) and as a `VAR` type before its TYPE block
+(`subrange11`); `setconst3` (forward `CONST`); `minmaxreal3` (SYSTEM
+`REAL64`); the `imp*` qualified-import family (partly a corpus-harness
+transitive-`.def` gap).

+ 26 - 13
docs/summary_set-constants-2026-10-18.md

@@ -1,16 +1,18 @@
 # Session summary — SET CONST + builtin CONST folding 2026-10-18
 
-Branch **`resolve-check`**.  Suite **228/228**; fixpoint **OK
-(3,829,455 bytes)**; corpus **391/612 compile-OK, 0 crashes**.
+Branch **`resolve-check`**.  Suite **229/229**; fixpoint **OK
+(3,839,005 bytes)**; corpus **393/612 compile-OK, 0 crashes**.
 
-Tags: `v3-set-constants`, `v3-const-builtin-fold`, `v3-const-conv-fold`.
+Tags: `v3-set-constants`, `v3-const-builtin-fold`, `v3-const-conv-fold`,
+`v3-array-index-fwd`.
 
 ## What this session did
 
 Landed the two features recorded in `docs/analysis_gaps.md` §9 by the
 previous corpus sweep — **set constants** (static masks) and **builtin
 calls in `CONST` initialisers** — then went further on `CONST`
-initialisers.  Corpus **382 → 391** (+9 files, 0 crashes).
+initialisers and forward type references.  Corpus **382 → 393**
+(+11 files, 0 crashes).
 
 ```mod
 CONST Digits = CharSet{"0".."9"};          (* char range *)
@@ -77,34 +79,45 @@ conversions: `INT`/`LONGINT`→`REAL` (and `FLOAT`, via `NormReal`),
 `INT`↔`LONGINT` (identity on an immediate), and identical-class
 `LONGINT`→`LONGINT`.  Corpus **389 → 391**.
 
+## Forward array-index type
+
+`TYPE a = ARRAY idx OF T; idx = [-2..2]` (and `ARRAY sub OF …` inside a
+record/pointer, `record7`/`complextypes`) was a `230`: the index alias is
+unresolved when the array is built.  `SymTab` now marks forward aliases
+(`tFwd`, set by `ForwardType`) and defers such arrays with placeholder
+bounds (`DeferArrayIdx`); `EndTypeBlock` patches their `[lo..hi]`
+(`FixupArrayIdxs`) once the alias resolves.  Generic type formals are not
+marked, so they are unaffected.  Corpus **391 → 393**; suite test
+`t_arrfwd`.
+
 ## Not fixed (recorded)
 
 - **`setconst3.mod`** still fails: its `VAR mem: ARRAY [0..CARDINAL(
   addressLines)]` names a `CONST` declared *after* the `VAR` (a forward
   CONST reference), which is a separate gap.  Its `SET CONST` itself now
   parses.
-- Forward *type* references in an array index (`VAR a: ARRAY ind OF …`
-  with `ind` later, `record7`, `complextypes`) and in a `CONST`
-  conversion (`subrange4`/`7`); `minmaxreal3` (SYSTEM `REAL64`); the
-  `imp*` qualified-import family (partly a corpus-harness transitive
-  `.def` gap).
+- Forward *type* references in a `CONST` conversion (`subrange4`/`7`)
+  and as a `VAR` type before its TYPE block (`subrange11`);
+  `minmaxreal3` (SYSTEM `REAL64`); the `imp*` qualified-import family
+  (partly a corpus-harness transitive-`.def` gap).
 
 ## Files
 
 `compiler/src/Lower.{def,mod}` (evaluator + `PoolSet` call),
 `compiler/src/QbeGen.{def,mod}` (`PoolSet`/`FlushSets`/pool state),
+`compiler/src/SymTab.{def,mod}` (forward array-index deferral),
 `compiler/src/M2.atg` (`ConstDecl`, `Design`, `CAP`/`ABS`/`ODD` folds,
-`VAL` conversion folds),
+`VAL` conversion folds, array-index defer),
 `compiler/tests/t_setconst.mod`, `t_bad_setconst.mod`,
 `t_constbuiltin.mod`, `t_constreal.mod`, `t_constlong.mod`,
-`compiler/run_tests.sh`.
+`t_arrfwd.mod`, `compiler/run_tests.sh`.
 
 ## Resume
 
 ```sh
 cd .../m2compiler-V3
 git checkout resolve-check
-cd compiler && ./build.sh && ./run_tests.sh   # 228/228
+cd compiler && ./build.sh && ./run_tests.sh   # 229/229
 cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
-M2FLAGS="" ./.scratch/corpusx.sh              # 391 OK, 0 crash
+M2FLAGS="" ./.scratch/corpusx.sh              # 393 OK, 0 crash
 ```