Browse Source

compiler: extract symbol table management

Eric Streit 2 days ago
parent
commit
0e0e9d8750

+ 3 - 2
SUMMARY.md

@@ -1213,8 +1213,9 @@ CALC compiles to its final `.`, and every default check is green.
   71 `.pas`, no archives).
 - The compiler implementation is now split into `CompilerShared` (image,
   patch and error state), `CompilerUtil` (pure helpers), `CompilerSource`
-  (cursor and `{$I}` expansion) and `CompilerEmit` (primitive 8086 emitters).
-  `Compiler.mod` retains the parser, symbol table, declarations and driver.
+  (cursor and `{$I}` expansion), `CompilerSymbols` (symbol entries, lookup,
+  insertion and scope hiding) and `CompilerEmit` (primitive 8086 emitters).
+  `Compiler.mod` retains the parser, declarations, code generation and driver.
 
 This does not claim the whole Turbo Pascal 3 standard library or every TP3
 compiler option.  The corpus is the regression target; the historical notes

+ 6 - 184
shell/Compiler.mod

@@ -63,7 +63,7 @@ FROM Runtime IMPORT RT_Build, RT_Size, RT_Byte, RT_Entry, LoadBias ;
    encodings (the entry JMP, every CALL and JMP) must NOT get it: both
    operands shift together and the +0100h cancels. *)
 
-FROM CompilerShared IMPORT MaxCode, CodeMax, EMemOvf, ECompOvf,
+FROM CompilerShared IMPORT MaxCode, CodeMax, EUnknown, EMemOvf, ECompOvf,
                           EFileNF, EInclNest, OK,
                           PatchRec, cbuf, pc, imgReady, patches, nPatch,
                           srcPos, abortFac, errNum, txerrPos, Err ;
@@ -74,6 +74,9 @@ FROM CompilerSource IMPORT CurCh, GetCh, PeekAhead, Upper, SetSourcePath, Expand
 FROM CompilerUtil IMPORT Digit, Alpha, AlphaNum, IsHexCh, W16, DropCh,
                           DropB, DropC, BitAnd, BitOr, BitNot, NameEq,
                           CopyStr, NumToName ;
+FROM CompilerSymbols IMPORT MaxName, SymEntry, symtab, symTop, lexnest, wrd,
+                             NewSym, Search, DupTest, HideLocals,
+                             CopyWord, SaveWord ;
 
 (* ---------------------------------------------------------------- *)
 (*  constants                                                       *)
@@ -81,7 +84,6 @@ FROM CompilerUtil IMPORT Digit, Alpha, AlphaNum, IsHexCh, W16, DropCh,
 
 CONST
    MaxLine   = 128 ;
-   MaxName   = 63 ;
 
    (* Size of the entry jump at image offset 0: E9 lo hi.  The jump's
       displacement is relative to the END of the jump, so every offset in the
@@ -99,7 +101,6 @@ CONST
       moved. *)
    DataStart = 0A000H ;      (* image offset of the first global (memory 0A100h) *)
 
-   MaxSym    = 3000 ;
    MaxPend   = 400 ;
    MaxFields = 2000 ;          (* record fields, in a table of their own: a
                                   field is scoped to its record, not global *)
@@ -193,7 +194,7 @@ CONST
 
    (* TP3 error numbers *)
    ENoSemi    = 1 ;  EPointExp  = 10 ;  ESimpType  = 30 ;
-   EUnknown   = 41 ; EConstRange = 45 ; ENoLib     = 102 ; ETypeErr   = 56 ;
+   EConstRange = 45 ; ENoLib     = 102 ; ETypeErr   = 56 ;
    EIoHere    = 66 ;            (* I/O not allowed here - TPSRC8 prderrtp *)
 
    AposC      = 39 ;            (* ORD ("'") - avoids quote-in-quote *)
@@ -203,36 +204,6 @@ CONST
 (* ---------------------------------------------------------------- *)
 
 TYPE
