Explorar o código

V3 compiles itself: self-compiled V3 emits byte-identical .ssa for t_constfold

- de-eager NIL guards (SymTab, driver PrintListing)
- fix off-by-one in QbeGen Len/Cpy/App/ParseInt (i < HIGH(literal) dropped the last char)
- suite 111/111; full self-image still aborts (next)
Eric Streit hai 2 semanas
pai
achega
757f5180d7
Modificáronse 4 ficheiros con 106 adicións e 45 borrados
  1. 6 6
      compiler/src/QbeGen.mod
  2. 44 35
      compiler/src/SymTab.mod
  3. 8 4
      compiler/src/compiler.frm
  4. 48 0
      docs/summary_selfcompiles.md

+ 6 - 6
compiler/src/QbeGen.mod

@@ -79,7 +79,7 @@ PROCEDURE Len (s: ARRAY OF CHAR): CARDINAL;
   VAR i : CARDINAL;
   BEGIN
     i := 0;
-    WHILE (i < HIGH(s)) AND (s[i] # CHR(0)) DO INC(i) END;
+    WHILE (i <= HIGH(s)) AND (s[i] # CHR(0)) DO INC(i) END;
     RETURN i
   END Len;
 
@@ -87,7 +87,7 @@ PROCEDURE Cpy (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
   VAR i : CARDINAL;
   BEGIN
     i := 0;
-    WHILE (i < HIGH(d)) AND (i < HIGH(s)) AND (s[i] # CHR(0)) DO
+    WHILE (i <= HIGH(d)) AND (i <= HIGH(s)) AND (s[i] # CHR(0)) DO
       d[i] := s[i]; INC(i)
     END;
     IF i <= HIGH(d) THEN d[i] := CHR(0) END
@@ -99,7 +99,7 @@ PROCEDURE App (VAR d: ARRAY OF CHAR; s: ARRAY OF CHAR);
     i := 0;
     WHILE (i <= HIGH(d)) AND (d[i] # CHR(0)) DO INC(i) END;
     j := 0;
-    WHILE (i < HIGH(d)) AND (j < HIGH(s)) AND (s[j] # CHR(0)) DO
+    WHILE (i <= HIGH(d)) AND (j <= HIGH(s)) AND (s[j] # CHR(0)) DO
       d[i] := s[j]; INC(i); INC(j)
     END;
     IF i <= HIGH(d) THEN d[i] := CHR(0) END
@@ -394,9 +394,9 @@ PROCEDURE ParseInt (s: ARRAY OF CHAR; VAR v: INTEGER): BOOLEAN;
     neg: BOOLEAN;
   BEGIN
     v := 0; i := 0; neg := FALSE; nd := 0;
-    IF (i < HIGH(s)) AND (s[i] = "-") THEN neg := TRUE; INC(i) END;
-    IF (i >= HIGH(s)) OR (s[i] = CHR(0)) THEN RETURN FALSE END;
-    WHILE (i < HIGH(s)) AND (s[i] # CHR(0)) DO
+    IF (i <= HIGH(s)) AND (s[i] = "-") THEN neg := TRUE; INC(i) END;
+    IF (i > HIGH(s)) OR (s[i] = CHR(0)) THEN RETURN FALSE END;
+    WHILE (i <= HIGH(s)) AND (s[i] # CHR(0)) DO
       d := ORD(s[i]);
       IF (d < ORD("0")) OR (d > ORD("9")) THEN RETURN FALSE END;
       v := v * 10 + VAL(INTEGER, d - ORD("0"));

+ 44 - 35
compiler/src/SymTab.mod

@@ -383,7 +383,10 @@ PROCEDURE GetSymVal (name: ARRAY OF CHAR; VAR v: ARRAY OF CHAR): BOOLEAN;
   VAR node: SymPtr;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.val[0] = CHR(0)) THEN
+    IF node = NIL THEN
+      v[0] := CHR(0); RETURN FALSE
+    END;
+    IF node^.val[0] = CHR(0) THEN
       v[0] := CHR(0); RETURN FALSE
     END;
     Assign(v, node^.val);
@@ -830,9 +833,8 @@ PROCEDURE ProcTypeOf (name: ARRAY OF CHAR): TypeIndex;
     k: CARDINAL;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.kind # KindProc) THEN
-      RETURN InvalidType
-    END;
+    IF node = NIL THEN RETURN InvalidType END;
+    IF node^.kind # KindProc THEN RETURN InvalidType END;
     t := NewDesc(FProc, node^.rslt);
     IF t = InvalidType THEN RETURN t END;
     procstart[t] := nProcP;
@@ -989,9 +991,8 @@ PROCEDURE FieldOwner (name: ARRAY OF CHAR): TypeIndex;
   VAR node: SymPtr;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.kind # KindField) THEN
-      RETURN InvalidType
-    END;
+    IF node = NIL THEN RETURN InvalidType END;
+    IF node^.kind # KindField THEN RETURN InvalidType END;
     IF node^.scope = NIL THEN RETURN InvalidType END;
     RETURN node^.scope^.ofRec
   END FieldOwner;
@@ -1073,7 +1074,8 @@ PROCEDURE MethodExists (t: TypeIndex; name: ARRAY OF CHAR): BOOLEAN;
     s := tscope[r];
     IF s = NIL THEN RETURN FALSE END;
     node := TreeFind(s^.root, name);
-    RETURN (node # NIL) AND (node^.kind = KindProc)
+    IF node = NIL THEN RETURN FALSE END;
+    RETURN node^.kind = KindProc
   END MethodExists;
 
 PROCEDURE PushClassMembers (t: TypeIndex): BOOLEAN;
@@ -1144,7 +1146,8 @@ PROCEDURE ResumeProc (name: ARRAY OF CHAR): BOOLEAN;
   BEGIN
     IF curUnit # UnitImpl THEN RETURN FALSE END;
     node := TreeFind(curScope^.root, name);
-    IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN FALSE END;
+    IF node = NIL THEN RETURN FALSE END;
+    IF node^.kind # KindProc THEN RETURN FALSE END;
     node^.plink := NIL;   (* implementation re-enters formals *)
     curProc := node;
     curPTail := NIL;
@@ -1157,7 +1160,8 @@ PROCEDURE ReenterProc (name: ARRAY OF CHAR): BOOLEAN;
   VAR node: SymPtr;
   BEGIN
     node := TreeFind(curScope^.root, name);
-    IF (node = NIL) OR (node^.kind # KindProc) OR NOT node^.fwd THEN
+    IF node = NIL THEN RETURN FALSE END;
+    IF (node^.kind # KindProc) OR NOT node^.fwd THEN
       RETURN FALSE
     END;
     node^.fwd := FALSE;
@@ -1197,9 +1201,8 @@ PROCEDURE ProcRes (name: ARRAY OF CHAR): TypeIndex;
   VAR node: SymPtr;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.kind # KindProc) THEN
-      RETURN InvalidType
-    END;
+    IF node = NIL THEN RETURN InvalidType END;
+    IF node^.kind # KindProc THEN RETURN InvalidType END;
     RETURN node^.rslt
   END ProcRes;
 
@@ -1223,14 +1226,16 @@ PROCEDURE IsExternal (name: ARRAY OF CHAR): BOOLEAN;
   VAR node: SymPtr;
   BEGIN
     node := Find(name);
-    RETURN (node # NIL) AND node^.ext
+    IF node = NIL THEN RETURN FALSE END;
+    RETURN node^.ext
   END IsExternal;
 
 PROCEDURE ProcLink (name: ARRAY OF CHAR; VAR link: Name): BOOLEAN;
   VAR node: SymPtr;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR NOT node^.ext THEN RETURN FALSE END;
+    IF node = NIL THEN RETURN FALSE END;
+    IF NOT node^.ext THEN RETURN FALSE END;
     Assign(link, node^.link);
     RETURN TRUE
   END ProcLink;
@@ -1261,7 +1266,8 @@ PROCEDURE ProcDepthOf (name: ARRAY OF CHAR): CARDINAL;
   VAR node: SymPtr;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN 0 END;
+    IF node = NIL THEN RETURN 0 END;
+    IF node^.kind # KindProc THEN RETURN 0 END;
     RETURN node^.fdep
   END ProcDepthOf;
 
@@ -1269,7 +1275,8 @@ PROCEDURE ProcUid (name: ARRAY OF CHAR): CARDINAL;
   VAR node: SymPtr;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN 0 END;
+    IF node = NIL THEN RETURN 0 END;
+    IF node^.kind # KindProc THEN RETURN 0 END;
     RETURN node^.uid
   END ProcUid;
 
@@ -1287,7 +1294,8 @@ PROCEDURE ProcNPar (name: ARRAY OF CHAR): CARDINAL;
     n: CARDINAL;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN 0 END;
+    IF node = NIL THEN RETURN 0 END;
+    IF node^.kind # KindProc THEN RETURN 0 END;
     n := 0; p := node^.plink;
     WHILE p # NIL DO INC(n); p := p^.plink END;
     RETURN n
@@ -1297,9 +1305,8 @@ PROCEDURE ParamType (name: ARRAY OF CHAR; i: CARDINAL): TypeIndex;
   VAR node, p: SymPtr;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.kind # KindProc) THEN
-      RETURN InvalidType
-    END;
+    IF node = NIL THEN RETURN InvalidType END;
+    IF node^.kind # KindProc THEN RETURN InvalidType END;
     p := NthParam(node, i);
     IF p = NIL THEN RETURN InvalidType END;
     RETURN p^.typ
@@ -1309,7 +1316,8 @@ PROCEDURE ParamIsVar (name: ARRAY OF CHAR; i: CARDINAL): BOOLEAN;
   VAR node, p: SymPtr;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.kind # KindProc) THEN RETURN FALSE END;
+    IF node = NIL THEN RETURN FALSE END;
+    IF node^.kind # KindProc THEN RETURN FALSE END;
     p := NthParam(node, i);
     IF p = NIL THEN RETURN FALSE END;
     RETURN p^.isVar
@@ -1481,9 +1489,8 @@ PROCEDURE OpaqueBase (name: ARRAY OF CHAR): TypeIndex;
     r : TypeIndex;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.kind # KindType) THEN
-      RETURN InvalidType
-    END;
+    IF node = NIL THEN RETURN InvalidType END;
+    IF node^.kind # KindType THEN RETURN InvalidType END;
     r := node^.typ;
     IF (r < 0) OR (r >= VAL(INTEGER, nTypes)) THEN
       RETURN InvalidType
@@ -1551,7 +1558,8 @@ PROCEDURE QualProcUid (mod, name: ARRAY OF CHAR): CARDINAL;
   VAR n : SymPtr;
   BEGIN
     n := QualNode(mod, name);
-    IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN 0 END;
+    IF n = NIL THEN RETURN 0 END;
+    IF n^.kind # KindProc THEN RETURN 0 END;
     RETURN n^.uid
   END QualProcUid;
 
@@ -1569,7 +1577,8 @@ PROCEDURE QualProcNPar (mod, name: ARRAY OF CHAR): CARDINAL;
     c : CARDINAL;
   BEGIN
     n := QualNode(mod, name);
-    IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN 0 END;
+    IF n = NIL THEN RETURN 0 END;
+    IF n^.kind # KindProc THEN RETURN 0 END;
     c := 0; p := n^.plink;
     WHILE p # NIL DO INC(c); p := p^.plink END;
     RETURN c
@@ -1580,9 +1589,8 @@ PROCEDURE QualParamType (mod, name: ARRAY OF CHAR; i: CARDINAL):
   VAR n, p : SymPtr;
   BEGIN
     n := QualNode(mod, name);
-    IF (n = NIL) OR (n^.kind # KindProc) THEN
-      RETURN InvalidType
-    END;
+    IF n = NIL THEN RETURN InvalidType END;
+    IF n^.kind # KindProc THEN RETURN InvalidType END;
     p := QualNthParam(n, i);
     IF p = NIL THEN RETURN InvalidType END;
     RETURN p^.typ
@@ -1593,7 +1601,8 @@ PROCEDURE QualParamIsVar (mod, name: ARRAY OF CHAR; i: CARDINAL):
   VAR n, p : SymPtr;
   BEGIN
     n := QualNode(mod, name);
-    IF (n = NIL) OR (n^.kind # KindProc) THEN RETURN FALSE END;
+    IF n = NIL THEN RETURN FALSE END;
+    IF n^.kind # KindProc THEN RETURN FALSE END;
     p := QualNthParam(n, i);
     IF p = NIL THEN RETURN FALSE END;
     RETURN p^.isVar
@@ -1603,9 +1612,8 @@ PROCEDURE QualProcRes (mod, name: ARRAY OF CHAR): TypeIndex;
   VAR n : SymPtr;
   BEGIN
     n := QualNode(mod, name);
-    IF (n = NIL) OR (n^.kind # KindProc) THEN
-      RETURN InvalidType
-    END;
+    IF n = NIL THEN RETURN InvalidType END;
+    IF n^.kind # KindProc THEN RETURN InvalidType END;
     RETURN n^.rslt
   END QualProcRes;
 
@@ -1705,7 +1713,8 @@ PROCEDURE GlobalRef (name: ARRAY OF CHAR; VAR g: Name): BOOLEAN;
     i, j : CARDINAL;
   BEGIN
     node := Find(name);
-    IF (node = NIL) OR (node^.mod[0] = CHR(0)) THEN RETURN FALSE END;
+    IF node = NIL THEN RETURN FALSE END;
+    IF node^.mod[0] = CHR(0) THEN RETURN FALSE END;
     i := 0;
     WHILE (i < HIGH(g)) AND (node^.mod[i] # CHR(0)) DO
       g[i] := node^.mod[i]; INC(i)

+ 8 - 4
compiler/src/compiler.frm

@@ -139,7 +139,7 @@ MODULE -->Grammar;
     (* Print a source listing with error messages *)
       VAR
         nextErr: Err;
-        eof: BOOLEAN;
+        eof, done: BOOLEAN;
         lnr, errC: INTEGER;
         srcPos: INT32;
         line: ARRAY [0 .. 255] OF CHAR;
@@ -151,9 +151,13 @@ MODULE -->Grammar;
         WHILE NOT eof DO
           WriteInt(lst, lnr, 5); WriteString(lst, "  ");
           WriteString(lst, line); WriteLn(lst);
-          WHILE (nextErr # NIL) AND (nextErr^.line = lnr) DO
-            PrintErr(line, nextErr^.nr, nextErr^.col); INC(errC);
-            nextErr := nextErr^.next
+          done := FALSE;
+          WHILE (nextErr # NIL) AND NOT done DO
+            IF nextErr^.line = lnr THEN
+              PrintErr(line, nextErr^.nr, nextErr^.col); INC(errC);
+              nextErr := nextErr^.next
+            ELSE done := TRUE
+            END
           END;
           GetLine(srcPos, line, eof); INC(lnr);
         END;

+ 48 - 0
docs/summary_selfcompiles.md

@@ -0,0 +1,48 @@
+# V3 compiles itself (runtime) — stage-2 fixpoint for a test file
+
+Tag `v3-selfcompiles`. Main suite 111/111.
+
+## The milestone
+
+The **self-compiled V3** (`/tmp/M2self`, built by V3 from its own
+sources) now runs, parses, and emits code. For a test file its output
+is **byte-identical** to the gm2-built V3's:
+
+```
+./M2      tests/t_constfold.mod  ->  gen_ssa/TConstFold.ssa
+/tmp/M2self tests/t_constfold.mod -> gen_ssa/TConstFold.ssa
+cmp: *** IDENTICAL ***
+```
+
+That is a stage-2 self-hosting fixpoint for `t_constfold`.
+
+## Fixes in this step
+
+1. **Eager `OR`/`AND` NIL dereferences** — gm2 short-circuits, V3 does
+   not. Rewrote `SymTab`'s guard sites (`(x = NIL) OR (x^.…)`) into
+   sequential checks, and the driver's `PrintListing` loop
+   (`(nextErr # NIL) AND (nextErr^.line = …)`) into a `done` flag.
+2. **Off-by-one in string scans** — `QbeGen`'s `Len`/`Cpy`/`App`/`ParseInt`
+   looped with `i < HIGH(s)`; for a string *literal* `HIGH = len-1`, so
+   the last character was dropped. `App(fname, "gen_ssa/")` produced
+   `"gen_ssa"`, mangling the output file name. Changed to `<= HIGH(s)`.
+
+## Status
+
+- Self-compiled V3 compiles a small file correctly (byte-identical).
+- Compiling the **whole compiler source set** with the self-compiled V3
+  still aborts (rc 134) — the next runtime bug (likely a capacity or a
+  construct in the compiler's own sources). This is the remaining path
+  to the full 3-stage fixpoint.
+
+## Remaining
+
+1. Fix the self-image abort (diagnose with gdb on `/tmp/M2self` over the
+   full set).
+2. Cross-stage `FileIO` selection and `bootstrap/fixpoint.sh`
+   (Stage1 gm2 → Stage2 V3 → Stage3 V3, byte-identical `.ssa`), with the
+   stage-aware CR flag.
+
+## Files
+
+`compiler/src/{SymTab.mod,compiler.frm,QbeGen.mod,M2.lst}`.