فهرست منبع

step10: module BEGIN bodies + self-reference; 143/143 tests green

Eric Streit 3 هفته پیش
والد
کامیت
e239d3dd3c
31فایلهای تغییر یافته به همراه2655 افزوده شده و 2124 حذف شده
  1. BIN
      BBadDup.MC4
  2. BIN
      BBadNest.MC4
  3. BIN
      BBadRet.MC4
  4. BIN
      BCall.MC4
  5. BIN
      BInit.MC4
  6. BIN
      BOrder.MC4
  7. BIN
      M2c
  8. 85 21
      M2c.atg
  9. 2149 2085
      M2c.lst
  10. 84 18
      M2cP.mod
  11. BIN
      M2cP.o
  12. 7 0
      MGen.def
  13. 30 0
      MGen.mod
  14. BIN
      MGen.o
  15. 7 0
      SymTab.def
  16. 34 0
      SymTab.mod
  17. BIN
      SymTab.o
  18. 50 0
      docs/summary_step10.md
  19. 10 0
      run_tests.sh
  20. 22 0
      tests/b_bad_dup.LST
  21. 15 0
      tests/b_bad_dup.mod
  22. 21 0
      tests/b_bad_nest.LST
  23. 14 0
      tests/b_bad_nest.mod
  24. 17 0
      tests/b_bad_ret.LST
  25. 10 0
      tests/b_bad_ret.mod
  26. 22 0
      tests/b_call.LST
  27. 16 0
      tests/b_call.mod
  28. 16 0
      tests/b_init.LST
  29. 10 0
      tests/b_init.mod
  30. 21 0
      tests/b_order.LST
  31. 15 0
      tests/b_order.mod

BIN
BBadDup.MC4


BIN
BBadNest.MC4


BIN
BBadRet.MC4


BIN
BCall.MC4


BIN
BInit.MC4


BIN
BOrder.MC4



+ 85 - 21
M2c.atg

@@ -3,9 +3,10 @@ COMPILER M2c
    (see MGen for details).
    (see MGen for details).
 
 
    - program module only, no DEFINITION / IMPLEMENTATION split
    - program module only, no DEFINITION / IMPLEMENTATION split
-   - local MODULEs (single-file, no nesting, no bodies): EXPORT of
-     VARs, CONSTs, TYPEs and procedures (value/VAR params, functions,
-     open array formals with fixed actuals); use as M.x / M.P(args);
+   - local MODULEs (single-file, no nesting): EXPORT of VARs, CONSTs,
+     TYPEs and procedures (value/VAR params, functions, open array
+     formals with fixed actuals); use as M.x / M.P(args); optional
+     BEGIN..END init bodies run at startup in declaration order;
      no PRIORITY
      no PRIORITY
    - procedures: declarations (nested), value and VAR parameters,
    - procedures: declarations (nested), value and VAR parameters,
      functions with RETURN, recursion, FORWARD headings;
      functions with RETURN, recursion, FORWARD headings;
@@ -254,10 +255,13 @@ PRODUCTIONS
                                            SymTab.CloseProc;
                                            SymTab.CloseProc;
                                            MGen.DefLabel(endL); .) ) .
                                            MGen.DefLabel(endL); .) ) .
   ModuleDecl                            (. VAR n, m, e: SymTab.Name;
   ModuleDecl                            (. VAR n, m, e: SymTab.Name;
-                                             noMod, enterOk: BOOLEAN; .)
+                                             noMod, enterOk,
+                                             hasInit: BOOLEAN;
+                                             initL, initN: INTEGER; .)
     = "MODULE"                          (. noMod := SymTab.InProc()
     = "MODULE"                          (. noMod := SymTab.InProc()
                                                   OR SymTab.InModule();
                                                   OR SymTab.InModule();
-                                           enterOk := FALSE; .)
+                                           enterOk := FALSE;
+                                           hasInit := FALSE; .)
       GetIdent<n>                       (. IF noMod THEN
       GetIdent<n>                       (. IF noMod THEN
                                            SemError(230)
                                            SemError(230)
                                          ELSIF ~SymTab.EnterModule(n) THEN
                                          ELSIF ~SymTab.EnterModule(n) THEN
@@ -278,10 +282,24 @@ PRODUCTIONS
                                          END; .) } ]
                                          END; .) } ]
       ";"
       ";"
       { Declaration }
       { Declaration }
