Преглед изворни кода

v3 step 8.3 — QbeGen compiles clean under V3; empty statements + 1-char string coercion (105/105)

Eric Streit пре 2 недеља
родитељ
комит
bb94cad987
7 измењених фајлова са 1571 додато и 1431 уклоњено
  1. 1 0
      compiler/run_tests.sh
  2. 19 2
      compiler/src/M2.atg
  3. 1443 1426
      compiler/src/M2.lst
  4. 24 0
      compiler/src/QbeGen.def
  5. 14 3
      compiler/src/QbeGen.mod
  6. 13 0
      compiler/tests/t_emptystat.mod
  7. 57 0
      docs/summary_step8.3.md

+ 1 - 0
compiler/run_tests.sh

@@ -62,6 +62,7 @@ expect_run t_bool.mod 42
 expect_run t_real.mod 31
 expect_run t_array.mod 108
 expect_run t_constfold.mod 42
+expect_run t_emptystat.mod 42
 expect_run t_highlen.mod 18
 expect_run t_builtins.mod 42
 expect_run t_long.mod 42

+ 19 - 2
compiler/src/M2.atg

@@ -628,7 +628,9 @@ PRODUCTIONS
       GetIdent<m2>                      (. IF NOT SymTab.Equal(pn, m2) THEN
                                              SemError(202) END; .) .
   StatSeq
