Просмотр исходного кода

inline record array fields (standard M2 layout): SymTab layout/ComputeOffsets, QbeGen ArrBodyItems/RecItems/RecStatics/CopyRecord/field access, InitHeap in place; SymTab ALLOCATE->NEW (111/111)

Eric Streit 2 недель назад
Родитель
Сommit
b1837a940d
5 измененных файлов с 812 добавлено и 717 удалено
  1. 4 5
      compiler/src/M2.atg
  2. 621 622
      compiler/src/M2.lst
  3. 89 66
      compiler/src/QbeGen.mod
  4. 38 24
      compiler/src/SymTab.mod
  5. 60 0
      docs/summary_inline-array-fields.md

+ 4 - 5
compiler/src/M2.atg

@@ -1604,11 +1604,10 @@ PRODUCTIONS
                                                fn);
                                              t := SymTab.FieldType(t, fn);
                                              QbeGen.FieldAddr(q, fo, qe);
-                                             IF SymTab.ClassOf(t) =
-                                                SymTab.ClArray THEN
-                                               QbeGen.ElemLoad(qe, t, q)
-                                             ELSE QbeGen.CopyOp(qe, q)
-                                             END;
+                                             (* array fields are inline:
+                                                the field address is the
+                                                descriptor, like records *)
+                                             QbeGen.CopyOp(qe, q);
                                              sfx := TRUE
                                            END; .)
       | "^"

+ 621 - 622
compiler/src/M2.lst

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

+ 89 - 66
compiler/src/QbeGen.mod

@@ -1565,13 +1565,79 @@ PROCEDURE Trap;
 (* Scalars/sets inline, array fields as 8-byte pointers to static
    descriptors, nested records inline. Static offsets throughout. *)
 
+PROCEDURE ArrBodyItems (prefix: ARRAY OF CHAR; t: INTEGER);
+(* Inline contents of an array descriptor (no "data $name = {" wrapper
+   and no closing brace): "l <n>[, <elem>...]".  Nested levels are
+   referenced as $prefix_i (emitted by ArrData). *)
+   VAR n, i: CARDINAL;
+     elem: SymTab.TypeIndex;
+     ecls: INTEGER;
+     esz: CARDINAL;
+     bv: QVal;
+   BEGIN
+    n := SymTab.ArrayLen(t);
+    elem := SymTab.ArrayElem(t);
+    ecls := SymTab.ClassOf(elem);
+    W("l ");
+    IntStr(VAL(INTEGER, n), bv);
+    W(bv);
+    IF ecls = SymTab.ClArray THEN
+      i := 0;
+      WHILE i < n DO
+        W(", l $"); W(prefix); W("_");
+        IntStr(VAL(INTEGER, i), bv);
+        W(bv);
+        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
+        W(", z ");
+        IntStr(VAL(INTEGER, n * esz), bv);
+        W(bv)
+      END
+    END
+   END ArrBodyItems;
+
+PROCEDURE ArrData (name: ARRAY OF CHAR; t: INTEGER);
+(* "data $name = { <items> }" plus, for nested levels, the recursive
+   sub-descriptor data $name_i. *)
+   VAR n, i: CARDINAL;
+     elem: SymTab.TypeIndex;
+     bv: QVal;
+     sub: QVal;
+   BEGIN
+    IF NOT opened THEN RETURN END;
+    W("data $"); W(name);
+    W(" = { ");
+    ArrBodyItems(name, t);
+    WL(" }");
+    elem := SymTab.ArrayElem(t);
+    IF SymTab.ClassOf(elem) = SymTab.ClArray THEN
+      n := SymTab.ArrayLen(t);
+      i := 0;
+      WHILE i < n DO
+        Cpy(sub, name); App(sub, "_");
+        IntStr(VAL(INTEGER, i), bv);
+        App(sub, bv);
+        ArrData(sub, elem);
+        INC(i)
+      END
+    END
+   END ArrData;
+
 PROCEDURE RecStatics (recname: ARRAY OF CHAR; t: SymTab.TypeIndex);