+      [ "BEGIN"                         (. hasInit := TRUE;
+                                           IF ~noMod & enterOk THEN
+                                             initL := MGen.NewLabel();
+                                             MGen.Jmp(initL);
+                                             initN := MGen.ModInitBegin();
+                                             IF initN < 0 THEN
+                                               SemError(230)
+                                             END
+                                           END; .)
+        StatSeq ]
       "END"
       "END"
       GetIdent<m>                       (. IF ~SymTab.Equal(n, m) THEN
       GetIdent<m>                       (. IF ~SymTab.Equal(n, m) THEN
                                            SemError(202)
                                            SemError(202)
                                          END;
                                          END;
+                                         IF hasInit & ~noMod & enterOk THEN
+                                           MGen.ModInitEnd(initN);
+                                           MGen.DefLabel(initL)
+                                         END;
                                          IF ~noMod & enterOk THEN
                                          IF ~noMod & enterOk THEN
                                            IF ~SymTab.ExitModule() THEN
                                            IF ~SymTab.ExitModule() THEN
                                              SemError(201)
                                              SemError(201)
@@ -341,9 +359,15 @@ PRODUCTIONS
                                            IF SymTab.ExpKind(n, m)
                                            IF SymTab.ExpKind(n, m)
                                               = SymTab.KindType THEN
                                               = SymTab.KindType THEN
                                              t := SymTab.ExpType(n, m)
                                              t := SymTab.ExpType(n, m)
+                                           ELSIF SymTab.SelfKind(n, m)
+                                              = SymTab.KindType THEN
+                                             t := SymTab.SymType(m)
                                            ELSE
                                            ELSE
-                                             IF SymTab.ExpKind(n, m) = -1 THEN
-                                               SemError(201)
+                                             IF SymTab.ExpKind(n, m) < 0 THEN
+                                               IF SymTab.SelfKind(n, m) < 0 THEN
+                                                 SemError(201)
+                                               ELSE SemError(221)
+                                               END
                                              ELSE SemError(221)
                                              ELSE SemError(221)
                                              END;
                                              END;
                                              t := SymTab.InvalidType
                                              t := SymTab.InvalidType
@@ -840,6 +864,13 @@ PRODUCTIONS
                                            IF isModP THEN
                                            IF isModP THEN
                                              modPNum := SymTab.ExpProc(pn,
                                              modPNum := SymTab.ExpProc(pn,
                                                               exp);
                                                               exp);
+                                             IF (modPNum < 0)
+                                                & (SymTab.SelfKind(pn,
+                                                     exp)
+                                                   = SymTab.KindProc) THEN
+                                               modPNum :=
+                                                 SymTab.ProcNum(exp)
+                                             END;
                                              IF modPNum < 0 THEN
                                              IF modPNum < 0 THEN
                                                IF SymTab.ExpKind(pn,
                                                IF SymTab.ExpKind(pn,
                                                     exp) # -1 THEN
                                                     exp) # -1 THEN
@@ -1442,6 +1473,7 @@ PRODUCTIONS
                                              esl, ebytes: CARDINAL;
                                              esl, ebytes: CARDINAL;
                                              firstT: BOOLEAN;
                                              firstT: BOOLEAN;
                                              clsI: INTEGER;
                                              clsI: INTEGER;
+                                             sk: INTEGER;
                                              qM: SymTab.Name; .)
                                              qM: SymTab.Name; .)
     =                                   (. sfx := FALSE; .)
     =                                   (. sfx := FALSE; .)
       { "."                             (. firstT := ~sfx;
       { "."                             (. firstT := ~sfx;
@@ -1462,13 +1494,37 @@ PRODUCTIONS
                                            END; .)
                                            END; .)
         GetIdent<m>                     (. IF (k = SymTab.KindModule) THEN
         GetIdent<m>                     (. IF (k = SymTab.KindModule) THEN
                                              IF SymTab.ExpKind(bn, m) = -1 THEN
                                              IF SymTab.ExpKind(bn, m) = -1 THEN
-                                               SemError(201);
-                                               MGen.CopyName(m, lx);
-                                               t := SymTab.InvalidType;
-                                               IF doLoad THEN
-                                                 MGen.Drop; MGen.PushInt(0)
-                                               ELSIF firstT THEN
-                                               ELSE MGen.Drop
+                                               sk := SymTab.SelfKind(bn, m);
+                                               IF sk = SymTab.KindProc THEN
+                                                 MGen.CopyName(m, lx);
+                                                 t := SymTab.InvalidType;
+                                                 IF doLoad THEN
+                                                   MGen.Drop; MGen.PushInt(0)
+                                                 ELSIF firstT THEN
+                                                 ELSE MGen.Drop
+                                                 END
+                                               ELSIF sk # -1 THEN
+                                                 t := SymTab.SymType(m);
+                                                 k := sk;
+                                                 SymTab.SelfQual(m, qM);
+                                                 IF doLoad THEN
+                                                   MGen.Drop;
+                                                   MGen.GlobalAddr(qM)
+                                                 ELSE
+                                                   IF firstT THEN
+                                                   ELSE MGen.Drop
+                                                   END;
+                                                   MGen.GlobalAddr(qM)
+                                                 END
+                                               ELSE
+                                                 SemError(201);
+                                                 MGen.CopyName(m, lx);
+                                                 t := SymTab.InvalidType;
+                                                 IF doLoad THEN
+                                                   MGen.Drop; MGen.PushInt(0)
+                                                 ELSIF firstT THEN
+                                                 ELSE MGen.Drop
+                                                 END
                                                END
                                                END
                                              ELSIF SymTab.ExpKind(bn, m)
                                              ELSIF SymTab.ExpKind(bn, m)
                                                     = SymTab.KindProc THEN
                                                     = SymTab.KindProc THEN
@@ -1900,7 +1956,7 @@ PRODUCTIONS
                                              lxD, lx2: MGen.LitStr;
                                              lxD, lx2: MGen.LitStr;
                                              v2: BOOLEAN;
                                              v2: BOOLEAN;
                                              vn2: SymTab.Name;
                                              vn2: SymTab.Name;
-                                             vi: INTEGER;
+                                             vi, mpF: INTEGER;
                                              c: CARDINAL;
                                              c: CARDINAL;
                                              b: LONGCARD;
                                              b: LONGCARD;
                                              sfxF: BOOLEAN;
                                              sfxF: BOOLEAN;
@@ -2029,12 +2085,20 @@ PRODUCTIONS
                                              ELSIF (SymTab.SymKind(bnF)
                                              ELSIF (SymTab.SymKind(bnF)
                                                        = SymTab.KindModule)
                                                        = SymTab.KindModule)
                                                 & sfxF
                                                 & sfxF
-                                                & (SymTab.StrLen(lxD) > 0)
-                                                & (SymTab.ExpProc(bnF,
-                                                     lxD) >= 0) THEN
-                                               t := SymTab.ProcRetByNum(
-                                                      SymTab.ExpProc(bnF,
-                                                        lxD))
+                                                & (SymTab.StrLen(lxD) > 0) THEN
+                                               mpF := SymTab.ExpProc(bnF,
+                                                        lxD);
+                                               IF (mpF < 0)
+                                                  & (SymTab.SelfKind(bnF,
+                                                       lxD)
+                                                     = SymTab.KindProc) THEN
+                                                 mpF := SymTab.ProcNum(lxD)
+                                               END;
+                                               IF mpF >= 0 THEN
+                                                 t := SymTab.ProcRetByNum(mpF)
+                                               ELSE
+                                                 t := SymTab.InvalidType
+                                               END
                                              ELSE
                                              ELSE
                                                t := SymTab.InvalidType
                                                t := SymTab.InvalidType
                                              END
                                              END

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2149 - 2085
M2c.lst


+ 84 - 18
M2cP.mod

@@ -272,7 +272,7 @@ PROCEDURE Fact (VAR t: SymTab.TypeIndex; VAR lx: MGen.LitStr;
     lxD, lx2: MGen.LitStr;
     lxD, lx2: MGen.LitStr;
     v2: BOOLEAN;
     v2: BOOLEAN;
     vn2: SymTab.Name;
     vn2: SymTab.Name;
-    vi: INTEGER;
+    vi, mpF: INTEGER;
     c: CARDINAL;
     c: CARDINAL;
     b: LONGCARD;
     b: LONGCARD;
     sfxF: BOOLEAN;
     sfxF: BOOLEAN;
@@ -414,12 +414,20 @@ PROCEDURE Fact (VAR t: SymTab.TypeIndex; VAR lx: MGen.LitStr;
             ELSIF (SymTab.SymKind(bnF)
             ELSIF (SymTab.SymKind(bnF)
                       = SymTab.KindModule)
                       = SymTab.KindModule)
                & sfxF
                & sfxF
-               & (SymTab.StrLen(lxD) > 0)
-               & (SymTab.ExpProc(bnF,
-                    lxD) >= 0) THEN
-              t := SymTab.ProcRetByNum(
-                     SymTab.ExpProc(bnF,
-                       lxD))
+               & (SymTab.StrLen(lxD) > 0) THEN
+              mpF := SymTab.ExpProc(bnF,
+                       lxD);
+              IF (mpF < 0)
+                 & (SymTab.SelfKind(bnF,
+                      lxD)
+                    = SymTab.KindProc) THEN
+                mpF := SymTab.ProcNum(lxD)
+              END;
+              IF mpF >= 0 THEN
+                t := SymTab.ProcRetByNum(mpF)
+              ELSE
+                t := SymTab.InvalidType
+              END
             ELSE
             ELSE
               t := SymTab.InvalidType
               t := SymTab.InvalidType
             END
             END
@@ -730,6 +738,13 @@ PROCEDURE CallTail (pn: SymTab.Name; exp: SymTab.Name; sfx: BOOLEAN;
     IF isModP THEN
     IF isModP THEN
       modPNum := SymTab.ExpProc(pn,
       modPNum := SymTab.ExpProc(pn,
                        exp);
                        exp);
+      IF (modPNum < 0)
+         & (SymTab.SelfKind(pn,
+              exp)
+            = SymTab.KindProc) THEN
+        modPNum :=
+          SymTab.ProcNum(exp)
+      END;
       IF modPNum < 0 THEN
       IF modPNum < 0 THEN
         IF SymTab.ExpKind(pn,
         IF SymTab.ExpKind(pn,
              exp) # -1 THEN
              exp) # -1 THEN
@@ -804,6 +819,7 @@ PROCEDURE DesignTail (VAR t: SymTab.TypeIndex; VAR k: INTEGER;
     esl, ebytes: CARDINAL;
     esl, ebytes: CARDINAL;
     firstT: BOOLEAN;
     firstT: BOOLEAN;
     clsI: INTEGER;
     clsI: INTEGER;
+    sk: INTEGER;
     qM: SymTab.Name;
     qM: SymTab.Name;
   BEGIN
   BEGIN
     sfx := FALSE;;
     sfx := FALSE;;
@@ -829,13 +845,37 @@ PROCEDURE DesignTail (VAR t: SymTab.TypeIndex; VAR k: INTEGER;
         GetIdent(m);
         GetIdent(m);
         IF (k = SymTab.KindModule) THEN
         IF (k = SymTab.KindModule) THEN
           IF SymTab.ExpKind(bn, m) = -1 THEN
           IF SymTab.ExpKind(bn, m) = -1 THEN
-            SemError(201);
-            MGen.CopyName(m, lx);
-            t := SymTab.InvalidType;
-            IF doLoad THEN
-              MGen.Drop; MGen.PushInt(0)
-            ELSIF firstT THEN
-            ELSE MGen.Drop
+            sk := SymTab.SelfKind(bn, m);
+            IF sk = SymTab.KindProc THEN
+              MGen.CopyName(m, lx);
+              t := SymTab.InvalidType;
+              IF doLoad THEN
+                MGen.Drop; MGen.PushInt(0)
+              ELSIF firstT THEN
+              ELSE MGen.Drop
+              END
+            ELSIF sk # -1 THEN
+              t := SymTab.SymType(m);
+              k := sk;
+              SymTab.SelfQual(m, qM);
+              IF doLoad THEN
+                MGen.Drop;
+                MGen.GlobalAddr(qM)
+              ELSE
+                IF firstT THEN
+                ELSE MGen.Drop
+                END;
+                MGen.GlobalAddr(qM)
+              END
+            ELSE
+              SemError(201);
+              MGen.CopyName(m, lx);
+              t := SymTab.InvalidType;
+              IF doLoad THEN
+                MGen.Drop; MGen.PushInt(0)
+              ELSIF firstT THEN
+              ELSE MGen.Drop
+              END
             END
             END
           ELSIF SymTab.ExpKind(bn, m)
           ELSIF SymTab.ExpKind(bn, m)
                  = SymTab.KindProc THEN
                  = SymTab.KindProc THEN
@@ -2293,9 +2333,15 @@ PROCEDURE QualIdent (VAR t: SymTab.TypeIndex);
       IF SymTab.ExpKind(n, m)
       IF SymTab.ExpKind(n, m)
          = SymTab.KindType THEN
          = SymTab.KindType THEN
         t := SymTab.ExpType(n, m)
         t := SymTab.ExpType(n, m)
+      ELSIF SymTab.SelfKind(n, m)
+         = SymTab.KindType THEN
+        t := SymTab.SymType(m)
       ELSE
       ELSE
-        IF SymTab.ExpKind(n, m) = -1 THEN
-          SemError(201)
+        IF SymTab.ExpKind(n, m) < 0 THEN
+          IF SymTab.SelfKind(n, m) < 0 THEN
+            SemError(201)
+          ELSE SemError(221)
+          END
         ELSE SemError(221)
         ELSE SemError(221)
         END;
         END;
         t := SymTab.InvalidType
         t := SymTab.InvalidType
@@ -2439,12 +2485,15 @@ PROCEDURE ConstExpr (VAR t: SymTab.TypeIndex; VAR lx: MGen.LitStr);
 
 
 PROCEDURE ModuleDecl;
 PROCEDURE ModuleDecl;
   VAR n, m, e: SymTab.Name;
   VAR n, m, e: SymTab.Name;
-    noMod, enterOk: BOOLEAN;
+    noMod, enterOk,
+    hasInit: BOOLEAN;
+    initL, initN: INTEGER;
   BEGIN
   BEGIN
     Expect(5);
     Expect(5);
     noMod := SymTab.InProc()
     noMod := SymTab.InProc()
            OR SymTab.InModule();
            OR SymTab.InModule();
-    enterOk := FALSE;;
+    enterOk := FALSE;
+    hasInit := FALSE;;
     GetIdent(n);
     GetIdent(n);
     IF noMod THEN
     IF noMod THEN
     SemError(230)
     SemError(230)
@@ -2475,11 +2524,28 @@ PROCEDURE ModuleDecl;
     WHILE (sym = 5) OR (sym = 13) OR (sym = 14) OR (sym = 15) OR (sym = 18) DO
     WHILE (sym = 5) OR (sym = 13) OR (sym = 14) OR (sym = 15) OR (sym = 18) DO
       Declaration;
       Declaration;
     END;
     END;
+    IF (sym = 11) THEN
+      Get;
+      hasInit := TRUE;
+      IF ~noMod & enterOk THEN
+        initL := MGen.NewLabel();
+        MGen.Jmp(initL);
+        initN := MGen.ModInitBegin();
+        IF initN < 0 THEN
+          SemError(230)
+        END
+      END;;
+      StatSeq;
+    END;
     Expect(12);
     Expect(12);
     GetIdent(m);
     GetIdent(m);
     IF ~SymTab.Equal(n, m) THEN
     IF ~SymTab.Equal(n, m) THEN
     SemError(202)
     SemError(202)
     END;
     END;
+    IF hasInit & ~noMod & enterOk THEN
+    MGen.ModInitEnd(initN);
+    MGen.DefLabel(initL)
+    END;
     IF ~noMod & enterOk THEN
     IF ~noMod & enterOk THEN
     IF ~SymTab.ExitModule() THEN
     IF ~SymTab.ExitModule() THEN
       SemError(201)
       SemError(201)


+ 7 - 0
MGen.def

@@ -269,6 +269,13 @@ PROCEDURE CallDisplay (num: INTEGER; np: CARDINAL);
 PROCEDURE Leave (nPar: CARDINAL; func: BOOLEAN);
 PROCEDURE Leave (nPar: CARDINAL; func: BOOLEAN);
 (* 84H (proper) or 85H (function) procedure leave. *)
 (* 84H (proper) or 85H (function) procedure leave. *)
 
 
+PROCEDURE ModInitBegin (): INTEGER;
+(* Opens a module init body as a parameterless proper procedure,
+   recorded for the startup calls in BeginBody. -1 when full. *)
+
+PROCEDURE ModInitEnd (num: INTEGER);
+(* Closes a module init body (no-op for num < 0). *)
+
 (* ---- actual parameters (nested-call-safe frame stack) ---- *)
 (* ---- actual parameters (nested-call-safe frame stack) ---- *)
 
 
 PROCEDURE ActBegin (pn: ARRAY OF CHAR);
 PROCEDURE ActBegin (pn: ARRAY OF CHAR);

+ 30 - 0
MGen.mod

@@ -107,6 +107,8 @@ VAR
   procAddr : ARRAY [0 .. 64] OF INTEGER;
   procAddr : ARRAY [0 .. 64] OF INTEGER;
   maxNum : CARDINAL;
   maxNum : CARDINAL;
   mainAddr : CARDINAL;
   mainAddr : CARDINAL;
+  initNums : ARRAY [0 .. 7] OF INTEGER;
+  nInits : CARDINAL;
 
 
 (* ---------------- byte helpers ---------------- *)
 (* ---------------- byte helpers ---------------- *)
 
 
@@ -257,6 +259,7 @@ PROCEDURE OpenModule (name: ARRAY OF CHAR);
     nLab := 0; nFix := 0; loopTop := 0; noSup := 0; noEmit := 0;
     nLab := 0; nFix := 0; loopTop := 0; noSup := 0; noEmit := 0;
   actTop := 0; withTop := 0;
   actTop := 0; withTop := 0;
     maxNum := 0; mainAddr := 0;
     maxNum := 0; mainAddr := 0;
+    nInits := 0;
     i := 0;
     i := 0;
     WHILE i <= 64 DO procAddr[i] := -1; INC(i) END;
     WHILE i <= 64 DO procAddr[i] := -1; INC(i) END;
     inBody := FALSE;
     inBody := FALSE;
@@ -348,6 +351,11 @@ PROCEDURE BeginBody;
       PushValue(inits[i].kind, inits[i].ival, inits[i].bits);
       PushValue(inits[i].kind, inits[i].ival, inits[i].bits);
       EmitOpB(OPstoreGlb, inits[i].idx);
       EmitOpB(OPstoreGlb, inits[i].idx);
       INC(i)
       INC(i)
+    END;
+    i := 0;
+    WHILE i < nInits DO
+      CallProc(initNums[i]);
+      INC(i)
     END
     END
   END BeginBody;
   END BeginBody;
 
 
@@ -599,6 +607,27 @@ PROCEDURE CallDisplay (num: INTEGER; np: CARDINAL);
     EmitOpB(OPcallFrame, VAL(CARDINAL, num))
     EmitOpB(OPcallFrame, VAL(CARDINAL, num))
   END CallDisplay;
   END CallDisplay;
 
 
+PROCEDURE ModInitBegin (): INTEGER;
+(* Opens a module init body as a parameterless proper procedure
+   (module bodies declare no locals; globals are used directly).
+   Records its number for the startup calls in BeginBody.
+   -1 when the proc table or init list is full. *)
+  VAR num : INTEGER;
+  BEGIN
+    IF (maxNum >= 64) OR (nInits > 7) THEN RETURN -1 END;
+    num := VAL(INTEGER, maxNum + 1);
+    initNums[nInits] := num;
+    INC(nInits);
+    ProcEntry(num, 0);
+    RETURN num
+  END ModInitBegin;
+
+PROCEDURE ModInitEnd (num: INTEGER);
+(* Closes a module init body (no-op for num < 0). *)
+  BEGIN
+    IF num >= 0 THEN Leave(0, FALSE) END
+  END ModInitEnd;
+
 PROCEDURE Leave (nPar: CARDINAL; func: BOOLEAN);
 PROCEDURE Leave (nPar: CARDINAL; func: BOOLEAN);
   BEGIN
   BEGIN
     IF nPar > 255 THEN nPar := 255 END;
     IF nPar > 255 THEN nPar := 255 END;
@@ -1619,6 +1648,7 @@ BEGIN
   nLab := 0; nFix := 0; loopTop := 0; noSup := 0; noEmit := 0;
   nLab := 0; nFix := 0; loopTop := 0; noSup := 0; noEmit := 0;
   actTop := 0; withTop := 0;
   actTop := 0; withTop := 0;
   maxNum := 0; mainAddr := 0;
   maxNum := 0; mainAddr := 0;
+  nInits := 0;
   inBody := FALSE;
   inBody := FALSE;
   modName[0] := 0C
   modName[0] := 0C
 END MGen.
 END MGen.


+ 7 - 0
SymTab.def

@@ -148,6 +148,13 @@ PROCEDURE ExpQual (mod, exp: ARRAY OF CHAR; VAR qual: Name);
 (* Qualified MGen name ("M.x"), empty if absent / not a variable
 (* Qualified MGen name ("M.x"), empty if absent / not a variable
    or constant. *)
    or constant. *)
 
 
+PROCEDURE SelfKind (mod, exp: ARRAY OF CHAR): INTEGER;
+(* Kind of exp as M.exp from inside M itself (live body scope,
+   since exports resolve only at END). -1 if not applicable. *)
+
+PROCEDURE SelfQual (exp: ARRAY OF CHAR; VAR qual: Name);
+(* CurMod.exp for a self reference (call only when SelfKind # -1). *)
+
 PROCEDURE PushRecord (t: TypeIndex): BOOLEAN;
 PROCEDURE PushRecord (t: TypeIndex): BOOLEAN;
 (* Pushes a scope containing t's fields (as KindField). FALSE if t
 (* Pushes a scope containing t's fields (as KindField). FALSE if t
    is not a record type (or invalid). Caller must PopScope after. *)
    is not a record type (or invalid). Caller must PopScope after. *)

+ 34 - 0
SymTab.mod

@@ -83,6 +83,7 @@ VAR
   retSt : ARRAY [0 .. MaxPDepth] OF TypeIndex;
   retSt : ARRAY [0 .. MaxPDepth] OF TypeIndex;
   modNames : ARRAY [0 .. 7] OF Name;
   modNames : ARRAY [0 .. 7] OF Name;
   modTop : CARDINAL;
   modTop : CARDINAL;
+  modLevs : ARRAY [0 .. 7] OF CARDINAL;
   modExps : ARRAY [0 .. 7] OF ARRAY [0 .. 31] OF Name;
   modExps : ARRAY [0 .. 7] OF ARRAY [0 .. 31] OF Name;
   modNExps : ARRAY [0 .. 7] OF CARDINAL;
   modNExps : ARRAY [0 .. 7] OF CARDINAL;
   expMod : ARRAY [0 .. 127] OF Name;
   expMod : ARRAY [0 .. 127] OF Name;
@@ -395,6 +396,7 @@ PROCEDURE EnterModule (name: ARRAY OF CHAR): BOOLEAN;
     modNExps[modTop] := 0;
     modNExps[modTop] := 0;
     INC(modTop);
     INC(modTop);
     PushScope;
     PushScope;
+    modLevs[modTop - 1] := curLev;
     RETURN TRUE
     RETURN TRUE
   END EnterModule;
   END EnterModule;
 
 
@@ -513,6 +515,38 @@ PROCEDURE ExpQual (mod, exp: ARRAY OF CHAR; VAR qual: Name);
     IF k <= HIGH(qual) THEN qual[k] := 0C END
     IF k <= HIGH(qual) THEN qual[k] := 0C END
   END ExpQual;
   END ExpQual;
 
 
+PROCEDURE SelfKind (mod, exp: ARRAY OF CHAR): INTEGER;
+(* Kind of exp as a self-qualified M.exp reference from inside module
+   M itself (the export table only fills at END, so the live body
+   scope is consulted). -1 when not inside M or not at body level. *)
+  VAR idx : INTEGER;
+  BEGIN
+    IF modTop = 0 THEN RETURN -1 END;
+    IF ~Equal(modNames[modTop - 1], mod) THEN RETURN -1 END;
+    idx := Find(exp);
+    IF idx = -1 THEN RETURN -1 END;
+    IF syms[idx].lev # modLevs[modTop - 1] THEN RETURN -1 END;
+    RETURN syms[idx].kind
+  END SelfKind;
+
+PROCEDURE SelfQual (exp: ARRAY OF CHAR; VAR qual: Name);
+(* CurMod.exp for a self reference (call only when SelfKind # -1). *)
+  VAR m : Name;
+    j, k : CARDINAL;
+  BEGIN
+    CurModName(m);
+    k := 0; j := 0;
+    WHILE (k < HIGH(qual)) & (m[j] # 0C) DO
+      qual[k] := m[j]; INC(k); INC(j)
+    END;
+    IF k <= HIGH(qual) THEN qual[k] := "."; INC(k) END;
+    j := 0;
+    WHILE (k < HIGH(qual)) & (exp[j] # 0C) DO
+      qual[k] := exp[j]; INC(k); INC(j)
+    END;
+    IF k <= HIGH(qual) THEN qual[k] := 0C END
+  END SelfQual;
+
 (* ---------------- type descriptors ---------------- *)
 (* ---------------- type descriptors ---------------- *)
 
 
 PROCEDURE NewDesc (form: INTEGER; ref: TypeIndex): TypeIndex;
 PROCEDURE NewDesc (form: INTEGER; ref: TypeIndex): TypeIndex;

BIN
SymTab.o


+ 50 - 0
docs/summary_step10.md

@@ -0,0 +1,50 @@
+# Step 10 — Module BEGIN bodies + self-reference (uncommitted)
+
+143/143 tests green (137 + 3 run + 3 rejection), mc64 boot + example
+green, both Showcases unchanged (157, 83).
+
+## Goal
+
+Complete single-file local modules: optional `BEGIN..END` init bodies run
+at startup in declaration order, including calls to the module's own
+procedures (plain and `M.`-qualified).
+
+## What was built
+
+- `MGen`: module inits compile as parameterless proper procedures
+  (`ModInitBegin` allocates a proc-table number + `ENTER`, `ModInitEnd`
+  emits `LEAVE`); `BeginBody` calls them in order after const inits,
+  before program statements. Max 8 inits (module limit), sharing the 64
+  proc numbers (print helper still takes `maxNum+1` at `EndModule`).
+- `M2c.atg` `ModuleDecl`: optional `BEGIN StatSeq`, jumped over inline
+  (`Jmp`/`DefLabel` like procedures), skipped entirely for
+  nested/duplicate modules. `RETURN` in a body is already 232 (not in a
+  proc); header updated (`no bodies` dropped).
+- `SymTab`: `modLevs[]` records each module's body scope level;
+  `SelfKind(mod, exp)` resolves `M.x` against the live body scope (the
+  export table only fills at `END`), guarded to body level so nested
+  scopes can't hijack; `SelfQual` builds `M.x` for codegen.
+- `M2c.atg` call sites use it: `DesignTail` (vars/consts/procs),
+  `CallTail` (by-number via `ProcNum`), `Fact` (return types),
+  `QualIdent` (`M.T` inside `M`).
+
+## Tests — 143/143 (137 + 3 + 3)
+
+3 run: `b_init` 42, `b_order` 111 (two inits, order + cross-module read),
+`b_call` 15 (plain `Inc()` and `M.Inc()` from init). 3 rejections, each
+exactly one error: `b_bad_ret` 232, `b_bad_nest` 230, `b_bad_dup` 200.
+
+## Bugs found and fixed
+
+1. `M.Inc()` inside `M` gave 201: the export table is empty until `END`.
+   Self-scope fallback fixes vars, consts, procs, and types uniformly.
+2. gm2 16.0.1 ICE (deterministic, no source location) on
+   `x = -1 & (y = -1)` in generated `M2cP.mod` — minimized to
+   `IF a = -1 & (b = -1) THEN END` in 20 lines. Workaround: nested `IF`s
+   with `< 0` (single `F() = -1` and `(x < 0) & ...` shapes compile).
+   New rule: never compare against a negative literal inside an `&` chain.
+
+## Known limits (deferred)
+
+`DEFINITION`/`IMPLEMENTATION` split (the remaining big item), `WITH`-field
+`VAR` actuals, `CHAR`/`BOOLEAN` tails as `VAR` actuals, open-to-open.

+ 10 - 0
run_tests.sh

@@ -273,5 +273,15 @@ expect_fail t_bad_mtype.mod "not a type name"
 expect_fail t_bad_mghost.mod "undeclared identifier"
 expect_fail t_bad_mghost.mod "undeclared identifier"
 expect_fail t_bad_mmod.mod "not supported in this phase"
 expect_fail t_bad_mmod.mod "not supported in this phase"
 
 
+echo "=== Step-10 run tests (module BEGIN bodies) ==="
+expect_run b_init.mod 42
+expect_run b_order.mod 111
+expect_run b_call.mod 15
+
+echo "=== Step-10 rejection tests ==="
+expect_fail b_bad_ret.mod "bad RETURN"
+expect_fail b_bad_nest.mod "not supported in this phase"
+expect_fail b_bad_dup.mod "duplicate identifier"
+
 echo "=== $pass passed, $fail failed ==="
 echo "=== $pass passed, $fail failed ==="
 test "$fail" = 0
 test "$fail" = 0

+ 22 - 0
tests/b_bad_dup.LST

@@ -0,0 +1,22 @@
+Listing:
+
+    1  MODULE BBadDup;
+    2  MODULE M EXPORT cnt;
+    3  VAR cnt : INTEGER;
+    4  BEGIN
+    5    cnt := 1
+    6  END M;
+    7  MODULE M EXPORT k;
+*****         ^ duplicate identifier
+    8  VAR k : INTEGER;
+    9  BEGIN
+   10    k := 2
+   11  END M;
+   12  VAR ExitCode : INTEGER;
+   13  BEGIN
+   14    ExitCode := 0
+   15  END BBadDup.
+
+    1 error
+
+

+ 15 - 0
tests/b_bad_dup.mod

@@ -0,0 +1,15 @@
+MODULE BBadDup;
+MODULE M EXPORT cnt;
+VAR cnt : INTEGER;
+BEGIN
+  cnt := 1
+END M;
+MODULE M EXPORT k;
+VAR k : INTEGER;
+BEGIN
+  k := 2
+END M;
+VAR ExitCode : INTEGER;
+BEGIN
+  ExitCode := 0
+END BBadDup.

+ 21 - 0
tests/b_bad_nest.LST

@@ -0,0 +1,21 @@
+Listing:
+
+    1  MODULE BBadNest;
+    2  VAR ExitCode : INTEGER;
+    3  PROCEDURE P;
+    4  MODULE M EXPORT cnt;
+*****         ^ not supported in this phase
+    5  VAR cnt : INTEGER;
+    6  BEGIN
+    7    cnt := 1
+    8  END M;
+    9  BEGIN
+   10    ExitCode := 0
+   11  END P;
+   12  BEGIN
+   13    ExitCode := 0
+   14  END BBadNest.
+
+    1 error
+
+

+ 14 - 0
tests/b_bad_nest.mod

@@ -0,0 +1,14 @@
+MODULE BBadNest;
+VAR ExitCode : INTEGER;
+PROCEDURE P;
+MODULE M EXPORT cnt;
+VAR cnt : INTEGER;
+BEGIN
+  cnt := 1
+END M;
+BEGIN
+  ExitCode := 0
+END P;
+BEGIN
+  ExitCode := 0
+END BBadNest.

+ 17 - 0
tests/b_bad_ret.LST

@@ -0,0 +1,17 @@
+Listing:
+
+    1  MODULE BBadRet;
+    2  MODULE M EXPORT cnt;
+    3  VAR cnt : INTEGER;
+    4  BEGIN
+    5    RETURN
+*****    ^ bad RETURN
+    6  END M;
+    7  VAR ExitCode : INTEGER;
+    8  BEGIN
+    9    ExitCode := 0
+   10  END BBadRet.
+
+    1 error
+
+

+ 10 - 0
tests/b_bad_ret.mod

@@ -0,0 +1,10 @@
+MODULE BBadRet;
+MODULE M EXPORT cnt;
+VAR cnt : INTEGER;
+BEGIN
+  RETURN
+END M;
+VAR ExitCode : INTEGER;
+BEGIN
+  ExitCode := 0
+END BBadRet.

+ 22 - 0
tests/b_call.LST

@@ -0,0 +1,22 @@
+Listing:
+
+    1  MODULE BCall;
+    2  MODULE M EXPORT cnt, Inc;
+    3  VAR cnt : INTEGER;
+    4  PROCEDURE Inc;
+    5  BEGIN
+    6    cnt := cnt + 5
+    7  END Inc;
+    8  BEGIN
+    9    Inc();
+   10    M.Inc()
+   11  END M;
+   12  VAR ExitCode : INTEGER;
+   13  BEGIN
+   14    M.Inc();
+   15    ExitCode := M.cnt
+   16  END BCall.
+
+    0 errors
+
+

+ 16 - 0
tests/b_call.mod

@@ -0,0 +1,16 @@
+MODULE BCall;
+MODULE M EXPORT cnt, Inc;
+VAR cnt : INTEGER;
+PROCEDURE Inc;
+BEGIN
+  cnt := cnt + 5
+END Inc;
+BEGIN
+  Inc();
+  M.Inc()
+END M;
+VAR ExitCode : INTEGER;
+BEGIN
+  M.Inc();
+  ExitCode := M.cnt
+END BCall.

+ 16 - 0
tests/b_init.LST

@@ -0,0 +1,16 @@
+Listing:
+
+    1  MODULE BInit;
+    2  MODULE M EXPORT cnt;
+    3  VAR cnt : INTEGER;
+    4  BEGIN
+    5    cnt := 42
+    6  END M;
+    7  VAR ExitCode : INTEGER;
+    8  BEGIN
+    9    ExitCode := M.cnt
+   10  END BInit.
+
+    0 errors
+
+

+ 10 - 0
tests/b_init.mod

@@ -0,0 +1,10 @@
+MODULE BInit;
+MODULE M EXPORT cnt;
+VAR cnt : INTEGER;
+BEGIN
+  cnt := 42
+END M;
+VAR ExitCode : INTEGER;
+BEGIN
+  ExitCode := M.cnt
+END BInit.

+ 21 - 0
tests/b_order.LST

@@ -0,0 +1,21 @@
+Listing:
+
+    1  MODULE BOrder;
+    2  MODULE A EXPORT x;
+    3  VAR x : INTEGER;
+    4  BEGIN
+    5    x := 1
+    6  END A;
+    7  MODULE B EXPORT y;
+    8  VAR y : INTEGER;
+    9  BEGIN
+   10    y := A.x + 10
+   11  END B;
+   12  VAR ExitCode : INTEGER;
+   13  BEGIN
+   14    ExitCode := A.x * 100 + B.y
+   15  END BOrder.
+
+    0 errors
+
+

+ 15 - 0
tests/b_order.mod

@@ -0,0 +1,15 @@
+MODULE BOrder;
+MODULE A EXPORT x;
+VAR x : INTEGER;
+BEGIN
+  x := 1
+END A;
+MODULE B EXPORT y;
+VAR y : INTEGER;
+BEGIN
+  y := A.x + 10
+END B;
+VAR ExitCode : INTEGER;
+BEGIN
+  ExitCode := A.x * 100 + B.y
+END BOrder.

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است