DIRECTORY
  PrintingDefs USING [OutCode],
  String USING [EqualString],
  Storage USING [FreeString, CopyString],
  SymbolTableDefs USING [SymbolType, SymbolEntry];
  
SymbolTableImpl: PROGRAM
    IMPORTS PrintingDefs, String, Storage
    EXPORTS SymbolTableDefs = {
    
    foundSlot: CARDINAL;
    symbolTableSize: CARDINAL = 200;
    blockNestingLevel: CARDINAL ← 0;
    echoSymbolTables: PUBLIC BOOLEAN;  -- echo symbol tables to executive
			               -- at the end of each block
    
    SymbolTable: ARRAY [0..symbolTableSize) OF SymbolTableDefs.SymbolEntry;
    
    
  InitializeSymbolTable: PUBLIC PROCEDURE [] = {
  
      blockNestingLevel ← 0;
      FOR i: CARDINAL IN [0..symbolTableSize) DO
          SymbolTable[i].type ← unused;  ENDLOOP;
      };
      
      
  EnterBlock: PUBLIC PROCEDURE [] = {
  
      blockNestingLevel ← blockNestingLevel + 1;
      };
    

  ExitBlock: PUBLIC PROCEDURE [] = {
  
      FOR i: CARDINAL IN [0..symbolTableSize) DO
          IF SymbolTable[i].type # unused
	  AND SymbolTable[i].blockLevel = blockNestingLevel THEN {
	      Storage.FreeString[SymbolTable[i].name];
	      Storage.FreeString[SymbolTable[i].typeName];
	      SymbolTable[i].type ← unused;  };
	  ENDLOOP;
      blockNestingLevel ← blockNestingLevel - 1;
      };
    

  EnterSymbol: PUBLIC PROCEDURE [symName: LONG STRING, symType: SymbolTableDefs.SymbolType,
    symBaseType: SymbolTableDefs.SymbolType, symTypeName: LONG STRING,
    symPointerCount: CARDINAL, blockHeader: BOOLEAN ← FALSE] = {
    
      FOR i: CARDINAL IN [0..symbolTableSize) DO
          IF SymbolTable[i].type = unused THEN GOTO FoundOne;
          REPEAT
              FoundOne => foundSlot ← i;
	      FINISHED => ERROR;
          ENDLOOP;
      SymbolTable[foundSlot].name ← Storage.CopyString[symName];
      SymbolTable[foundSlot].type ← symType;
      SymbolTable[foundSlot].baseType ← symBaseType;
      SymbolTable[foundSlot].typeName ← Storage.CopyString[symTypeName];
      SymbolTable[foundSlot].pointerCount ← symPointerCount;
      SymbolTable[foundSlot].blockLevel ←
          				IF NOT blockHeader
          				THEN blockNestingLevel
	 				ELSE blockNestingLevel + 1;
      };
    
    
  LookUpSymbol: PUBLIC PROCEDURE[symName: LONG STRING]
      RETURNS [symType: SymbolTableDefs.SymbolType,
          symBaseType: SymbolTableDefs.SymbolType,
          symTypeName: LONG STRING, symPointerCount: CARDINAL] = {
      
      FOR blockBeingSearched: CARDINAL DECREASING IN [0..blockNestingLevel] DO
	  FOR i: CARDINAL IN [0..symbolTableSize) DO
              IF SymbolTable[i].type # unused
	      AND SymbolTable[i].blockLevel = blockBeingSearched
	      AND String.EqualString[symName, SymbolTable[i].name] THEN {
	          symType ← SymbolTable[i].type;
	          symBaseType ← SymbolTable[i].baseType;
	          symTypeName ← SymbolTable[i].typeName;
	          symPointerCount ← SymbolTable[i].pointerCount;
	          RETURN;  };
	      ENDLOOP;
	  ENDLOOP;
      RETURN [none, none, NIL, 0];
      };
      
      
  PrintSymbolTable: PUBLIC PROCEDURE[] = {
      oneChar: LONG STRING ← [1];
      padChars: CARDINAL;
  
      IF NOT echoSymbolTables THEN RETURN;
      PrintingDefs.OutCode["--*** SYMBOL TABLE CONTENTS IN THIS BLOCK ***\n"L, 0];
      PrintingDefs.OutCode[
          "--name        type       basetype   typeName            ↑s  blockLevel\n"L, 0];
      PrintingDefs.OutCode[
          "--====        ====       ========   ========            ==  ==========\n"L, 0];
      oneChar.length ← 1;
      FOR i: CARDINAL IN [0..symbolTableSize) DO
          IF SymbolTable[i].type # unused THEN {
	      PrintingDefs.OutCode["--"L, 0];
              PrintingDefs.OutCode[SymbolTable[i].name, 0];
	      THROUGH [SymbolTable[i].name.length..12) DO
	      			 -- pad to size 12 field
	          PrintingDefs.OutCode[" "L, 0];  ENDLOOP;
	      SELECT SymbolTable[i].type FROM
	          none        => PrintingDefs.OutCode["none       "L, 0];
	          short       => PrintingDefs.OutCode["short      "L, 0];
	          long        => PrintingDefs.OutCode["long       "L, 0];
	          pointer     => PrintingDefs.OutCode["pointer    "L, 0];
	          array       => PrintingDefs.OutCode["array      "L, 0];
	          arrayArray  => PrintingDefs.OutCode["arrayArray "L, 0];
	          structure   => PrintingDefs.OutCode["structure  "L, 0];
	          union       => PrintingDefs.OutCode["union      "L, 0];
	          enumeration => PrintingDefs.OutCode["enumeration"L, 0];
	          real        => PrintingDefs.OutCode["real       "L, 0];
	          double      => PrintingDefs.OutCode["double     "L, 0];
	          boolean     => PrintingDefs.OutCode["boolean    "L, 0];
		  ENDCASE     => PrintingDefs.OutCode["ERROR      "L, 0];
	      SELECT SymbolTable[i].baseType FROM
	          none        => PrintingDefs.OutCode["none       "L, 0];
	          short       => PrintingDefs.OutCode["short      "L, 0];
	          long        => PrintingDefs.OutCode["long       "L, 0];
	          pointer     => PrintingDefs.OutCode["pointer    "L, 0];
	          array       => PrintingDefs.OutCode["array      "L, 0];
	          arrayArray  => PrintingDefs.OutCode["arrayArray "L, 0];
	          structure   => PrintingDefs.OutCode["structure  "L, 0];
	          union       => PrintingDefs.OutCode["union      "L, 0];
	          enumeration => PrintingDefs.OutCode["enumeration"L, 0];
	          real        => PrintingDefs.OutCode["real       "L, 0];
	          double      => PrintingDefs.OutCode["double     "L, 0];
	          boolean     => PrintingDefs.OutCode["boolean    "L, 0];
		  ENDCASE     => PrintingDefs.OutCode["ERROR      "L, 0];
	      PrintingDefs.OutCode[SymbolTable[i].typeName, 0];
	      padChars ← IF SymbolTable[i].typeName = NIL THEN 0
	                 ELSE SymbolTable[i].typeName.length;
	      THROUGH [padChars..20) DO		 -- pad to size 20 field
	          PrintingDefs.OutCode[" "L, 0];  ENDLOOP;
	      oneChar.text[0] ← '0 + SymbolTable[i].pointerCount;
	      PrintingDefs.OutCode[oneChar, 0];
	      PrintingDefs.OutCode["       "L, 0];
	      oneChar.text[0] ← '0 + SymbolTable[i].blockLevel;
	      PrintingDefs.OutCode[oneChar, 0];
	      PrintingDefs.OutCode["\n"L, 0];  };
	  ENDLOOP;
      };
      
	  
  FinalizeSymbolTable: PUBLIC PROCEDURE[] = {
      
      IF FALSE THEN FOR i: CARDINAL IN [0..symbolTableSize) DO
          IF SymbolTable[i].type # unused THEN {
	      Storage.FreeString[SymbolTable[i].name];
	      Storage.FreeString[SymbolTable[i].typeName];
	      SymbolTable[i].type ← unused;  };
	  ENDLOOP;
      };
      
  }.