Procházet zdrojové kódy

forward procedure calls: M2S+M2P compile clean under V3 (FORWARD via CR without -m, BITSET, typed set ctor, empty ELSIF, file-handle fix); 110/110

Eric Streit před 2 týdny
rodič
revize
6cd5ef994e

+ 17 - 1
compiler/src/M2.atg

@@ -1101,7 +1101,7 @@ PRODUCTIONS
                                            QbeGen.NewLabel(lThen);
                                            QbeGen.Jnz(q, lThen, lElse);
                                            QbeGen.EmitLabel(lThen); .)
-        "THEN" StatSeq                  (. QbeGen.Jmp(lEnd); .) }
+        "THEN" [ StatSeq ]              (. QbeGen.Jmp(lEnd); .) }
       [ "ELSE"                          (. QbeGen.EmitLabel(lElse);
                                            hasElse := TRUE; .)
         [ StatSeq ] ]
@@ -1924,6 +1924,7 @@ PRODUCTIONS
                                                      SymTab.ClRecord)) THEN
                                              QbeGen.NoteAddr(qd, qd)
                                            END; .)
+      [ TypedSetLit<dt, q>              (. t := dt; .) ]
       [ ArgList<qn, dt, qd, TRUE, ct2, q2, called>
                                         (. t := ct2;
                                            QbeGen.CopyOp(q2, q); .) ]
@@ -2103,6 +2104,21 @@ PRODUCTIONS
                                            QbeGen.SetZero(q, 8); .)
       [ SetElem<t, q> { "," SetElem<t, q> } ]
       "}" .
+  (* Typed set constructor: TypeName{ elems } — e.g. BITSET{0},
+     BITSET{}.  The declared type (not SET OF [0..255]) sets the
+     width and element span. *)
+  TypedSetLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+                                        (. VAR nw: CARDINAL; .)
+    = "{"                               (. IF SymTab.ClassOf(vt) #
+                                              SymTab.ClSet THEN
+                                             SemError(230); nw := 8
+                                           ELSE nw := SymTab.SetWords(vt);
+                                             IF nw = 0 THEN nw := 8 END
+                                           END;
+                                           QbeGen.NewSetTemp(nw, q);
+                                           QbeGen.SetZero(q, nw); .)
+      [ SetElem<vt, q> { "," SetElem<vt, q> } ]
+      "}" .
   SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
                                              qe, q2: QbeGen.QVal;
                                              v, v2: INTEGER;

+ 262 - 246
compiler/src/M2.lst

@@ -1118,7 +1118,7 @@ Listing:
  1101                                             QbeGen.NewLabel(lThen);
  1102                                             QbeGen.Jnz(q, lThen, lElse);
  1103                                             QbeGen.EmitLabel(lThen); .)
- 1104          "THEN" StatSeq                  (. QbeGen.Jmp(lEnd); .) }
+ 1104          "THEN" [ StatSeq ]              (. QbeGen.Jmp(lEnd); .) }
  1105        [ "ELSE"                          (. QbeGen.EmitLabel(lElse);
  1106                                             hasElse := TRUE; .)
  1107          [ StatSeq ] ]
@@ -1941,248 +1941,264 @@ Listing:
  1924                                                       SymTab.ClRecord)) THEN
  1925                                               QbeGen.NoteAddr(qd, qd)
  1926                                             END; .)
