-- file SLList.mesa 
-- last edited by Satterthwaite, September 16, 1982 8:26 am

DIRECTORY
  BcdDefs: TYPE USING [VersionStamp],
  CBinary: TYPE USING [DebugTab],
  CharIO: TYPE USING [PutChar, PutDecimal, PutString],
  CompilerUtil: TYPE USING [StreamId, TableId, PrintSymbols, PrintBodies],
  Environment: TYPE USING [PageNumber, PageCount],
  FileSegment: TYPE USING [Pages, nullPages],
  Heap: TYPE USING [systemZone],
  ListerOps: TYPE USING [],
  ListerUtil: TYPE USING [
    CreateStream, LoadBcd, LoadModule, Message, PutFileID, PutVersions,
    SetFileName, SetRoutineSymbols, UnknownModule],
  LiteralOps: TYPE USING [Initialize, Finalize],
  OSMiscOps: TYPE USING [FindFile, FileError],
  Runtime: TYPE USING [GetTableBase, GlobalFrame],
  Stream: TYPE USING [Handle, Delete],
  Strings: TYPE USING [String, AppendString],
  SymbolTable: TYPE USING [Acquire, Base, Release, SetCacheSize],
  TreeOps: TYPE USING [Finalize, Initialize];

SLList: PROGRAM
    IMPORTS
      CBinary, CharIO, CompilerUtil, Heap, ListerUtil,
      LiteralOps, OSMiscOps, Runtime, Stream, Strings, SymbolTable, TreeOps
    EXPORTS CompilerUtil, ListerOps = {
  OPEN ListerUtil;
  
 -- output streams
 
  out: Stream.Handle ← NIL;
  
  OpenOutput: PROC [root: Strings.String] = {
    outName: STRING ← [40];
    ListerUtil.SetFileName[outName, root, "sl"L];
    out ← ListerUtil.CreateStream[outName]};
    
  CloseOutput: PROC = {
    Stream.Delete[out];  out ← NIL};
    
 -- symbol table bases
 
  symbols: SymbolTable.Base ← NIL;

 -- overall control
 
  CommandOption: TYPE = {none, bodies, symbols, both};
  MapOptions: ARRAY BOOL OF ARRAY BOOL OF CommandOption = [
    [none, bodies], [symbols, both]];
    
  SymbolSeg: TYPE = RECORD [
    base: Environment.PageNumber,
    pages: Environment.PageCount];
      

  PrintSyms: PROC [
      sseg: FileSegment.Pages, option: CommandOption, versions: BOOL] = {
    SymbolTable.SetCacheSize[0];	-- flush cache
    symbols ← SymbolTable.Acquire[sseg];
    ListerUtil.SetRoutineSymbols[symbols];
    IF versions THEN {
      version, creator: BcdDefs.VersionStamp;
      version ← symbols.stHandle.version;
      creator ← symbols.stHandle.creator;
      ListerUtil.PutVersions[out, @version, @creator]};
    TreeOps.Initialize[NIL, NIL]; LiteralOps.Initialize[NIL, Heap.systemZone];
    IF option = symbols OR option = both THEN
      CompilerUtil.PrintSymbols[NIL, symbols.stHandle.definitionsFile];
    IF option = bodies OR option = both THEN CompilerUtil.PrintBodies[NIL];
    LiteralOps.Finalize[];  TreeOps.Finalize[];
    SymbolTable.Release[symbols]; symbols ← NIL};
    
  MakeBcdFilename: PROC [bcd, root: Strings.String] = {
    Strings.AppendString[bcd, root];
    FOR i: CARDINAL IN [0..bcd.length) DO IF bcd[i] = '. THEN RETURN ENDLOOP;
    Strings.AppendString[bcd, ".bcd"L]};
    
  DoSymbols: PROC [root: Strings.String, option: CommandOption] = {
    OPEN ListerUtil;
    bcdFile: Strings.String ← [100];
    bcdSeg, sSeg: FileSegment.Pages;
    MakeBcdFilename[bcdFile, root];
    bcdSeg ← LoadBcd[bcdFile];
    IF bcdSeg = FileSegment.nullPages THEN GO TO NoFile;
    [symbols: sSeg] ← LoadModule[bcdSeg, root ! UnknownModule => {GOTO NoModule}];
    IF sSeg = FileSegment.nullPages THEN GO TO NoSymbols;
    OpenOutput[root];
    ListerUtil.PutFileID[out];
    PrintSyms[sSeg, option, FALSE];
    CloseOutput[];
    EXITS
      NoFile => Message["File could not be opened"L];
      NoModule => {
        Message["File does not contain module "L]; Message[root]};
      NoSymbols => Message["Symbols not available"L]};
    
  DoSymbolSegment: PROC [
      root: Strings.String, pages: SymbolSeg, option: CommandOption] = {
    bcdFile: Strings.String ← [100];
    sseg: FileSegment.Pages;
    MakeBcdFilename[bcdFile, root];
    sseg ← [
      file: OSMiscOps.FindFile[bcdFile ! OSMiscOps.FileError => {GO TO NoFile}],
      span: [pages.base, pages.pages] --! SwapProblem[] => {GO TO BadSegment}--];
    OpenOutput[root];
    CharIO.PutString[out, "Symbol Table in file: "L];
    CharIO.PutString[out, root];
    CharIO.PutString[out, ", base: "L];  CharIO.PutDecimal[out, pages.base];
    CharIO.PutString[out, ", pages: "L]; CharIO.PutDecimal[out, pages.pages];
    CharIO.PutChar[out, '\n];
    PrintSyms[sseg, option, TRUE];
    EXITS
      NoFile => Message["File not found"L];
      --BadSegment => Message["Bad Segment"L]--};
    
  ListSymbols: PUBLIC PROC [root: Strings.String, symbols, trees: BOOL] = {
    DoSymbols[root, MapOptions[symbols][trees]]};
    

-- replacements for compiler utilities

 -- CompilerUtil
 
  AcquireTable: PUBLIC PROC [id: CompilerUtil.TableId] RETURNS [LONG POINTER] = {
    RETURN[
      IF id # $debug THEN NIL
      ELSE Runtime.GetTableBase[Runtime.GlobalFrame[CBinary.DebugTab]]]};
    
  ReleaseTable: PUBLIC PROC [CompilerUtil.TableId] = {};

  AcquireStream: PUBLIC PROC [id: CompilerUtil.StreamId] RETURNS [Stream.Handle] = {
    RETURN[IF id = $log THEN out ELSE NIL]};
    
  ReleaseStream: PUBLIC PROC [CompilerUtil.StreamId] = {};    
  
  }.