-(* Pre-pass: static array objects for array fields, recursive. *)
-  VAR n, i: CARDINAL;
+(* Pre-pass: static sub-descriptors for NESTED array fields (the
+   top-level array field is now inline in the record), recursive. *)
+  VAR n, i, k, an: CARDINAL;
     fn: SymTab.Name;
-    ft: SymTab.TypeIndex;
+    ft, et: SymTab.TypeIndex;
     cls: INTEGER;
-    sub: QVal;
+    sub, bv: QVal;
   BEGIN
     n := SymTab.FieldCount(t);
     i := 0;
@@ -1580,8 +1646,19 @@ PROCEDURE RecStatics (recname: ARRAY OF CHAR; t: SymTab.TypeIndex);
       ft := SymTab.FieldType(t, fn);
       cls := SymTab.ClassOf(ft);
       IF cls = SymTab.ClArray THEN
-        Cpy(sub, recname); App(sub, "_"); App(sub, fn);
-        ArrData(sub, ft)
+        et := SymTab.ArrayElem(ft);
+        IF SymTab.ClassOf(et) = SymTab.ClArray THEN
+          an := SymTab.ArrayLen(ft);
+          k := 0;
+          WHILE k < an DO
+            Cpy(sub, recname); App(sub, "_"); App(sub, fn);
+            App(sub, "_");
+            IntStr(VAL(INTEGER, k), bv);
+            App(sub, bv);
+            ArrData(sub, et);
+            INC(k)
+          END
+        END
       ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
         Cpy(sub, recname); App(sub, "_"); App(sub, fn);
         RecStatics(sub, ft)
