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

fix: make Lower V3-legal and stop the fixpoint masking errors

V3 (unlike gm2) has no whole-module pass: a call to a procedure declared
later in the same module is reported as `invalid call` and codegen drops
the call. Lower.mod's mutually recursive walkers (CanExpr, CanDecls,
CanProc, IsBuiltin, LowerExpr, LowerStmt, LowerDecls) were called before
their declarations, so the compiler session reported 45 `invalid call`
errors in Lower.mod and emitted degraded code for the whole Lower module.
Declare them in Lower.def (definition-visible throughout the impl) since
gm2's link pass rejects FORWARD.

Also fix SymTab.FormalOk so two open-array formals are compatible when
their element types match: each `ARRAY OF T` declaration allocates a
fresh descriptor, so a DEFINITION/IMPLEMENTATION pair never shares the
type index and SameType rejected it (e.g. LowerSession's
`units: ARRAY OF AST.Node`).

Remove the debug ASTDUMP from M2.atg and gate M2make on "Parsed
correctly" instead of "Parsed": the ASTDUMP printed the string literal
'Parsed correctly', which satisfied the check while the compiler was
actually reporting "Incorrect source". The fixpoint had been passing
with a broken compiler session.

The compiler session now parses with zero errors; suite 204/204 and
fixpoint byte-identical (3,409,871 bytes).
Eric Streit 5 дней назад
Родитель
Сommit
a3ef897134

+ 14 - 1
compiler/src/Lower.def

@@ -11,13 +11,26 @@ DEFINITION MODULE Lower;
    the tables below while the scope is open, so the walk can resolve names
    after SymTab has popped their scopes. *)
 
-IMPORT AST, SymTab;
+IMPORT AST, SymTab, QbeGen;
 
 PROCEDURE CanLower (unit: AST.Node): BOOLEAN;
 PROCEDURE LowerUnit (unit: AST.Node);
 PROCEDURE LowerSession (units: ARRAY OF AST.Node; n: CARDINAL;
                         progName: ARRAY OF CHAR);
 
+(* The expression/statement/declaration walkers are mutually recursive.
+   gm2's link pass rejects FORWARD and V3 has no whole-module pass, so
+   they are declared here (definition-visible throughout the
+   implementation) instead of being forward-declared. *)
+PROCEDURE CanExpr (n: AST.Node): BOOLEAN;
+PROCEDURE CanDecls (seq: AST.Node): BOOLEAN;
+PROCEDURE CanProc (proc: AST.Node): BOOLEAN;
+PROCEDURE IsBuiltin (nm: ARRAY OF CHAR): BOOLEAN;
+PROCEDURE LowerExpr (n: AST.Node; VAR t: SymTab.TypeIndex;
+                     VAR q: QbeGen.QVal);
+PROCEDURE LowerStmt (seq: AST.Node);
+PROCEDURE LowerDecls (seq: AST.Node);
+
 PROCEDURE Reset;
 PROCEDURE NoteVar (name: ARRAY OF CHAR; kind: INTEGER; t: SymTab.TypeIndex);
 PROCEDURE ScopeEnter;

+ 3 - 2
compiler/src/Lower.mod

@@ -1,7 +1,8 @@
 IMPLEMENTATION MODULE Lower;
 (* Scalar/boolean/control-flow walk (L0-L2): see Lower.def and
-   docs/plan-lower.md.  No FORWARD declarations: sequence iteration and
-   statement dispatch are merged into CanStmt / LowerStmt. *)
+   docs/plan-lower.md.  The mutually recursive walkers are declared in
+   Lower.def (gm2's link pass rejects FORWARD, V3 has no whole-module
+   pass, so a definition-visible declaration breaks the cycle). *)
 
 IMPORT AST, SymTab, QbeGen;
 

+ 1 - 1
compiler/src/M2.atg

@@ -246,7 +246,7 @@ PRODUCTIONS
     = (. twoPhase := TRUE; astCur := AST.NoNode; astStmt := AST.NoNode; astDecl := AST.NoNode; astImp := AST.NoNode; astImpTail := AST.NoNode;
                                            astImp := AST.NoNode;
                                            astImpTail := AST.NoNode; .)