- 1927        [ ArgList<qn, dt, qd, TRUE, ct2, q2, called>
- 1928                                          (. t := ct2;
- 1929                                             QbeGen.CopyOp(q2, q); .) ]
- 1930                                          (. IF NOT called
- 1931   AND (dk = SymTab.KindProc) THEN
- 1932                                               (* bare zero-arg function
- 1933                                                  call (parentheses may be
- 1934                                                  omitted); a proper or
- 1935                                                  parameterised proc here
- 1936                                                  is 230 *)
- 1937                                               IF (SymTab.ProcNPar(qn) = 0)
- 1938   AND (SymTab.ProcRes(qn) #
- 1939                                                     SymTab.InvalidType) THEN
- 1940                                                 QbeGen.Mangled(qn,
- 1941                                                   SymTab.ProcUid(qn), qm0);
- 1942                                                 QbeGen.CallBegin(qm0,
- 1943                                                   SymTab.ProcRes(qn),
- 1944                                                   SymTab.ProcDepthOf(qn),
- 1945                                                   SymTab.IsExternal(qn));
- 1946                                                 QbeGen.CallEnd(TRUE, q);
- 1947                                                 t := SymTab.ProcRes(qn)
- 1948                                               ELSE
- 1949                                                 (* procedure used as a
- 1950                                                    value (assign to a
- 1951                                                    procedure variable):
- 1952                                                    its code address *)
- 1953                                                 t := SymTab.ProcTypeOf(qn);
- 1954                                                 QbeGen.Mangled(qn,
- 1955                                                   SymTab.ProcUid(qn), qm0);
- 1956                                                 QbeGen.ProcAddr(qm0, q)
- 1957                                               END
- 1958                                             END; .)
- 1959      | ( "HIGH"                          (. isHigh := TRUE; .)
- 1960        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
- 1961        "(" Design<dt, dk, qd, qn, sfx> ")"
- 1962                                          (. IF dt = SymTab.InvalidType THEN
- 1963                                             ELSIF SymTab.ClassOf(dt) #
- 1964                                                   SymTab.ClArray THEN
- 1965                                               SemError(217);
- 1966                                               t := SymTab.InvalidType;
- 1967                                               QbeGen.CopyOp("0", q)
- 1968                                             ELSE
- 1969                                               IF isHigh THEN
- 1970                                                 IF SymTab.IsOpenArray(dt) THEN
- 1971                                                   QbeGen.OpenHi(qd, qr)
- 1972                                                 ELSE
- 1973                                                   QbeGen.IntStr(
- 1974                                                     SymTab.ArrayHi(dt), qr)
- 1975                                                 END
- 1976                                               ELSE
- 1977                                                 IF SymTab.IsOpenArray(dt) THEN
- 1978                                                   QbeGen.LoadCount(qd, qr)
- 1979                                                 ELSE
- 1980                                                   QbeGen.IntStr(VAL(
- 1981                                                     INTEGER,
- 1982                                                     SymTab.ArrayLen(dt)),
- 1983                                                     qr)
- 1984                                                 END
- 1985                                               END;
- 1986                                                t := SymTab.IntType();
- 1987                                                QbeGen.CopyOp(qr, q)
- 1988                                              END; .)
- 1989      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
- 1990                                          (. IF dt = SymTab.InvalidType THEN
- 1991                                               t := SymTab.InvalidType;
- 1992                                               QbeGen.CopyOp("0", q)
- 1993                                             ELSE
- 1994                                               QbeGen.IntStr(VAL(INTEGER,
- 1995                                                 SymTab.ObjectSize(dt)), q);
- 1996                                               t := SymTab.IntType()
- 1997                                             END; .)
- 1998      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
- 1999                                          (. IF dt = SymTab.InvalidType THEN
- 2000                                               t := SymTab.InvalidType;
- 2001                                               QbeGen.CopyOp("0", q)
- 2002                                             ELSE
- 2003                                               IF sfx THEN
- 2004                                                 QbeGen.CopyOp(qd, q)
- 2005                                               ELSIF (dk = SymTab.KindVar)
- 2006                                                  OR (dk = SymTab.KindParam) THEN
- 2007                                                 QbeGen.AddrOf(qn, q)
- 2008                                               ELSE SemError(230);
- 2009                                                 QbeGen.CopyOp("0", q)
- 2010                                               END;
- 2011                                               t := SymTab.AddrType()
- 2012                                             END; .)
- 2013      | "CHR" "(" Expr<et, q> ")"
- 2014                                          (. IF (et # SymTab.InvalidType)
- 2015   AND NOT SymTab.IsIntFamily(et) THEN
- 2016                                               SemError(211) END;
- 2017                                             t := SymTab.CharType(); .)
- 2018      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
- 2019                                          (. IF et # SymTab.InvalidType THEN
- 2020                                               IF (SymTab.ClassOf(et) #
- 2021                                                   SymTab.ClChar)
- 2022   AND (SymTab.ClassOf(et) #
- 2023                                                     SymTab.ClBool)
- 2024   AND (SymTab.ClassOf(et) #
- 2025                                                     SymTab.ClEnum)
- 2026   AND NOT SymTab.IsIntFamily(et) THEN
- 2027                                                 SemError(211) END
- 2028                                             END;
- 2029                                             t := SymTab.IntType(); .)
- 2030      | "CAP" "(" Expr<et, q> ")"
- 2031                                          (. QbeGen.CapQ(q, qa);
- 2032                                             QbeGen.CopyOp(qa, q);
- 2033                                             t := SymTab.CharType(); .)
- 2034      | "ABS" "(" Expr<et, q> ")"
- 2035                                          (. IF (et # SymTab.InvalidType)
- 2036   AND NOT SymTab.IsIntFamily(et)
- 2037   AND (SymTab.ClassOf(et) #
- 2038                                                  SymTab.ClReal) THEN
- 2039                                               SemError(211)
- 2040                                             ELSE QbeGen.AbsQ(q, qa,
- 2041                                                    SymTab.ClassOf(et) =
- 2042                                                      SymTab.ClReal);
- 2043                                               QbeGen.CopyOp(qa, q)
- 2044                                             END;
- 2045                                             t := et; .)
- 2046      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
- 2047                                          (. IF NOT SymTab.Lookup(vn) THEN
- 2048                                               SemError(201);
- 2049                                               t := SymTab.InvalidType
- 2050                                             ELSE vt := SymTab.SymType(vn);
- 2051                                               IF vt = SymTab.InvalidType THEN
- 2052                                                 t := SymTab.InvalidType
- 2053                                               ELSIF et =
- 2054                                                  SymTab.InvalidType THEN
- 2055                                                 t := vt
- 2056                                               ELSE
- 2057                                                 c1 := SymTab.ClassOf(et);
- 2058                                                 c2 := SymTab.ClassOf(vt);
- 2059                                                 IF ((c1 = SymTab.ClInt)
- 2060                                                     OR (c1 =
- 2061                                                        SymTab.ClChar)
- 2062                                                     OR (c1 =
- 2063                                                        SymTab.ClBool)
- 2064                                                     OR (c1 =
- 2065                                                        SymTab.ClEnum))
- 2066   AND ((c2 = SymTab.ClInt)
- 2067                                                     OR (c2 =
- 2068                                                        SymTab.ClChar)
- 2069                                                     OR (c2 =
- 2070                                                        SymTab.ClBool)
- 2071                                                     OR (c2 =
- 2072                                                        SymTab.ClEnum)) THEN
- 2073                                                   t := vt
- 2074                                                 ELSIF (c1 = SymTab.ClPtr)
- 2075   AND (c2 = SymTab.ClPtr) THEN
- 2076                                                   t := vt
- 2077                                                 ELSIF (c1 = SymTab.ClReal)
- 2078   AND (c2 = SymTab.ClReal) THEN
- 2079                                                   t := vt
- 2080                                                 ELSE SemError(230);
- 2081                                                   t := SymTab.InvalidType
- 2082                                                 END
- 2083                                               END
- 2084                                             END; .)
- 2085      | "(" Expr<et, q> ")"               (. t := et; .)
- 2086      | SetLit<st, sq>                    (. t := st;
- 2087                                             QbeGen.CopyOp(sq, q); .)
- 2088      | ( "NOT" | "~" ) Fact<t2, q2>      (. IF SymTab.BoolCheck(t2) THEN
- 2089                                               t := SymTab.BoolType()
- 2090                                             ELSE SemError(212);
- 2091                                               t := SymTab.InvalidType END;
- 2092                                             IF t # SymTab.InvalidType THEN
- 2093                                               QbeGen.NotQ(q2, q)
- 2094                                             ELSE QbeGen.CopyOp("0", q)
- 2095                                             END; .) .
- 2096    (* Set literals are SET OF [0..255] (8 words); elements validated
- 2097       0..255 statically when foldable (222 otherwise), runtime trap
- 2098       for computed elements. Ranges always lower via SetRange. *)
- 2099    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
- 2100      = "{"                               (. t := SymTab.NewSet(
- 2101                                               SymTab.NewSubR(0, 255));
- 2102                                             QbeGen.NewSetTemp(8, q);
- 2103                                             QbeGen.SetZero(q, 8); .)
- 2104        [ SetElem<t, q> { "," SetElem<t, q> } ]
- 2105        "}" .
- 2106    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
- 2107                                               qe, q2: QbeGen.QVal;
- 2108                                               v, v2: INTEGER;
- 2109                                               lo: INTEGER;
- 2110                                               span: CARDINAL;
- 2111                                               cl, cl2: INTEGER;
- 2112                                               hasR: BOOLEAN; .)
- 2113      =                                   (. hasR := FALSE; .)
- 2114        Expr<et, qe>
- 2115        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
- 2116                                          (. lo := SymTab.SetBaseLo(st);
- 2117                                             span := SymTab.SetCount(st);
- 2118                                             IF (et = SymTab.InvalidType)
- 2119                                                OR (hasR AND (et2 =
- 2120                                                   SymTab.InvalidType)) THEN
- 2121                                             ELSE cl :=
- 2122                                                    SymTab.ClassOf(et);
- 2123                                               IF hasR THEN
- 2124                                                 cl2 :=
- 2125                                                   SymTab.ClassOf(et2)
- 2126                                               ELSE cl2 := SymTab.ClInt
- 2127                                               END;
- 2128                                               IF ((cl # SymTab.ClInt)
- 2129   AND (cl # SymTab.ClChar)
- 2130   AND (cl # SymTab.ClBool))
- 2131                                                  OR (hasR AND 
- 2132                                                     ((cl2
- 2133                                                       # SymTab.ClInt)
- 2134   AND (cl2
- 2135                                                        # SymTab.ClChar)
- 2136   AND (cl2
- 2137                                                        # SymTab.ClBool))) THEN
- 2138                                                 SemError(222)
- 2139                                               ELSIF hasR
- 2140   AND SymTab.ConstInt(qe, v)
- 2141   AND SymTab.ConstInt(q2,
- 2142                                                     v2)
- 2143   AND ((v < lo)
- 2144                                                     OR (v2 < lo)
- 2145                                                     OR (v >= lo +
- 2146                                                        VAL(INTEGER, span))
- 2147                                                     OR (v2 >= lo +
- 2148                                                        VAL(INTEGER, span))
- 2149                                                     OR (v > v2)) THEN
- 2150                                                 SemError(222)
- 2151                                                ELSIF hasR THEN
- 2152                                                  QbeGen.SetRange(sq, qe, q2,
- 2153                                                    lo, span)
- 2154                                                ELSIF SymTab.ConstInt(qe,
- 2155                                                        v)
- 2156   AND ((v < lo)
- 2157                                                      OR (v >= lo +
- 2158                                                         VAL(INTEGER,
- 2159                                                           span))) THEN
- 2160                                                  SemError(222)
- 2161                                                ELSE QbeGen.SetBit(sq, qe,
- 2162                                                  lo, span)
- 2163                                               END
- 2164                                             END; .) .
- 2165    GetIdent<VAR n: SymTab.Name>
- 2166      = ident                             (. LexName(n); .) .
- 2167  
- 2168  END M2.
+ 1927        [ TypedSetLit<dt, q>              (. t := dt; .) ]
+ 1928        [ ArgList<qn, dt, qd, TRUE, ct2, q2, called>
+ 1929                                          (. t := ct2;
+ 1930                                             QbeGen.CopyOp(q2, q); .) ]
+ 1931                                          (. IF NOT called
+ 1932   AND (dk = SymTab.KindProc) THEN
+ 1933                                               (* bare zero-arg function
+ 1934                                                  call (parentheses may be
+ 1935                                                  omitted); a proper or
+ 1936                                                  parameterised proc here
+ 1937                                                  is 230 *)
+ 1938                                               IF (SymTab.ProcNPar(qn) = 0)
+ 1939   AND (SymTab.ProcRes(qn) #
+ 1940                                                     SymTab.InvalidType) THEN
+ 1941                                                 QbeGen.Mangled(qn,
+ 1942                                                   SymTab.ProcUid(qn), qm0);
+ 1943                                                 QbeGen.CallBegin(qm0,
+ 1944                                                   SymTab.ProcRes(qn),
+ 1945                                                   SymTab.ProcDepthOf(qn),
+ 1946                                                   SymTab.IsExternal(qn));
+ 1947                                                 QbeGen.CallEnd(TRUE, q);
+ 1948                                                 t := SymTab.ProcRes(qn)
+ 1949                                               ELSE
+ 1950                                                 (* procedure used as a
+ 1951                                                    value (assign to a
+ 1952                                                    procedure variable):
+ 1953                                                    its code address *)
+ 1954                                                 t := SymTab.ProcTypeOf(qn);
+ 1955                                                 QbeGen.Mangled(qn,
+ 1956                                                   SymTab.ProcUid(qn), qm0);
+ 1957                                                 QbeGen.ProcAddr(qm0, q)
+ 1958                                               END
+ 1959                                             END; .)
+ 1960      | ( "HIGH"                          (. isHigh := TRUE; .)
+ 1961        | ( "LEN" | "LENGTH" )            (. isHigh := FALSE; .) )
+ 1962        "(" Design<dt, dk, qd, qn, sfx> ")"
+ 1963                                          (. IF dt = SymTab.InvalidType THEN
+ 1964                                             ELSIF SymTab.ClassOf(dt) #
+ 1965                                                   SymTab.ClArray THEN
+ 1966                                               SemError(217);
+ 1967                                               t := SymTab.InvalidType;
+ 1968                                               QbeGen.CopyOp("0", q)
+ 1969                                             ELSE
+ 1970                                               IF isHigh THEN
+ 1971                                                 IF SymTab.IsOpenArray(dt) THEN
+ 1972                                                   QbeGen.OpenHi(qd, qr)
+ 1973                                                 ELSE
+ 1974                                                   QbeGen.IntStr(
+ 1975                                                     SymTab.ArrayHi(dt), qr)
+ 1976                                                 END
+ 1977                                               ELSE
+ 1978                                                 IF SymTab.IsOpenArray(dt) THEN
+ 1979                                                   QbeGen.LoadCount(qd, qr)
+ 1980                                                 ELSE
+ 1981                                                   QbeGen.IntStr(VAL(
+ 1982                                                     INTEGER,
+ 1983                                                     SymTab.ArrayLen(dt)),
+ 1984                                                     qr)
+ 1985                                                 END
+ 1986                                               END;
+ 1987                                                t := SymTab.IntType();
+ 1988                                                QbeGen.CopyOp(qr, q)
+ 1989                                              END; .)
+ 1990      | ( "SIZE" | "TSIZE" ) "(" Design<dt, dk, qd, qn, sfx> ")"
+ 1991                                          (. IF dt = SymTab.InvalidType THEN
+ 1992                                               t := SymTab.InvalidType;
+ 1993                                               QbeGen.CopyOp("0", q)
+ 1994                                             ELSE
+ 1995                                               QbeGen.IntStr(VAL(INTEGER,
+ 1996                                                 SymTab.ObjectSize(dt)), q);
+ 1997                                               t := SymTab.IntType()
+ 1998                                             END; .)
+ 1999      | "ADR" "(" Design<dt, dk, qd, qn, sfx> ")"
+ 2000                                          (. IF dt = SymTab.InvalidType THEN
+ 2001                                               t := SymTab.InvalidType;
+ 2002                                               QbeGen.CopyOp("0", q)
+ 2003                                             ELSE
+ 2004                                               IF sfx THEN
+ 2005                                                 QbeGen.CopyOp(qd, q)
+ 2006                                               ELSIF (dk = SymTab.KindVar)
+ 2007                                                  OR (dk = SymTab.KindParam) THEN
+ 2008                                                 QbeGen.AddrOf(qn, q)
+ 2009                                               ELSE SemError(230);
+ 2010                                                 QbeGen.CopyOp("0", q)
+ 2011                                               END;
+ 2012                                               t := SymTab.AddrType()
+ 2013                                             END; .)
+ 2014      | "CHR" "(" Expr<et, q> ")"
+ 2015                                          (. IF (et # SymTab.InvalidType)
+ 2016   AND NOT SymTab.IsIntFamily(et) THEN
+ 2017                                               SemError(211) END;
+ 2018                                             t := SymTab.CharType(); .)
+ 2019      | ( "ORD" | "ORDL" ) "(" Expr<et, q> ")"
+ 2020                                          (. IF et # SymTab.InvalidType THEN
+ 2021                                               IF (SymTab.ClassOf(et) #
+ 2022                                                   SymTab.ClChar)
+ 2023   AND (SymTab.ClassOf(et) #
+ 2024                                                     SymTab.ClBool)
+ 2025   AND (SymTab.ClassOf(et) #
+ 2026                                                     SymTab.ClEnum)
+ 2027   AND NOT SymTab.IsIntFamily(et) THEN
+ 2028                                                 SemError(211) END
+ 2029                                             END;
+ 2030                                             t := SymTab.IntType(); .)
+ 2031      | "CAP" "(" Expr<et, q> ")"
+ 2032                                          (. QbeGen.CapQ(q, qa);
+ 2033                                             QbeGen.CopyOp(qa, q);
+ 2034                                             t := SymTab.CharType(); .)
+ 2035      | "ABS" "(" Expr<et, q> ")"
+ 2036                                          (. IF (et # SymTab.InvalidType)
+ 2037   AND NOT SymTab.IsIntFamily(et)
+ 2038   AND (SymTab.ClassOf(et) #
+ 2039                                                  SymTab.ClReal) THEN
+ 2040                                               SemError(211)
+ 2041                                             ELSE QbeGen.AbsQ(q, qa,
+ 2042                                                    SymTab.ClassOf(et) =
+ 2043                                                      SymTab.ClReal);
+ 2044                                               QbeGen.CopyOp(qa, q)
+ 2045                                             END;
+ 2046                                             t := et; .)
+ 2047      | "VAL" "(" GetIdent<vn> "," Expr<et, q> ")"
+ 2048                                          (. IF NOT SymTab.Lookup(vn) THEN
+ 2049                                               SemError(201);
+ 2050                                               t := SymTab.InvalidType
+ 2051                                             ELSE vt := SymTab.SymType(vn);
+ 2052                                               IF vt = SymTab.InvalidType THEN
+ 2053                                                 t := SymTab.InvalidType
+ 2054                                               ELSIF et =
+ 2055                                                  SymTab.InvalidType THEN
+ 2056                                                 t := vt
+ 2057                                               ELSE
+ 2058                                                 c1 := SymTab.ClassOf(et);
+ 2059                                                 c2 := SymTab.ClassOf(vt);
+ 2060                                                 IF ((c1 = SymTab.ClInt)
+ 2061                                                     OR (c1 =
+ 2062                                                        SymTab.ClChar)
+ 2063                                                     OR (c1 =
+ 2064                                                        SymTab.ClBool)
+ 2065                                                     OR (c1 =
+ 2066                                                        SymTab.ClEnum))
+ 2067   AND ((c2 = SymTab.ClInt)
+ 2068                                                     OR (c2 =
+ 2069                                                        SymTab.ClChar)
+ 2070                                                     OR (c2 =
+ 2071                                                        SymTab.ClBool)
+ 2072                                                     OR (c2 =
+ 2073                                                        SymTab.ClEnum)) THEN
+ 2074                                                   t := vt
+ 2075                                                 ELSIF (c1 = SymTab.ClPtr)
+ 2076   AND (c2 = SymTab.ClPtr) THEN
+ 2077                                                   t := vt
+ 2078                                                 ELSIF (c1 = SymTab.ClReal)
+ 2079   AND (c2 = SymTab.ClReal) THEN
+ 2080                                                   t := vt
+ 2081                                                 ELSE SemError(230);
+ 2082                                                   t := SymTab.InvalidType
+ 2083                                                 END
+ 2084                                               END
+ 2085                                             END; .)
+ 2086      | "(" Expr<et, q> ")"               (. t := et; .)
+ 2087      | SetLit<st, sq>                    (. t := st;
+ 2088                                             QbeGen.CopyOp(sq, q); .)
+ 2089      | ( "NOT" | "~" ) Fact<t2, q2>      (. IF SymTab.BoolCheck(t2) THEN
+ 2090                                               t := SymTab.BoolType()
+ 2091                                             ELSE SemError(212);
+ 2092                                               t := SymTab.InvalidType END;
+ 2093                                             IF t # SymTab.InvalidType THEN
+ 2094                                               QbeGen.NotQ(q2, q)
+ 2095                                             ELSE QbeGen.CopyOp("0", q)
+ 2096                                             END; .) .
+ 2097    (* Set literals are SET OF [0..255] (8 words); elements validated
+ 2098       0..255 statically when foldable (222 otherwise), runtime trap
+ 2099       for computed elements. Ranges always lower via SetRange. *)
+ 2100    SetLit<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2101      = "{"                               (. t := SymTab.NewSet(
+ 2102                                               SymTab.NewSubR(0, 255));
+ 2103                                             QbeGen.NewSetTemp(8, q);
+ 2104                                             QbeGen.SetZero(q, 8); .)
+ 2105        [ SetElem<t, q> { "," SetElem<t, q> } ]
+ 2106        "}" .
+ 2107    (* Typed set constructor: TypeName{ elems } — e.g. BITSET{0},
+ 2108       BITSET{}.  The declared type (not SET OF [0..255]) sets the
+ 2109       width and element span. *)
+ 2110    TypedSetLit<vt: SymTab.TypeIndex; VAR q: QbeGen.QVal>
+ 2111                                          (. VAR nw: CARDINAL; .)
+ 2112      = "{"                               (. IF SymTab.ClassOf(vt) #
+ 2113                                                SymTab.ClSet THEN
+ 2114                                               SemError(230); nw := 8
+ 2115                                             ELSE nw := SymTab.SetWords(vt);
+ 2116                                               IF nw = 0 THEN nw := 8 END
+ 2117                                             END;
+ 2118                                             QbeGen.NewSetTemp(nw, q);
+ 2119                                             QbeGen.SetZero(q, nw); .)
+ 2120        [ SetElem<vt, q> { "," SetElem<vt, q> } ]
+ 2121        "}" .
+ 2122    SetElem<st: SymTab.TypeIndex; sq: QbeGen.QVal>         (. VAR et, et2: SymTab.TypeIndex;
+ 2123                                               qe, q2: QbeGen.QVal;
+ 2124                                               v, v2: INTEGER;
+ 2125                                               lo: INTEGER;
+ 2126                                               span: CARDINAL;
+ 2127                                               cl, cl2: INTEGER;
+ 2128                                               hasR: BOOLEAN; .)
+ 2129      =                                   (. hasR := FALSE; .)
+ 2130        Expr<et, qe>
+ 2131        [ ".." Expr<et2, q2>              (. hasR := TRUE; .) ]
+ 2132                                          (. lo := SymTab.SetBaseLo(st);
+ 2133                                             span := SymTab.SetCount(st);
+ 2134                                             IF (et = SymTab.InvalidType)
+ 2135                                                OR (hasR AND (et2 =
+ 2136                                                   SymTab.InvalidType)) THEN
+ 2137                                             ELSE cl :=
+ 2138                                                    SymTab.ClassOf(et);
+ 2139                                               IF hasR THEN
+ 2140                                                 cl2 :=
+ 2141                                                   SymTab.ClassOf(et2)
+ 2142                                               ELSE cl2 := SymTab.ClInt
+ 2143                                               END;
+ 2144                                               IF ((cl # SymTab.ClInt)
+ 2145   AND (cl # SymTab.ClChar)
+ 2146   AND (cl # SymTab.ClBool))
+ 2147                                                  OR (hasR AND 
+ 2148                                                     ((cl2
+ 2149                                                       # SymTab.ClInt)
+ 2150   AND (cl2
+ 2151                                                        # SymTab.ClChar)
+ 2152   AND (cl2
+ 2153                                                        # SymTab.ClBool))) THEN
+ 2154                                                 SemError(222)
+ 2155                                               ELSIF hasR
+ 2156   AND SymTab.ConstInt(qe, v)
+ 2157   AND SymTab.ConstInt(q2,
+ 2158                                                     v2)
+ 2159   AND ((v < lo)
+ 2160                                                     OR (v2 < lo)
+ 2161                                                     OR (v >= lo +
+ 2162                                                        VAL(INTEGER, span))
+ 2163                                                     OR (v2 >= lo +
+ 2164                                                        VAL(INTEGER, span))
+ 2165                                                     OR (v > v2)) THEN
+ 2166                                                 SemError(222)
+ 2167                                                ELSIF hasR THEN
+ 2168                                                  QbeGen.SetRange(sq, qe, q2,
+ 2169                                                    lo, span)
+ 2170                                                ELSIF SymTab.ConstInt(qe,
+ 2171                                                        v)
+ 2172   AND ((v < lo)
+ 2173                                                      OR (v >= lo +
+ 2174                                                         VAL(INTEGER,
+ 2175                                                           span))) THEN
+ 2176                                                  SemError(222)
+ 2177                                                ELSE QbeGen.SetBit(sq, qe,
+ 2178                                                  lo, span)
+ 2179                                               END
+ 2180                                             END; .) .
+ 2181    GetIdent<VAR n: SymTab.Name>
+ 2182      = ident                             (. LexName(n); .) .
+ 2183  
+ 2184  END M2.
 
     0 errors
 
@@ -2190,10 +2206,10 @@ Listing:
 Statistics:
 
   nr of terminals:        93 (limit   400)
-  nr of non-terminals:    77 (limit   210)
+  nr of non-terminals:    78 (limit   210)
   nr of pragmas:           0 (limit   407)
-  nr of symbolnodes:     170 (limit   500)
-  nr of graphnodes:      838 (limit  1500)
+  nr of symbolnodes:     171 (limit   500)
+  nr of graphnodes:      850 (limit  1500)
   nr of conditionsets:     9 (limit   100)
   nr of charactersets:    12 (limit   250)
 

+ 3 - 0
compiler/src/SymTab.mod

@@ -87,6 +87,7 @@ VAR
   nProc : CARDINAL;
   nextUid : CARDINAL;
   dInt, dCard, dReal, dChar, dBool, dNil, dAddr, dLong : TypeIndex;
+  dBitset : TypeIndex;   (* BITSET = SET OF [0..15] *)
   globScope : ScopePtr;  (* the global scope (module names live here) *)
   curMod : INTEGER;      (* current registry slot, -1 between units *)
   curUnit : INTEGER;     (* UnitProg/Def/Impl, -1 between units *)
@@ -1929,6 +1930,7 @@ PROCEDURE Init;
     dNil := NewDesc(FNil, InvalidType);
     dAddr := NewDesc(FPtr, InvalidType);   (* ADDRESS: pointer-sized *)
     dLong := NewDesc(FLong, InvalidType);  (* LONGINT/LONGCARD: 64-bit *)
+    dBitset := NewSet(NewSubR(0, 15));     (* BITSET *)
     Predef("INTEGER", KindPredef, dInt);
     Predef("CARDINAL", KindPredef, dCard);
     Predef("SHORTINT", KindPredef, dInt);
@@ -1941,6 +1943,7 @@ PROCEDURE Init;
     Predef("TRUE", KindConst, dBool);
     Predef("FALSE", KindConst, dBool);
     Predef("ADDRESS", KindPredef, dAddr);
+    Predef("BITSET", KindPredef, dBitset);
     Predef("NIL", KindConst, dNil)
   END Init;
 

+ 6 - 0
compiler/src/compiler.frm

@@ -312,6 +312,12 @@ MODULE -->Grammar;
         PrintConsoleErrors(sourceName);
         bad := TRUE
       END;
+      (* Release the source handle before the next file: the host
+         FileIO caps open files at BitSetSize (16), and a session may
+         compile more sources than that. *)
+      IF (src # FileIO.StdIn) & (src # FileIO.StdOut) THEN
+        FileIO.Close(src)
+      END;
       INC(f)
     END;
 

+ 82 - 0
docs/summary_forward-calls.md

@@ -0,0 +1,82 @@
+# Within-module forward procedure calls — M2S and M2P compile clean (110/110)
+
+Tag `v3-forward-calls`.
+
+## The finding
+
+CR's parser output **relies on gm2 hoisting**: by default it wraps its
+forward declarations in a comment (`(* ----- FORWARD not needed in
+multipass compilers … *)`). The `-m` flag toggles that
+(`M  Suppresses FORWARD declarations in parser (for multipass
+compilers)`), and our `build.sh` passed `-m`.
+
+V3 is single-pass, so with `-m` the generated `M2P.mod` had ~102
+`undeclared identifier` errors for its own procedures.
+
+## The fix (two halves)
+
+1. **Emit real `FORWARD` declarations for V3-facing generation** — run
+   CR **without `-m`**. V3 already supports `FORWARD` (including
+   mutual recursion); verified with a direct test.
+2. **Keep `-m` for the gm2 stage-1 build.** gm2 *compiles* `FORWARD`
+   fine (`gm2 -c` OK) but its link-time whole-program/“pass 3”
+   recompilation rejects `FORWARD` in an implementation module
+   (`too many errors in pass 3`); reproduced minimally, and
+   `-fscaffold-*`, `-fno-whole-program` etc. do not help.
+
+So the bootstrap is stage-specific: stage 1 (gm2) generates with `-m`;
+stage 2+ (V3) generates without `-m`. The `.ssa` fixpoint is between
+V3 stages, both using the `FORWARD` form.
+
+## Other fixes in this step
+
+- **Empty `ELSIF … THEN` body** — the earlier `[ StatSeq ]` change had
+  missed the `ELSIF` site (different indentation); CR-generated code
+  hits it (comment-only `THEN`).
+- **`BITSET`** — added as a predefined type (`SET OF [0..15]`).
+- **Typed set constructor** `TypeName{ … }` (`BITSET{0}`,
+  `BITSET{}`) — new `TypedSetLit` rule; `Fact` uses it when a type
+  name designator is followed by `{`.
+- **File-handle leak** — `compiler.frm` never closed the source file,
+  so each session source consumed a handle and the host `FileIO` cap
+  (`MaxFiles = BitSetSize` = 16) tripped once a session had >16
+  sources (exactly the compiler's own build). The driver now closes
+  `src` after each file.
+
+## Result
+
+Under V3 (sources generated without `-m`):
+
+| Source | Errors |
+|---|---|
+| `SymTab` | 0 |
+| `QbeGen` | 0 |
+| `M2S` | 0 |
+| `M2P` | **0** (was 107 before FORWARDs, then 5, then 0) |
+
+Main suite **110/110**.
+
+## Remaining: the driver `M2.mod` (12 errors)
+
+- **Nested modules** — the driver's `ListHandler` is a Wirth-style
+  local `MODULE … EXPORT StoreError, PrintListing, …`, which V3 parses
+  but marks 230; its exports (`StoreError`, `PrintListing`,
+  `PrintConsoleErrors`, `ResetErrors`) are therefore undeclared at the
+  enclosing scope.
+- **String building** — the driver uses `Strings.Delete`/`Append` to
+  construct file names. V3's descriptor header is *both* the
+  open-array count and the logical string length (`m2setlen` sets it),
+  so once `Assign` shrinks it, `Append` writing past the logical
+  length traps. `Delete` alone is fine; incremental `Append` needs a
+  model decision (or a driver rewrite).
+
+## Build note
+
+Generating for V3 (no `-m`) and for gm2 (`-m`) are different commands;
+this wants a small stage-aware build script (or a `build_v3.sh`),
+which also feeds `bootstrap/fixpoint.sh`.
+
+## Files
+
+`compiler/src/M2.atg`, `compiler/src/SymTab.mod`,
+`compiler/src/compiler.frm`, `compiler/src/M2.lst`.