Forráskód Böngészése

NUL-terminated string model: CHAR arrays reserve a terminator slot; stdlib Strings + shim NUL-based; bounds allow index=count (111/111)

Eric Streit 2 hete
szülő
commit
bc7fc8ef62

+ 14 - 2
compiler/src/M2.atg

@@ -1508,10 +1508,16 @@ PRODUCTIONS
                                                SymTab.IsOpenArray(t);
                                              IF isOpen THEN
                                                QbeGen.CopyOp("0", qlo);
-                                               QbeGen.OpenHi(q, qhi)
+                                               IF SymTab.IsCharArray(t) THEN
+                                                 QbeGen.OpenHiChar(q, qhi)
+                                               ELSE QbeGen.OpenHi(q, qhi)
+                                               END
                                              ELSE
                                                lo := SymTab.ArrayLo(t);
                                                hi := SymTab.ArrayHi(t);
+                                               IF SymTab.IsCharArray(t) THEN
+                                                 hi := hi + 1
+                                               END;
                                                QbeGen.IntStr(lo, qlo);
                                                QbeGen.IntStr(hi, qhi)
                                              END;
@@ -1544,10 +1550,16 @@ PRODUCTIONS
                                                SymTab.IsOpenArray(t);
                                              IF isOpen THEN
                                                QbeGen.CopyOp("0", qlo);
-                                               QbeGen.OpenHi(q, qhi)
+                                               IF SymTab.IsCharArray(t) THEN
+                                                 QbeGen.OpenHiChar(q, qhi)
+                                               ELSE QbeGen.OpenHi(q, qhi)
+                                               END
                                              ELSE
                                                lo := SymTab.ArrayLo(t);
                                                hi := SymTab.ArrayHi(t);
+                                               IF SymTab.IsCharArray(t) THEN
+                                                 hi := hi + 1
+                                               END;
                                                QbeGen.IntStr(lo, qlo);
                                                QbeGen.IntStr(hi, qhi)
                                              END;

+ 727 - 715
compiler/src/M2.lst

@@ -1525,723 +1525,735 @@ Listing:
  1508                                                 SymTab.IsOpenArray(t);
  1509                                               IF isOpen THEN
  1510                                                 QbeGen.CopyOp("0", qlo);
