Browse Source

lower L7: DefUnit AST + working session re-emit

- DefUnit now builds a decl sequence, recording proc headings as
  NkProcDecl; LowerDecls replays a bodyless proc as a heading
  (BeginFunc/FuncParam/AbortFunc).
- LowerSession: name the image after the program module, EndModule with
  that name; MaterializeGlobals also materializes TYPE/CLASS names so
  module-level resolution works after scopes close.
- SymTab.ReenterModGlobal: re-enter a global with an explicit defining
  module (nested-module globals keep their "<outer>_<name>" symbol).
- Driver: AST.Init once per session under -lower (all units' ASTs stay
  valid), per file otherwise; the old grammar-side LowerUnit call is gone.

lower_ok_files added; DBasicProg/DQualProg/TQual/TQualP sessions
byte-match.  Suite 204/204; FIXPOINT OK (3,405,813 bytes).
Eric Streit 5 days ago
parent
commit
ce2fc676f1

+ 24 - 0
compiler/run_tests.sh

@@ -466,6 +466,26 @@ lower_ok() {
     fail=$((fail+1)); echo "FAIL(lower): $name .ssa mismatch"
   fi
 }
+lower_ok_files() {
+  # $1 = program module name, then the session source files (program last)
+  prog="$1"; shift
+  files=""
+  for f in "$@"; do
+    case "$f" in */*) files="$files $f";; *) files="$files tests/$f";; esac
+  done
+  rm -f "gen_ssa/${prog}L.ssa"
+  if ./M2 -lower $files 2>&1 | grep -q "Parsed correctly"; then :; else
+    fail=$((fail+1)); echo "FAIL(lower): $prog rejected"; return
+  fi
+  if [ ! -f "gen_ssa/${prog}L.ssa" ]; then
+    fail=$((fail+1)); echo "FAIL(lower): $prog no gen_ssa/${prog}L.ssa"; return
+  fi
+  if cmp -s "gen_ssa/$prog.ssa" "gen_ssa/${prog}L.ssa"; then
+    pass=$((pass+1)); echo "PASS(lower): $prog"
+  else
+    fail=$((fail+1)); echo "FAIL(lower): $prog .ssa mismatch"
+  fi
+}
 lower_ok t_exit.mod
 lower_ok t_arith.mod
 lower_ok t_lower1.mod
@@ -478,6 +498,10 @@ lower_ok t_classsibling.mod
 lower_ok t_class.mod
 lower_ok t_classinit.mod
 lower_ok t_virtual.mod
+lower_ok_files DBasicProg d_basic.def d_basic.mod d_basic_prog.mod
+lower_ok_files DQualProg d_basic.def d_basic.mod d_qual_prog.mod
+lower_ok_files TQual d_libc.def t_qual.mod
+lower_ok_files TQualP d_qualp.def t_qualp.mod
 lower_ok t_lower4.mod
 lower_ok t_lower4case.mod
 lower_ok t_lower4with.mod

+ 23 - 9
compiler/src/Lower.mod

@@ -36,6 +36,7 @@ VAR
   withTop  : CARDINAL;
   curMethCls : SymTab.TypeIndex;   (* class bound by the last obj.Method *)
   curImplCls : SymTab.TypeIndex;   (* class whose implementation is open *)
+  curUnitName : SymTab.Name;       (* unit being re-emitted (LowerSession) *)
 
 PROCEDURE CopyN (src: ARRAY OF CHAR; VAR dst: ARRAY OF CHAR);
   VAR i: CARDINAL;
@@ -1703,7 +1704,7 @@ PROCEDURE ReenterGlobals (seq: AST.Node);
         j := 0;
         WHILE j < AST.NChild(c) DO
           Name(AST.Child(c, j), nm);
-          IF SymTab.Enter(nm, SymTab.KindVar) THEN
+          IF SymTab.ReenterModGlobal(nm, SymTab.KindVar, curUnitName) THEN
             SymTab.SetSymType(nm, AST.Ty(c))
           END;
           INC(j)
@@ -1773,10 +1774,15 @@ PROCEDURE LowerDecls (seq: AST.Node);
           INC(j)
         END;
         QbeGen.SetFuncRes(res);
-        QbeGen.EndFuncHeader;
-        LowerDecls(AST.Child(c, 2));
-        LowerStmt(AST.Child(c, 1));
-        QbeGen.EndFunc(res)
+        IF AST.Child(c, 1) = AST.NoNode THEN
+          (* declaration-only (definition module): replay the heading *)
+          QbeGen.AbortFunc
+        ELSE
+          QbeGen.EndFuncHeader;
+          LowerDecls(AST.Child(c, 2));
+          LowerStmt(AST.Child(c, 1));
+          QbeGen.EndFunc(res)
+        END
       END;
       INC(i)
     END
@@ -1802,6 +1808,11 @@ PROCEDURE MaterializeGlobals (unitName: ARRAY OF CHAR; decls: AST.Node);
           END;
           INC(j)
         END
+      ELSIF (AST.Kind(c) = AST.NkTypeDecl) OR (AST.Kind(c) = AST.NkClassDecl) THEN
+        IF AST.NChild(c) >= 1 THEN
+          Name(AST.Child(c, 0), nm);
+          IF NOT SymTab.Materialize(unitName, nm) THEN END
+        END
       END;
       INC(i)
     END
@@ -1811,6 +1822,7 @@ PROCEDURE LowerOneUnit (u: AST.Node; isProg: BOOLEAN);
   VAR nm: SymTab.Name;
   BEGIN
     Name(AST.Child(u, 0), nm);
+    CopySpan(nm, curUnitName, 0, 0);
     QbeGen.SetModule(nm);
     MaterializeGlobals(nm, AST.Child(u, 1));
     LowerDecls(AST.Child(u, 1));
@@ -1827,11 +1839,13 @@ PROCEDURE LowerOneUnit (u: AST.Node; isProg: BOOLEAN);
 PROCEDURE LowerSession (units: ARRAY OF AST.Node; n: CARDINAL;
                         progName: ARRAY OF CHAR);
 (* Re-emit a whole session (all units, in order) into one image. *)
-  VAR i, j: CARDINAL; out: ARRAY [0 .. 255] OF CHAR;
+  VAR i, j: CARDINAL; out: ARRAY [0 .. 255] OF CHAR; pn: SymTab.Name;
   BEGIN
+    IF n = 0 THEN RETURN END;
+    Name(AST.Child(units[n - 1], 0), pn);
     j := 0;
-    WHILE (j <= 254) AND (j <= HIGH(progName)) AND (progName[j] # CHR(0)) DO
-      out[j] := progName[j]; INC(j)
+    WHILE (j <= 254) AND (pn[j] # CHR(0)) DO
+      out[j] := pn[j]; INC(j)
     END;
     out[j] := "L"; INC(j); out[j] := CHR(0);
     withTop := 0;
@@ -1843,7 +1857,7 @@ PROCEDURE LowerSession (units: ARRAY OF AST.Node; n: CARDINAL;
       LowerOneUnit(units[i], i = n - 1);
       INC(i)
     END;
-    QbeGen.EndModule(progName)
+    QbeGen.EndModule(pn)
   END LowerSession;
 
 PROCEDURE LowerUnit (unit: AST.Node);

+ 22 - 10
compiler/src/M2.atg

@@ -243,7 +243,7 @@ TOKENS
 
 PRODUCTIONS
   M2
-    = (. AST.Init; twoPhase := TRUE; astCur := AST.NoNode; astStmt := AST.NoNode; astDecl := AST.NoNode; astImp := AST.NoNode; astImpTail := AST.NoNode;
+    = (. 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); .) .
@@ -257,7 +257,8 @@ PRODUCTIONS
   (* Step 4.3: one session compiles DEFINITION, its IMPLEMENTATION
      and one program (last) into one image. Units share the symbol
      table; imports materialize exported names. *)
-  DefUnit                               (. VAR m1, m2, pn: SymTab.Name; .)
+  DefUnit                               (. VAR m1, m2, pn: SymTab.Name;
+                                             astSeq, astTail, astProc: AST.Node; .)
     = "DEFINITION" "MODULE"
       GetIdent<m1>                      (. IF NOT SymTab.BeginDef(m1) THEN
                                              SemError(200) END;
@@ -270,14 +271,29 @@ PRODUCTIONS
                                               names are already exported
                                               by the module scope *) .)
         GetIdent<pn> { "," GetIdent<pn> } ";" ]
-      { ConstBlock | TypeBlock<TRUE> | VarBlock
+                                        (. astSeq := AST.NoNode;
+                                           astTail := AST.NoNode; .)
+      { ConstBlock                      (. AstAppend(AST.NkDeclSeq,
+                                             astSeq, astTail, astDecl); .)
+      | TypeBlock<TRUE>                 (. AstAppend(AST.NkDeclSeq,
+                                             astSeq, astTail, astDecl); .)
+      | VarBlock                        (. AstAppend(AST.NkDeclSeq,
+                                             astSeq, astTail, astDecl); .)
       | ProcHeading<pn, SymTab.InvalidType> ";"
-                                        (. SymTab.CloseProc;
-                                             QbeGen.AbortFunc; .) }
+                                        (. (* a heading only: record it so
+                                              Lower can replay it *)
+                                           astProc := AST.MakeNode(AST.NkProcDecl);
+                                           AST.SetOp(astProc, 0);
+                                           AST.SetChild(astProc, 0,
+                                             AST.MakeLeaf(AST.NkIdent, pn));
+                                           AstAppend(AST.NkDeclSeq,
+                                             astSeq, astTail, astProc);
+                                           SymTab.CloseProc;
+                                           QbeGen.AbortFunc; .) }
                                         (. astUnit := AST.MakeNode(AST.NkUnit);
                                            AST.SetChild(astUnit, 0,
                                              AST.MakeLeaf(AST.NkIdent, m1));
-                                           AST.SetChild(astUnit, 1, astDecl);
+                                           AST.SetChild(astUnit, 1, astSeq);
                                            AST.SetChild(astUnit, 3, astImp);
                                            astDecl := AST.NoNode;
                                            astStmt := AST.NoNode; .)
@@ -384,10 +400,6 @@ PRODUCTIONS
                                            AST.SetChild(astNode, 3, astImp);
                                            astUnit := astNode;
                                            QbeGen.EndModule(m1);
-                                           IF lowerRequested
-                                              AND Lower.CanLower(astNode) THEN
-                                             Lower.LowerUnit(astNode)
-                                           END;
                                            SymTab.EndUnit; .) .
   DeclSeq                               (. VAR astSeq, astTail: AST.Node; .)
     =                                   (. astSeq := AST.NoNode;

File diff suppressed because it is too large
+ 3563 - 3551
compiler/src/M2.lst


+ 6 - 0
compiler/src/SymTab.def

@@ -73,6 +73,12 @@ PROCEDURE Enter (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
 (* Enters name at the current scope level (type InvalidType).
    Returns FALSE on duplicate within the same level. *)
 
+PROCEDURE ReenterModGlobal (name: ARRAY OF CHAR; kind: INTEGER;
+                            modName: ARRAY OF CHAR): BOOLEAN;
+(* Lower helper: enters name at the current scope with an explicit
+   defining-module name (used when re-emitting a unit after its scope
+   has closed).  FALSE on duplicate. *)
+
 PROCEDURE EnterPending (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
 (* Like Enter, but remembers the entry for a later FixPending call
    (used for VAR identifier lists whose type is parsed afterwards).

+ 10 - 0
compiler/src/SymTab.mod

@@ -310,6 +310,16 @@ PROCEDURE Enter (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
     RETURN RawEnter(name, kind) # NIL
   END Enter;
 
+PROCEDURE ReenterModGlobal (name: ARRAY OF CHAR; kind: INTEGER;
+                            modName: ARRAY OF CHAR): BOOLEAN;
+  VAR node: SymPtr;
+  BEGIN
+    node := RawEnter(name, kind);
+    IF node = NIL THEN RETURN FALSE END;
+    Assign(node^.mod, modName);
+    RETURN TRUE
+  END ReenterModGlobal;
+
 PROCEDURE EnterPending (name: ARRAY OF CHAR; kind: INTEGER): BOOLEAN;
   VAR node: SymPtr;
   BEGIN

+ 2 - 0
compiler/src/compiler.frm

@@ -313,6 +313,7 @@ MODULE -->Grammar;
     BaseName(files[nFiles - 1], progName);
     IF lowerAst THEN SetLower(TRUE) END;
     SymTab.Init;
+    IF lowerAst THEN AST.Init END;   (* once: -lower re-emits the session *)
     QbeGen.OpenModule(progName);
     Error := StoreError;
 
@@ -333,6 +334,7 @@ MODULE -->Grammar;
 
       FileIO.WriteString(FileIO.StdOut, "Parsing");
       FileIO.WriteLn(FileIO.StdOut);
+      IF NOT lowerAst THEN AST.Init END;
       Parse;
       IF lowerAst AND (nUnits <= HIGH(units)) THEN
         units[nUnits] := GetUnit(); INC(nUnits)

+ 4 - 0
compiler/tests/d_libc.def

@@ -0,0 +1,4 @@
+DEFINITION MODULE DLibC;
+(* Qualified CONST access; definitions emit no code. *)
+CONST K = 42;
+END DLibC.

+ 3 - 0
compiler/tests/d_qualp.def

@@ -0,0 +1,3 @@
+DEFINITION MODULE DQualP;
+PROCEDURE P;
+END DQualP.

+ 6 - 0
compiler/tests/t_qual.mod

@@ -0,0 +1,6 @@
+MODULE TQual;
+IMPORT DLibC;
+VAR ExitCode : INTEGER;
+BEGIN
+  ExitCode := DLibC.K
+END TQual.

+ 7 - 0
compiler/tests/t_qualp.mod

@@ -0,0 +1,7 @@
+MODULE TQualP;
+IMPORT DQualP;
+VAR ExitCode : INTEGER;
+BEGIN
+  DQualP.P;
+  ExitCode := 0
+END TQualP.

Some files were not shown because too many files changed in this diff