-   SymEntry =
-      RECORD
-         name   : ARRAY [0..MaxName] OF CHAR ;
-         tag    : CARDINAL ;
-         cls    : CARDINAL ;
-         size   : CARDINAL ;
-         elem   : CARDINAL ;
-         off    : CARDINAL ;
-         lval   : LONGINT ;
-         lo, hi : LONGINT ;         (* an ORDINAL type's bounds: an enumeration
-                                       (0..n-1) or a subrange.  Needed so
-                                       `set of T' can size its base. *)
-         fldFirst, fldLast : CARDINAL ;  (* a RECORD type's field range in the
-                                       field table (0,0 when not a record) *)
-         arrIdx : CARDINAL ;        (* an ARRAY type's shape in ArrRec (0 = no) *)
-         parmFirst, parmCount : CARDINAL ;  (* a PROCEDURE/FUNCTION's parameters:
-                                       symtab indices, in declaration order *)
-         isKbd  : BOOLEAN ;          (* the predefined KBD file: reads are console *)
-         isPort : BOOLEAN ;          (* the predefined PORT byte array *)
-         isVar  : BOOLEAN ;          (* a VAR parameter: the slot holds an address *)
-         level  : CARDINAL ;
-         local  : BOOLEAN ;
-         parent : CARDINAL ;       (* lexical parent procedure, 0 at top level *)
-         staticOff : CARDINAL ;    (* nested proc's hidden static-link local *)
-         resvar : CARDINAL ;
-         goPos  : CARDINAL ;
-         defnd  : BOOLEAN ;
-         fwd    : BOOLEAN ;
-      END ;
-
    PendRec =
       RECORD
          kind  : CARDINAL ;         (* 0 goto, 1 call *)
@@ -290,11 +261,7 @@ TYPE
          ecls   : CARDINAL ;        (* element CLASS, for a subscripted value *)
          fldFirst, fldLast : CARDINAL ;  (* leaf record metadata *)
          elemType : CARDINAL ;
-    elemLo, elemHi : LONGINT ;
-    fieldPtrElem : CARDINAL ;
-    variantBase, armRunning, armMax, savePosVar : CARDINAL ;
-    moreFields : BOOLEAN ;
-    tagName : ARRAY [0..MaxName] OF CHAR ;      (* pointer target / named element type *)
+         elemLo, elemHi : LONGINT ;  (* leaf element subrange bounds *)
       END ;
 
 (* ---------------------------------------------------------------- *)
@@ -313,8 +280,6 @@ VAR
    constBlob : ARRAY [0..511] OF CHAR ;  (* bytes of a set/array typed constant
                                              while it is being built *)
 
-   wrd  : ARRAY [0..MaxName] OF CHAR ;
-
    (* String-literal pool.
 
       TP3 does not put a literal in the data segment at all: it emits the
@@ -331,9 +296,6 @@ VAR
    strCnt  : CARDINAL ;        (* literals collected so far *)
    rdStrX  : CARDINAL ;        (* pool index of the literal RdConst just read *)
 
-   symtab : ARRAY [0..MaxSym - 1] OF SymEntry ;
-   symTop : CARDINAL ;
-
    pend    : ARRAY [0..MaxPend - 1] OF PendRec ;
    nPend   : CARDINAL ;
 
@@ -452,7 +414,6 @@ VAR
                                 on the stack, limit in CX; exit code 16 if the
                                 result would be too long *)
 
-   lexnest  : CARDINAL ;
    curProc  : CARDINAL ;       (* symbol of the procedure body being compiled *)
    curStaticOff : CARDINAL ;   (* its hidden static-link slot, 0 if none *)
    curIsFunc : BOOLEAN ;
@@ -951,145 +912,6 @@ END EmRet ;
 (*  symbol table                                                    *)
 (* ---------------------------------------------------------------- *)
 
-PROCEDURE CopyWord (name : ARRAY OF CHAR) ;
-(* stash current word into global wrd (uppercased) *)
-VAR i : CARDINAL ;
-BEGIN
-   i := 0 ;
-   LOOP
-      IF i > HIGH (name) THEN
-         wrd [i] := 0C ;
-         RETURN
-      END ;
-      IF i > MaxName THEN
-         wrd [MaxName] := 0C ;
-         RETURN
-      END ;
-      IF name [i] = 0C THEN
-         wrd [i] := 0C ;
-         RETURN
-      END ;
-      wrd [i] := Upper (name [i]) ;
-      INC (i)
-   END
-END CopyWord ;
-
-PROCEDURE SaveWord (VAR dst : ARRAY OF CHAR) ;
-(* copy wrd into dst *)
-VAR i : CARDINAL ;
-BEGIN
-   i := 0 ;
-   LOOP
-      IF i > HIGH (dst) THEN
-         dst [HIGH (dst)] := 0C ;
-         RETURN
-      END ;
-      IF i > MaxName THEN
-         dst [MaxName] := 0C ;
-         RETURN
-      END ;
-      dst [i] := wrd [i] ;
-      IF wrd [i] = 0C THEN
-         RETURN
-      END ;
-      INC (i)
-   END
-END SaveWord ;
-
-PROCEDURE NewSym (name : ARRAY OF CHAR ; tag : CARDINAL ;
-                  cls, size, elem, off : CARDINAL ; v : LONGINT ;
-                  local : BOOLEAN) : CARDINAL ;
-VAR e : SymEntry ;
-BEGIN
-   IF symTop >= MaxSym THEN
-      Err (ECompOvf) ;
-      RETURN 0
-   END ;
-   CopyWord (name) ;
-   CopyStr (e.name, wrd) ;
-   e.tag := tag ;
-   e.cls := cls ;
-   e.size := size ;
-   e.elem := elem ;
-   e.off := off ;
-   e.lval := v ;
-   e.lo := 0 ;
-   e.hi := 0 ;
-   e.fldFirst := 0 ;
-   e.fldLast := 0 ;
-   e.arrIdx := 0 ;
-   e.parmFirst := 0 ;
-   e.parmCount := 0 ;
-   e.isKbd := FALSE ;
-   e.isPort := FALSE ;
-   e.isVar := FALSE ;
-   e.level := lexnest ;
-   e.local := local ;
-   e.parent := 0 ;
-   e.staticOff := 0 ;
-   e.resvar := 0 ;
-   e.goPos := 0 ;
-   e.defnd := FALSE ;
-   e.fwd := FALSE ;
-   symtab [symTop] := e ;
-   INC (symTop) ;
-   RETURN symTop - 1
-END NewSym ;
-
-PROCEDURE Search (nm : ARRAY OF CHAR ; VAR idx : CARDINAL) : BOOLEAN ;
-(* find nm among symbols visible at the current lexical level *)
-VAR p : CARDINAL ;
-BEGIN
-   CopyWord (nm) ;
-   p := symTop ;
-   WHILE p > 0 DO
-      DEC (p) ;
-      IF symtab [p].level <= lexnest THEN
-         IF NameEq (symtab [p].name, wrd) THEN
-            idx := p ;
-            RETURN TRUE
-         END
-      END
-   END ;
-   RETURN FALSE
-END Search ;
-
-PROCEDURE DupTest (nm : ARRAY OF CHAR) ;
-(* A name may be declared twice only in the SAME scope.  This used to reject
-   any name Search could see, so a parameter could not shadow a global - legal
-   ISO Pascal, and CALC.INC's `procedure IBMCh(var Ch: Char)' does exactly
-   that (`Ch' is a global).  Same-level duplicates stay errors: two parameters
-   in one list, two locals, or two globals. *)
-VAR i : CARDINAL ;
-BEGIN
-   IF Search (nm, i) THEN
-      IF symtab [i].level = lexnest THEN
-         Err (EUnknown)
-      END
-   END
-END DupTest ;
-
-PROCEDURE HideLocals (from : CARDINAL) ;
-(* Make every symbol from index `from' up invisible to everything outside the
-   procedure that declared it.
-   Search accepts a symbol when its level is <= lexnest, and every procedure
-   body is compiled at the same depth (lexnest 1), so a finished procedure's
-   parameters stayed visible to the NEXT procedure: a second `a : integer'
-   was a duplicate (err 41) and an unqualified `a' inside procedure two read
-   procedure one's argument.  Level 0FFFFH fails `level <= lexnest' at every
-   depth a later procedure can be at, and by the time this runs the body that
-   could still legitimately see them is finished.
-   The symbols are relabelled, not popped: symtab[old].resvar holds an INDEX,
-   and a function's result variable is one of the entries being hidden. *)
-VAR p : CARDINAL ;
-BEGIN
-   p := from ;
-   WHILE p < symTop DO
-      symtab [p].level := 0FFFFH ;
-      INC (p)
-   END
-END HideLocals ;
-
 (* ---------------------------------------------------------------- *)
 (*  lexer                                                           *)
 (* ---------------------------------------------------------------- *)

+ 1 - 0
shell/CompilerShared.def

@@ -12,6 +12,7 @@ CONST
    MaxCode = 0A000H ;
    CodeMax = 0A000H ;
    MaxPatch = 2000 ;
+   EUnknown = 41 ;
    EMemOvf = 98 ;
    ECompOvf = 99 ;
    EFileNF = 90 ;

+ 56 - 0
shell/CompilerSymbols.def

@@ -0,0 +1,56 @@
+DEFINITION MODULE CompilerSymbols ;
+
+(* Symbol table management: entry type, storage, insertion, lookup and scope
+   hiding.  Compiler.mod imports these names unqualified. *)
+
+CONST
+   MaxName = 63 ;
+   MaxSym  = 3000 ;
+
+TYPE
+   SymEntry =
+      RECORD
+         name   : ARRAY [0..MaxName] OF CHAR ;
+         tag    : CARDINAL ;
+         cls    : CARDINAL ;
+         size   : CARDINAL ;
+         elem   : CARDINAL ;
+         off    : CARDINAL ;
+         lval   : LONGINT ;
+         lo, hi : LONGINT ;         (* an ORDINAL type's bounds: an enumeration
+                                       (0..n-1) or a subrange.  Needed so
+                                       `set of T' can size its base. *)
+         fldFirst, fldLast : CARDINAL ;  (* a RECORD type's field range in the
+                                       field table (0,0 when not a record) *)
+         arrIdx : CARDINAL ;        (* an ARRAY type's shape in ArrRec (0 = no) *)
+         parmFirst, parmCount : CARDINAL ;  (* a PROCEDURE/FUNCTION's parameters:
+                                       symtab indices, in declaration order *)
+         isKbd  : BOOLEAN ;          (* the predefined KBD file: reads are console *)
+         isPort : BOOLEAN ;          (* the predefined PORT byte array *)
+         isVar  : BOOLEAN ;          (* a VAR parameter: the slot holds an address *)
+         level  : CARDINAL ;
+         local  : BOOLEAN ;
+         parent : CARDINAL ;       (* lexical parent procedure, 0 at top level *)
+         staticOff : CARDINAL ;    (* nested proc's hidden static-link local *)
+         resvar : CARDINAL ;
+         goPos  : CARDINAL ;
+         defnd  : BOOLEAN ;
+         fwd    : BOOLEAN ;
+      END ;
+
+VAR
+   symtab : ARRAY [0..MaxSym - 1] OF SymEntry ;
+   symTop : CARDINAL ;
+   lexnest : CARDINAL ;
+   wrd : ARRAY [0..MaxName] OF CHAR ;
+
+PROCEDURE CopyWord (name : ARRAY OF CHAR) ;
+PROCEDURE SaveWord (VAR dst : ARRAY OF CHAR) ;
+PROCEDURE NewSym (name : ARRAY OF CHAR ; tag : CARDINAL ;
+                  cls, size, elem, off : CARDINAL ; v : LONGINT ;
+                  local : BOOLEAN) : CARDINAL ;
+PROCEDURE Search (nm : ARRAY OF CHAR ; VAR idx : CARDINAL) : BOOLEAN ;
+PROCEDURE DupTest (nm : ARRAY OF CHAR) ;
+PROCEDURE HideLocals (from : CARDINAL) ;
+
+END CompilerSymbols.

+ 151 - 0
shell/CompilerSymbols.mod

@@ -0,0 +1,151 @@
+IMPLEMENTATION MODULE CompilerSymbols ;
+
+(* Symbol table and name scoping: storage, insertion, visibility-aware lookup,
+   duplicate detection, and hiding a finished procedure's locals.  The lexer's
+   current word and lexical level live here because Search and NewSym are the
+   only users that define their meaning. *)
+
+FROM CompilerShared IMPORT Err, ECompOvf, EUnknown ;
+FROM CompilerSource IMPORT Upper ;
+FROM CompilerUtil IMPORT NameEq, CopyStr ;
+
+PROCEDURE CopyWord (name : ARRAY OF CHAR) ;
+(* stash current word into global wrd (uppercased) *)
+VAR i : CARDINAL ;
+BEGIN
+   i := 0 ;
+   LOOP
+      IF i > HIGH (name) THEN
+         wrd [i] := 0C ;
+         RETURN
+      END ;
+      IF i > MaxName THEN
+         wrd [MaxName] := 0C ;
+         RETURN
+      END ;
+      IF name [i] = 0C THEN
+         wrd [i] := 0C ;
+         RETURN
+      END ;
+      wrd [i] := Upper (name [i]) ;
+      INC (i)
+   END
+END CopyWord ;
+
+PROCEDURE SaveWord (VAR dst : ARRAY OF CHAR) ;
+(* copy wrd into dst *)
+VAR i : CARDINAL ;
+BEGIN
+   i := 0 ;
+   LOOP
+      IF i > HIGH (dst) THEN
+         dst [HIGH (dst)] := 0C ;
+         RETURN
+      END ;
+      IF i > MaxName THEN
+         dst [MaxName] := 0C ;
+         RETURN
+      END ;
+      dst [i] := wrd [i] ;
+      IF wrd [i] = 0C THEN
+         RETURN
+      END ;
+      INC (i)
+   END
+END SaveWord ;
+
+PROCEDURE NewSym (name : ARRAY OF CHAR ; tag : CARDINAL ;
+                  cls, size, elem, off : CARDINAL ; v : LONGINT ;
+                  local : BOOLEAN) : CARDINAL ;
+VAR e : SymEntry ;
+BEGIN
+   IF symTop >= MaxSym THEN
+      Err (ECompOvf) ;
+      RETURN 0
+   END ;
+   CopyWord (name) ;
+   CopyStr (e.name, wrd) ;
+   e.tag := tag ;
+   e.cls := cls ;
+   e.size := size ;
+   e.elem := elem ;
+   e.off := off ;
+   e.lval := v ;
+   e.lo := 0 ;
+   e.hi := 0 ;
+   e.fldFirst := 0 ;
+   e.fldLast := 0 ;
+   e.arrIdx := 0 ;
+   e.parmFirst := 0 ;
+   e.parmCount := 0 ;
+   e.isKbd := FALSE ;
+   e.isPort := FALSE ;
+   e.isVar := FALSE ;
+   e.level := lexnest ;
+   e.local := local ;
+   e.parent := 0 ;
+   e.staticOff := 0 ;
+   e.resvar := 0 ;
+   e.goPos := 0 ;
+   e.defnd := FALSE ;
+   e.fwd := FALSE ;
+   symtab [symTop] := e ;
+   INC (symTop) ;
+   RETURN symTop - 1
+END NewSym ;
+
+PROCEDURE Search (nm : ARRAY OF CHAR ; VAR idx : CARDINAL) : BOOLEAN ;
+(* find nm among symbols visible at the current lexical level *)
+VAR p : CARDINAL ;
+BEGIN
+   CopyWord (nm) ;
+   p := symTop ;
+   WHILE p > 0 DO
+      DEC (p) ;
+      IF symtab [p].level <= lexnest THEN
+         IF NameEq (symtab [p].name, wrd) THEN
+            idx := p ;
+            RETURN TRUE
+         END
+      END
+   END ;
+   RETURN FALSE
+END Search ;
+
+PROCEDURE DupTest (nm : ARRAY OF CHAR) ;
+(* A name may be declared twice only in the SAME scope.  This used to reject
+   any name Search could see, so a parameter could not shadow a global - legal
+   ISO Pascal, and CALC.INC's `procedure IBMCh(var Ch: Char)' does exactly
+   that (`Ch' is a global).  Same-level duplicates stay errors: two parameters
+   in one list, two locals, or two globals. *)
+VAR i : CARDINAL ;
+BEGIN
+   IF Search (nm, i) THEN
+      IF symtab [i].level = lexnest THEN
+         Err (EUnknown)
+      END
+   END
+END DupTest ;
+
+PROCEDURE HideLocals (from : CARDINAL) ;
+(* Make every symbol from index `from' up invisible to everything outside the
+   procedure that declared it.
+   Search accepts a symbol when its level is <= lexnest, and every procedure
+   body is compiled at the same depth (lexnest 1), so a finished procedure's
+   parameters stayed visible to the NEXT procedure: a second `a : integer'
+   was a duplicate (err 41) and an unqualified `a' inside procedure two read
+   procedure one's argument.  Level 0FFFFH fails `level <= lexnest' at every
+   depth a later procedure can be at, and by the time this runs the body that
+   could still legitimately see them is finished.
+   The symbols are relabelled, not popped: symtab[old].resvar holds an INDEX,
+   and a function's result variable is one of the entries being hidden. *)
+VAR p : CARDINAL ;
+BEGIN
+   p := from ;
+   WHILE p < symTop DO
+      symtab [p].level := 0FFFFH ;
+      INC (p)
+   END
+END HideLocals ;
+
+END CompilerSymbols.

+ 6 - 3
shell/Makefile

@@ -6,8 +6,8 @@ FLAGS = -fiso
 # pass-3 rollup on a compiler-size program ("too many errors in pass 3"), so
 # the import closure is generated first and the link then consumes it.  Phase 1
 # exiting 1 is the expected rollup, hence the `|| true`.
-MODS  = Shell Term TermCfg Keys Posix TextBuf Editor CompilerShared CompilerUtil CompilerSource CompilerEmit Compiler Runtime Linker Exec86
-LINK  = Shell.mod Term.o TermCfg.o Keys.o Posix.o TextBuf.o Editor.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerEmit.o Compiler.o Runtime.o Linker.o Exec86.o
+MODS  = Shell Term TermCfg Keys Posix TextBuf Editor CompilerShared CompilerUtil CompilerSource CompilerSymbols CompilerEmit Compiler Runtime Linker Exec86
+LINK  = Shell.mod Term.o TermCfg.o Keys.o Posix.o TextBuf.o Editor.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerSymbols.o CompilerEmit.o Compiler.o Runtime.o Linker.o Exec86.o
 
 all: tpshell tp3cfg
 
@@ -54,10 +54,13 @@ CompilerUtil.o: CompilerUtil.mod CompilerUtil.def
 CompilerSource.o: CompilerSource.mod CompilerSource.def CompilerShared.def
 	$(GM2) $(FLAGS) -c CompilerSource.mod
 
+CompilerSymbols.o: CompilerSymbols.mod CompilerSymbols.def CompilerShared.def CompilerSource.def CompilerUtil.def
+	$(GM2) $(FLAGS) -c CompilerSymbols.mod
+
 CompilerEmit.o: CompilerEmit.mod CompilerEmit.def CompilerShared.def
 	$(GM2) $(FLAGS) -c CompilerEmit.mod
 
-Compiler.o: Compiler.mod Compiler.def TextBuf.def Runtime.def CompilerShared.def CompilerUtil.def CompilerSource.def CompilerEmit.def
+Compiler.o: Compiler.mod Compiler.def TextBuf.def Runtime.def CompilerShared.def CompilerUtil.def CompilerSource.def CompilerSymbols.def CompilerEmit.def
 	$(GM2) $(FLAGS) -c Compiler.mod
 
 Runtime.o: Runtime.mod Runtime.def

+ 11 - 3
shell/tests/nonvacuity.sh

@@ -154,6 +154,7 @@ SAVED_CI=../tmp/nonvacuity.comimage.py
 SAVED_T=../tmp/nonvacuity.comtest.py
 SAVED_C=../tmp/nonvacuity.Compiler.mod
 SAVED_CS=../tmp/nonvacuity.CompilerSource.mod
+SAVED_CY=../tmp/nonvacuity.CompilerSymbols.mod
 SAVED_CE=../tmp/nonvacuity.CompilerEmit.mod
 SAVED_PY=../tmp/nonvacuity.modrm11.py
 SAVED_S=../tmp/nonvacuity.modrm11.s
@@ -165,6 +166,7 @@ cp tests/comimage.py "$SAVED_CI" || exit 1
 cp tests/comtest.py "$SAVED_T" || exit 1
 cp Compiler.mod "$SAVED_C" || exit 1
 cp CompilerSource.mod "$SAVED_CS" || exit 1
+cp CompilerSymbols.mod "$SAVED_CY" || exit 1
 cp CompilerEmit.mod "$SAVED_CE" || exit 1
 cp tests/probe/modrm11.py "$SAVED_PY" || exit 1
 cp tests/probe/modrm11.s "$SAVED_S" || exit 1
@@ -177,12 +179,14 @@ restore_all () {
     cp "$SAVED_T" tests/comtest.py
     cp "$SAVED_C" Compiler.mod
     cp "$SAVED_CS" CompilerSource.mod
+    cp "$SAVED_CY" CompilerSymbols.mod
     cp "$SAVED_CE" CompilerEmit.mod
     cp "$SAVED_PY" tests/probe/modrm11.py
     cp "$SAVED_S" tests/probe/modrm11.s
     "$GM2" -fiso -c CompilerShared.mod >/dev/null 2>&1
     "$GM2" -fiso -c CompilerUtil.mod >/dev/null 2>&1
     "$GM2" -fiso -c CompilerSource.mod >/dev/null 2>&1
+    "$GM2" -fiso -c CompilerSymbols.mod >/dev/null 2>&1
     "$GM2" -fiso -c CompilerEmit.mod >/dev/null 2>&1
     "$GM2" -fiso -c Runtime.mod >/dev/null 2>&1
     "$GM2" -fiso -c Exec86.mod >/dev/null 2>&1
@@ -213,6 +217,7 @@ trap 'exit 143' TERM
 restore_compiler () {
     cp "$SAVED_C" Compiler.mod
     cp "$SAVED_CS" CompilerSource.mod
+    cp "$SAVED_CY" CompilerSymbols.mod
     cp "$SAVED_CE" CompilerEmit.mod
 }
 
@@ -424,13 +429,14 @@ rebuild_compiler () {
     $GM2 -fiso -c CompilerShared.mod >/dev/null 2>&1 || return 1
     $GM2 -fiso -c CompilerUtil.mod >/dev/null 2>&1 || return 1
     $GM2 -fiso -c CompilerSource.mod >/dev/null 2>&1 || return 1
+    $GM2 -fiso -c CompilerSymbols.mod >/dev/null 2>&1 || return 1
     $GM2 -fiso -c CompilerEmit.mod >/dev/null 2>&1 || return 1
     $GM2 -fiso -c Compiler.mod >/dev/null 2>&1 || return 1
     $GM2 -fiso -fgen-module-list=tests/ct.lst -o /dev/null \
-        tests/ComTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerEmit.o Compiler.o Runtime.o Linker.o \
+        tests/ComTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerSymbols.o CompilerEmit.o Compiler.o Runtime.o Linker.o \
         >/dev/null 2>&1
     $GM2 -fiso -fuse-list=tests/ct.lst -o comtest \
-        tests/ComTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerEmit.o Compiler.o Runtime.o Linker.o \
+        tests/ComTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerSymbols.o CompilerEmit.o Compiler.o Runtime.o Linker.o \
         >/dev/null 2>&1 || return 1
     return 0
 }
@@ -708,10 +714,12 @@ mutate_file () {
 
 mutate_compiler () { mutate_file Compiler.mod "$SAVED_C" "$1" ; }
 mutate_emit () { mutate_file CompilerEmit.mod "$SAVED_CE" "$1" ; }
+mutate_symbols () { mutate_file CompilerSymbols.mod "$SAVED_CY" "$1" ; }
 
 restore_compiler () {
     cp "$SAVED_C" Compiler.mod
     cp "$SAVED_CS" CompilerSource.mod
+    cp "$SAVED_CY" CompilerSymbols.mod
     cp "$SAVED_CE" CompilerEmit.mod
 }
 
@@ -2031,7 +2039,7 @@ restore_compiler
 # `IBMCh(var Ch: Char)' collided with the global `Ch'.  Make the level test
 # unconditional and t73 is ERR 41 at the parameter name again.
 restore_compiler
-if mutate_compiler 's|      IF symtab \[i\].level = lexnest THEN|      IF TRUE THEN|'; then
+if mutate_symbols 's|      IF symtab \[i\].level = lexnest THEN|      IF TRUE THEN|'; then
     if rebuild_compiler; then
         expect_red "t73 red when a parameter may not shadow a global"             "expected: OK 340 8" tests/run_compile_tests.sh
     else

+ 2 - 2
shell/tests/run_com_exec.py

@@ -212,8 +212,8 @@ def ensure_comtest():
     # stale compiler, so a fix is invisible and a test that should have gone
     # red stays green.  The .mod files are kept in the list anyway, so editing a
     # source without running make also forces a relink.
-    objs = ["TextBuf.o", "Posix.o", "CompilerShared.o", "CompilerUtil.o", "CompilerSource.o", "CompilerEmit.o", "Compiler.o", "Runtime.o", "Linker.o"]
-    newer = objs + ["CompilerShared.mod", "CompilerUtil.mod", "CompilerSource.mod", "CompilerEmit.mod", "Compiler.mod", "Runtime.mod", "Linker.mod", "TextBuf.mod",
+    objs = ["TextBuf.o", "Posix.o", "CompilerShared.o", "CompilerUtil.o", "CompilerSource.o", "CompilerSymbols.o", "CompilerEmit.o", "Compiler.o", "Runtime.o", "Linker.o"]
+    newer = objs + ["CompilerShared.mod", "CompilerUtil.mod", "CompilerSource.mod", "CompilerSymbols.mod", "CompilerEmit.mod", "Compiler.mod", "Runtime.mod", "Linker.mod", "TextBuf.mod",
                     "Posix.c", os.path.join("tests", "ComTest.mod")]
     if os.path.exists(exe):
         t = os.path.getmtime(exe)

+ 3 - 3
shell/tests/run_com_tests.sh

@@ -39,7 +39,7 @@ if [ -n "$CHECK_ONLY" ]; then
     [ -d "$OUT" ] || { echo "RESULT: FAIL (no such directory: $OUT)"; exit 1; }
 else
 [ -f Posix.o ] || cc -c Posix.c || exit 1
-for m in TextBuf CompilerShared CompilerUtil CompilerSource CompilerEmit Compiler Runtime Linker; do
+for m in TextBuf CompilerShared CompilerUtil CompilerSource CompilerSymbols CompilerEmit Compiler Runtime Linker; do
    $GM2 $FLAGS -c $m.mod >../tmp/cm_c_$m 2>&1 \
       || { echo "COMPILE_FAIL $m"; grep -m5 "error:" ../tmp/cm_c_$m; exit 1; }
 done
@@ -48,11 +48,11 @@ $GM2 $FLAGS -c tests/ComTest.mod >../tmp/cm_c_ComTest 2>&1 \
 
 rm -f tests/ct.lst comtest
 $GM2 $FLAGS -fgen-module-list=tests/ct.lst -o /dev/null \
-    tests/ComTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerEmit.o Compiler.o Runtime.o Linker.o \
+    tests/ComTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerSymbols.o CompilerEmit.o Compiler.o Runtime.o Linker.o \
     >../tmp/cm_p1 2>&1
 p1=$?
 $GM2 $FLAGS -fuse-list=tests/ct.lst -o comtest \
-    tests/ComTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerEmit.o Compiler.o Runtime.o Linker.o \
+    tests/ComTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerSymbols.o CompilerEmit.o Compiler.o Runtime.o Linker.o \
     >../tmp/cm_p2 2>&1
 p2=$?
 if [ $p2 -ne 0 ]; then

+ 8 - 7
shell/tests/run_compile_tests.sh

@@ -27,9 +27,9 @@ mkdir -p ../tmp
 # So compiletest is rebuilt whenever it is older than ANY input: the object
 # files it links, the sources those came from, and its own source.
 STALE=no
-for f in compiletest TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerEmit.o Compiler.o Runtime.o \
+for f in compiletest TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerSymbols.o CompilerEmit.o Compiler.o Runtime.o \
          tests/CompileTest.mod TextBuf.mod Posix.c Posix.def \
-         CompilerShared.mod CompilerUtil.mod CompilerSource.mod CompilerEmit.mod Compiler.mod Runtime.mod Linker.mod; do
+         CompilerShared.mod CompilerUtil.mod CompilerSource.mod CompilerSymbols.mod CompilerEmit.mod Compiler.mod Runtime.mod Linker.mod; do
     if [ -e "$f" ] && [ compiletest -ot "$f" ]; then STALE=yes; break; fi
 done
 if [ "$STALE" = yes ]; then
@@ -37,17 +37,18 @@ if [ "$STALE" = yes ]; then
     rm -f compiletest
 fi
 
-if [ ! -f TextBuf.o ] || [ ! -f CompilerShared.o ] || [ ! -f CompilerUtil.o ] || [ ! -f CompilerSource.o ] || [ ! -f CompilerEmit.o ] \
+if [ ! -f TextBuf.o ] || [ ! -f CompilerShared.o ] || [ ! -f CompilerUtil.o ] || [ ! -f CompilerSource.o ] || [ ! -f CompilerSymbols.o ] || [ ! -f CompilerEmit.o ] \
    || [ ! -f Compiler.o ] || [ ! -f Posix.o ] || [ ! -f Runtime.o ] \
    || [ TextBuf.mod -nt TextBuf.o ] || [ CompilerShared.mod -nt CompilerShared.o ] \
    || [ CompilerShared.def -nt CompilerShared.o ] \
    || [ CompilerUtil.mod -nt CompilerUtil.o ] || [ CompilerUtil.def -nt CompilerUtil.o ] \
    || [ CompilerSource.mod -nt CompilerSource.o ] || [ CompilerSource.def -nt CompilerSource.o ] \
+   || [ CompilerSymbols.mod -nt CompilerSymbols.o ] || [ CompilerSymbols.def -nt CompilerSymbols.o ] \
    || [ CompilerEmit.mod -nt CompilerEmit.o ] || [ CompilerEmit.def -nt CompilerEmit.o ] \
    || [ Compiler.mod -nt Compiler.o ] \
    || [ Runtime.mod -nt Runtime.o ] || [ Runtime.def -nt Runtime.o ] \
    || [ Compiler.def -nt Compiler.o ] \
-   || [ CompilerShared.def -nt Compiler.o ] || [ CompilerUtil.def -nt Compiler.o ] || [ CompilerSource.def -nt Compiler.o ] || [ CompilerEmit.def -nt Compiler.o ] \
+   || [ CompilerShared.def -nt Compiler.o ] || [ CompilerUtil.def -nt Compiler.o ] || [ CompilerSource.def -nt Compiler.o ] || [ CompilerSymbols.def -nt Compiler.o ] || [ CompilerEmit.def -nt Compiler.o ] \
    || [ Posix.c -nt Posix.o ] || [ Posix.def -nt Posix.o ]; then
    echo "building support modules (source newer than object)..."
    # Runtime is listed because Compiler now links against it: the blob is
@@ -59,7 +60,7 @@ if [ ! -f TextBuf.o ] || [ ! -f CompilerShared.o ] || [ ! -f CompilerUtil.o ] ||
       cc -c Posix.c >../tmp/ct_c_Posix 2>&1 \
          || { echo "COMPILE_FAIL Posix"; grep -m5 "error:" ../tmp/ct_c_Posix; exit 1; }
    fi
-   for m in TextBuf CompilerShared CompilerUtil CompilerSource CompilerEmit Compiler Runtime; do
+   for m in TextBuf CompilerShared CompilerUtil CompilerSource CompilerSymbols CompilerEmit Compiler Runtime; do
       $GM2 $FLAGS -c $m.mod >../tmp/ct_c_$m 2>&1
       if [ $? -ne 0 ]; then
          echo "COMPILE_FAIL $m"
@@ -72,10 +73,10 @@ fi
 
 rm -f tests/ct.lst compiletest
 $GM2 $FLAGS -fgen-module-list=tests/ct.lst -o /dev/null \
-    tests/CompileTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerEmit.o Compiler.o Runtime.o >../tmp/ct_p1 2>&1
+    tests/CompileTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerSymbols.o CompilerEmit.o Compiler.o Runtime.o >../tmp/ct_p1 2>&1
 p1=$?
 $GM2 $FLAGS -fuse-list=tests/ct.lst -o compiletest \
-    tests/CompileTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerEmit.o Compiler.o Runtime.o >../tmp/ct_p2 2>&1
+    tests/CompileTest.mod TextBuf.o Posix.o CompilerShared.o CompilerUtil.o CompilerSource.o CompilerSymbols.o CompilerEmit.o Compiler.o Runtime.o >../tmp/ct_p2 2>&1
 p2=$?
 if [ $p2 -ne 0 ]; then
    echo "LINK_FAIL p1_rc=$p1 p2_rc=$p2"