-      Unit "." (. FileIO.WriteString(FileIO.StdOut, "ASTDUMP:"); FileIO.WriteLn(FileIO.StdOut); AST.Dump(astUnit, 0); .) .
+      Unit "." .
   (* Units: program modules compile fully; DEFINITION and
      IMPLEMENTATION modules parse + check now but lower in step 4
      (each ends with one 230); same for nested local modules. *)

+ 2 - 2
compiler/src/M2.lst

@@ -264,7 +264,7 @@ Listing:
   246      = (. twoPhase := TRUE; astCur := AST.NoNode; astStmt := AST.NoNode; astDecl := AST.NoNode; astImp := AST.NoNode; astImpTail := AST.NoNode;
   247                                             astImp := AST.NoNode;
   248                                             astImpTail := AST.NoNode; .)
-  249        Unit "." (. FileIO.WriteString(FileIO.StdOut, "ASTDUMP:"); FileIO.WriteLn(FileIO.StdOut); AST.Dump(astUnit, 0); .) .
+  249        Unit "." .
   250    (* Units: program modules compile fully; DEFINITION and
   251       IMPLEMENTATION modules parse + check now but lower in step 4
   252       (each ends with one 230); same for nested local modules. *)
@@ -3857,7 +3857,7 @@ Statistics:
   nr of non-terminals:    85 (limit   210)
   nr of pragmas:           0 (limit   396)
   nr of symbolnodes:     189 (limit   500)
-  nr of graphnodes:     1111 (limit  1500)
+  nr of graphnodes:     1110 (limit  1500)
   nr of conditionsets:    11 (limit   100)
   nr of charactersets:    16 (limit   250)
 

+ 7 - 0
compiler/src/SymTab.mod

@@ -376,6 +376,13 @@ PROCEDURE FormalOk (a, b: TypeIndex): BOOLEAN;
     END;
     IF SameType(a, b) THEN RETURN TRUE END;
     IF IsIntFamily(a) AND IsIntFamily(b) THEN RETURN TRUE END;
+    (* Open-array formals are structurally compatible when their element
+       types match: each `ARRAY OF T` declaration allocates a fresh
+       descriptor, so a DEFINITION/IMPLEMENTATION pair never shares the
+       type index and SameType would otherwise reject it. *)
+    IF IsOpenArray(a) AND IsOpenArray(b) THEN
+      RETURN SameType(ArrayElem(a), ArrayElem(b))
+    END;
     RETURN StrCompat(a, b)
   END FormalOk;
 

+ 1 - 1
tools/m2make/M2make.mod

@@ -797,7 +797,7 @@ BEGIN
     IF Len(tmpP) > 0 THEN AppendTok(cmd, tmpP) END;
     INC(k)
   END;
-  AppendSeg(cmd, " 2>&1 | tee m2make.log | grep -q Parsed");
+  AppendSeg(cmd, " 2>&1 | tee m2make.log | grep -q 'Parsed correctly'");
   AppendSeg(cmd, " && qbe -o gen_ssa/");
   AppendSeg(cmd, progName);
   AppendSeg(cmd, ".s gen_ssa/");

+ 1 - 1
tools/m2make/build_m2.sh

@@ -36,7 +36,7 @@ else
       "../$SYS/SysShim.def" "../$SYS/SysShim.mod" \
       "../$SYS/FileIO.def" "../$SYS/FileIO.mod" \
       M2makeOS.def M2makeOS.mod M2make.mod \
-      2>&1 | tee m2.log | grep -q Parsed || exit 1
+      2>&1 | tee m2.log | grep -q "Parsed correctly" || exit 1
   echo "=== Assembling and linking ==="
   qbe -o gen_ssa/M2make.s gen_ssa/M2make.ssa || exit 1
   cc gen_ssa/M2make.s "../$SYS/shim.c" m2make_os.c \