-    = Statement { ";" Statement } .
+    = Statement { ";" [ Statement ] } .
+  (* Trailing/empty statements (`a; ; b`, Coco/R's generated `;;`)
+     are accepted: the statement after ';' is optional. *)
   Statement                             (. VAR lx: QbeGen.QVal; .)
     = AssOrCall
     | IfStat
@@ -976,7 +978,22 @@ PRODUCTIONS
                                                SemError(233)
                                              END
                                            ELSE
-                                             IF NOT SymTab.Assignable(at,
+                                             IF (SymTab.ClassOf(at)
+                                                = SymTab.ClChar)
+  AND (SymTab.ClassOf(ft) = SymTab.ClArray)
+  AND (SymTab.ClassOf(SymTab.ArrayElem(ft))
+       = SymTab.ClChar)
+  AND QbeGen.IsImm(qe) THEN
+                                               (* 1-char string
+                                                  literal passed to
+                                                  ARRAY OF CHAR *)
+                                               QbeGen.DeclCharStr(qe,
+                                                    qa);
+                                               IF NOT QbeGen.CallArg(qa,
+                                                  "l") THEN
+                                                 SemError(233)
+                                               END
+                                             ELSIF NOT SymTab.Assignable(at,
                                                   ft) THEN
                                                SemError(233)
                                              ELSE

Разлика између датотеке није приказан због своје велике величине
+ 1443 - 1426
compiler/src/M2.lst


+ 24 - 0
compiler/src/QbeGen.def

@@ -237,6 +237,11 @@ PROCEDURE DeclStr (text: ARRAY OF CHAR; VAR q: QVal);
 (* Emits `data $strN = { l len, b ... }` for a quoted literal and
    returns its address operand. Deterministic counter. *)
 
+PROCEDURE DeclCharStr (ch: ARRAY OF CHAR; VAR q: QVal);
+(* ch is the decimal ordinal of a CHAR literal; emits the equivalent
+   1-character string descriptor and returns its address. Lets a
+   1-char string literal be passed to an ARRAY OF CHAR formal. *)
+
 PROCEDURE WidenIndex (idx: ARRAY OF CHAR; VAR q: QVal);
 (* Immediates copy through; w-temps widen via extsw to l. *)
 
@@ -333,4 +338,23 @@ PROCEDURE CopyRecord (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
 (* Deep whole-record copy: scalars/sets by load/store, arrays via
    CopyArray on dereferenced fields, nested records recurse. *)
 
+(* ---------------- internal helpers ---------------- *)
+(* Declared here so they are visible throughout the implementation
+   (ISO Modula-2: declaration before use) without FORWARD, which the
+   gm2 whole-program pass rejects. Not part of the backend's usable
+   API; do not call from generated parser code. *)
+
+PROCEDURE LocFindUp (name: ARRAY OF CHAR; VAR levels: CARDINAL;
+                     VAR flat: INTEGER): BOOLEAN;
+PROCEDURE LocAdd (name: ARRAY OF CHAR; tag: INTEGER; rep: ARRAY OF CHAR;
+                   cls: CHAR; typ: INTEGER);
+PROCEDURE ResClass (t: INTEGER): CHAR;
+PROCEDURE AllocLocal (t: INTEGER; VAR slot: QVal);
+PROCEDURE HApp (s: ARRAY OF CHAR);
+PROCEDURE UpAddrOf (flat: INTEGER; levels: CARDINAL; VAR q: QVal);
+PROCEDURE Revive;
+PROCEDURE FlushStrings;
+PROCEDURE ArrData (name: ARRAY OF CHAR; t: INTEGER);
+PROCEDURE HeapSize (t: INTEGER): CARDINAL;
+
 END QbeGen.

+ 14 - 3
compiler/src/QbeGen.mod

@@ -1918,7 +1918,7 @@ PROCEDURE CopySet (dst: ARRAY OF CHAR; src: ARRAY OF CHAR;
       EmitLabel(lbad);
       Trap;
       EmitLabel(lok)
-    END;;
+    END;
     IF m > 0 THEN
       IntStr(VAL(INTEGER, m * 4), n);
       NewTemp(qr);
@@ -2149,6 +2149,17 @@ PROCEDURE DeclStr (text: ARRAY OF CHAR; VAR q: QVal);
     App(q, nm)
   END DeclStr;
 
+PROCEDURE DeclCharStr (ch: ARRAY OF CHAR; VAR q: QVal);
+  VAR v: INTEGER;
+    txt: ARRAY [0 .. 3] OF CHAR;
+  BEGIN
+    IF ParseInt(ch, v) AND (v >= 0) AND (v < 256) THEN
+      txt[0] := '"'; txt[1] := CHR(v); txt[2] := '"'; txt[3] := CHR(0);
+      DeclStr(txt, q)
+    ELSE Cpy(q, "0")
+    END
+  END DeclCharStr;
+
 PROCEDURE FlushStrings;
 (* Emits all recorded string literals as top-level data. *)
   VAR k, i, L: CARDINAL;
@@ -2176,7 +2187,7 @@ PROCEDURE FlushStrings;
     END
   END FlushStrings;
 
-PROCEDURE ArrData (name: ARRAY OF CHAR; t: SymTab.TypeIndex);
+PROCEDURE ArrData (name: ARRAY OF CHAR; t: INTEGER);
 (* Recursive data emission; nested levels as $name_i. *)
    VAR n, i: CARDINAL;
      elem: SymTab.TypeIndex;
@@ -2275,7 +2286,7 @@ PROCEDURE Remark (s: ARRAY OF CHAR);
    and members stay garbage per Wirth, except nested objects which
    are allocated recursively. DISPOSE is shallow (documented). *)
 
-PROCEDURE HeapSize (t: SymTab.TypeIndex): CARDINAL;
+PROCEDURE HeapSize (t: INTEGER): CARDINAL;
   VAR cls: INTEGER;
   BEGIN
     cls := SymTab.ClassOf(t);

+ 13 - 0
compiler/tests/t_emptystat.mod

@@ -0,0 +1,13 @@
+MODULE TEmptyStat;
+// Empty statements (`;;`, lone `;`) and a trailing `;` are accepted.
+// Exit 42.
+VAR ExitCode : INTEGER;
+VAR i : INTEGER;
+BEGIN
+  i := 0;;
+  i := i + 40
+  ;
+  ;
+  i := i + 2;
+  ExitCode := i
+END TEmptyStat.

+ 57 - 0
docs/summary_step8.3.md

@@ -0,0 +1,57 @@
+# V3 step 8.3 — `QbeGen` compiles clean; empty statements; 1-char strings (105/105)
+
+Both hand-written compiler modules now compile clean under V3.
+
+## What landed
+
+1. **Within-module forward procedure calls (gm2-compatible sources).**
+   `QbeGen.mod` calls 10 internal helpers before their definitions.
+   gm2's `FORWARD` is unusable (its whole-program pass errors with
+   `too many errors in pass 3` — reproduced with a minimal module),
+   and reordering cascades through `NewTemp`/`Op3L`/`Revive`/
+   `HeapSize`/`InitStack`. Fix: declare the 10 helpers in
+   `QbeGen.def` (its role is already "everything the generated
+   parser needs"), so they are visible throughout the
+   implementation. `ArrData`/`HeapSize` signatures use `INTEGER` in
+   both def and impl.
+
+2. **Single-character string literals for `ARRAY OF CHAR`.** `"("`,
+   `"0"`, `"$"` etc. were typed `CHAR`, so `W("(")` reported
+   "invalid call". New `QbeGen.DeclCharStr` synthesizes the
+   equivalent 1-char string descriptor; `ActParam` uses it when the
+   formal is an array of `CHAR` and the actual is an immediate
+   `CHAR`. This cleared all 85 remaining `QbeGen` errors.
+
+3. **Empty statements.** `StatSeq = Statement { ";" [ Statement ] }`
+   accepts `;;`, lone `;` and trailing `;` — required because
+   Coco/R emits `;;` in the generated `M2P.mod`. New test
+   `tests/t_emptystat.mod` (42). Also removed a stray `END;;` in
+   `QbeGen.mod`.
+
+## Result
+
+- `SymTab.def/.mod`: clean (step 8.2).
+- `QbeGen.def/.mod`: **clean** (this step).
+- Suite **105/105**, build warning-free.
+
+## Remaining self-hosting gaps (measured)
+
+Coco/R-generated sources `src/M2S.mod` (30 errors), `src/M2P.mod`,
+`src/M2.mod`:
+
+- **Procedure types** are unsupported: `GetCH = PROCEDURE (INT32):
+  CHAR;` and procedure variables (`CurrentCh: GetCH;`), and the
+  `Error: PROCEDURE (...)` callback in `M2S.def`. This is the main
+  `M2S` blocker (`invalid Type`, then cascade). Likely step 9.
+- **`INT32` (a `FileIO.INT32` alias) is seen as "not a type name"**
+  in `M2S.mod` var/param types — need to confirm once procedure
+  types parse.
+- **Host `FileIO` open-file cap:** `MaxFiles = BitSetSize` (16)
+  blocks compiling all ~16 compiler modules in one driver session
+  (`Too many files`). Raise it, or use the self-hosted `FileIO`
+  (stage-2 syslib) whose limit can be larger.
+
+## Files
+
+`compiler/src/{QbeGen.def,QbeGen.mod,M2.atg}`,
+`compiler/tests/t_emptystat.mod`, `compiler/run_tests.sh`.

Неке датотеке нису приказане због велике количине промена