-- Statement.mesa -- last modified by Sweet, September 12, 1980 9:11 AM -- last modified by Satterthwaite, July 15, 1982 9:11 am -- last modified by Donahue, 10-Dec-81 9:39:18 DIRECTORY Alloc: TYPE USING [Notifier], Code: TYPE USING [ actenable, caseCVState, catchcount, catchoutrecord, cfsi, cfSize, CodeNotImplemented, codeptr, curctxlvl, fileindex, framesz, inlineFileIndex, StackNotEmptyAtStatement, substenable, xtracting], CodeDefs: TYPE USING [ Base, Byte, CaseCVState, CodeCCIndex, codeType, JumpType, LabelCCIndex, LabelCCNull, LabelInfoIndex, Lexeme, NULLfileindex, NullLex, OtherCCIndex, StackIndex, TempStateRecord, VarComponent, VarIndex], ComData: TYPE USING [bodyIndex, switches, textIndex], FOpCodes: TYPE USING [ qBCAST, qBCASTL, qBNDCK, qCATCH, qDADD, qDCOMP, qDEC, qDST, qDSUB, qDUCOMP, qINC, qLL, qLST, qLSTF, qNOTIFY, qNOTIFYL, qPUSH, qRET, qSL], Log: TYPE USING [Error, Warning], P5: TYPE USING [ BindStmtExp, CallCatch, CaseStmtExp, CaseTest, Exp, FlowTree, GenAnonLex, GenHeapLex, GetLabelMark, LabelCreate, LabelList, LogHeapFree, MakeExitLabel, P5Error, PopInVals, PopTempState, PurgeHeapList, PurgePendTempList, PushHeapList, PushLex, PushRhs, PushTempState, ReleaseTempLex, SAssign, SysCall, SysError, TTAssign], P5L: TYPE USING [LoadAddress, MakeComponent, VarForLex], P5S: TYPE USING [ Assign, Call, CatchMark, Continue, Exit, Extract, Free, GoTo, Join, Label, Lock, Loop, ProcInit, Restart, Result, Resume, Retry, Return, RetWithError, SigErr, Start, Stop, Subst, Unlock, Wait], P5U: TYPE USING [ CCellAlloc, ComputeFrameSize, CreateLabel, InsertLabel, LabelAlloc, Out0, Out1, OutJump, OutSource, PushLitVal, TreeLiteralValue, WordsForOperand], PrincOps: TYPE USING [AllocationVectorSize, localbase], Stack: TYPE USING [ Clear, Decr, Depth, Incr, Mark, New, Off, On, Pop, Reset, Restore], SymbolOps: TYPE USING [TransferTypes], Symbols: TYPE USING [ Base, bodyType, BTIndex, BTNull, ContextLevel, CSEIndex, CSENull, CTXIndex, CTXNull, ctxType, ISEIndex, ISENull, RecordSEIndex, RecordSENull, SEIndex, seType], Tree: TYPE USING [Base, Index, Link, Map, NodeName, Null, Scan, treeType], TreeOps: TYPE USING [ FreeTree, GetNode, GetSe, ReverseUpdateList, ScanList, SetShared, UpdateList]; Statement: PROGRAM IMPORTS MPtr: ComData, CPtr: Code, P5U, P5L, P5, P5S, Stack, SymbolOps, TreeOps, Log EXPORTS CodeDefs, P5 = BEGIN OPEN FOpCodes, CodeDefs; -- imported definitions SEIndex: TYPE = Symbols.SEIndex; ISEIndex: TYPE = Symbols.ISEIndex; ISENull: ISEIndex = Symbols.ISENull; CSEIndex: TYPE = Symbols.CSEIndex; RecordSEIndex: TYPE = Symbols.RecordSEIndex; RecordSENull: RecordSEIndex = Symbols.RecordSENull; BTIndex: TYPE = Symbols.BTIndex; BTNull: BTIndex = Symbols.BTNull; 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 base (local copy) cb: CodeDefs.Base; -- code base (local copy) StatementNotify: PUBLIC 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]; END; catchEndLabel: LabelCCIndex ← LabelCCNull; recentStmt: PUBLIC Tree.Link; -- for debugging StatementTree: PUBLIC PROC [t: Tree.Link] RETURNS [Tree.Link] = BEGIN -- generates code for Mesa statements node: Tree.Index; saveHeapList: ISEIndex; saveIndex: CARDINAL = MPtr.textIndex; recentStmt ← t; IF t = Tree.Null THEN RETURN [Tree.Null]; BEGIN ENABLE BEGIN P5.LogHeapFree => RESUME [TRUE, P5.GenHeapLex[]]; CPtr.CodeNotImplemented => IF ~MPtr.switches['d] THEN GO TO unimplementedConstruct; END; saveHeapList ← P5.PushHeapList[]; WITH t SELECT FROM subtree => BEGIN fIndex: CARDINAL ← CPtr.inlineFileIndex; node ← index; IF fIndex = NULLfileindex THEN fIndex ← tb[node].info; IF fIndex # NULLfileindex THEN SELECT tb[node].name FROM list, block, null => NULL; -- info is not a valid file index ENDCASE => {CPtr.fileindex ← MPtr.textIndex ← fIndex; P5U.OutSource[fIndex]}; IF ~CPtr.xtracting AND Stack.Depth[] # 0 THEN {SIGNAL CPtr.StackNotEmptyAtStatement; Stack.Clear[]}; SELECT tb[node].name FROM list => t ← TreeOps.UpdateList[t, StatementTree]; block => Block[node]; start => P5S.Start[node]; restart => P5S.Restart[node]; stop => P5S.Stop[node]; dst => DumpState[node]; lst => LoadState[node]; lstf => LoadStateFree[node]; call, portcall => P5S.Call[node]; signal, error => P5S.SigErr[node]; syscall => SysCallStmt[node]; syserror => P5.SysError[]; label => P5S.Label[node]; assign => P5S.Assign[node]; extract => P5S.Extract[node]; if => IfStmt[node]; case => [] ← P5.CaseStmtExp[node, FALSE]; bind => [] ← P5.BindStmtExp[node, FALSE]; do => DoStmt[node]; exit => P5S.Exit[]; loop => P5S.Loop[]; retry => P5S.Retry[]; continue => P5S.Continue[]; goto => P5S.GoTo[node]; catchmark => P5S.CatchMark[node]; return => P5S.Return[node]; resume => P5S.Resume[node]; reject => Reject[]; result => P5S.Result[node]; open => Open[node]; enable => Enable[node]; checked => tb[node].son[1] ← StatementTree[tb[node].son[1]]; procinit => P5S.ProcInit[node]; wait => P5S.Wait[node]; notify => Notify[node]; broadcast => Broadcast[node]; join => P5S.Join[node]; unlock => P5S.Unlock[node]; lock => P5S.Lock[node]; subst => P5S.Subst[node]; free => P5S.Free[node]; xerror => P5S.RetWithError[node]; null => NULL; ENDCASE => GO TO unimplementedConstruct; END; ENDCASE; P5.PurgeHeapList[saveHeapList]; P5.PurgePendTempList[]; EXITS unimplementedConstruct => {Log.Error[unimplemented]; Stack.Clear[]}; END; MPtr.textIndex ← saveIndex; RETURN [TreeOps.FreeTree[t]] END; SysCallStmt: PROC [node: Tree.Index] = BEGIN Stack.Mark[]; TreeOps.ScanList[tb[node].son[2], P5.PushRhs]; P5.SysCall[P5U.TreeLiteralValue[tb[node].son[1]]]; END; Open: PROC [node: Tree.Index] = BEGIN OPEN TreeOps; OpenItem: PROC [t: Tree.Link] RETURNS [Tree.Link] = BEGIN SetShared[t, FALSE]; RETURN [FreeTree[t]] END; tb[node].son[2] ← StatementTree[tb[node].son[2]]; tb[node].son[1] ← ReverseUpdateList[tb[node].son[1], OpenItem]; END; DumpState: PROC [node: Tree.Index] = INLINE BEGIN -- generates dumpstate DLState[node, qDST]; END; LoadState: PROC [node: Tree.Index] = INLINE BEGIN -- generates loadstate DLState[node, qLST]; P5.CallCatch[Tree.Null]; END; LoadStateFree: PROC [node: Tree.Index] = INLINE BEGIN -- generates loadstateandfree DLState[node, qLSTF]; P5U.OutJump[JumpRet, LabelCCNull]; END; DLState: PROC [node: Tree.Index, opc: Byte] = BEGIN -- does state move after checking for small currentcontext address lowBound: CARDINAL = PrincOps.localbase+2; var: VarComponent = P5L.MakeComponent[P5L.VarForLex[P5.Exp[tb[node].son[1]]]]; WITH var SELECT FROM frame => BEGIN IF level # CPtr.curctxlvl THEN {Log.Error[stateVector]; RETURN}; IF wd NOT IN [lowBound..LAST[Byte]] THEN Log.Warning[stateVector]; P5U.Out1[opc, wd]; END; ENDCASE => Log.Error[stateVector]; END; Block: PROC [node: Tree.Index] = BEGIN bti: BTIndex = tb[node].info; EnterBlock[bti]; tb[node].son[1] ← StatementTree[tb[node].son[1]]; tb[node].son[2] ← StatementTree[tb[node].son[2]]; ExitBlock[bti]; END; EnterBlock: PUBLIC PROC [bti: BTIndex] = BEGIN IF CPtr.inlineFileIndex = NULLfileindex THEN CPtr.fileindex ← MPtr.textIndex ← bb[bti].sourceIndex ELSE bb[bti].sourceIndex ← CPtr.inlineFileIndex; P5U.OutSource[bb[bti].sourceIndex]; P5U.CCellAlloc[other]; cb[LOOPHOLE[CPtr.codeptr, OtherCCIndex]].obody ← markbody[start: TRUE, index: bti]; END; ExitBlock: PUBLIC PROC [bti: BTIndex] = BEGIN P5U.CCellAlloc[other]; cb[LOOPHOLE[CPtr.codeptr, OtherCCIndex]].obody ← markbody[start: FALSE, index: bti]; END; IfStmt: PROC [node: Tree.Index] = BEGIN -- generates code for an IF statement eLabel: LabelCCIndex = P5U.LabelAlloc[]; P5.FlowTree[tb[node].son[1], FALSE, eLabel ! P5.LogHeapFree => RESUME [FALSE, NullLex]]; P5.PurgePendTempList[]; tb[node].son[2] ← StatementTree[tb[node].son[2]]; IF tb[node].son[3] # Tree.Null THEN BEGIN iLabel: LabelCCIndex = P5U.LabelAlloc[]; P5U.OutJump[Jump, iLabel]; P5U.InsertLabel[eLabel]; tb[node].son[3] ← StatementTree[tb[node].son[3]]; P5U.InsertLabel[iLabel]; END ELSE P5U.InsertLabel[eLabel]; END; DoStmt: PROC [rootNode: Tree.Index] = BEGIN -- generates code for all the loop statments stepLoop, tempIndex, tempEnd, upLoop, forSeqLoop, bigForSeq: BOOLEAN ← FALSE; signed, long: BOOLEAN ← FALSE; sSon, eSon: Tree.Link; node, subNode: Tree.Index; bti: BTIndex ← BTNull; intType: Tree.NodeName; indexLex: se Lexeme; endLex: Lexeme; topLabel: LabelCCIndex = P5U.LabelAlloc[]; startLabel: LabelCCIndex; finLabel: LabelCCIndex = P5U.LabelAlloc[]; endLabel, loopLabel: LabelCCIndex; labelMark: LabelInfoIndex = P5.GetLabelMark[]; UpdateCV: PROC [loadLong: BOOLEAN] = BEGIN IF long THEN BEGIN IF loadLong THEN P5.PushLex[indexLex]; P5U.PushLitVal[1]; P5U.PushLitVal[0]; P5U.Out0[IF upLoop THEN qDADD ELSE qDSUB]; P5.SAssign[indexLex.lexsei]; END ELSE P5U.Out0[IF upLoop THEN qINC ELSE qDEC]; END; -- set up for EXIT clause [exit: endLabel, loop: loopLabel] ← P5.MakeExitLabel[]; TreeOps.ScanList[tb[rootNode].son[5], P5.LabelCreate]; -- handle initialization node IF tb[rootNode].son[1] = Tree.Null THEN P5U.InsertLabel[topLabel] ELSE BEGIN node ← TreeOps.GetNode[tb[rootNode].son[1]]; bti ← tb[node].info; IF bti # BTNull THEN EnterBlock[bti]; SELECT tb[node].name FROM forseq => BEGIN t1: Tree.Link = tb[node].son[1]; t2: Tree.Link = tb[node].son[2]; indexLex ← [se[TreeOps.GetSe[t1]]]; forSeqLoop ← TRUE; bigForSeq ← P5U.WordsForOperand[t1] > 2; IF bigForSeq THEN {P5.TTAssign[t1, t2]; P5U.InsertLabel[topLabel]} ELSE {P5.PushRhs[t2]; P5U.InsertLabel[topLabel]; P5.SAssign[indexLex.lexsei]}; P5.PurgeHeapList[ISENull]; END; upthru, downthru => BEGIN ENABLE P5.LogHeapFree => RESUME [FALSE, NullLex]; cvBound: Tree.Link = tb[node].son[3]; nonempty: BOOLEAN = tb[node].attr1; stepLoop ← TRUE; upLoop ← tb[node].name = upthru; subNode ← TreeOps.GetNode[tb[node].son[2]]; intType ← tb[subNode].name; IF tb[subNode].attr1 THEN SIGNAL CPtr.CodeNotImplemented; long ← tb[subNode].attr2; signed ← tb[subNode].attr3; WITH tb[node].son[1] SELECT FROM subtree => -- son1 is empty {indexLex ← P5.GenAnonLex[IF long THEN 2 ELSE 1]; tempIndex ← TRUE}; symbol => indexLex ← Lexeme[se[index]]; ENDCASE; IF upLoop THEN {sSon ← tb[subNode].son[1]; eSon ← tb[subNode].son[2]} ELSE BEGIN SELECT intType FROM intCO => intType ← intOC; intOC => intType ← intCO; ENDCASE; sSon ← tb[subNode].son[2]; eSon ← tb[subNode].son[1]; END; WITH e: eSon SELECT FROM literal => WITH e.info SELECT FROM word => endLex ← Lexeme[literal[word[index]]]; ENDCASE => P5.P5Error[769]; symbol => IF seb[e.index].immutable THEN endLex ← Lexeme[se[e.index]] ELSE BEGIN endLex ← P5.GenAnonLex[IF long THEN 2 ELSE 1]; P5.PushRhs[e]; tempEnd ← TRUE; WITH endLex SELECT FROM se => P5.SAssign[lexsei]; ENDCASE; END; ENDCASE => BEGIN endLex ← P5.GenAnonLex[IF long THEN 2 ELSE 1]; P5.PushRhs[e]; tempEnd ← TRUE; WITH endLex SELECT FROM se => P5.SAssign[lexsei]; ENDCASE; END; startLabel ← P5U.LabelAlloc[]; P5.PushRhs[sSon]; IF long THEN P5.SAssign[indexLex.lexsei]; IF (intType = intCC OR intType = intOO) AND ~nonempty THEN BEGIN -- earlier passes check for empty intervals TopTest: ARRAY BOOLEAN OF ARRAY BOOLEAN OF ARRAY BOOLEAN OF JumpType = [ [[UJumpL,UJumpLE], -- unsigned, down, closed/open [UJumpG,UJumpGE]], -- unsigned, up, closed/open [[JumpL,JumpLE], -- signed, down, closed/open [JumpG,JumpGE]]]; -- signed, up, closed/open IF long THEN {P5U.Out0[qPUSH]; P5U.Out0[qPUSH]}; P5.PushLex[endLex]; IF long THEN {P5U.Out0[IF signed THEN qDCOMP ELSE qDUCOMP]; P5U.PushLitVal[0]}; P5U.OutJump[TopTest[long OR signed][upLoop][intType = intOO], finLabel]; IF ~long THEN P5U.Out0[qPUSH]; END; IF ~long THEN Stack.Decr[1]; P5U.OutJump[Jump, startLabel]; P5U.InsertLabel[topLabel]; IF ~long THEN P5U.Out0[qPUSH]; SELECT intType FROM intCC => {UpdateCV[TRUE]; P5U.InsertLabel[startLabel]}; intOC => UpdateCV[TRUE]; intCO, intOO => NULL; ENDCASE; IF ~long THEN BEGIN IF cvBound # Tree.Null THEN {P5.PushRhs[cvBound]; P5U.Out0[FOpCodes.qBNDCK]}; P5.SAssign[indexLex.lexsei]; END; END; ENDCASE; END; -- now the pre-body test IF tb[rootNode].son[2] # Tree.Null THEN P5.FlowTree[tb[rootNode].son[2], FALSE, finLabel ! P5.LogHeapFree => RESUME [FALSE, NullLex]]; -- ignore the opens (tb[rootNode].son3) -- now the body tb[rootNode].son[4] ← StatementTree[tb[rootNode].son[4]]; -- now (update and) test the control variable P5U.InsertLabel[loopLabel]; IF stepLoop THEN BEGIN IF long AND (intType = intOC OR intType = intOO) THEN P5U.InsertLabel[startLabel]; P5.PushLex[indexLex]; SELECT intType FROM intCC => NULL; intCO => {UpdateCV[FALSE]; P5U.InsertLabel[startLabel]}; intOC => IF ~long THEN P5U.InsertLabel[startLabel]; intOO => {IF ~long THEN P5U.InsertLabel[startLabel]; UpdateCV[FALSE]}; ENDCASE; IF long THEN SELECT intType FROM intCO, intOO => {P5U.Out0[qPUSH]; P5U.Out0[qPUSH]}; ENDCASE; P5.PushLex[endLex]; IF long THEN {P5U.Out0[IF signed THEN qDCOMP ELSE qDUCOMP]; P5U.PushLitVal[0]}; P5U.OutJump[ IF ~long AND ~signed THEN IF upLoop THEN UJumpL ELSE UJumpG ELSE IF upLoop THEN JumpL ELSE JumpG, topLabel]; P5U.OutJump[Jump, finLabel]; IF tempEnd THEN P5.ReleaseTempLex[LOOPHOLE[endLex, se Lexeme]]; IF tempIndex THEN P5.ReleaseTempLex[indexLex]; END ELSE BEGIN IF forSeqLoop THEN BEGIN IF bigForSeq THEN P5.TTAssign[[symbol[indexLex.lexsei]], tb[node].son[3]] ELSE P5.PushRhs[tb[node].son[3]]; P5.PurgeHeapList[ISENull]; END; P5U.OutJump[Jump, topLabel]; END; Stack.Reset[]; P5.PurgePendTempList[]; -- now the labelled EXITs P5.LabelList[tb[rootNode].son[5], endLabel, labelMark]; -- finally the FINISHED clause P5U.InsertLabel[finLabel]; tb[rootNode].son[6] ← StatementTree[tb[rootNode].son[6]]; IF bti # BTNull THEN ExitBlock[bti]; P5U.InsertLabel[endLabel]; END; CatchPhrase: PUBLIC PROC [node: Tree.Index] = BEGIN -- process a catchphrase at procedure call aroundLabel: LabelCCIndex = P5U.LabelAlloc[]; saveCfSize: CARDINAL = CPtr.cfSize; saveCfsi: CARDINAL = CPtr.cfsi; r: CodeCCIndex; CPtr.catchcount ← CPtr.catchcount + 1; P5U.Out1[qCATCH, 0]; r ← LOOPHOLE[CPtr.codeptr, CodeCCIndex]; P5U.OutJump[JumpA, aroundLabel]; SCatchPhrase[node]; cb[r].parameters[1] ← CPtr.cfsi; P5U.InsertLabel[aroundLabel]; CPtr.catchcount ← CPtr.catchcount - 1; CPtr.cfSize ← saveCfSize; CPtr.cfsi ← saveCfsi; END; Enable: PROC [node: Tree.Index] = BEGIN -- generate code for an ENABLE aroundLabel: LabelCCIndex = P5U.LabelAlloc[]; enableLabel: LabelCCIndex; saveActEnable: LabelCCIndex = CPtr.actenable; saveSubstEnable: LabelCCIndex = CPtr.substenable; saveCfSize: CARDINAL = CPtr.cfSize; saveCfsi: CARDINAL = CPtr.cfsi; CPtr.catchcount ← CPtr.catchcount + 1; P5U.OutJump[JumpA, aroundLabel]; enableLabel ← P5U.CreateLabel[]; SCatchPhrase[TreeOps.GetNode[tb[node].son[1]]]; P5U.InsertLabel[aroundLabel]; CPtr.actenable ← enableLabel; IF tb[node].attr3 THEN CPtr.substenable ← enableLabel; CPtr.catchcount ← CPtr.catchcount - 1; tb[node].son[2] ← StatementTree[tb[node].son[2]]; CPtr.actenable ← saveActEnable; CPtr.substenable ← saveSubstEnable; CPtr.cfSize ← saveCfSize; CPtr.cfsi ← saveCfsi; END; SCatchPhrase: PUBLIC PROC [node: Tree.Index] = BEGIN -- main subr for catchphrases and ENABLEs saveCaseCVState: CaseCVState = CPtr.caseCVState; saveEndLabel: LabelCCIndex = catchEndLabel; oldStkPtr: StackIndex = Stack.New[]; oldCfSize: CARDINAL = CPtr.cfSize; msgTemp, sigTemp: se Lexeme; saveActEnable: LabelCCIndex = CPtr.actenable; tempState: TempStateRecord; CatchScan: PROC [t: Tree.Link] = BEGIN fail: LabelCCIndex = P5U.LabelAlloc[]; [] ← CatchItem[node:TreeOps.GetNode[t], failLabel: fail]; P5U.OutJump[Jump, catchEndLabel]; P5U.InsertLabel[fail]; END; catchEndLabel ← P5U.LabelAlloc[]; CPtr.curctxlvl ← CPtr.curctxlvl + 1; P5.PushTempState[@tempState, tb[node].info]; CPtr.cfSize ← 0; Stack.Incr[1]; -- signal code is on stack IF CPtr.actenable # LabelCCNull THEN BEGIN sigTemp ← P5.GenAnonLex[1]; msgTemp ← P5.GenAnonLex[1]; P5U.Out1[qLL,PrincOps.localbase+1]; P5.SAssign[msgTemp.lexsei]; P5.SAssign[sigTemp.lexsei]; P5.PushLex[sigTemp]; END; CPtr.caseCVState ← singleLoaded; CPtr.actenable ← LabelCCNull; TreeOps.ScanList[tb[node].son[1], CatchScan]; IF tb[node].son[1] = Tree.Null THEN Stack.Pop[]; IF tb[node].son[2] # Tree.Null THEN tb[node].son[2] ← StatementTree[tb[node].son[2]]; CPtr.actenable ← saveActEnable; P5U.InsertLabel[catchEndLabel]; Stack.Off[]; IF CPtr.actenable # LabelCCNull THEN BEGIN P5.PushLex[sigTemp]; P5.PushLex[msgTemp]; P5U.Out1[qSL,PrincOps.localbase+1]; P5U.OutJump[Jump, CPtr.actenable]; P5.ReleaseTempLex[msgTemp]; P5.ReleaseTempLex[sigTemp]; END ELSE BEGIN P5U.PushLitVal[0]; P5U.Out0[qRET]; P5U.OutJump[JumpRet,LabelCCNull]; END; Stack.On[]; CPtr.curctxlvl ← CPtr.curctxlvl-1; CPtr.caseCVState ← saveCaseCVState; catchEndLabel ← saveEndLabel; CPtr.cfSize ← MAX[oldCfSize, CPtr.framesz]; P5.PopTempState[@tempState]; CPtr.cfsi ← P5U.ComputeFrameSize[CPtr.cfSize]; IF bb[MPtr.bodyIndex].resident THEN CPtr.cfsi ← CPtr.cfsi + PrincOps.AllocationVectorSize; Stack.Restore[oldStkPtr]; END; CatchItem: PROC [node: Tree.Index, failLabel: LabelCCIndex] = BEGIN -- generate code for a CATCH item saveCatchOutRecord: RecordSEIndex = CPtr.catchoutrecord; inRecord: RecordSEIndex; tSei: CSEIndex = tb[node].info; saveInCtxLevel, saveOutCtxLevel: Symbols.ContextLevel; inCtx, outCtx: Symbols.CTXIndex ← Symbols.CTXNull; P5.CaseTest[tb[node].son[1], failLabel]; IF tSei = Symbols.CSENull THEN inRecord ← CPtr.catchoutrecord ← RecordSENull ELSE BEGIN [inRecord, CPtr.catchoutrecord] ← SymbolOps.TransferTypes[tSei]; IF inRecord # RecordSENull THEN BEGIN inCtx ← seb[inRecord].fieldCtx; saveInCtxLevel ← ctxb[inCtx].level; ctxb[inCtx].level ← CPtr.curctxlvl; END; IF CPtr.catchoutrecord # RecordSENull THEN BEGIN outCtx ← seb[CPtr.catchoutrecord].fieldCtx; saveOutCtxLevel ← ctxb[outCtx].level; ctxb[outCtx].level ← CPtr.curctxlvl; END; END; P5.PopInVals[inRecord, TRUE]; tb[node].son[2] ← StatementTree[tb[node].son[2]]; IF inCtx # Symbols.CTXNull THEN ctxb[inCtx].level ← saveInCtxLevel; IF outCtx # Symbols.CTXNull THEN ctxb[outCtx].level ← saveOutCtxLevel; CPtr.catchoutrecord ← saveCatchOutRecord; END; Reject: PROC = INLINE BEGIN P5U.OutJump[Jump,catchEndLabel]; END; Notify: PROC [node: Tree.Index] = BEGIN r: VarIndex = P5L.VarForLex[P5.Exp[tb[node].son[1]]]; P5U.Out0[IF P5L.LoadAddress[r].long THEN qNOTIFYL ELSE qNOTIFY]; END; Broadcast: PROC [node: Tree.Index] = BEGIN r: VarIndex = P5L.VarForLex[P5.Exp[tb[node].son[1]]]; P5U.Out0[IF P5L.LoadAddress[r].long THEN qBCASTL ELSE qBCAST]; END; END.