-- file Temp.mesa
-- last modified by Sweet, 9-Oct-81 11:38:06
-- last modified by Satterthwaite, December 16, 1982 10:15 am

DIRECTORY
  Alloc: TYPE USING [Notifier],
  Code: TYPE USING [
    bodyComRetLabel, bodyOutRecord, bodyRetLabel, curctxlvl, fileindex, 
    firstTemp, framesz, inlineFileIndex, mainBody, tempcontext, tempstart],
  CodeDefs: TYPE USING [
    Base, codeType, Lexeme, StackIndex, StatementStateRecord, TempStateRecord],
  ComData: TYPE USING [bodyIndex, globalFrameSize, mainCtx],
  FOpCodes: TYPE USING [qFF],
  Log: TYPE USING [Error, ErrorSei],
  P5: TYPE USING [PushLex],
  P5U: TYPE USING [LabelAlloc, Out0, WordsForString],
  PrincOps: TYPE USING [MaxFrameSize],
  Stack: TYPE USING [Dump, New, Prefix],
  SymbolOps: TYPE USING [MakeCtxSe, NewCtx, NextSe, SetSeLink],
  Symbols: TYPE USING [
    Base, BitAddress, bodyType, CTXNull, ctxType, HTNull, ISEIndex, ISENull, lZ,
    seType, typeANY, WordLength];


