DIRECTORY Alloc: TYPE USING [Notifier, AddNotify, DropNotify], Code: TYPE USING [ actenable, bodyComRetLabel, bodyFileIndex, bodyInRecord, bodyOutRecord, bodyRetLabel, caseCVState, catchcount, catchoutrecord, cfSize, codeptr, curctxlvl, fileindex, firstTemp, framesz, inlineFileIndex, mainBody, reentryLabel, StackNotEmptyAtStatement, substenable, tailJumpOK, tempcontext, tempstart, xtracting], CodeDefs: TYPE USING [ AddressNotify, Base, CallsNotify, CCIndex, CCNull, codeType, ConstructorNotify, CountingNotify, CrossJumpNotify, DJumpsNotify, ExpressionNotify, FinalNotify, FlowExpressionNotify, FlowNotify, JumpCCNull, LabelCCIndex, LabelCCNull, Lexeme, MaxParmsInStack, NULLfileindex, NullLex, OutCodeNotify, PeepholeNotify, SelectionNotify, StatementNotify, StatementStateRecord, StoreNotify, TempNotify, VarBasicsNotify, VarIndex, VarMoveNotify, VarUtilsNotify], ComData: TYPE USING [ bodyIndex, globalFrameSize, nErrors, objectBytes, stopping, table, textIndex], FOpCodes: TYPE USING [ qLADRB, qLI, qLINKB, qLL, qME, qMEL, qMXD, qMXDL, qPSD, qRET, qSG], P5: TYPE USING [ BuildArgRecord, EndCodeFile, Exp, ExtractFrom, Fixup, FreeTempSei, GenStringBodyLex, LogHeapFree, OutBinary, PopStatementState, PRetLex, ProcessGlobalStrings, ProcessLocalStrings, PurgePendTempList, PushArgRecord, PushStatementState, StartCodeFile, StatementTree, TempInit], P5L: TYPE USING [LoadAddress, TOSAddrLex, TOSLex, VarFinal, VarForLex], P5S: TYPE USING [], P5U: TYPE USING [ CgenUtilInit, CgenUtilNotify, CreateLabel, DeleteCell, InsertLabel, LabelAlloc, NextVar, OperandType, Out0, Out1, OutJump, OutSource, PushLitVal, TreeLiteralValue, WordsForSei], PrincOps: TYPE USING [globalbase, localbase], Stack: TYPE USING [ Decr, Depth, Dump, Incr, Init, Load, Off, On, Reset, StackImplNotify, Top], SymbolOps: TYPE USING [EnumerateBodies, NextSe, TransferTypes], Symbols: TYPE USING [ Base, bodyType, BTIndex, CBTIndex, CSEIndex, CSENull, ctxType, ISEIndex, ISENull, RecordSEIndex, RecordSENull, RootBti, seType], Tree: TYPE USING [Base, Index, Link, Null, treeType], TreeOps: TYPE USING [ FreeNode, FreeTree, MakeList, MakeNode, PushList, PushNode, PushSe, PushTree, SearchList]; Driver: PROGRAM IMPORTS Alloc, MPtr: ComData, CPtr: Code, CodeDefs, P5, P5L, P5U, Stack, SymbolOps, TreeOps EXPORTS P5, P5S = BEGIN OPEN CodeDefs; localbase: CARDINAL = PrincOps.localbase; globalbase: CARDINAL = PrincOps.globalbase; CSEIndex: TYPE = Symbols.CSEIndex; CSENull: CSEIndex = Symbols.CSENull; ISEIndex: TYPE = Symbols.ISEIndex; ISENull: ISEIndex = Symbols.ISENull; RecordSEIndex: TYPE = Symbols.RecordSEIndex; RecordSENull: RecordSEIndex = Symbols.RecordSENull; tb: Tree.Base; -- tree base (local copy) seb: Symbols.Base; -- semantic entry base (local copy) ctxb: Symbols.Base; -- context entry base (local copy) bb: Symbols.Base; -- body entry base (local copy) cb: CodeDefs.Base; -- code base (local copy) DriverNotify: Alloc.Notifier = BEGIN -- called by allocator whenever table area is repacked seb _ base[Symbols.seType]; ctxb _ base[Symbols.ctxType]; bb _ base[Symbols.bodyType]; tb _ base[Tree.treeType]; cb _ base[codeType]; P5U.CgenUtilNotify[base]; AddressNotify[base]; ExpressionNotify[base]; FlowExpressionNotify[base]; FlowNotify[base]; Stack.StackImplNotify[base]; TempNotify[base]; StatementNotify[base]; SelectionNotify[base]; ConstructorNotify[base]; StoreNotify[base]; CountingNotify[base]; CallsNotify[base]; OutCodeNotify[base]; FinalNotify[base]; CrossJumpNotify[base]; DJumpsNotify[base]; PeepholeNotify[base]; VarUtilsNotify[base]; VarBasicsNotify[base]; VarMoveNotify[base]; END; CodePassError: PUBLIC ERROR [n: CARDINAL] = CODE; P5Error: PUBLIC PROC [n: CARDINAL] = {ERROR CodePassError[n]}; codeStart: LabelCCIndex; mLock: Tree.Link; longLock: BOOL; Module: PUBLIC PROC = BEGIN -- main driver for code generation (MPtr.table).AddNotify[DriverNotify]; CPtr.bodyInRecord _ CPtr.bodyOutRecord _ RecordSENull; P5U.CgenUtilInit[MPtr.table]; P5.TempInit[]; Stack.Init[]; Stack.Off[]; CPtr.inlineFileIndex _ NULLfileindex; CPtr.xtracting _ FALSE; CPtr.caseCVState _ none; CPtr.catchoutrecord _ RecordSENull; CPtr.catchcount _ 0; CPtr.actenable _ CPtr.substenable _ LabelCCNull; CPtr.codeptr _ codeStart _ LabelCCNull; P5.StartCodeFile[]; [] _ SymbolOps.EnumerateBodies[Symbols.RootBti, Body]; MPtr.objectBytes _ P5.EndCodeFile[]; Stack.Reset[]; P5L.VarFinal[]; (MPtr.table).DropNotify[DriverNotify] END; Body: PROC [bti: Symbols.BTIndex] RETURNS [stop: BOOL _ FALSE] = BEGIN WITH body: bb[bti] SELECT FROM Callable => IF ~body.inline THEN ProcBody[LOOPHOLE[bti]]; ENDCASE; END; ProcBody: PROC [bti: Symbols.CBTIndex] = BEGIN -- produces code for body bodyNode: Tree.Index; CPtr.mainBody _ (bti = Symbols.RootBti); MPtr.bodyIndex _ bti; MPtr.textIndex _ bb[bti].sourceIndex; WITH bi: bb[bti].info SELECT FROM Internal => BEGIN bodyNode _ bi.bodyTree; CPtr.curctxlvl _ bb[bti].level; [CPtr.bodyInRecord, CPtr.bodyOutRecord] _ SymbolOps.TransferTypes[bb[bti].ioType]; CPtr.firstTemp _ CPtr.tempstart _ CPtr.framesz _ bi.frameSize; CPtr.cfSize _ 0; CPtr.bodyFileIndex _ CPtr.fileindex _ bb[bti].sourceIndex; CPtr.tailJumpOK _ TRUE; CPtr.bodyRetLabel _ P5U.LabelAlloc[]; CPtr.bodyComRetLabel _ P5U.LabelAlloc[]; CPtr.codeptr _ CCNull; codeStart _ P5U.CreateLabel[]; P5U.OutSource[bb[bti].sourceIndex]; ctxb[CPtr.tempcontext].level _ CPtr.curctxlvl; IF Stack.Depth[] # 0 THEN SIGNAL CPtr.StackNotEmptyAtStatement; WITH bb[bti] SELECT FROM Inner => P5U.Out1[FOpCodes.qLINKB, frameOffset-localbase]; ENDCASE; Stack.On[]; CPtr.reentryLabel _ P5U.CreateLabel[]; -- for reentry on tail recursion PopInVals[CPtr.bodyInRecord, FALSE]; P5.PurgePendTempList[]; IF CPtr.mainBody THEN MPtr.globalFrameSize _ P5.ProcessGlobalStrings[MPtr.globalFrameSize]; CPtr.firstTemp _ CPtr.tempstart _ P5.ProcessLocalStrings[CPtr.tempstart, bi.thread]; bi.frameSize _ CPtr.framesz _ MAX [CPtr.framesz, CPtr.tempstart]; IF CPtr.mainBody AND MPtr.stopping THEN {P5U.Out1[FOpCodes.qLADRB, 0]; P5U.Out1[FOpCodes.qSG, globalbase]}; IF bb[bti].entry THEN SetLock[tb[bodyNode].son[4]] ELSE mLock _ Tree.Null; tb[bodyNode].son[2] _ P5.StatementTree[tb[bodyNode].son[2]]; tb[bodyNode].son[3] _ P5.StatementTree[tb[bodyNode].son[3]]; tb[bodyNode].son[1] _ Tree.Null; IF Stack.Depth[] # 0 THEN SIGNAL CPtr.StackNotEmptyAtStatement; InsertRetLabels[mLock # Tree.Null]; Stack.Reset[]; IF CPtr.mainBody AND MPtr.stopping THEN {P5U.Out1[FOpCodes.qLI, 0]; P5U.Out1[FOpCodes.qSG, globalbase]}; Stack.Off[]; P5U.Out0[FOpCodes.qRET]; P5.PurgePendTempList[]; bi.frameSize _ CPtr.framesz; IF MPtr.nErrors = 0 THEN P5.Fixup[codeStart, bb[bti].entryIndex]; END; ENDCASE; TreeOps.FreeNode[bodyNode]; IF MPtr.nErrors = 0 THEN P5.OutBinary[bti, codeStart] ELSE BEGIN c, next: CCIndex; FOR c _ codeStart, next WHILE c # CCNull DO next _ cb[c].flink; P5U.DeleteCell[c]; ENDLOOP; END; END; SSubst: PROC [node: Tree.Index] RETURNS [nRets: CARDINAL] = BEGIN saveEnable: LabelCCIndex = CPtr.substenable; ss: StatementStateRecord; tSei: CSEIndex = P5U.OperandType[tb[node].son[1]]; P5.PushStatementState[@ss]; CPtr.substenable _ CPtr.actenable; CPtr.bodyOutRecord _ SymbolOps.TransferTypes[tSei].typeOut; tb[node].son[2] _ P5.StatementTree[tb[node].son[2]]; IF Stack.Depth[] # 0 THEN SIGNAL CPtr.StackNotEmptyAtStatement; InsertRetLabels[FALSE]; -- if entry procedure, lock already dealt with Stack.Reset[]; nRets _ P5U.WordsForSei[CPtr.bodyOutRecord]; P5.PopStatementState[@ss]; CPtr.substenable _ saveEnable; RETURN END; InsertRetLabels: PROC [monitored: BOOL] = BEGIN IF CPtr.bodyComRetLabel # LabelCCNull THEN BEGIN P5U.InsertLabel[CPtr.bodyComRetLabel]; IF monitored THEN ReleaseLock[]; IF cb[CPtr.bodyComRetLabel].jumplist # JumpCCNull THEN PushRetVals[]; P5U.InsertLabel[CPtr.bodyRetLabel]; CPtr.bodyComRetLabel _ LabelCCNull; CPtr.bodyRetLabel _ LabelCCNull; END; END; Subst: PUBLIC PROC [node: Tree.Index] = BEGIN [] _ SSubst[node]; END; SubstExp: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN nRets: CARDINAL = SSubst[node]; RETURN [P5.PRetLex[nRets, node, FALSE]] END; PopInVals: PUBLIC PROC [irecord: RecordSEIndex, isenable: BOOL] = BEGIN nParms: CARDINAL; r: VarIndex; t: Tree.Link; sei: ISEIndex; np: CARDINAL _ 0; IF irecord = CSENull THEN RETURN; nParms _ P5U.WordsForSei[irecord]; IF nParms = 0 THEN RETURN; IF isenable THEN IF nParms <= 1 THEN RETURN ELSE P5U.Out1[FOpCodes.qLL,localbase+1]; sei _ P5U.NextVar[ctxb[seb[irecord].fieldCtx].seList]; UNTIL sei = ISENull DO TreeOps.PushSe[sei]; TreeOps.PushTree[Tree.Null]; TreeOps.PushNode[assign, 2]; np _ np+1; sei _ P5U.NextVar[SymbolOps.NextSe[sei]]; ENDLOOP; TreeOps.PushList[np]; t _ TreeOps.MakeNode[exlist, 1]; IF nParms > MaxParmsInStack OR (isenable AND nParms > 1) THEN BEGIN IF ~isenable THEN Stack.Incr[1]; r _ P5L.TOSAddrLex[nParms].lexbdoi; END ELSE BEGIN Stack.Incr[nParms]; r _ P5L.VarForLex[P5L.TOSLex[nParms]]; END; P5.ExtractFrom[t, irecord, r, (nParms > MaxParmsInStack AND ~isenable)]; t _ TreeOps.FreeTree[t]; END; PushRetVals: PROC = BEGIN -- pushes the return vals from a body onto the stack sei: ISEIndex; nRetVals: CARDINAL; np: CARDINAL _ 0; t: Tree.Link; IF CPtr.bodyOutRecord = CSENull THEN RETURN; nRetVals _ P5U.WordsForSei[CPtr.bodyOutRecord]; sei _ ctxb[seb[CPtr.bodyOutRecord].fieldCtx].seList; UNTIL sei = ISENull DO TreeOps.PushSe[sei]; np _ np+1; sei _ P5U.NextVar[SymbolOps.NextSe[sei]]; ENDLOOP; t _ TreeOps.MakeList[np]; [] _ P5.BuildArgRecord[t, CPtr.bodyOutRecord, FALSE, FALSE, FALSE]; t _ TreeOps.FreeTree[t]; END; SetLock: PROC [lock: Tree.Link] = BEGIN retryEntry: LabelCCIndex = P5U.CreateLabel[]; longLock _ P5L.LoadAddress[P5L.VarForLex[P5.Exp[(mLock _ lock)]]]; P5U.Out0[IF longLock THEN FOpCodes.qMEL ELSE FOpCodes.qME]; P5U.Out1[FOpCodes.qLI, 0]; P5U.OutJump[JumpE, retryEntry]; END; ReleaseLock: PUBLIC PROC = BEGIN Stack.Dump[]; [] _ P5L.LoadAddress[P5L.VarForLex[P5.Exp[mLock]]]; P5U.Out0[IF longLock THEN FOpCodes.qMXDL ELSE FOpCodes.qMXD]; END; SReturn: PROC [node: Tree.Index, isResume: BOOL] = BEGIN -- generate code for RETURN and RESUME nRetVals: CARDINAL; nStack: CARDINAL; rSei: RecordSEIndex; monitored: BOOL; IF ~isResume AND CommonRet[tb[node].son[1]] THEN BEGIN P5U.OutJump[Jump, CPtr.bodyComRetLabel]; RETURN END; monitored _ ~isResume AND tb[node].attr1; IF monitored AND tb[node].attr2 THEN {ReleaseLock[]; monitored _ FALSE}; rSei _ IF isResume THEN CPtr.catchoutrecord ELSE CPtr.bodyOutRecord; nRetVals _ IF tb[node].attr3 THEN P5.PushArgRecord[tb[node].son[1], rSei, isResume, isResume, FALSE] ELSE P5.BuildArgRecord[tb[node].son[1], rSei, isResume, isResume, FALSE]; nStack _ IF nRetVals > MaxParmsInStack OR isResume AND nRetVals # 0 THEN 1 ELSE nRetVals; IF monitored THEN {Stack.Dump[]; ReleaseLock[]}; IF nStack # 0 THEN BEGIN Stack.Load[Stack.Top[nStack], nStack]; Stack.Decr[nStack]; -- remove from model END; IF isResume THEN BEGIN P5U.PushLitVal[1]; Stack.Decr[1]; P5U.Out0[FOpCodes.qRET]; P5U.OutJump[JumpRet, LabelCCNull]; END ELSE P5U.OutJump[Jump, CPtr.bodyRetLabel]; END; Result: PUBLIC PROC [node: Tree.Index] = Return; Return: PUBLIC PROC [node: Tree.Index] = BEGIN -- produce code for RETURN SReturn[node, FALSE ! P5.LogHeapFree => RESUME[FALSE, NullLex]]; END; Resume: PUBLIC PROC [node: Tree.Index] = BEGIN -- produce code for RESUME SReturn[node, TRUE ! P5.LogHeapFree => RESUME[FALSE, NullLex]]; END; CommonRet: PROC [t: Tree.Link] RETURNS [common: BOOL _ TRUE] = BEGIN -- test if the returns list duplicats the returns declaration sei: ISEIndex; Item: PROC [t: Tree.Link] RETURNS [BOOL] = BEGIN WITH t SELECT FROM symbol => common _ (sei = index); literal, subtree => common _ FALSE; ENDCASE; IF sei # ISENull THEN sei _ P5U.NextVar[SymbolOps.NextSe[sei]]; RETURN [~common] END; IF t = Tree.Null THEN RETURN; IF CPtr.bodyOutRecord # CSENull THEN sei _ P5U.NextVar[ctxb[seb[CPtr.bodyOutRecord].fieldCtx].seList] ELSE RETURN [FALSE]; TreeOps.SearchList[t, Item]; RETURN END; Lock: PUBLIC PROC [node: Tree.Index] = BEGIN saveLock: Tree.Link = mLock; SetLock[tb[node].son[2]]; tb[node].son[1] _ P5.StatementTree[tb[node].son[1]]; InsertRetLabels[TRUE]; -- we are in an INLINE procedure mLock _ saveLock; END; StringInit: PUBLIC PROC [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- inits string storage and pushes pointer on stack nchars: CARDINAL = P5U.TreeLiteralValue[tb[node].son[2]]; l: se Lexeme _ P5.GenStringBodyLex[nchars]; [] _ P5L.LoadAddress[P5L.VarForLex[l]]; P5.FreeTempSei[l.lexsei]; P5U.PushLitVal[0]; P5U.PushLitVal[nchars]; P5U.Out1[FOpCodes.qPSD, 0]; RETURN [P5L.TOSLex[1]] END; END. Driver.mesa last modified by Sweet, Oct 25, 1980 4:09 PM last modified by Satterthwaite, November 2, 1982 3:52 pm imported definitions set up input and output contexts init the code stream and put down bracketing labels init data for creating temporaries tuck parameters away into the frame do type table and string literals do initialization code and main body generate code for declaration initializations and statements push the return values onto the stack write frame size into bodyitem fixup jumps output the object code Ê Á˜J˜Jšœ ™ Jšœ,™,Jšœ8™8J˜šÏk ˜ Jšœœœ#˜4šœœœ˜J˜GJ˜GJ˜DJ˜@J˜#—šœ œœ˜J˜=J˜AJ˜MJ˜LJ˜AJ˜JJ˜—šœ œœ˜J˜N—šœ œœ˜J˜C—šœœœ˜J˜BJ˜EJ˜=J˜K—Jšœœœ8˜GJšœœœ˜šœœœ˜J˜OJ˜SJ˜ —Jšœ œœ˜-šœœœ˜J˜K—Jšœ œœ*˜?šœ œœ˜J˜?J˜A—Jšœœœ%˜5šœ œœ˜J˜NJ˜ J˜——šœ˜JšœU˜\Jšœ ˜Jš˜Jšœ ˜J˜Jšœ™J˜Jšœ œ˜)Jšœ œ˜+J˜Jšœ œ˜"J˜$Jšœ œ˜"J˜$Jšœœ˜,J˜3J˜J˜JšœÏc˜)Jšœž#˜7Jšœž"˜7Jšœž˜2Jšœž˜-J˜˜Jšœž6˜=J˜J˜J˜J˜J˜J˜J˜J˜GJ˜J˜J˜.J˜CJ˜J˜(J˜+J˜J˜CJšœ˜J˜J˜—Jš œœœœœ˜1J˜Jš Ïnœœœœœ˜>J˜J˜J˜J˜Jšœ œ˜J˜šŸœœœ˜Jšœž"˜(J˜%J˜6J˜J˜J˜J˜%Jšœœ˜J˜J˜#J˜J˜0J˜'J˜J˜6J˜$J˜J˜J˜%Jšœ˜J˜J˜—š Ÿœœœœœ˜@Jš˜šœœ˜Jšœ œœ œ˜9Jšœ˜—Jšœ˜J˜J˜—šŸœœ˜(Jšœž˜J˜J˜J˜(J˜J˜%J˜šœœ˜!˜ Jš˜J˜J˜J˜Jšœ ™ J˜RJ˜J˜>J˜J˜:Jšœœ˜J˜Jšœ3™3J˜J˜%J˜(J˜J˜J˜#J˜Jšœ"™"J˜J˜.J˜Jšœ#™#J˜Jšœœœ˜?šœ œ˜J˜:Jšœ˜—J˜ Jšœ'ž ˜GJšœœ˜$J˜J˜Jšœ!™!J˜šœ˜J˜E—J˜TJšœœ ˜AJ˜Jšœ$™$J˜šœœ˜'J˜CJ˜—Jšœœ˜2Jšœ˜J˜Jšœ<™œ˜I—˜ Jšœœ œœ˜AJšœ ˜J˜—šœ ˜J˜—šœ ˜Jš˜J˜&Jšœž˜(Jšœ˜—šœ œ˜Jš˜J˜!J˜J˜#Jš˜—Jšœ&˜*Jšœ˜J˜J˜—JšŸœœœ˜0J˜šŸœœœ˜(Jšœž˜ Jšœœœœ ˜@Jšœ˜J˜J˜—šŸœœœ˜(Jšœž˜ Jšœœœœ ˜?Jšœ˜J˜J˜—š Ÿ œœœ œœ˜>Jšœž=˜CJ˜J˜šŸœœœœ˜*Jš˜šœœ˜J˜!Jšœœ˜#Jšœ˜—Jšœœ*˜?Jšœ ˜Jšœ˜J˜—Jšœœœ˜šœ˜$J˜@—Jšœœœ˜J˜Jš˜Jšœ˜J˜—šŸœœœ˜&Jš˜J˜J˜J˜4Jšœœž ˜7J˜Jšœ˜J˜—šŸ œœœœ ˜=Jšœž3˜9Jšœœ)˜9J˜+J˜'J˜J˜J˜J˜Jšœ˜Jšœ˜J˜—Jšœ˜J˜J˜——…—1H@