- 1511                                                 QbeGen.OpenHi(q, qhi)
- 1512                                               ELSE
- 1513                                                 lo := SymTab.ArrayLo(t);
- 1514                                                 hi := SymTab.ArrayHi(t);
- 1515                                                 QbeGen.IntStr(lo, qlo);
- 1516                                                 QbeGen.IntStr(hi, qhi)
- 1517                                               END;
- 1518                                               QbeGen.CheckRange(ql, qlo,
- 1519                                                 qhi);
- 1520                                               eT := SymTab.ArrayElem(t);
- 1521                                               QbeGen.ElemAddr(q, ql, qlo,
- 1522                                                 t, qe);
- 1523                                               IF SymTab.ClassOf(eT) =
- 1524                                                  SymTab.ClArray THEN
- 1525                                                 QbeGen.ElemLoad(qe, eT, q)
- 1526                                               ELSE QbeGen.CopyOp(qe, q)
- 1527                                               END;
- 1528                                               t := eT; sfx := TRUE
- 1529                                             END; .)
- 1530          { "," Expr<it, iq>
- 1531                                          (. IF t = SymTab.InvalidType THEN
- 1532                                             ELSIF SymTab.ClassOf(t) #
- 1533                                                   SymTab.ClArray THEN
- 1534                                               SemError(217);
- 1535                                               t := SymTab.InvalidType
- 1536                                             ELSIF NOT SymTab.IsIntFamily(it)
- 1537   AND (SymTab.ClassOf(it) #
- 1538                                                   SymTab.ClChar) THEN
- 1539                                               SemError(218);
- 1540                                               t := SymTab.InvalidType
- 1541                                             ELSE
- 1542                                               QbeGen.WidenIndex(iq, ql);
- 1543                                               isOpen :=
- 1544                                                 SymTab.IsOpenArray(t);
- 1545                                               IF isOpen THEN
- 1546                                                 QbeGen.CopyOp("0", qlo);
- 1547                                                 QbeGen.OpenHi(q, qhi)
- 1548                                               ELSE
- 1549                                                 lo := SymTab.ArrayLo(t);
- 1550                                                 hi := SymTab.ArrayHi(t);
- 1551                                                 QbeGen.IntStr(lo, qlo);
- 1552                                                 QbeGen.IntStr(hi, qhi)
- 1553                                               END;
- 1554                                               QbeGen.CheckRange(ql, qlo,
- 1555                                                 qhi);
- 1556                                               eT := SymTab.ArrayElem(t);
- 1557                                               QbeGen.ElemAddr(q, ql, qlo,
- 1558                                                 t, qe);
- 1559                                               IF SymTab.ClassOf(eT) =
- 1560                                                  SymTab.ClArray THEN
- 1561                                                 QbeGen.ElemLoad(qe, eT, q)
- 1562                                               ELSE QbeGen.CopyOp(qe, q)
- 1563                                               END;
- 1564                                               t := eT; sfx := TRUE
- 1565                                             END; .) }
- 1566          "]"
- 1567        | "." GetIdent<fn>
- 1568                                          (. IF k = SymTab.KindModule THEN
- 1569                                               (* qualified L.x: materialize
- 1570                                                  the export, then load it *)
- 1571                                               IF NOT SymTab.MaterializeAlias(n,
- 1572                                                    fn, mal) THEN
- 1573                                                 SemError(201);
- 1574                                                 t := SymTab.InvalidType;
- 1575                                                 QbeGen.CopyOp("0", q)
- 1576                                               ELSE
- 1577                                                 QbeGen.CopyOp(mal, qn);
- 1578                                                 t := SymTab.SymType(mal);
- 1579                                                 k := SymTab.SymKind(mal);
- 1580                                                 sfx := FALSE;
- 1581                                                 IF k = SymTab.KindProc THEN
- 1582                                                   (* call: ArgList supplies
- 1583                                                      the value *)
- 1584                                                   QbeGen.CopyOp("0", q)
- 1585                                                 ELSIF NOT QbeGen.LoadDesignator(
- 1586                                                      mal, t, k, q) THEN
- 1587                                                   SemError(230);
- 1588                                                   QbeGen.CopyOp("0", q)
- 1589                                                 END
- 1590                                               END
- 1591                                             ELSIF t = SymTab.InvalidType THEN
- 1592                                             ELSIF (SymTab.ClassOf(t) #
- 1593                                                    SymTab.ClRecord)
- 1594   AND (SymTab.ClassOf(t) #
- 1595                                                   SymTab.ClClass) THEN
- 1596                                               SemError(215);
- 1597                                               t := SymTab.InvalidType
- 1598                                             ELSIF NOT SymTab.FieldExists(t,
- 1599                                                      fn) THEN
- 1600                                               SemError(216);
- 1601                                               t := SymTab.InvalidType
- 1602                                             ELSE
- 1603                                               fo := SymTab.FieldOffset(t,
- 1604                                                 fn);
- 1605                                               t := SymTab.FieldType(t, fn);
- 1606                                               QbeGen.FieldAddr(q, fo, qe);
- 1607                                               (* array fields are inline:
- 1608                                                  the field address is the
- 1609                                                  descriptor, like records *)
- 1610                                               QbeGen.CopyOp(qe, q);
- 1611                                               sfx := TRUE
- 1612                                             END; .)
- 1613        | "^"
- 1614                                          (. IF t = SymTab.InvalidType THEN
- 1615                                             ELSIF SymTab.ClassOf(t) #
- 1616                                                   SymTab.ClPtr THEN
- 1617                                               SemError(219);
- 1618                                               t := SymTab.InvalidType
- 1619                                             ELSE
- 1620                                               bt := SymTab.PtrBase(t);
- 1621                                               IF bt = SymTab.InvalidType THEN
- 1622                                               ELSE
- 1623                                                 IF sfx THEN
- 1624                                                   QbeGen.ElemLoad(q, t,
- 1625                                                     qb);
- 1626                                                   QbeGen.CopyOp(qb, q)
- 1627                                                 END;
- 1628                                                 t := bt;
- 1629                                                 IF (SymTab.ClassOf(bt) =
- 1630                                                    SymTab.ClInt)
- 1631                                                    OR (SymTab.ClassOf(bt) =
- 1632                                                        SymTab.ClBool)
- 1633                                                    OR (SymTab.ClassOf(bt) =
- 1634                                                        SymTab.ClChar)
- 1635                                                    OR (SymTab.ClassOf(bt) =
- 1636                                                        SymTab.ClReal) THEN
- 1637                                                   sfx := TRUE
- 1638                                                 ELSE sfx := FALSE
- 1639                                                 END
- 1640                                               END
- 1641                                             END; .) } .
- 1642    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1643                                          (. VAR t2: SymTab.TypeIndex;
- 1644                                               op: INTEGER;
- 1645                                               q2, qt, wl: QbeGen.QVal;
- 1646                                               isR: BOOLEAN; .)
- 1647      = SimExpr<t, q>
- 1648        [ Rel<op> SimExpr<t2, q2>
- 1649          (. IF op = SymTab.OpIn THEN
- 1650               IF SymTab.InCheck(t, t2) THEN
- 1651                 IF (t = SymTab.InvalidType)
- 1652                    OR (t2 = SymTab.InvalidType) THEN
- 1653                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 1654                 ELSE
- 1655                   QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2),
- 1656                     SymTab.SetCount(t2), qt);
- 1657                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 1658                 END
- 1659               ELSE SemError(222); t := SymTab.InvalidType;
- 1660                 QbeGen.CopyOp("0", q)
- 1661               END
- 1662             ELSIF SymTab.RelCheck(t, t2, op) THEN
- 1663               IF (t = SymTab.InvalidType)
- 1664                  OR (t2 = SymTab.InvalidType) THEN
- 1665                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
- 1666               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
- 1667                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
- 1668                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
- 1669   AND (op # SymTab.OpNeq2) THEN
- 1670                   SemError(213); t := SymTab.InvalidType;
- 1671                   QbeGen.CopyOp("0", q)
- 1672                 ELSE
- 1673                   QbeGen.CmpL(op, q, q2, qt);
- 1674                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 1675                 END
- 1676               ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
- 1677                  OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 1678                 QbeGen.CmpSet(op, q, q2,
- 1679                   SymTab.SetWords(t), SymTab.SetWords(t2), qt);
- 1680                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 1681               ELSIF SymTab.IsLongFamily(t)
- 1682                  OR SymTab.IsLongFamily(t2) THEN
- 1683                 IF SymTab.IsIntFamily(t) THEN
- 1684                   QbeGen.WidenLong(q, wl); QbeGen.CopyOp(wl, q)
- 1685                 END;
- 1686                 IF SymTab.IsIntFamily(t2) THEN
- 1687                   QbeGen.WidenLong(q2, wl); QbeGen.CopyOp(wl, q2)
- 1688                 END;
- 1689                 QbeGen.CmpLong(op, q, q2, qt);
- 1690                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
- 1691               ELSE
- 1692                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 1693                 t := SymTab.BoolType();
- 1694                 QbeGen.Cmp(op, q, q2, qt, isR);
- 1695                 QbeGen.CopyOp(qt, q)
- 1696               END
- 1697             ELSE SemError(213); t := SymTab.InvalidType;
- 1698               QbeGen.CopyOp("0", q)
- 1699             END; .) ] .
- 1700    Rel<VAR op: INTEGER>
- 1701      = "="                               (. op := SymTab.OpEq; .)
- 1702      | "#"                               (. op := SymTab.OpNeq1; .)
- 1703      | "<"                               (. op := SymTab.OpLt; .)
- 1704      | "<="                              (. op := SymTab.OpLe; .)
- 1705      | ">"                               (. op := SymTab.OpGt; .)
- 1706      | ">="                              (. op := SymTab.OpGe; .)
- 1707      | "IN"                              (. op := SymTab.OpIn; .) .
- 1708    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1709                                          (. VAR t2, res2, lt, rt:
- 1710                                                 SymTab.TypeIndex;
- 1711                                               op: INTEGER;
- 1712                                               q2, qt, wq, qf:
- 1713                                                 QbeGen.QVal;
- 1714                                               neg, isR, isL, folded:
- 1715                                                 BOOLEAN;
- 1716                                               lw, rw, mw: CARDINAL; .)
- 1717      =                                   (. neg := FALSE; .)
- 1718        [ "+" | "-"                       (. neg := TRUE; .) ]
- 1719        Term<t, q>                        (. IF neg THEN
- 1720                                             IF QbeGen.IsImm(q) THEN
- 1721                                               QbeGen.NegFold(q, q)
- 1722                                             ELSE QbeGen.NewTemp(qt);
- 1723                                               QbeGen.NegQ(q, qt,
- 1724                                                 SymTab.ClassOf(t)
- 1725                                                 = SymTab.ClReal);
- 1726                                               QbeGen.CopyOp(qt, q)
- 1727                                             END
- 1728                                           END; .)
- 1729        { AddOp<op> Term<t2, q2>
- 1730          (. IF op = SymTab.OpOr THEN
- 1731               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 1732                 t := SymTab.BoolType()
- 1733               ELSE SemError(212); t := SymTab.InvalidType END;
- 1734               IF t # SymTab.InvalidType THEN
- 1735                 QbeGen.NewTemp(qt);
- 1736                 QbeGen.Op3("or", qt, q, q2, FALSE);
- 1737                 QbeGen.CopyOp(qt, q)
- 1738               ELSE QbeGen.CopyOp("0", q)
- 1739               END
- 1740             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 1741   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 1742   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 1743               lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 1744               mw := lw;
- 1745               IF rw > mw THEN mw := rw END;
- 1746               IF op = SymTab.OpAdd THEN
- 1747                 QbeGen.SetBinOp(0, q, q2, lw, rw, qt)
- 1748               ELSE
- 1749                 QbeGen.SetBinOp(2, q, q2, lw, rw, qt)
- 1750               END;
- 1751               t := SymTab.NewSet(
- 1752                      SymTab.NewSubR(0,
- 1753                        VAL(INTEGER, mw) * 32 - 1));
- 1754               QbeGen.CopyOp(qt, q)
- 1755             ELSE
- 1756               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
- 1757                 lt := t; rt := t2; t := res2
- 1758               ELSE SemError(211); t := SymTab.InvalidType END;
- 1759               IF t # SymTab.InvalidType THEN
- 1760                 isL := SymTab.IsLongFamily(t);
- 1761                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 1762                 folded := FALSE;
- 1763                 IF (NOT isL) AND (NOT isR)
- 1764    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 1765                   IF op = SymTab.OpAdd THEN
- 1766                     folded := QbeGen.Fold2(0, q, q2, qf)
- 1767                   ELSE
- 1768                     folded := QbeGen.Fold2(1, q, q2, qf)
- 1769                   END
- 1770                 END;
- 1771                 IF folded THEN QbeGen.CopyOp(qf, q)
- 1772                 ELSE
- 1773                 IF isL THEN
- 1774                   IF SymTab.IsIntFamily(lt) THEN
- 1775                     QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
- 1776                   END;
- 1777                   IF SymTab.IsIntFamily(rt) THEN
- 1778                     QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
- 1779                   END;
- 1780                   QbeGen.NewTemp(qt);
- 1781                   IF op = SymTab.OpAdd THEN
- 1782                     QbeGen.Op3L("add", qt, q, q2)
- 1783                   ELSE
- 1784                     QbeGen.Op3L("sub", qt, q, q2)
- 1785                   END
- 1786                 ELSE
- 1787                   QbeGen.NewTemp(qt);
- 1788                   IF op = SymTab.OpAdd THEN
- 1789                     QbeGen.Op3("add", qt, q, q2, isR)
- 1790                   ELSE
- 1791                     QbeGen.Op3("sub", qt, q, q2, isR)
- 1792                   END
- 1793                 END;
- 1794                 QbeGen.CopyOp(qt, q)
- 1795                 END
- 1796               ELSE QbeGen.CopyOp("0", q)
- 1797               END
- 1798             END; .) } .
- 1799    AddOp<VAR op: INTEGER>
- 1800      = "+"                               (. op := SymTab.OpAdd; .)
- 1801      | "-"                               (. op := SymTab.OpSub; .)
- 1802      | "OR"                              (. op := SymTab.OpOr; .) .
- 1803    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1804                                          (. VAR t2, res2, lt, rt:
- 1805                                                 SymTab.TypeIndex;
- 1806                                               op: INTEGER;
- 1807                                               q2, qt, wq, qf:
- 1808                                                 QbeGen.QVal;
- 1809                                               isR, isL, folded: BOOLEAN;
- 1810                                               lw, rw, mw: CARDINAL; .)
- 1811      = Fact<t, q> { MulOp<op> Fact<t2, q2>
- 1812        (. IF op = SymTab.OpAnd THEN
- 1813             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
- 1814               t := SymTab.BoolType()
- 1815             ELSE SemError(212); t := SymTab.InvalidType END;
- 1816             IF t # SymTab.InvalidType THEN
- 1817               QbeGen.NewTemp(qt);
- 1818               QbeGen.Op3("and", qt, q, q2, FALSE);
- 1819               QbeGen.CopyOp(qt, q)
- 1820             ELSE QbeGen.CopyOp("0", q)
- 1821             END
- 1822           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
- 1823   AND (SymTab.ClassOf(t) = SymTab.ClSet)
- 1824   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
- 1825             lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
- 1826             mw := lw;
- 1827             IF rw > mw THEN mw := rw END;
- 1828             IF op = SymTab.OpTimes THEN
- 1829               QbeGen.SetBinOp(1, q, q2, lw, rw, qt)
- 1830             ELSE
- 1831               QbeGen.SetBinOp(3, q, q2, lw, rw, qt)
- 1832             END;
- 1833             t := SymTab.NewSet(
- 1834                    SymTab.NewSubR(0,
- 1835                      VAL(INTEGER, mw) * 32 - 1));
- 1836             QbeGen.CopyOp(qt, q)
- 1837           ELSE
- 1838             IF SymTab.ArithCheck(t, t2,
- 1839                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
- 1840                  res2) THEN
- 1841               lt := t; rt := t2; t := res2
- 1842             ELSE SemError(211); t := SymTab.InvalidType END;
- 1843             IF t # SymTab.InvalidType THEN
- 1844               isL := SymTab.IsLongFamily(t);
- 1845               isR := SymTab.ClassOf(t) = SymTab.ClReal;
- 1846               folded := FALSE;
- 1847               IF (NOT isL) AND (NOT isR)
- 1848    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
- 1849                 IF op = SymTab.OpTimes THEN
- 1850                   folded := QbeGen.Fold2(2, q, q2, qf)
- 1851                 ELSIF op = SymTab.OpDiv THEN
- 1852                   folded := QbeGen.Fold2(3, q, q2, qf)
- 1853                 ELSIF op = SymTab.OpMod THEN
- 1854                   folded := QbeGen.Fold2(4, q, q2, qf)
- 1855                 END
- 1856               END;
- 1857               IF folded THEN QbeGen.CopyOp(qf, q)
- 1858               ELSE
- 1859               IF isL THEN
- 1860                 IF SymTab.IsIntFamily(lt) THEN
- 1861                   QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
- 1862                 END;
- 1863                 IF SymTab.IsIntFamily(rt) THEN
- 1864                   QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
- 1865                 END;
- 1866                 QbeGen.NewTemp(qt);
- 1867                 IF op = SymTab.OpTimes THEN
- 1868                   QbeGen.Op3L("mul", qt, q, q2)
- 1869                 ELSIF (op = SymTab.OpDiv)
- 1870                    OR (op = SymTab.OpSlash) THEN
- 1871                   QbeGen.Op3L("div", qt, q, q2)
- 1872                 ELSE
- 1873                   QbeGen.Op3L("rem", qt, q, q2)
- 1874                 END
- 1875               ELSE
- 1876                 QbeGen.NewTemp(qt);
- 1877                 IF op = SymTab.OpTimes THEN
- 1878                   QbeGen.Op3("mul", qt, q, q2, isR)
- 1879                 ELSIF (op = SymTab.OpDiv)
- 1880                    OR (op = SymTab.OpSlash) THEN
- 1881                   QbeGen.Op3("div", qt, q, q2, isR)
- 1882                 ELSE
- 1883                   QbeGen.Op3("rem", qt, q, q2, isR)
- 1884                 END
- 1885               END;
- 1886               QbeGen.CopyOp(qt, q)
- 1887               END
- 1888             ELSE QbeGen.CopyOp("0", q)
- 1889             END
- 1890           END; .) } .
- 1891    MulOp<VAR op: INTEGER>
- 1892      = "*"                               (. op := SymTab.OpTimes; .)
- 1893      | "/"                               (. op := SymTab.OpSlash; .)
- 1894      | "DIV"                             (. op := SymTab.OpDiv; .)
- 1895      | "MOD"                             (. op := SymTab.OpMod; .)
- 1896      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
- 1897    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 1898                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
- 1899                                               et, dt, t2, st, ct2:
- 1900                                                 SymTab.TypeIndex;
- 1901                                               dk: INTEGER;
- 1902                                               qd, q2, sq, qa, qm0, qr:
- 1903                                                 QbeGen.QVal;
- 1904                                               qn, vn: SymTab.Name;
- 1905                                               vt: SymTab.TypeIndex;
- 1906                                               c1, c2: INTEGER;
- 1907                                               called, isHigh, sfx, isCh:
- 1908                                                 BOOLEAN; .)
- 1909      = integer                           (. LexString(s);
- 1910                                             QbeGen.NormInt(s, q);
- 1911                                             t := SymTab.IntType(); .)
- 1912      | charConst                         (. LexString(s);
- 1913                                             QbeGen.NormLit(s, q, isCh);
- 1914                                             t := SymTab.CharType(); .)
- 1915      | real                              (. LexString(s);
- 1916                                             QbeGen.NormReal(s, q);
- 1917                                             t := SymTab.RealType(); .)
- 1918      | string                            (. LexString(s);
- 1919                                             IF SymTab.StrLen(s) = 3 THEN
- 1920                                               t := SymTab.CharType();
- 1921                                               QbeGen.IntStr(
- 1922                                                 QbeGen.CharVal(s), q)
- 1923                                             ELSE t := SymTab.NewStr();
- 1924                                               QbeGen.DeclStr(s, q);
- 1925                                               (* a literal's value IS its
- 1926                                                  static descriptor address *)
- 1927                                               QbeGen.NoteAddr(q, q)
- 1928                                             END; .)
- 1929      | Design<dt, dk, qd, qn, sfx>       (. called := FALSE;
- 1930                                             t := dt;
- 1931                                             IF sfx THEN
- 1932                                               IF dt =
- 1933                                                  SymTab.InvalidType THEN
- 1934                                                 QbeGen.CopyOp("0", q)
- 1935                                               ELSIF (SymTab.ClassOf(dt) =
- 1936                                                      SymTab.ClRecord)
- 1937                                                  OR (SymTab.ClassOf(dt) =
- 1938                                                      SymTab.ClSet)
- 1939                                                  OR (SymTab.ClassOf(dt) =
- 1940                                                      SymTab.ClArray)
- 1941                                                  OR (SymTab.ClassOf(dt) =
- 1942                                                      SymTab.ClClass) THEN
- 1943                                                 QbeGen.CopyOp(qd, q)
- 1944                                               ELSE QbeGen.ElemLoad(qd, dt,
- 1945                                                 q)
- 1946                                               END
- 1947                                             ELSE QbeGen.CopyOp(qd, q)
- 1948                                             END;
- 1949                                             IF (dk = SymTab.KindVar)
- 1950                                                OR (dk = SymTab.KindParam)
- 1951                                                OR (dk =
- 1952                                                   SymTab.KindField) THEN
- 1953                                               IF sfx THEN
- 1954                                                 QbeGen.NoteAddr(q, qd)
- 1955                                               ELSE
- 1956                                                 QbeGen.AddrOf(qn, qa);
- 1957                                                 QbeGen.NoteAddr(q, qa)
+ 1511                                                 IF SymTab.IsCharArray(t) THEN
+ 1512                                                   QbeGen.OpenHiChar(q, qhi)
+ 1513                                                 ELSE QbeGen.OpenHi(q, qhi)
+ 1514                                                 END
+ 1515                                               ELSE
+ 1516                                                 lo := SymTab.ArrayLo(t);
+ 1517                                                 hi := SymTab.ArrayHi(t);
+ 1518                                                 IF SymTab.IsCharArray(t) THEN
+ 1519                                                   hi := hi + 1
+ 1520                                                 END;
+ 1521                                                 QbeGen.IntStr(lo, qlo);
+ 1522                                                 QbeGen.IntStr(hi, qhi)
+ 1523                                               END;
+ 1524                                               QbeGen.CheckRange(ql, qlo,
+ 1525                                                 qhi);
+ 1526                                               eT := SymTab.ArrayElem(t);
+ 1527                                               QbeGen.ElemAddr(q, ql, qlo,
+ 1528                                                 t, qe);
+ 1529                                               IF SymTab.ClassOf(eT) =
+ 1530                                                  SymTab.ClArray THEN
+ 1531                                                 QbeGen.ElemLoad(qe, eT, q)
+ 1532                                               ELSE QbeGen.CopyOp(qe, q)
+ 1533                                               END;
+ 1534                                               t := eT; sfx := TRUE
+ 1535                                             END; .)
+ 1536          { "," Expr<it, iq>
+ 1537                                          (. IF t = SymTab.InvalidType THEN
+ 1538                                             ELSIF SymTab.ClassOf(t) #
+ 1539                                                   SymTab.ClArray THEN
+ 1540                                               SemError(217);
+ 1541                                               t := SymTab.InvalidType
+ 1542                                             ELSIF NOT SymTab.IsIntFamily(it)
+ 1543   AND (SymTab.ClassOf(it) #
+ 1544                                                   SymTab.ClChar) THEN
+ 1545                                               SemError(218);
+ 1546                                               t := SymTab.InvalidType
+ 1547                                             ELSE
+ 1548                                               QbeGen.WidenIndex(iq, ql);
+ 1549                                               isOpen :=
+ 1550                                                 SymTab.IsOpenArray(t);
+ 1551                                               IF isOpen THEN
+ 1552                                                 QbeGen.CopyOp("0", qlo);
+ 1553                                                 IF SymTab.IsCharArray(t) THEN
+ 1554                                                   QbeGen.OpenHiChar(q, qhi)
+ 1555                                                 ELSE QbeGen.OpenHi(q, qhi)
+ 1556                                                 END
+ 1557                                               ELSE
+ 1558                                                 lo := SymTab.ArrayLo(t);
+ 1559                                                 hi := SymTab.ArrayHi(t);
+ 1560                                                 IF SymTab.IsCharArray(t) THEN
+ 1561                                                   hi := hi + 1
+ 1562                                                 END;
+ 1563                                                 QbeGen.IntStr(lo, qlo);
+ 1564                                                 QbeGen.IntStr(hi, qhi)
+ 1565                                               END;
+ 1566                                               QbeGen.CheckRange(ql, qlo,
+ 1567                                                 qhi);
+ 1568                                               eT := SymTab.ArrayElem(t);
+ 1569                                               QbeGen.ElemAddr(q, ql, qlo,
+ 1570                                                 t, qe);
+ 1571                                               IF SymTab.ClassOf(eT) =
+ 1572                                                  SymTab.ClArray THEN
+ 1573                                                 QbeGen.ElemLoad(qe, eT, q)
+ 1574                                               ELSE QbeGen.CopyOp(qe, q)
+ 1575                                               END;
+ 1576                                               t := eT; sfx := TRUE
+ 1577                                             END; .) }
+ 1578          "]"
+ 1579        | "." GetIdent<fn>
+ 1580                                          (. IF k = SymTab.KindModule THEN
+ 1581                                               (* qualified L.x: materialize
+ 1582                                                  the export, then load it *)
+ 1583                                               IF NOT SymTab.MaterializeAlias(n,
+ 1584                                                    fn, mal) THEN
+ 1585                                                 SemError(201);
+ 1586                                                 t := SymTab.InvalidType;
+ 1587                                                 QbeGen.CopyOp("0", q)
+ 1588                                               ELSE
+ 1589                                                 QbeGen.CopyOp(mal, qn);
+ 1590                                                 t := SymTab.SymType(mal);
+ 1591                                                 k := SymTab.SymKind(mal);
+ 1592                                                 sfx := FALSE;
+ 1593                                                 IF k = SymTab.KindProc THEN
+ 1594                                                   (* call: ArgList supplies
+ 1595                                                      the value *)
+ 1596                                                   QbeGen.CopyOp("0", q)
+ 1597                                                 ELSIF NOT QbeGen.LoadDesignator(
+ 1598                                                      mal, t, k, q) THEN
+ 1599                                                   SemError(230);
+ 1600                                                   QbeGen.CopyOp("0", q)
+ 1601                                                 END
+ 1602                                               END
+ 1603                                             ELSIF t = SymTab.InvalidType THEN
+ 1604                                             ELSIF (SymTab.ClassOf(t) #
+ 1605                                                    SymTab.ClRecord)
+ 1606   AND (SymTab.ClassOf(t) #
+ 1607                                                   SymTab.ClClass) THEN
+ 1608                                               SemError(215);
+ 1609                                               t := SymTab.InvalidType
+ 1610                                             ELSIF NOT SymTab.FieldExists(t,
+ 1611                                                      fn) THEN
+ 1612                                               SemError(216);
+ 1613                                               t := SymTab.InvalidType
+ 1614                                             ELSE
+ 1615                                               fo := SymTab.FieldOffset(t,
+ 1616                                                 fn);
+ 1617                                               t := SymTab.FieldType(t, fn);
+ 1618                                               QbeGen.FieldAddr(q, fo, qe);
+ 1619                                               (* array fields are inline:
+ 1620                                                  the field address is the
+ 1621                                                  descriptor, like records *)
+ 1622                                               QbeGen.CopyOp(qe, q);
+ 1623                                               sfx := TRUE
+ 1624                                             END; .)
+ 1625        | "^"
+ 1626                                          (. IF t = SymTab.InvalidType THEN
+ 1627                                             ELSIF SymTab.ClassOf(t) #
+ 1628                                                   SymTab.ClPtr THEN
+ 1629                                               SemError(219);
+ 1630                                               t := SymTab.InvalidType
+ 1631                                             ELSE
+ 1632                                               bt := SymTab.PtrBase(t);
+ 1633                                               IF bt = SymTab.InvalidType THEN
+ 1634                                               ELSE
+ 1635                                                 IF sfx THEN
+ 1636                                                   QbeGen.ElemLoad(q, t,
+ 1637                                                     qb);
+ 1638                                                   QbeGen.CopyOp(qb, q)
+ 1639                                                 END;
+ 1640                                                 t := bt;
+ 1641                                                 IF (SymTab.ClassOf(bt) =
+ 1642                                                    SymTab.ClInt)
+ 1643                                                    OR (SymTab.ClassOf(bt) =
+ 1644                                                        SymTab.ClBool)
+ 1645                                                    OR (SymTab.ClassOf(bt) =
+ 1646                                                        SymTab.ClChar)
+ 1647                                                    OR (SymTab.ClassOf(bt) =
+ 1648                                                        SymTab.ClReal) THEN
+ 1649                                                   sfx := TRUE
+ 1650                                                 ELSE sfx := FALSE
+ 1651                                                 END
+ 1652                                               END
+ 1653                                             END; .) } .
+ 1654    Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1655                                          (. VAR t2: SymTab.TypeIndex;
+ 1656                                               op: INTEGER;
+ 1657                                               q2, qt, wl: QbeGen.QVal;
+ 1658                                               isR: BOOLEAN; .)
+ 1659      = SimExpr<t, q>
+ 1660        [ Rel<op> SimExpr<t2, q2>
+ 1661          (. IF op = SymTab.OpIn THEN
+ 1662               IF SymTab.InCheck(t, t2) THEN
+ 1663                 IF (t = SymTab.InvalidType)
+ 1664                    OR (t2 = SymTab.InvalidType) THEN
+ 1665                   t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 1666                 ELSE
+ 1667                   QbeGen.InSet(q, q2, SymTab.SetBaseLo(t2),
+ 1668                     SymTab.SetCount(t2), qt);
+ 1669                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 1670                 END
+ 1671               ELSE SemError(222); t := SymTab.InvalidType;
+ 1672                 QbeGen.CopyOp("0", q)
+ 1673               END
+ 1674             ELSIF SymTab.RelCheck(t, t2, op) THEN
+ 1675               IF (t = SymTab.InvalidType)
+ 1676                  OR (t2 = SymTab.InvalidType) THEN
+ 1677                 t := SymTab.BoolType(); QbeGen.CopyOp("0", q)
+ 1678               ELSIF (SymTab.ClassOf(t) = SymTab.ClPtr)
+ 1679                  OR (SymTab.ClassOf(t2) = SymTab.ClPtr) THEN
+ 1680                 IF (op # SymTab.OpEq) AND (op # SymTab.OpNeq1)
+ 1681   AND (op # SymTab.OpNeq2) THEN
+ 1682                   SemError(213); t := SymTab.InvalidType;
+ 1683                   QbeGen.CopyOp("0", q)
+ 1684                 ELSE
+ 1685                   QbeGen.CmpL(op, q, q2, qt);
+ 1686                   t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 1687                 END
+ 1688               ELSIF (SymTab.ClassOf(t) = SymTab.ClSet)
+ 1689                  OR (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 1690                 QbeGen.CmpSet(op, q, q2,
+ 1691                   SymTab.SetWords(t), SymTab.SetWords(t2), qt);
+ 1692                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 1693               ELSIF SymTab.IsLongFamily(t)
+ 1694                  OR SymTab.IsLongFamily(t2) THEN
+ 1695                 IF SymTab.IsIntFamily(t) THEN
+ 1696                   QbeGen.WidenLong(q, wl); QbeGen.CopyOp(wl, q)
+ 1697                 END;
+ 1698                 IF SymTab.IsIntFamily(t2) THEN
+ 1699                   QbeGen.WidenLong(q2, wl); QbeGen.CopyOp(wl, q2)
+ 1700                 END;
+ 1701                 QbeGen.CmpLong(op, q, q2, qt);
+ 1702                 t := SymTab.BoolType(); QbeGen.CopyOp(qt, q)
+ 1703               ELSE
+ 1704                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 1705                 t := SymTab.BoolType();
+ 1706                 QbeGen.Cmp(op, q, q2, qt, isR);
+ 1707                 QbeGen.CopyOp(qt, q)
+ 1708               END
+ 1709             ELSE SemError(213); t := SymTab.InvalidType;
+ 1710               QbeGen.CopyOp("0", q)
+ 1711             END; .) ] .
+ 1712    Rel<VAR op: INTEGER>
+ 1713      = "="                               (. op := SymTab.OpEq; .)
+ 1714      | "#"                               (. op := SymTab.OpNeq1; .)
+ 1715      | "<"                               (. op := SymTab.OpLt; .)
+ 1716      | "<="                              (. op := SymTab.OpLe; .)
+ 1717      | ">"                               (. op := SymTab.OpGt; .)
+ 1718      | ">="                              (. op := SymTab.OpGe; .)
+ 1719      | "IN"                              (. op := SymTab.OpIn; .) .
+ 1720    SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1721                                          (. VAR t2, res2, lt, rt:
+ 1722                                                 SymTab.TypeIndex;
+ 1723                                               op: INTEGER;
+ 1724                                               q2, qt, wq, qf:
+ 1725                                                 QbeGen.QVal;
+ 1726                                               neg, isR, isL, folded:
+ 1727                                                 BOOLEAN;
+ 1728                                               lw, rw, mw: CARDINAL; .)
+ 1729      =                                   (. neg := FALSE; .)
+ 1730        [ "+" | "-"                       (. neg := TRUE; .) ]
+ 1731        Term<t, q>                        (. IF neg THEN
+ 1732                                             IF QbeGen.IsImm(q) THEN
+ 1733                                               QbeGen.NegFold(q, q)
+ 1734                                             ELSE QbeGen.NewTemp(qt);
+ 1735                                               QbeGen.NegQ(q, qt,
+ 1736                                                 SymTab.ClassOf(t)
+ 1737                                                 = SymTab.ClReal);
+ 1738                                               QbeGen.CopyOp(qt, q)
+ 1739                                             END
+ 1740                                           END; .)
+ 1741        { AddOp<op> Term<t2, q2>
+ 1742          (. IF op = SymTab.OpOr THEN
+ 1743               IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 1744                 t := SymTab.BoolType()
+ 1745               ELSE SemError(212); t := SymTab.InvalidType END;
+ 1746               IF t # SymTab.InvalidType THEN
+ 1747                 QbeGen.NewTemp(qt);
+ 1748                 QbeGen.Op3("or", qt, q, q2, FALSE);
+ 1749                 QbeGen.CopyOp(qt, q)
+ 1750               ELSE QbeGen.CopyOp("0", q)
+ 1751               END
+ 1752             ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 1753   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 1754   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 1755               lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 1756               mw := lw;
+ 1757               IF rw > mw THEN mw := rw END;
+ 1758               IF op = SymTab.OpAdd THEN
+ 1759                 QbeGen.SetBinOp(0, q, q2, lw, rw, qt)
+ 1760               ELSE
+ 1761                 QbeGen.SetBinOp(2, q, q2, lw, rw, qt)
+ 1762               END;
+ 1763               t := SymTab.NewSet(
+ 1764                      SymTab.NewSubR(0,
+ 1765                        VAL(INTEGER, mw) * 32 - 1));
+ 1766               QbeGen.CopyOp(qt, q)
+ 1767             ELSE
+ 1768               IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
+ 1769                 lt := t; rt := t2; t := res2
+ 1770               ELSE SemError(211); t := SymTab.InvalidType END;
+ 1771               IF t # SymTab.InvalidType THEN
+ 1772                 isL := SymTab.IsLongFamily(t);
+ 1773                 isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 1774                 folded := FALSE;
+ 1775                 IF (NOT isL) AND (NOT isR)
+ 1776    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 1777                   IF op = SymTab.OpAdd THEN
+ 1778                     folded := QbeGen.Fold2(0, q, q2, qf)
+ 1779                   ELSE
+ 1780                     folded := QbeGen.Fold2(1, q, q2, qf)
+ 1781                   END
+ 1782                 END;
+ 1783                 IF folded THEN QbeGen.CopyOp(qf, q)
+ 1784                 ELSE
+ 1785                 IF isL THEN
+ 1786                   IF SymTab.IsIntFamily(lt) THEN
+ 1787                     QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
+ 1788                   END;
+ 1789                   IF SymTab.IsIntFamily(rt) THEN
+ 1790                     QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
+ 1791                   END;
+ 1792                   QbeGen.NewTemp(qt);
+ 1793                   IF op = SymTab.OpAdd THEN
+ 1794                     QbeGen.Op3L("add", qt, q, q2)
+ 1795                   ELSE
+ 1796                     QbeGen.Op3L("sub", qt, q, q2)
+ 1797                   END
+ 1798                 ELSE
+ 1799                   QbeGen.NewTemp(qt);
+ 1800                   IF op = SymTab.OpAdd THEN
+ 1801                     QbeGen.Op3("add", qt, q, q2, isR)
+ 1802                   ELSE
+ 1803                     QbeGen.Op3("sub", qt, q, q2, isR)
+ 1804                   END
+ 1805                 END;
+ 1806                 QbeGen.CopyOp(qt, q)
+ 1807                 END
+ 1808               ELSE QbeGen.CopyOp("0", q)
+ 1809               END
+ 1810             END; .) } .
+ 1811    AddOp<VAR op: INTEGER>
+ 1812      = "+"                               (. op := SymTab.OpAdd; .)
+ 1813      | "-"                               (. op := SymTab.OpSub; .)
+ 1814      | "OR"                              (. op := SymTab.OpOr; .) .
+ 1815    Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1816                                          (. VAR t2, res2, lt, rt:
+ 1817                                                 SymTab.TypeIndex;
+ 1818                                               op: INTEGER;
+ 1819                                               q2, qt, wq, qf:
+ 1820                                                 QbeGen.QVal;
+ 1821                                               isR, isL, folded: BOOLEAN;
+ 1822                                               lw, rw, mw: CARDINAL; .)
+ 1823      = Fact<t, q> { MulOp<op> Fact<t2, q2>
+ 1824        (. IF op = SymTab.OpAnd THEN
+ 1825             IF SymTab.BoolCheck(t) AND SymTab.BoolCheck(t2) THEN
+ 1826               t := SymTab.BoolType()
+ 1827             ELSE SemError(212); t := SymTab.InvalidType END;
+ 1828             IF t # SymTab.InvalidType THEN
+ 1829               QbeGen.NewTemp(qt);
+ 1830               QbeGen.Op3("and", qt, q, q2, FALSE);
+ 1831               QbeGen.CopyOp(qt, q)
+ 1832             ELSE QbeGen.CopyOp("0", q)
+ 1833             END
+ 1834           ELSIF (t # SymTab.InvalidType) AND (t2 # SymTab.InvalidType)
+ 1835   AND (SymTab.ClassOf(t) = SymTab.ClSet)
+ 1836   AND (SymTab.ClassOf(t2) = SymTab.ClSet) THEN
+ 1837             lw := SymTab.SetWords(t); rw := SymTab.SetWords(t2);
+ 1838             mw := lw;
+ 1839             IF rw > mw THEN mw := rw END;
+ 1840             IF op = SymTab.OpTimes THEN
+ 1841               QbeGen.SetBinOp(1, q, q2, lw, rw, qt)
+ 1842             ELSE
+ 1843               QbeGen.SetBinOp(3, q, q2, lw, rw, qt)
+ 1844             END;
+ 1845             t := SymTab.NewSet(
+ 1846                    SymTab.NewSubR(0,
+ 1847                      VAL(INTEGER, mw) * 32 - 1));
+ 1848             QbeGen.CopyOp(qt, q)
+ 1849           ELSE
+ 1850             IF SymTab.ArithCheck(t, t2,
+ 1851                  (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
+ 1852                  res2) THEN
+ 1853               lt := t; rt := t2; t := res2
+ 1854             ELSE SemError(211); t := SymTab.InvalidType END;
+ 1855             IF t # SymTab.InvalidType THEN
+ 1856               isL := SymTab.IsLongFamily(t);
+ 1857               isR := SymTab.ClassOf(t) = SymTab.ClReal;
+ 1858               folded := FALSE;
+ 1859               IF (NOT isL) AND (NOT isR)
+ 1860    AND QbeGen.IsImm(q) AND QbeGen.IsImm(q2) THEN
+ 1861                 IF op = SymTab.OpTimes THEN
+ 1862                   folded := QbeGen.Fold2(2, q, q2, qf)
+ 1863                 ELSIF op = SymTab.OpDiv THEN
+ 1864                   folded := QbeGen.Fold2(3, q, q2, qf)
+ 1865                 ELSIF op = SymTab.OpMod THEN
+ 1866                   folded := QbeGen.Fold2(4, q, q2, qf)
+ 1867                 END
+ 1868               END;
+ 1869               IF folded THEN QbeGen.CopyOp(qf, q)
+ 1870               ELSE
+ 1871               IF isL THEN
+ 1872                 IF SymTab.IsIntFamily(lt) THEN
+ 1873                   QbeGen.WidenLong(q, wq); QbeGen.CopyOp(wq, q)
+ 1874                 END;
+ 1875                 IF SymTab.IsIntFamily(rt) THEN
+ 1876                   QbeGen.WidenLong(q2, wq); QbeGen.CopyOp(wq, q2)
+ 1877                 END;
+ 1878                 QbeGen.NewTemp(qt);
+ 1879                 IF op = SymTab.OpTimes THEN
+ 1880                   QbeGen.Op3L("mul", qt, q, q2)
+ 1881                 ELSIF (op = SymTab.OpDiv)
+ 1882                    OR (op = SymTab.OpSlash) THEN
+ 1883                   QbeGen.Op3L("div", qt, q, q2)
+ 1884                 ELSE
+ 1885                   QbeGen.Op3L("rem", qt, q, q2)
+ 1886                 END
+ 1887               ELSE
+ 1888                 QbeGen.NewTemp(qt);
+ 1889                 IF op = SymTab.OpTimes THEN
+ 1890                   QbeGen.Op3("mul", qt, q, q2, isR)
+ 1891                 ELSIF (op = SymTab.OpDiv)
+ 1892                    OR (op = SymTab.OpSlash) THEN
+ 1893                   QbeGen.Op3("div", qt, q, q2, isR)
+ 1894                 ELSE
+ 1895                   QbeGen.Op3("rem", qt, q, q2, isR)
+ 1896                 END
+ 1897               END;
+ 1898               QbeGen.CopyOp(qt, q)
+ 1899               END
+ 1900             ELSE QbeGen.CopyOp("0", q)
+ 1901             END
+ 1902           END; .) } .
+ 1903    MulOp<VAR op: INTEGER>
+ 1904      = "*"                               (. op := SymTab.OpTimes; .)
+ 1905      | "/"                               (. op := SymTab.OpSlash; .)
+ 1906      | "DIV"                             (. op := SymTab.OpDiv; .)
+ 1907      | "MOD"                             (. op := SymTab.OpMod; .)
+ 1908      | ( "AND" | "&" )                   (. op := SymTab.OpAnd; .) .
+ 1909    Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 1910                                          (. VAR s: ARRAY [0 .. 255] OF CHAR;
+ 1911                                               et, dt, t2, st, ct2:
+ 1912                                                 SymTab.TypeIndex;
+ 1913                                               dk: INTEGER;
+ 1914                                               qd, q2, sq, qa, qm0, qr:
+ 1915                                                 QbeGen.QVal;
+ 1916                                               qn, vn: SymTab.Name;
+ 1917                                               vt: SymTab.TypeIndex;
+ 1918                                               c1, c2: INTEGER;
+ 1919                                               called, isHigh, sfx, isCh:
+ 1920                                                 BOOLEAN; .)
+ 1921      = integer                           (. LexString(s);
+ 1922                                             QbeGen.NormInt(s, q);
+ 1923                                             t := SymTab.IntType(); .)
+ 1924      | charConst                         (. LexString(s);
+ 1925                                             QbeGen.NormLit(s, q, isCh);
+ 1926                                             t := SymTab.CharType(); .)
+ 1927      | real                              (. LexString(s);
+ 1928                                             QbeGen.NormReal(s, q);
+ 1929                                             t := SymTab.RealType(); .)
+ 1930      | string                            (. LexString(s);
+ 1931                                             IF SymTab.StrLen(s) = 3 THEN
+ 1932                                               t := SymTab.CharType();
+ 1933                                               QbeGen.IntStr(
+ 1934                                                 QbeGen.CharVal(s), q)
+ 1935                                             ELSE t := SymTab.NewStr();
+ 1936                                               QbeGen.DeclStr(s, q);
+ 1937                                               (* a literal's value IS its
+ 1938                                                  static descriptor address *)
+ 1939                                               QbeGen.NoteAddr(q, q)
+ 1940                                             END; .)
+ 1941      | Design<dt, dk, qd, qn, sfx>       (. called := FALSE;
+ 1942                                             t := dt;
+ 1943                                             IF sfx THEN
+ 1944                                               IF dt =
+ 1945                                                  SymTab.InvalidType THEN
+ 1946                                                 QbeGen.CopyOp("0", q)
+ 1947                                               ELSIF (SymTab.ClassOf(dt) =
+ 1948                                                      SymTab.ClRecord)
+ 1949                                                  OR (SymTab.ClassOf(dt) =
+ 1950                                                      SymTab.ClSet)
+ 1951                                                  OR (SymTab.ClassOf(dt) =
+ 1952                                                      SymTab.ClArray)
+ 1953                                                  OR (SymTab.ClassOf(dt) =
+ 1954                                                      SymTab.ClClass) THEN
+ 1955                                                 QbeGen.CopyOp(qd, q)
+ 1956                                               ELSE QbeGen.ElemLoad(qd, dt,
+ 1957                                                 q)
  1958                                               END
- 1959                                             ELSIF sfx
- 1960   AND (dt #
- 1961                                                   SymTab.InvalidType)
- 1962   AND ((SymTab.ClassOf(dt) =
- 1963                                                    SymTab.ClArray)
- 1964                                                   OR (SymTab.ClassOf(dt) =
- 1965                                                       SymTab.ClSet)
- 1966                                                   OR (SymTab.ClassOf(dt) =
- 1967                                                       SymTab.ClRecord)) THEN
- 1968                                               QbeGen.NoteAddr(qd, qd)
- 1969                                             END; .)
- 1970        [ TypedSetLit<dt, q>              (. t := dt; .) ]
- 1971        [ ArgList<qn, dt, qd, TRUE, ct2, q2, called>
- 1972                                          (. t := ct2;
- 1973                                             QbeGen.CopyOp(q2, q); .) ]
- 1974                                          (. IF NOT called
- 1975   AND (dk = SymTab.KindProc) THEN
- 1976                                               (* bare zero-arg function
- 1977                                                  call (parentheses may be
- 1978                                                  omitted); a proper or
- 1979                                                  parameterised proc here
- 1980                                                  is 230 *)
- 1981                                               IF (SymTab.ProcNPar(qn) = 0)
- 1982   AND (SymTab.ProcRes(qn) #
- 1983                                                     SymTab.InvalidType) THEN
- 1984                                                 QbeGen.Mangled(qn,
- 1985                                                   SymTab.ProcUid(qn), qm0);
- 1986                                                 QbeGen.CallBegin(qm0,
- 1987                                                   SymTab.ProcRes(qn),
- 1988                                                   SymTab.ProcDepthOf(qn),
- 1989                                                   SymTab.IsExternal(qn));
- 1990                                                 QbeGen.CallEnd(TRUE, q);
- 1991                                                 t := SymTab.ProcRes(qn)
- 1992                                               ELSE
- 1993                                                 (* procedure used as a
- 1994                                                    value (assign to a
- 1995                                                    procedure variable):
- 1996                                                    its code address *)
- 1997                                                 t := SymTab.ProcTypeOf(qn);
- 1998                                                 QbeGen.Mangled(qn,
- 1999                                                   SymTab.ProcUid(qn), qm0);
- 2000                                                 QbeGen.ProcAddr(qm0, q)
- 2001                                               END
- 2002                                             END; .)
- 2003      | ( "HIGH"                          (. isHigh := TRUE; .)
- 2004        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
- 2005        "(" Design<dt, dk, qd, qn, sfx> ")"
- 2006                                          (. IF dt = SymTab.InvalidType THEN
- 2007                                             ELSIF SymTab.ClassOf(dt) #
- 2008                                                   SymTab.ClArray THEN
- 2009                                               SemError(217);
- 2010                                               t := SymTab.InvalidType;
- 2011                                               QbeGen.CopyOp("0", q)
- 2012                                             ELSE
- 2013                                               IF isHigh THEN
- 2014                                                 IF SymTab.IsOpenArray(dt) THEN
- 2015                                                   QbeGen.OpenHi(qd, qr)
- 2016                                                 ELSE
- 2017                                                   QbeGen.IntStr(
- 2018                                                     SymTab.ArrayHi(dt), qr)
- 2019                                                 END
- 2020                                               ELSE
- 2021                                                 IF SymTab.IsOpenArray(dt) THEN
- 2022                                                   QbeGen.LoadCount(qd, qr)
- 2023                                                 ELSE
- 2024                                                   QbeGen.IntStr(VAL(
- 2025                                                     INTEGER,
- 2026                                                     SymTab.ArrayLen(dt)),
- 2027                                                     qr)
- 2028                                                 END
- 2029                                               END;
- 2030                                                t := SymTab.IntType();
- 2031                                                QbeGen.CopyOp(qr, q)
- 2032                                              END; .)
- 2033      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
- 2034                                          (. IF dt = SymTab.InvalidType THEN
- 2035                                               t := SymTab.InvalidType;
- 2036                                               QbeGen.CopyOp("0", q)
- 2037                                             ELSE
- 2038                                               QbeGen.IntStr(VAL(INTEGER,
- 2039                                                 SymTab.ObjectSize(dt)), q);
- 2040                                               t := SymTab.IntType()
- 2041                                             END; .)
- 2042      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
- 2043                                          (. IF dt = SymTab.InvalidType THEN
- 2044                                               t := SymTab.InvalidType;
- 2045                                               QbeGen.CopyOp("0", q)
- 2046                                             ELSE
- 2047                                               IF sfx THEN
- 2048                                                 QbeGen.CopyOp(qd, q)
- 2049                                               ELSIF (dk = SymTab.KindVar)
- 2050                                                  OR (dk = SymTab.KindParam) THEN
- 2051                                                 QbeGen.AddrOf(qn, q)
- 2052                                               ELSE SemError(230);
- 2053                                                 QbeGen.CopyOp("0", q)
- 2054                                               END;
- 2055                                               t := SymTab.AddrType()
- 2056                                             END; .)
- 2057      | "CHR" "(" Expr<et, q> ")"
- 2058                                          (. IF (et # SymTab.InvalidType)
- 2059   AND NOT SymTab.IsIntFamily(et) THEN
- 2060                                               SemError(211) END;
- 2061                                             t := SymTab.CharType(); .)
- 2062      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
- 2063                                          (. IF et # SymTab.InvalidType THEN
- 2064                                               IF (SymTab.ClassOf(et) #
- 2065                                                   SymTab.ClChar)
- 2066   AND (SymTab.ClassOf(et) #
- 2067                                                     SymTab.ClBool)
- 2068   AND (SymTab.ClassOf(et) #
- 2069                                                     SymTab.ClEnum)
- 2070   AND NOT SymTab.IsIntFamily(et) THEN
- 2071                                                 SemError(211) END
- 2072                                             END;
- 2073                                             t := SymTab.IntType(); .)
- 2074      | "CAP" "(" Expr<et, q> ")"
- 2075                                          (. QbeGen.CapQ(q, qa);
- 2076                                             QbeGen.CopyOp(qa, q);
- 2077                                             t := SymTab.CharType(); .)
- 2078      | "ABS" "(" Expr<et, q> ")"
- 2079                                          (. IF (et # SymTab.InvalidType)
- 2080   AND NOT SymTab.IsIntFamily(et)
- 2081   AND (SymTab.ClassOf(et) #
- 2082                                                  SymTab.ClReal) THEN
- 2083                                               SemError(211)
- 2084                                             ELSE QbeGen.AbsQ(q, qa,
- 2085                                                    SymTab.ClassOf(et) =
- 2086                                                      SymTab.ClReal);
- 2087                                               QbeGen.CopyOp(qa, q)
- 2088                                             END;
- 2089                                             t := et; .)
- 2090      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
- 2091                                          (. IF NOT SymTab.Lookup(vn) THEN
- 2092                                               SemError(201);
- 2093                                               t := SymTab.InvalidType
- 2094                                             ELSE vt := SymTab.SymType(vn);
- 2095                                               IF vt = SymTab.InvalidType THEN
- 2096                                                 t := SymTab.InvalidType
- 2097                                               ELSIF et =
- 2098                                                  SymTab.InvalidType THEN
- 2099                                                 t := vt
- 2100                                               ELSE
- 2101                                                 c1 := SymTab.ClassOf(et);
- 2102                                                 c2 := SymTab.ClassOf(vt);
- 2103                                                 IF ((c1 = SymTab.ClInt)
- 2104                                                     OR (c1 =
- 2105                                                        SymTab.ClChar)
- 2106                                                     OR (c1 =
- 2107                                                        SymTab.ClBool)
- 2108                                                     OR (c1 =
- 2109                                                        SymTab.ClEnum))
- 2110   AND ((c2 = SymTab.ClInt)
- 2111                                                     OR (c2 =
- 2112                                                        SymTab.ClChar)
- 2113                                                     OR (c2 =
- 2114                                                        SymTab.ClBool)
- 2115                                                     OR (c2 =
- 2116                                                        SymTab.ClEnum)) THEN
- 2117                                                   t := vt
- 2118                                                 ELSIF (c1 = SymTab.ClPtr)
- 2119   AND (c2 = SymTab.ClPtr) THEN
- 2120                                                   t := vt
- 2121                                                 ELSIF (c1 = SymTab.ClReal)
- 2122   AND (c2 = SymTab.ClReal) THEN
- 2123                                                   t := vt
- 2124                                                 ELSE SemError(230);
- 2125                                                   t := SymTab.InvalidType
- 2126                                                 END
- 2127                                               END
- 2128                                             END; .)
- 2129      | "(" Expr<et, q> ")"               (. t := et; .)
- 2130      | SetLit<st, sq>                    (. t := st;
- 2131                                             QbeGen.CopyOp(sq, q); .)
- 2132      | ( "NOT" | "~" ) Fact<t2, q2>      (. IF SymTab.BoolCheck(t2) THEN
- 2133                                               t := SymTab.BoolType()
- 2134                                             ELSE SemError(212);
- 2135                                               t := SymTab.InvalidType END;
- 2136                                             IF t # SymTab.InvalidType THEN
- 2137                                               QbeGen.NotQ(q2, q)
- 2138                                             ELSE QbeGen.CopyOp("0", q)
- 2139                                             END; .) .
- 2140    (* Set literals are SET OF [0..255] (8 words); elements validated
- 2141       0..255 statically when foldable (222 otherwise), runtime trap
- 2142       for computed elements. Ranges always lower via SetRange. *)
- 2143    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2144      = "{"                               (. t := SymTab.NewSet(
- 2145                                               SymTab.NewSubR(0, 255));
- 2146                                             QbeGen.NewSetTemp(8, q);
- 2147                                             QbeGen.SetZero(q, 8); .)
- 2148        [ SetElem<t, q> { "," SetElem<t, q> } ]
- 2149        "}" .
- 2150    (* Typed set constructor: TypeName{ elems } — e.g. BITSET{0},
- 2151       BITSET{}.  The declared type (not SET OF [0..255]) sets the
- 2152       width and element span. *)
- 2153    TypedSetLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2154                                          (. VAR nw: CARDINAL; .)
- 2155      = "{"                               (. IF SymTab.ClassOf(vt) #
- 2156                                                SymTab.ClSet THEN
- 2157                                               SemError(230); nw := 8
- 2158                                             ELSE nw := SymTab.SetWords(vt);
- 2159                                               IF nw = 0 THEN nw := 8 END
- 2160                                             END;
- 2161                                             QbeGen.NewSetTemp(nw, q);
- 2162                                             QbeGen.SetZero(q, nw); .)
- 2163        [ SetElem<vt, q> { "," SetElem<vt, q> } ]
- 2164        "}" .
- 2165    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
- 2166                                               qe, q2: QbeGen.QVal;
- 2167                                               v, v2: INTEGER;
- 2168                                               lo: INTEGER;
- 2169                                               span: CARDINAL;
- 2170                                               cl, cl2: INTEGER;
- 2171                                               hasR: BOOLEAN; .)
- 2172      =                                   (. hasR := FALSE; .)
- 2173        Expr<et, qe>
- 2174        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
- 2175                                          (. lo := SymTab.SetBaseLo(st);
- 2176                                             span := SymTab.SetCount(st);
- 2177                                             IF (et = SymTab.InvalidType)
- 2178                                                OR (hasR AND (et2 =
- 2179                                                   SymTab.InvalidType)) THEN
- 2180                                             ELSE cl :=
- 2181                                                    SymTab.ClassOf(et);
- 2182                                               IF hasR THEN
- 2183                                                 cl2 :=
- 2184                                                   SymTab.ClassOf(et2)
- 2185                                               ELSE cl2 := SymTab.ClInt
- 2186                                               END;
- 2187                                               IF ((cl # SymTab.ClInt)
- 2188   AND (cl # SymTab.ClChar)
- 2189   AND (cl # SymTab.ClBool))
- 2190                                                  OR (hasR AND 
- 2191                                                     ((cl2
- 2192                                                       # SymTab.ClInt)
- 2193   AND (cl2
- 2194                                                        # SymTab.ClChar)
- 2195   AND (cl2
- 2196                                                        # SymTab.ClBool))) THEN
- 2197                                                 SemError(222)
- 2198                                               ELSIF hasR
- 2199   AND SymTab.ConstInt(qe, v)
- 2200   AND SymTab.ConstInt(q2,
- 2201                                                     v2)
- 2202   AND ((v < lo)
- 2203                                                     OR (v2 < lo)
- 2204                                                     OR (v >= lo +
- 2205                                                        VAL(INTEGER, span))
- 2206                                                     OR (v2 >= lo +
- 2207                                                        VAL(INTEGER, span))
- 2208                                                     OR (v > v2)) THEN
+ 1959                                             ELSE QbeGen.CopyOp(qd, q)
+ 1960                                             END;
+ 1961                                             IF (dk = SymTab.KindVar)
+ 1962                                                OR (dk = SymTab.KindParam)
+ 1963                                                OR (dk =
+ 1964                                                   SymTab.KindField) THEN
+ 1965                                               IF sfx THEN
+ 1966                                                 QbeGen.NoteAddr(q, qd)
+ 1967                                               ELSE
+ 1968                                                 QbeGen.AddrOf(qn, qa);
+ 1969                                                 QbeGen.NoteAddr(q, qa)
+ 1970                                               END
+ 1971                                             ELSIF sfx
+ 1972   AND (dt #
+ 1973                                                   SymTab.InvalidType)
+ 1974   AND ((SymTab.ClassOf(dt) =
+ 1975                                                    SymTab.ClArray)
+ 1976                                                   OR (SymTab.ClassOf(dt) =
+ 1977                                                       SymTab.ClSet)
+ 1978                                                   OR (SymTab.ClassOf(dt) =
+ 1979                                                       SymTab.ClRecord)) THEN
+ 1980                                               QbeGen.NoteAddr(qd, qd)
+ 1981                                             END; .)
+ 1982        [ TypedSetLit<dt, q>              (. t := dt; .) ]
+ 1983        [ ArgList<qn, dt, qd, TRUE, ct2, q2, called>
+ 1984                                          (. t := ct2;
+ 1985                                             QbeGen.CopyOp(q2, q); .) ]
+ 1986                                          (. IF NOT called
+ 1987   AND (dk = SymTab.KindProc) THEN
+ 1988                                               (* bare zero-arg function
+ 1989                                                  call (parentheses may be
+ 1990                                                  omitted); a proper or
+ 1991                                                  parameterised proc here
+ 1992                                                  is 230 *)
+ 1993                                               IF (SymTab.ProcNPar(qn) = 0)
+ 1994   AND (SymTab.ProcRes(qn) #
+ 1995                                                     SymTab.InvalidType) THEN
+ 1996                                                 QbeGen.Mangled(qn,
+ 1997                                                   SymTab.ProcUid(qn), qm0);
+ 1998                                                 QbeGen.CallBegin(qm0,
+ 1999                                                   SymTab.ProcRes(qn),
+ 2000                                                   SymTab.ProcDepthOf(qn),
+ 2001                                                   SymTab.IsExternal(qn));
+ 2002                                                 QbeGen.CallEnd(TRUE, q);
+ 2003                                                 t := SymTab.ProcRes(qn)
+ 2004                                               ELSE
+ 2005                                                 (* procedure used as a
+ 2006                                                    value (assign to a
+ 2007                                                    procedure variable):
+ 2008                                                    its code address *)
+ 2009                                                 t := SymTab.ProcTypeOf(qn);
+ 2010                                                 QbeGen.Mangled(qn,
+ 2011                                                   SymTab.ProcUid(qn), qm0);
+ 2012                                                 QbeGen.ProcAddr(qm0, q)
+ 2013                                               END
+ 2014                                             END; .)
+ 2015      | ( "HIGH"                          (. isHigh := TRUE; .)
+ 2016        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
+ 2017        "(" Design<dt, dk, qd, qn, sfx> ")"
+ 2018                                          (. IF dt = SymTab.InvalidType THEN
+ 2019                                             ELSIF SymTab.ClassOf(dt) #
+ 2020                                                   SymTab.ClArray THEN
+ 2021                                               SemError(217);
+ 2022                                               t := SymTab.InvalidType;
+ 2023                                               QbeGen.CopyOp("0", q)
+ 2024                                             ELSE
+ 2025                                               IF isHigh THEN
+ 2026                                                 IF SymTab.IsOpenArray(dt) THEN
+ 2027                                                   QbeGen.OpenHi(qd, qr)
+ 2028                                                 ELSE
+ 2029                                                   QbeGen.IntStr(
+ 2030                                                     SymTab.ArrayHi(dt), qr)
+ 2031                                                 END
+ 2032                                               ELSE
+ 2033                                                 IF SymTab.IsOpenArray(dt) THEN
+ 2034                                                   QbeGen.LoadCount(qd, qr)
+ 2035                                                 ELSE
+ 2036                                                   QbeGen.IntStr(VAL(
+ 2037                                                     INTEGER,
+ 2038                                                     SymTab.ArrayLen(dt)),
+ 2039                                                     qr)
+ 2040                                                 END
+ 2041                                               END;
+ 2042                                                t := SymTab.IntType();
+ 2043                                                QbeGen.CopyOp(qr, q)
+ 2044                                              END; .)
+ 2045      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
+ 2046                                          (. IF dt = SymTab.InvalidType THEN
+ 2047                                               t := SymTab.InvalidType;
+ 2048                                               QbeGen.CopyOp("0", q)
+ 2049                                             ELSE
+ 2050                                               QbeGen.IntStr(VAL(INTEGER,
+ 2051                                                 SymTab.ObjectSize(dt)), q);
+ 2052                                               t := SymTab.IntType()
+ 2053                                             END; .)
+ 2054      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 2055                                          (. IF dt = SymTab.InvalidType THEN
+ 2056                                               t := SymTab.InvalidType;
+ 2057                                               QbeGen.CopyOp("0", q)
+ 2058                                             ELSE
+ 2059                                               IF sfx THEN
+ 2060                                                 QbeGen.CopyOp(qd, q)
+ 2061                                               ELSIF (dk = SymTab.KindVar)
+ 2062                                                  OR (dk = SymTab.KindParam) THEN
+ 2063                                                 QbeGen.AddrOf(qn, q)
+ 2064                                               ELSE SemError(230);
+ 2065                                                 QbeGen.CopyOp("0", q)
+ 2066                                               END;
+ 2067                                               t := SymTab.AddrType()
+ 2068                                             END; .)
+ 2069      | "CHR" "(" Expr<et, q> ")"
+ 2070                                          (. IF (et # SymTab.InvalidType)
+ 2071   AND NOT SymTab.IsIntFamily(et) THEN
+ 2072                                               SemError(211) END;
+ 2073                                             t := SymTab.CharType(); .)
+ 2074      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
+ 2075                                          (. IF et # SymTab.InvalidType THEN
+ 2076                                               IF (SymTab.ClassOf(et) #
+ 2077                                                   SymTab.ClChar)
+ 2078   AND (SymTab.ClassOf(et) #
+ 2079                                                     SymTab.ClBool)
+ 2080   AND (SymTab.ClassOf(et) #
+ 2081                                                     SymTab.ClEnum)
+ 2082   AND NOT SymTab.IsIntFamily(et) THEN
+ 2083                                                 SemError(211) END
+ 2084                                             END;
+ 2085                                             t := SymTab.IntType(); .)
+ 2086      | "CAP" "(" Expr<et, q> ")"
+ 2087                                          (. QbeGen.CapQ(q, qa);
+ 2088                                             QbeGen.CopyOp(qa, q);
+ 2089                                             t := SymTab.CharType(); .)
+ 2090      | "ABS" "(" Expr<et, q> ")"
+ 2091                                          (. IF (et # SymTab.InvalidType)
+ 2092   AND NOT SymTab.IsIntFamily(et)
+ 2093   AND (SymTab.ClassOf(et) #
+ 2094                                                  SymTab.ClReal) THEN
+ 2095                                               SemError(211)
+ 2096                                             ELSE QbeGen.AbsQ(q, qa,
+ 2097                                                    SymTab.ClassOf(et) =
+ 2098                                                      SymTab.ClReal);
+ 2099                                               QbeGen.CopyOp(qa, q)
+ 2100                                             END;
+ 2101                                             t := et; .)
+ 2102      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
+ 2103                                          (. IF NOT SymTab.Lookup(vn) THEN
+ 2104                                               SemError(201);
+ 2105                                               t := SymTab.InvalidType
+ 2106                                             ELSE vt := SymTab.SymType(vn);
+ 2107                                               IF vt = SymTab.InvalidType THEN
+ 2108                                                 t := SymTab.InvalidType
+ 2109                                               ELSIF et =
+ 2110                                                  SymTab.InvalidType THEN
+ 2111                                                 t := vt
+ 2112                                               ELSE
+ 2113                                                 c1 := SymTab.ClassOf(et);
+ 2114                                                 c2 := SymTab.ClassOf(vt);
+ 2115                                                 IF ((c1 = SymTab.ClInt)
+ 2116                                                     OR (c1 =
+ 2117                                                        SymTab.ClChar)
+ 2118                                                     OR (c1 =
+ 2119                                                        SymTab.ClBool)
+ 2120                                                     OR (c1 =
+ 2121                                                        SymTab.ClEnum))
+ 2122   AND ((c2 = SymTab.ClInt)
+ 2123                                                     OR (c2 =
+ 2124                                                        SymTab.ClChar)
+ 2125                                                     OR (c2 =
+ 2126                                                        SymTab.ClBool)
+ 2127                                                     OR (c2 =
+ 2128                                                        SymTab.ClEnum)) THEN
+ 2129                                                   t := vt
+ 2130                                                 ELSIF (c1 = SymTab.ClPtr)
+ 2131   AND (c2 = SymTab.ClPtr) THEN
+ 2132                                                   t := vt
+ 2133                                                 ELSIF (c1 = SymTab.ClReal)
+ 2134   AND (c2 = SymTab.ClReal) THEN
+ 2135                                                   t := vt
+ 2136                                                 ELSE SemError(230);
+ 2137                                                   t := SymTab.InvalidType
+ 2138                                                 END
+ 2139                                               END
+ 2140                                             END; .)
+ 2141      | "(" Expr<et, q> ")"               (. t := et; .)
+ 2142      | SetLit<st, sq>                    (. t := st;
+ 2143                                             QbeGen.CopyOp(sq, q); .)
+ 2144      | ( "NOT" | "~" ) Fact<t2, q2>      (. IF SymTab.BoolCheck(t2) THEN
+ 2145                                               t := SymTab.BoolType()
+ 2146                                             ELSE SemError(212);
+ 2147                                               t := SymTab.InvalidType END;
+ 2148                                             IF t # SymTab.InvalidType THEN
+ 2149                                               QbeGen.NotQ(q2, q)
+ 2150                                             ELSE QbeGen.CopyOp("0", q)
+ 2151                                             END; .) .
+ 2152    (* Set literals are SET OF [0..255] (8 words); elements validated
+ 2153       0..255 statically when foldable (222 otherwise), runtime trap
+ 2154       for computed elements. Ranges always lower via SetRange. *)
+ 2155    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2156      = "{"                               (. t := SymTab.NewSet(
+ 2157                                               SymTab.NewSubR(0, 255));
+ 2158                                             QbeGen.NewSetTemp(8, q);
+ 2159                                             QbeGen.SetZero(q, 8); .)
+ 2160        [ SetElem<t, q> { "," SetElem<t, q> } ]
+ 2161        "}" .
+ 2162    (* Typed set constructor: TypeName{ elems } — e.g. BITSET{0},
+ 2163       BITSET{}.  The declared type (not SET OF [0..255]) sets the
+ 2164       width and element span. *)
+ 2165    TypedSetLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2166                                          (. VAR nw: CARDINAL; .)
+ 2167      = "{"                               (. IF SymTab.ClassOf(vt) #
+ 2168                                                SymTab.ClSet THEN
+ 2169                                               SemError(230); nw := 8
+ 2170                                             ELSE nw := SymTab.SetWords(vt);
+ 2171                                               IF nw = 0 THEN nw := 8 END
+ 2172                                             END;
+ 2173                                             QbeGen.NewSetTemp(nw, q);
+ 2174                                             QbeGen.SetZero(q, nw); .)
+ 2175        [ SetElem<vt, q> { "," SetElem<vt, q> } ]
+ 2176        "}" .
+ 2177    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
+ 2178                                               qe, q2: QbeGen.QVal;
+ 2179                                               v, v2: INTEGER;
+ 2180                                               lo: INTEGER;
+ 2181                                               span: CARDINAL;
+ 2182                                               cl, cl2: INTEGER;
+ 2183                                               hasR: BOOLEAN; .)
+ 2184      =                                   (. hasR := FALSE; .)
+ 2185        Expr<et, qe>
+ 2186        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
+ 2187                                          (. lo := SymTab.SetBaseLo(st);
+ 2188                                             span := SymTab.SetCount(st);
+ 2189                                             IF (et = SymTab.InvalidType)
+ 2190                                                OR (hasR AND (et2 =
+ 2191                                                   SymTab.InvalidType)) THEN
+ 2192                                             ELSE cl :=
+ 2193                                                    SymTab.ClassOf(et);
+ 2194                                               IF hasR THEN
+ 2195                                                 cl2 :=
+ 2196                                                   SymTab.ClassOf(et2)
+ 2197                                               ELSE cl2 := SymTab.ClInt
+ 2198                                               END;
+ 2199                                               IF ((cl # SymTab.ClInt)
+ 2200   AND (cl # SymTab.ClChar)
+ 2201   AND (cl # SymTab.ClBool))
+ 2202                                                  OR (hasR AND 
+ 2203                                                     ((cl2
+ 2204                                                       # SymTab.ClInt)
+ 2205   AND (cl2
+ 2206                                                        # SymTab.ClChar)
+ 2207   AND (cl2
+ 2208                                                        # SymTab.ClBool))) THEN
  2209                                                 SemError(222)
- 2210                                                ELSIF hasR THEN
- 2211                                                  QbeGen.SetRange(sq, qe, q2,
- 2212                                                    lo, span)
- 2213                                                ELSIF SymTab.ConstInt(qe,
- 2214                                                        v)
- 2215   AND ((v < lo)
- 2216                                                      OR (v >= lo +
- 2217                                                         VAL(INTEGER,
- 2218                                                           span))) THEN
- 2219                                                  SemError(222)
- 2220                                                ELSE QbeGen.SetBit(sq, qe,
- 2221                                                  lo, span)
- 2222                                               END
- 2223                                             END; .) .
- 2224    GetIdent<VAR n: SymTab.Name>
- 2225      = ident                             (. LexName(n); .) .
- 2226  
- 2227  END M2.
+ 2210                                               ELSIF hasR
+ 2211   AND SymTab.ConstInt(qe, v)
+ 2212   AND SymTab.ConstInt(q2,
+ 2213                                                     v2)
+ 2214   AND ((v < lo)
+ 2215                                                     OR (v2 < lo)
+ 2216                                                     OR (v >= lo +
+ 2217                                                        VAL(INTEGER, span))
+ 2218                                                     OR (v2 >= lo +
+ 2219                                                        VAL(INTEGER, span))
+ 2220                                                     OR (v > v2)) THEN
+ 2221                                                 SemError(222)
+ 2222                                                ELSIF hasR THEN
+ 2223                                                  QbeGen.SetRange(sq, qe, q2,
+ 2224                                                    lo, span)
+ 2225                                                ELSIF SymTab.ConstInt(qe,
+ 2226                                                        v)
+ 2227   AND ((v < lo)
+ 2228                                                      OR (v >= lo +
+ 2229                                                         VAL(INTEGER,
+ 2230                                                           span))) THEN
+ 2231                                                  SemError(222)
+ 2232                                                ELSE QbeGen.SetBit(sq, qe,
+ 2233                                                  lo, span)
+ 2234                                               END
+ 2235                                             END; .) .
+ 2236    GetIdent<VAR n: SymTab.Name>
+ 2237      = ident                             (. LexName(n); .) .
+ 2238  
+ 2239  END M2.
 
     0 errors
 

+ 4 - 0
compiler/src/QbeGen.def

@@ -261,6 +261,10 @@ PROCEDURE WidenIndex (idx: ARRAY OF CHAR; VAR q: QVal);
 PROCEDURE OpenHi (base: ARRAY OF CHAR; VAR q: QVal);
 (* q := loadl(base) - 1 in l (open-array upper bound). *)
 
+PROCEDURE OpenHiChar (base: ARRAY OF CHAR; VAR q: QVal);
+(* q := loadl(base) in l (CHAR arrays allow index = count: the NUL
+   terminator slot). *)
+
 PROCEDURE LoadCount (base: ARRAY OF CHAR; VAR q: QVal);
 (* q := loadl(base) in l (open-array element count). *)
 

+ 35 - 8
compiler/src/QbeGen.mod

@@ -1590,15 +1590,21 @@ PROCEDURE ArrBodyItems (prefix: ARRAY OF CHAR; t: INTEGER);
         INC(i)
       END
     ELSE
-      IF ecls = SymTab.ClChar THEN esz := 1
-      ELSIF (ecls = SymTab.ClReal) OR (ecls = SymTab.ClPtr)
-         OR (ecls = SymTab.ClProc) THEN esz := 8
-      ELSE esz := 4
-      END;
-      IF n > 0 THEN
+      IF ecls = SymTab.ClChar THEN
+        (* CHAR: n data bytes + one NUL terminator slot *)
         W(", z ");
-        IntStr(VAL(INTEGER, n * esz), bv);
+        IntStr(VAL(INTEGER, n + 1), bv);
         W(bv)
+      ELSE
+        IF (ecls = SymTab.ClReal) OR (ecls = SymTab.ClPtr)
+           OR (ecls = SymTab.ClProc) THEN esz := 8
+        ELSE esz := 4
+        END;
+        IF n > 0 THEN
+          W(", z ");
+          IntStr(VAL(INTEGER, n * esz), bv);
+          W(bv)
+        END
       END
     END
    END ArrBodyItems;
@@ -2122,6 +2128,15 @@ PROCEDURE OpenHi (base: ARRAY OF CHAR; VAR q: QVal);
     Op3L("sub", q, c, "1")
   END OpenHi;
 
+PROCEDURE OpenHiChar (base: ARRAY OF CHAR; VAR q: QVal);
+(* q := loadl(base) — the open-array count, i.e. the index of the NUL
+   terminator slot that CHAR arrays reserve. *)
+  BEGIN
+    NewTemp(q);
+    Revive;
+    W("  "); W(q); W(" =l loadl "); WL(base)
+  END OpenHiChar;
+
 PROCEDURE LoadCount (base: ARRAY OF CHAR; VAR q: QVal);
   BEGIN
     NewTemp(q);
@@ -2313,6 +2328,7 @@ PROCEDURE FlushStrings;
           W(bv);
           INC(i)
         END;
+        W(", b 0");   (* NUL terminator (count excludes it) *)
         WL(" }")
       END;
       INC(k)
@@ -2370,10 +2386,13 @@ PROCEDURE Remark (s: ARRAY OF CHAR);
 
 PROCEDURE HeapSize (t: INTEGER): CARDINAL;
   VAR cls: INTEGER;
+    n: CARDINAL;
   BEGIN
     cls := SymTab.ClassOf(t);
     IF cls = SymTab.ClArray THEN
-      RETURN 8 + SymTab.ArrayLen(t) * ElemSize(t)
+      n := SymTab.ArrayLen(t) * ElemSize(t);
+      IF SymTab.IsCharArray(t) THEN n := n + 1 END;
+      RETURN 8 + n
     END;
     RETURN SymTab.TypeSize(t)
   END HeapSize;
@@ -2408,6 +2427,14 @@ PROCEDURE InitHeap (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
       IntStr(VAL(INTEGER, SymTab.ArrayLen(t)), nb);
       Revive;
       W("  storel "); W(nb); W(", "); WL(addr);
+      IF SymTab.IsCharArray(t) THEN
+        (* NUL terminator slot at index = count *)
+        IntStr(VAL(INTEGER, 8 + SymTab.ArrayLen(t)), nb);
+        NewTemp(ea);
+        Op3L("add", ea, addr, nb);
+        Revive;
+        W("  storeb 0, "); WL(ea)
+      END;
       ecls := SymTab.ClassOf(SymTab.ArrayElem(t));
       IF ecls = SymTab.ClArray THEN
         n := SymTab.ArrayLen(t);

+ 4 - 0
compiler/src/SymTab.def

@@ -377,6 +377,10 @@ PROCEDURE SameType (a, b: TypeIndex): BOOLEAN;
 PROCEDURE FieldExists (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
 PROCEDURE FieldType (rec: TypeIndex; name: ARRAY OF CHAR): TypeIndex;
 PROCEDURE ArrayElem (t: TypeIndex): TypeIndex;
+PROCEDURE IsCharArray (t: TypeIndex): BOOLEAN;
+(* TRUE for arrays whose elements are CHAR: such arrays reserve one
+   extra zero byte (index = count) so NUL-scanning works, matching
+   gm2's NUL-terminated strings. *)
 PROCEDURE IsOpenArray (t: TypeIndex): BOOLEAN;
 PROCEDURE ArrayLo (t: TypeIndex): INTEGER;
 PROCEDURE ArrayHi (t: TypeIndex): INTEGER;

+ 11 - 2
compiler/src/SymTab.mod

@@ -862,9 +862,18 @@ PROCEDURE ElemBytes (t: TypeIndex): CARDINAL;
     RETURN 4
   END ElemBytes;
 
+PROCEDURE IsCharArray (t: TypeIndex): BOOLEAN;
+  BEGIN RETURN ClassOf(ArrayElem(t)) = ClChar END IsCharArray;
+
 PROCEDURE ArrObjSize (t: TypeIndex): CARDINAL;
-(* full inline size of a fixed array: header (count) + packed elements *)
-  BEGIN RETURN 8 + ArrayLen(t) * ElemBytes(t) END ArrObjSize;
+(* full inline size of a fixed array: header (count) + packed elements
+   (+1 terminator byte for CHAR arrays) *)
+  VAR n: CARDINAL;
+  BEGIN
+    n := ArrayLen(t) * ElemBytes(t);
+    IF IsCharArray(t) THEN n := n + 1 END;
+    RETURN 8 + n
+  END ArrObjSize;
 
 PROCEDURE TypeSizeD (t: TypeIndex; depth: CARDINAL): CARDINAL;
 (* Inline footprint in bytes: scalars 4/8, sets words*4, pointers,

+ 51 - 0
docs/summary_nul-strings.md

@@ -0,0 +1,51 @@
+# NUL-terminated string model (self-hosting unblocker)
+
+Tag `v3-nul-strings`. Main suite 111/111.
+
+## Why
+
+The compiler's own sources (and gm2) assume **NUL-terminated**
+strings: helpers like `SymTab.Assign`/`Equal` scan `WHILE s[i] # CHR(0)`.
+V3 stored `[count, bytes]` with **no terminator** and trapped when
+indexing past the count, so those scans aborted. Minimal repro:
+
+```modula2
+WHILE (i < HIGH(d)) AND (s[i] # CHR(0)) DO ... END;   (* s[n] out of bounds *)
+```
+
+## Change: every CHAR array reserves a terminator slot
+
+- **Model**: a CHAR array of count `n` has `n` data bytes plus one zero
+  byte at index `n`; indexed access is allowed for `0 .. n` (the
+  terminator is readable/writable). `LEN`/`HIGH` still report `n`/`n-1`.
+- **Emission**: `ArrBodyItems` emits `z (n+1)` for CHAR arrays; string
+  literals get a trailing `b 0`; `ArrObjSize`/`HeapSize` add 1; a
+  heap/local array's terminator is zeroed in `InitHeap`.
+- **Bounds**: `Design`'s index handlers use `ArrayHi+1` (fixed) or
+  `OpenHiChar` = count (open) for CHAR-element arrays (`SymTab.IsCharArray`).
+- **Shim**: `m2write`/`m2fputs`/`m2cstr` derive length by scanning
+  (`strnlen`, bounded by the capacity); `m2arg` copies + NUL-terminates
+  and **keeps the capacity** in `desc[0]` (it no longer overwrites it
+  with the length — that destroyed fixed-buffer capacity).
+- **stdlib `Strings`**: rewritten NUL-based (`Length` scans; `Assign`/
+  `Concat`/`Delete`/`Append` copy by scanned length bounded by
+  `HIGH(dst)` and NUL-terminate).
+
+## Result
+
+- Suite 111/111; the small `NEW` + inline-array-field repro now runs.
+- The **self-compiled compiler now runs**: it opens its input (self-
+  hosted `FileIO` + shim) and starts parsing.
+- It then segfaults in the scanner's `Reset` (`Parse → Reset`) — the
+  next runtime bug to chase.
+
+## Note
+
+`desc[0]` is now a **capacity** for arrays (and the literal length for
+string literals); string length is derived by scanning. `m2setlen` is
+effectively unused.
+
+## Files
+
+`runtime/syslib/shim.c`, `stdlib/strings.mod`,
+`compiler/src/{M2.atg,SymTab.def,SymTab.mod,QbeGen.def,QbeGen.mod,M2.lst}`.

+ 16 - 11
runtime/syslib/shim.c

@@ -17,10 +17,12 @@
    number of bytes written. */
 long m2write(long *desc)
 {
-    long n = desc[0];
+    /* desc[0] is the capacity; the string is NUL-terminated. */
+    char *s = (char *)(desc + 1);
+    size_t n = strnlen(s, (size_t)desc[0] + 1);
     if (n > 0)
-        write(1, (char *)(desc + 1), (size_t)n);
-    return n;
+        write(1, s, n);
+    return (long)n;
 }
 
 /* Write a newline to fd 1. */
@@ -60,9 +62,10 @@ long m2readint(void)
 /* Copy a descriptor string into a NUL-terminated buffer. */
 static void m2cstr(long *desc, char *buf, size_t cap)
 {
-    long n = desc[0];
-    if ((size_t)n >= cap) n = (long)(cap - 1);
-    if (n > 0) memcpy(buf, (char *)(desc + 1), (size_t)n);
+    char *s = (char *)(desc + 1);
+    size_t n = strnlen(s, (size_t)desc[0] + 1);
+    if (n >= cap) n = cap - 1;
+    if (n > 0) memcpy(buf, s, n);
     buf[n] = 0;
 }
 
@@ -105,10 +108,11 @@ long m2fputc(long h, long c)
 
 long m2fputs(long h, long *desc)
 {
-    long n = desc[0];
+    char *s = (char *)(desc + 1);
+    size_t n = strnlen(s, (size_t)desc[0] + 1);
     if (h == 0) return 0;
-    if (n > 0) fwrite((char *)(desc + 1), 1, (size_t)n, (FILE *)h);
-    return n;
+    if (n > 0) fwrite(s, 1, n, (FILE *)h);
+    return (long)n;
 }
 
 long m2freadint(long h)
@@ -217,13 +221,14 @@ long m2arg(long i, long *desc, long cap)
     long n;
 
     m2_argv_init();
-    if (i < 0 || i >= m2_nargs) { desc[0] = 0; return 0; }
+    if (i < 0 || i >= m2_nargs) { ((char *)(desc + 1))[0] = 0; return 0; }
     a = m2_args[i];
     n = (long)strlen(a);
     if (cap > 0 && n >= cap) n = cap - 1;
     if (n < 0) n = 0;
     memcpy((char *)(desc + 1), a, (size_t)n);
-    desc[0] = n;
+    if (n < cap) ((char *)(desc + 1))[n] = 0;  /* NUL terminator */
+    /* desc[0] (capacity) is left intact: length is derived by scanning */
     return 1;
 }
 

+ 55 - 50
stdlib/strings.mod

@@ -1,33 +1,63 @@
 IMPLEMENTATION MODULE Strings;
-(* The descriptor's header holds the logical length; Assign/Concat
-   update it (m2setlen), so Length reflects content, not capacity. *)
+(* NUL-terminated string operations, matching the V3 CHAR-array model
+   (every CHAR array reserves a terminator slot at index = count) and
+   gm2's conventions. Length scans for the terminator rather than using
+   the descriptor count, so fixed-size buffers holding shorter strings
+   behave correctly. *)
 
-PROCEDURE m2setlen(VAR s : ARRAY OF CHAR; n : INTEGER);
-  EXTERNAL;
-
-PROCEDURE Length(VAR s : ARRAY OF CHAR) : INTEGER;
+PROCEDURE Length (VAR s : ARRAY OF CHAR) : INTEGER;
+VAR i : INTEGER;
 BEGIN
-  RETURN LEN(s)
+  i := 0;
+  WHILE (i <= HIGH(s)) AND (s[i] # CHR(0)) DO INC(i) END;
+  RETURN i
 END Length;
 
-PROCEDURE Assign(VAR src, dst : ARRAY OF CHAR);
+PROCEDURE Assign (VAR src, dst : ARRAY OF CHAR);
 VAR i, n, cap : INTEGER;
 BEGIN
-  n := LEN(src);
-  cap := LEN(dst);
+  n := Length(src);
+  cap := HIGH(dst);
   IF n > cap THEN n := cap END;
   i := 0;
   WHILE i < n DO
     dst[i] := src[i];
     i := i + 1
   END;
-  m2setlen(dst, n)
+  dst[n] := CHR(0)
 END Assign;
 
-PROCEDURE Delete(VAR s : ARRAY OF CHAR; start, count : INTEGER);
+PROCEDURE Copy (VAR src, dst : ARRAY OF CHAR);
+BEGIN
+  Assign(src, dst)
+END Copy;
+
+PROCEDURE Concat (VAR s1, s2 : ARRAY OF CHAR; VAR dst : ARRAY OF CHAR);
+VAR i, n1, n2, cap : INTEGER;
+BEGIN
+  n1 := Length(s1);
+  n2 := Length(s2);
+  cap := HIGH(dst);
+  IF n1 > cap THEN n1 := cap END;
+  IF n1 + n2 > cap THEN n2 := cap - n1 END;
+  IF n2 < 0 THEN n2 := 0 END;
+  i := 0;
+  WHILE i < n1 DO
+    dst[i] := s1[i];
+    i := i + 1
+  END;
+  i := 0;
+  WHILE i < n2 DO
+    dst[n1 + i] := s2[i];
+    i := i + 1
+  END;
+  dst[n1 + n2] := CHR(0)
+END Concat;
+
+PROCEDURE Delete (VAR s : ARRAY OF CHAR; start, count : INTEGER);
 VAR n, i : INTEGER;
 BEGIN
-  n := LEN(s);
+  n := Length(s);
   IF start < 0 THEN start := 0 END;
   IF start > n THEN start := n END;
   IF count < 0 THEN count := 0 END;
@@ -37,55 +67,30 @@ BEGIN
     s[i] := s[i + count];
     i := i + 1
   END;
-  m2setlen(s, n - count)
+  s[n - count] := CHR(0)
 END Delete;
 
-PROCEDURE Append(VAR src, dst : ARRAY OF CHAR);
-VAR n, m, i : INTEGER;
+PROCEDURE Append (VAR src, dst : ARRAY OF CHAR);
+VAR n, m, cap, i : INTEGER;
 BEGIN
-  n := LEN(dst);
-  m := LEN(src);
+  n := Length(dst);
+  m := Length(src);
+  cap := HIGH(dst);
+  IF n + m > cap THEN m := cap - n END;
+  IF m < 0 THEN m := 0 END;
   i := 0;
   WHILE i < m DO
     dst[n + i] := src[i];
     i := i + 1
   END;
-  m2setlen(dst, n + m)
+  dst[n + m] := CHR(0)
 END Append;
 
-PROCEDURE Copy(VAR src, dst : ARRAY OF CHAR);
-BEGIN
-  Assign(src, dst)
-END Copy;
-
-PROCEDURE Concat(VAR s1, s2 : ARRAY OF CHAR; VAR dst : ARRAY OF CHAR);
-VAR i, n1, n2, cap : INTEGER;
-BEGIN
-  n1 := LEN(s1);
-  n2 := LEN(s2);
-  cap := LEN(dst);
-  IF n1 + n2 > cap THEN
-    n1 := cap - n2;
-    IF n1 < 0 THEN n1 := 0 END
-  END;
-  i := 0;
-  WHILE i < n1 DO
-    dst[i] := s1[i];
-    i := i + 1
-  END;
-  i := 0;
-  WHILE i < n2 DO
-    dst[n1 + i] := s2[i];
-    i := i + 1
-  END;
-  m2setlen(dst, n1 + n2)
-END Concat;
-
-PROCEDURE Compare(VAR s1, s2 : ARRAY OF CHAR) : INTEGER;
+PROCEDURE Compare (VAR s1, s2 : ARRAY OF CHAR) : INTEGER;
 VAR i, n1, n2, n : INTEGER;
 BEGIN
-  n1 := LEN(s1);
-  n2 := LEN(s2);
+  n1 := Length(s1);
+  n2 := Length(s2);
   n := n1;
   IF n2 < n THEN n := n2 END;
   i := 0;