Temp: PROGRAM
    IMPORTS MPtr: ComData, CPtr: Code, P5U, Log, P5, Stack, SymbolOps 
    EXPORTS CodeDefs, P5 =
  BEGIN
  OPEN CodeDefs;

  -- imported definitions

  BitAddress: TYPE = Symbols.BitAddress;
  ISEIndex: TYPE = Symbols.ISEIndex;
  ISENull: ISEIndex = Symbols.ISENull;
  WordLength: CARDINAL = Symbols.WordLength;


  InvalidHeapRelease: SIGNAL = CODE;
  InvalidTempRelease: SIGNAL = CODE;


  seb: Symbols.Base;		-- semantic entry base (local copy)
  ctxb: Symbols.Base;		-- context entry base (local copy)
  cb: CodeDefs.Base;		-- code base (local copy)
  bb: Symbols.Base;		-- body table base (local copy)

  TempNotify:  PUBLIC Alloc.Notifier =
    BEGIN  -- called by allocator whenever table area is repacked
    seb ← base[Symbols.seType];
    ctxb ← base[Symbols.ctxType];
    cb ← base[codeType];
    bb ← base[Symbols.bodyType];
    END;


  pendTempList, tempListPool, heapList: ISEIndex;

  TempInit: PUBLIC PROC =
    BEGIN -- called at beginning of MODULE to init stack stuff
    pendTempList ← tempListPool ← heapList ← ISENull;
    CPtr.tempcontext ← SymbolOps.NewCtx[Symbols.lZ];
    END;



  PushTempState: PUBLIC PROC [p: POINTER TO TempStateRecord, newfs: CARDINAL] =
    BEGIN
    p↑ ← [pendtemplist: pendTempList, templist: ISENull,
	    heaplist: heapList, tempctxlvl: ctxb[CPtr.tempcontext].level,
	    firstTemp: CPtr.firstTemp, tempstart: CPtr.tempstart,
	    framesz: CPtr.framesz];
    pendTempList ← heapList ← ISENull;
    ctxb[CPtr.tempcontext].level ← CPtr.curctxlvl;
    CPtr.firstTemp ← CPtr.tempstart ← CPtr.framesz ← newfs;
    END;



  PopTempState:  PUBLIC PROC [p: POINTER TO TempStateRecord] =
    BEGIN
    PurgePendTempList[];
    [pendtemplist: pendTempList, templist: ,
      heaplist: heapList, tempctxlvl: ctxb[CPtr.tempcontext].level,
      tempstart: CPtr.tempstart, firstTemp: CPtr.firstTemp,
      framesz: CPtr.framesz] ← p↑;
    END;


  PushStatementState: PUBLIC PROC [p: POINTER TO StatementStateRecord] =
    BEGIN
    Stack.Dump[];
    p↑ ← [retLabel: CPtr.bodyRetLabel,
	    comRetLabel: CPtr.bodyComRetLabel,
	    outRecord: CPtr.bodyOutRecord,
	    pendtemplist: pendTempList, 
	    stkPtr: Stack.New[], 
	    inlineFileIndex: CPtr.inlineFileIndex];
    CPtr.bodyRetLabel ← P5U.LabelAlloc[];
    CPtr.bodyComRetLabel ← P5U.LabelAlloc[];
    pendTempList ← ISENull;
    CPtr.inlineFileIndex ← CPtr.fileindex;
    END;



  PopStatementState:  PUBLIC PROC [p: POINTER TO StatementStateRecord] =
    BEGIN
    sp: StackIndex;
    PurgePendTempList[];
    [retLabel: CPtr.bodyRetLabel,
      comRetLabel: CPtr.bodyComRetLabel,
      pendtemplist: pendTempList,
      outRecord: CPtr.bodyOutRecord,
      stkPtr: sp,
      inlineFileIndex: CPtr.inlineFileIndex] ← p↑;
    Stack.Prefix[sp];
    END;


  GenTempLex:  PUBLIC PROC [nwords: CARDINAL] RETURNS [l: Lexeme.se] =
    BEGIN
    l ← CreateTempLex[CPtr.tempstart, nwords];
    ReleaseTempLex[l];
    BumpTemps[nwords];
    RETURN
    END;


  GenAnonLex:  PUBLIC PROC [nwords: CARDINAL] RETURNS [l: Lexeme.se] =
    BEGIN
    l ← CreateTempLex[CPtr.tempstart, nwords];
    BumpTemps[nwords];
    RETURN
    END;


  GenStringBodyLex:  PUBLIC PROC [nchars: CARDINAL] RETURNS [l: Lexeme.se] =
    BEGIN
    nwords: CARDINAL = P5U.WordsForString[nchars];
    IF ~CPtr.mainBody THEN l ← GenAnonLex[nwords]
    ELSE
      BEGIN
      l ← CreateTempLex[MPtr.globalFrameSize, nwords];
      seb[l.lexsei].idCtx ← MPtr.mainCtx;
      MPtr.globalFrameSize ← MPtr.globalFrameSize + nwords;
      IF MPtr.globalFrameSize > PrincOps.MaxFrameSize THEN
	Log.Error[addressOverflow];
      END;
    RETURN
    END;


  BumpTemps: PROC [n: CARDINAL] =
    BEGIN -- updates CPtr.tempstart (and CPtr.framesz, if necessary)
    CPtr.framesz ← MAX[CPtr.tempstart ← CPtr.tempstart+n, CPtr.framesz];
    IF CPtr.framesz > PrincOps.MaxFrameSize THEN
      Log.ErrorSei[addressOverflow, bb[MPtr.bodyIndex].id];
    END;


  PurgePendTempList:  PUBLIC PROC =
    BEGIN -- after each statment the temp sei's are released
    sei: ISEIndex ← pendTempList;
    nSei: ISEIndex;
    WHILE sei # ISENull DO
      nSei ← SymbolOps.NextSe[sei];
      ReleaseTempSei[sei];
      sei ← nSei;
      ENDLOOP;
    pendTempList ← ISENull;
    END;


  PurgeHeapList: PUBLIC PROC [oldheaplist: ISEIndex] =
    BEGIN -- after each statment the heap chunks are freed
    sei: ISEIndex ← heapList;
    nSei: ISEIndex;
    l: Lexeme.se ← Lexeme[se[NULL]];
    WHILE sei # ISENull DO
      nSei ← SymbolOps.NextSe[sei];
      l.lexsei ← sei;
      FreeHeapLex[l];
      sei ← nSei;
      ENDLOOP;
    heapList ← oldheaplist;
    END;


  FreeHeapLex: PUBLIC PROC [l: Lexeme.se] =
    BEGIN
    P5.PushLex[l];
    P5U.Out0[FOpCodes.qFF];
    ReleaseTempSei[l.lexsei];
    END;

  PushHeapList: PUBLIC PROC RETURNS [oldheaplist: ISEIndex] =
    BEGIN
    oldheaplist ← heapList;
    heapList ← ISENull;
    RETURN
    END;


  GenHeapLex: PUBLIC PROC RETURNS [l: Lexeme.se] =
    BEGIN
    l ← GenAnonLex[1];
    SymbolOps.SetSeLink[l.lexsei, heapList];
    heapList ← l.lexsei;
    RETURN
    END;


  FreeTempSei: PUBLIC PROC [sei: ISEIndex] =
    BEGIN -- de-links a temp sei from its chain
    SymbolOps.SetSeLink[sei, tempListPool];
    tempListPool ← sei;
    END;


  ReleaseTempSei:  PROC [sei: ISEIndex] =
    BEGIN -- puts a temp sei on the templist
    a: BitAddress = seb[sei].idValue;
    CPtr.tempstart ← MIN[CPtr.tempstart, a.wd];
    FreeTempSei[sei];
    END;


  CreateTempLex: PUBLIC PROC [wdoffset, nwords: INTEGER] RETURNS [Lexeme.se] =
    BEGIN -- inits (if nec) a new temp sei cell
    sei: ISEIndex;
    IF tempListPool # ISENull THEN
      BEGIN
      sei ← tempListPool;
      tempListPool ← SymbolOps.NextSe[sei];
      seb[sei].idCtx ← CPtr.tempcontext;
      END
    ELSE
      BEGIN
      sei ← SymbolOps.MakeCtxSe[Symbols.HTNull, Symbols.CTXNull];
      seb[sei].constant ← seb[sei].extended ← seb[sei].linkSpace ← FALSE;
      seb[sei].immutable ← TRUE;
      seb[sei].idCtx ← CPtr.tempcontext;
      seb[sei].idType ← Symbols.typeANY;
      END;
    SymbolOps.SetSeLink[sei, ISENull];
    seb[sei].idValue ← BitAddress[wd: wdoffset, bd: 0];
    seb[sei].idInfo ← nwords*WordLength;
    RETURN [[se[lexsei: sei]]]
    END;


  ReleaseTempLex: PUBLIC PROC [l: Lexeme.se] =
    BEGIN -- releases a cell of temporary storage
    IF SymbolOps.NextSe[l.lexsei] = ISENull THEN
      BEGIN
      SymbolOps.SetSeLink[l.lexsei, pendTempList];
      pendTempList ← l.lexsei;
      END;
    END;

  END.