@@ -1616,9 +1693,10 @@ PROCEDURE RecItems (t: SymTab.TypeIndex; prefix: ARRAY OF CHAR;
       IF cls = SymTab.ClReal THEN Sep; W("d 0")
       ELSIF cls = SymTab.ClChar THEN Sep; W("b 0")
       ELSIF cls = SymTab.ClArray THEN
+        (* array field: inline descriptor (was a pointer) *)
         Sep;
         Cpy(sub, prefix); App(sub, "_"); App(sub, fn);
-        W("l $"); W(sub)
+        ArrBodyItems(sub, ft)
       ELSIF cls = SymTab.ClSet THEN
         w := SymTab.SetWords(ft);
         IF w = 0 THEN w := 1 END;
@@ -1695,11 +1773,8 @@ PROCEDURE CopyRecord (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
       NewTemp(dd); Op3L("add", dd, dst, off);
       NewTemp(ds); Op3L("add", ds, src, off);
       IF cls = SymTab.ClArray THEN
-        NewTemp(di);
-        W("  "); W(di); W(" =l loadl "); WL(dd);
-        NewTemp(si);
-        W("  "); W(si); W(" =l loadl "); WL(ds);
-        CopyArray(di, si, ft)
+        (* inline array field: the field address is the descriptor *)
+        CopyArray(dd, ds, ft)
       ELSIF cls = SymTab.ClSet THEN
         CopySet(dd, ds, SymTab.SetWords(ft), SymTab.SetWords(ft))
       ELSIF (cls = SymTab.ClRecord) OR (cls = SymTab.ClClass) THEN
@@ -2244,56 +2319,6 @@ PROCEDURE FlushStrings;
     END
   END FlushStrings;
 
-PROCEDURE ArrData (name: ARRAY OF CHAR; t: INTEGER);
-(* Recursive data emission; nested levels as $name_i. *)
-   VAR n, i: CARDINAL;
-     elem: SymTab.TypeIndex;
-     ecls: INTEGER;
-     cls: INTEGER;
-     esz: CARDINAL;
-     bv: QVal;
-     sub: QVal;
-   BEGIN
-    IF NOT opened THEN RETURN END;
-    n := SymTab.ArrayLen(t);
-    elem := SymTab.ArrayElem(t);
-    ecls := SymTab.ClassOf(elem);
-    W("data $"); W(name);
-    W(" = { l ");
-    IntStr(VAL(INTEGER, n), bv);
-    W(bv);
-    IF ecls = SymTab.ClArray THEN
-      i := 0;
-      WHILE i < n DO
-        W(", l $"); W(name); W("_");
-        IntStr(VAL(INTEGER, i), bv);
-        W(bv);
-        INC(i)
-      END;
-      WL(" }");
-      i := 0;
-      WHILE i < n DO
-        Cpy(sub, name); App(sub, "_");
-        IntStr(VAL(INTEGER, i), bv);
-        App(sub, bv);
-        ArrData(sub, elem);
-        INC(i)
-      END
-    ELSE
-       IF ecls = SymTab.ClChar THEN esz := 1
-       ELSIF (ecls = SymTab.ClReal)
-          OR (ecls = SymTab.ClPtr) THEN esz := 8
-       ELSE esz := 4
-       END;
-       IF n > 0 THEN
-         W(", z ");
-         IntStr(VAL(INTEGER, n * esz), bv);
-         W(bv)
-       END;
-       WL(" }")
-     END
-   END ArrData;
-
 PROCEDURE DeclArr (name: ARRAY OF CHAR; t: INTEGER);
   BEGIN
     IF SymTab.IsOpenArray(t) OR (SymTab.ArrayDepth(t) = 0) THEN
@@ -2405,13 +2430,11 @@ PROCEDURE InitHeap (addr: ARRAY OF CHAR; t: SymTab.TypeIndex);
         ft := SymTab.FieldType(t, fn);
         ecls := SymTab.ClassOf(ft);
         IF ecls = SymTab.ClArray THEN
+          (* inline array field: initialize its header in place *)
           IntStr(SymTab.FieldOffset(t, fn), nb);
           NewTemp(fa);
           Op3L("add", fa, addr, nb);
-          NewHeap(ft, fb);
-          InitHeap(fb, ft);
-          Revive;
-          W("  storel "); W(fb); W(", "); WL(fa)
+          InitHeap(fa, ft)
         ELSIF (ecls = SymTab.ClRecord) OR (ecls = SymTab.ClClass) THEN
           IntStr(SymTab.FieldOffset(t, fn), nb);
           NewTemp(fa);

+ 38 - 24
compiler/src/SymTab.mod

@@ -1,8 +1,7 @@
 IMPLEMENTATION MODULE SymTab;
 
 IMPORT FileIO;
-FROM Storage IMPORT ALLOCATE;
-FROM SYSTEM IMPORT TSIZE;
+FROM Storage IMPORT ALLOCATE;  (* gm2 needs this for NEW substitution *)
 
 CONST
   MaxTypes  = 4096;
@@ -169,7 +168,7 @@ PROCEDURE NewScope (parent: ScopePtr; level: CARDINAL): ScopePtr;
 (* Heap-allocates a scope and appends it to the creation chain. *)
   VAR s: ScopePtr;
   BEGIN
-    ALLOCATE(s, TSIZE(ScopeNode));
+    NEW(s);
     s^.parent := parent;
     s^.root := NIL;
     s^.level := level;
@@ -244,7 +243,7 @@ PROCEDURE RawEnter (name: ARRAY OF CHAR; kind: INTEGER): SymPtr;
    BST; NIL on duplicate (node released to nobody: dropped). *)
   VAR node: SymPtr;
   BEGIN
-    ALLOCATE(node, TSIZE(SymNode));
+    NEW(node);
     Assign(node^.name, name);
     Assign(node^.sym, name);
     SetNodeMod(node);
@@ -312,7 +311,7 @@ PROCEDURE FieldPending (rec: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
   VAR f: FieldPtr;
   BEGIN
     IF FindField(rec, name) # NIL THEN RETURN FALSE END;
-    ALLOCATE(f, TSIZE(FieldNode));
+    NEW(f);
     Assign(f^.name, name);
     f^.typ := InvalidType;
     f^.owner := rec;
@@ -849,6 +848,24 @@ PROCEDURE ProcTypeOf (name: ARRAY OF CHAR): TypeIndex;
     RETURN t
   END ProcTypeOf;
 
+PROCEDURE ElemBytes (t: TypeIndex): CARDINAL;
+(* element size of array descriptor t (bytes) *)
+  VAR cls: INTEGER;
+  BEGIN
+    cls := ClassOf(ArrayElem(t));
+    IF cls = ClChar THEN RETURN 1 END;
+    IF cls = ClReal THEN RETURN 8 END;
+    IF (cls = ClArray) OR (cls = ClPtr) OR (cls = ClRecord)
+       OR (cls = ClClass) OR (cls = ClProc) THEN
+      RETURN 8
+    END;
+    RETURN 4
+  END ElemBytes;
+
+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;
+
 PROCEDURE TypeSizeD (t: TypeIndex; depth: CARDINAL): CARDINAL;
 (* Inline footprint in bytes: scalars 4/8, sets words*4, pointers,
    open and fixed arrays 8 (descriptor address — array objects live
@@ -872,7 +889,11 @@ PROCEDURE TypeSizeD (t: TypeIndex; depth: CARDINAL): CARDINAL;
         f := fields;
         WHILE f # NIL DO
           IF f^.owner = r THEN
-            n := n + TypeSizeD(f^.typ, depth + 1)
+            IF ClassOf(f^.typ) = ClArray THEN
+              n := n + ArrObjSize(f^.typ)  (* inline array field *)
+            ELSE
+              n := n + TypeSizeD(f^.typ, depth + 1)
+            END
           END;
           f := f^.next
         END;
@@ -888,19 +909,12 @@ PROCEDURE TypeSize (t: TypeIndex): CARDINAL;
     RETURN TypeSizeD(t, 0)
   END TypeSize;
 
-PROCEDURE ElemBytes (t: TypeIndex): CARDINAL;
-(* element size of array descriptor t (bytes) *)
-  VAR cls: INTEGER;
+PROCEDURE FieldSize (t: TypeIndex): CARDINAL;
+(* inline footprint of a record field: fixed arrays are inline objects *)
   BEGIN
-    cls := ClassOf(ArrayElem(t));
-    IF cls = ClChar THEN RETURN 1 END;
-    IF cls = ClReal THEN RETURN 8 END;
-    IF (cls = ClArray) OR (cls = ClPtr) OR (cls = ClRecord)
-       OR (cls = ClClass) OR (cls = ClProc) THEN
-      RETURN 8
-    END;
-    RETURN 4
-  END ElemBytes;
+    IF ClassOf(t) = ClArray THEN RETURN ArrObjSize(t) END;
+    RETURN TypeSizeD(t, 0)
+  END FieldSize;
 
 PROCEDURE ObjectSize (t: TypeIndex): CARDINAL;
 (* full allocation footprint: arrays 8 + count*elem, else TypeSize.
@@ -928,7 +942,7 @@ PROCEDURE ComputeOffsets (r: TypeIndex);
     f := fields;
     WHILE f # NIL DO
       IF f^.owner = r THEN
-        total := total + VAL(INTEGER, TypeSize(f^.typ));
+        total := total + VAL(INTEGER, FieldSize(f^.typ));
         INC(cnt)
       END;
       f := f^.next
@@ -937,7 +951,7 @@ PROCEDURE ComputeOffsets (r: TypeIndex);
     f := fields;
     WHILE f # NIL DO
       IF f^.owner = r THEN
-        off := off - VAL(INTEGER, TypeSize(f^.typ));
+        off := off - VAL(INTEGER, FieldSize(f^.typ));
         DEC(ord);
         f^.off := off;
         f^.ord := ord
@@ -1327,7 +1341,7 @@ PROCEDURE EnterIn (s: ScopePtr; name: ARRAY OF CHAR;
                     kind: INTEGER): BOOLEAN;
   VAR node: SymPtr;
   BEGIN
-    ALLOCATE(node, TSIZE(SymNode));
+    NEW(node);
     Assign(node^.name, name);
     Assign(node^.sym, name);
     node^.mod[0] := CHR(0);
@@ -1596,7 +1610,7 @@ PROCEDURE ExportUp (name: ARRAY OF CHAR);
     parent := curScope^.parent;
     IF parent = NIL THEN RETURN END;
     IF TreeFind(parent^.root, name) # NIL THEN RETURN END;
-    ALLOCATE(node, TSIZE(SymNode));
+    NEW(node);
     node^ := src^;
     node^.left := NIL;
     node^.right := NIL;
@@ -1615,7 +1629,7 @@ PROCEDURE Materialize (mod, name: ARRAY OF CHAR): BOOLEAN;
     IF src = NIL THEN RETURN FALSE END;
     (* already visible (repeat import): nothing to do *)
     IF TreeFind(curScope^.root, name) # NIL THEN RETURN TRUE END;
-    ALLOCATE(node, TSIZE(SymNode));
+    NEW(node);
     node^ := src^;
     node^.left := NIL;
     node^.right := NIL;
@@ -1652,7 +1666,7 @@ PROCEDURE MaterializeAlias (mod, name: ARRAY OF CHAR;
     IF src = NIL THEN RETURN FALSE END;
     BuildAlias(mod, name, alias);
     IF TreeFind(curScope^.root, alias) = NIL THEN
-      ALLOCATE(node, TSIZE(SymNode));
+      NEW(node);
       node^ := src^;
       Assign(node^.name, alias);   (* BST key *)
       Assign(node^.sym, name);     (* real symbol name *)

+ 60 - 0
docs/summary_inline-array-fields.md

@@ -0,0 +1,60 @@
+# Inline record array fields (self-hosting layout fix)
+
+Tag `v3-inline-array-fields`. Main suite 111/111; full compiler source
+set still compiles under V3 and links.
+
+## Why
+
+V3 stored a record's array fields as **8-byte pointers to static
+descriptors**, initialised only for static records. Heap records
+(`ALLOCATE`/`NEW`) never initialised them, so `SymTab.RawEnter`'s
+`Assign(node^.name, …)` dereferenced garbage → the self-compiled
+compiler crashed at startup.
+
+Standard Modula-2 (and gm2) store record array fields **inline**, so
+V3 now does too.
+
+## Changes
+
+- **SymTab layout**: a fixed-array field occupies its full inline
+  object (`ArrObjSize = 8 + count*elemBytes`), not 8. `TypeSizeD`'s
+  record branch and `ComputeOffsets` use `FieldSize`; new
+  `ArrObjSize`/`FieldSize`; `ElemBytes` moved earlier.
+- **QbeGen data**: `ArrBodyItems` (inline descriptor contents:
+  `l <n>, z <bytes>` or `l <n>, l $sub_i, …`) + `ArrData` (wraps it and
+  emits nested `$name_i`). `RecItems` emits array fields inline;
+  `RecStatics` only emits sub-descriptors for *nested* array fields.
+- **Field access**: `Design`'s `.field` now passes the field *address*
+  for array fields (was `ElemLoad` of the pointer).
+- **CopyRecord**: array fields copied via `CopyArray(fieldAddr, …)`.
+- **InitHeap**: a record's inline array field is initialised in place
+  (header = count), no separate allocation.
+- **SymTab**: `ALLOCATE(x, TSIZE(T))` → `NEW(x)` (typed allocation runs
+  `InitHeap`). `FROM Storage IMPORT ALLOCATE` kept for gm2's `NEW`.
+
+## Remaining blocker (the string model)
+
+Running the self-compiled compiler still aborts, but now in a
+reproducible, understood place: the compiler's string helpers scan an
+argument for a trailing `NUL` (`SymTab.Assign`, `Equal`, `StrLen`, …),
+while V3 strings are **count + bytes with no terminator** and trap when
+indexed past the count. Minimal repro:
+
+```modula2
+PROCEDURE Copy (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
+BEGIN ... WHILE (i < HIGH(d)) AND (s[i] # CHR(0)) DO ... END ... END Copy;
+Copy(p^.n, "hi");   (* s[2] out of bounds -> abort *)
+```
+
+gm2 strings are NUL-terminated so the sources work there. Options:
+1. **NUL-terminate V3 CHAR arrays** (reserve a terminator slot, allow
+   reading index = count, emit `z (n+1)`, literals `… , b 0`). Keeps the
+   sources unchanged; broad but mechanical.
+2. Rewrite every NUL-scanning helper in the compiler sources to be
+   length-based (must stay gm2-compatible) — larger.
+
+Then: the rest of the bootstrap (cross-stage `FileIO`, `fixpoint.sh`).
+
+## Files
+
+`compiler/src/{M2.atg,SymTab.mod,QbeGen.mod,M2.lst}`.