Statement.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Sweet, September 12, 1980 9:11 AM
Satterthwaite, April 16, 1986 3:49:52 pm PST
Donahue, 10-Dec-81 9:39:18
Russ Atkinson (RRA) March 6, 1985 11:27:09 pm PST
DIRECTORY
Alloc USING [Notifier],
Code USING [actenable, caseCVState, catchcount, catchoutrecord, cfsi, cfSize, CodeNotImplemented, codeptr, curctxlvl, fileLoc, framesz, inlineFileLoc, StackNotEmptyAtStatement, substenable, xtracting],
CodeDefs USING [Base, Byte, CaseCVState, CodeCCIndex, codeType, FrameStateRecord, JumpType, LabelCCIndex, LabelCCNull, LabelInfoIndex, Lexeme, NullLex, OtherCCIndex, StackIndex, VarComponent, VarIndex],
ComData USING [bodyIndex, switches, textIndex],
FOpCodes USING [qBCAST, qBCASTL, qBNDCK, qCATCH, qDADD, qDCOMP, qDEC, qDST, qDSUB, qDUCOMP, qINC, qLL, qLST, qLSTF, qNOTIFY, qNOTIFYL, qPUSH, qRET, qSL],
Log USING [Error, Warning],
P5 USING [BindStmtExp, CallCatch, CaseStmtExp, CaseTest, Exp, FlowTree, GenAnonLex, GenHeapLex, GetLabelMark, LabelCreate, LabelList, LogHeapFree, MakeExitLabel, P5Error, PopFrameState, PopInVals, PurgeHeapList, PurgePendTempList, PushFrameState, PushHeapList, PushLex, PushRhs, ReleaseTempLex, SAssign, SysCall, SysError, TTAssign],
P5L USING [LoadAddress, MakeComponent, VarForLex],
P5S 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 USING [CCellAlloc, ComputeFrameSize, CreateLabel, InsertLabel, LabelAlloc, Out0, Out1, OutJump, OutSource, PushLitVal, TreeLiteralValue, WordsForOperand],
PrincOps USING [AllocationVectorSize, localbase],
SourceMap USING [Loc, nullLoc, Down, Up],
Stack USING [Clear, Decr, Depth, Incr, Mark, New, Off, On, Pop, Reset, Restore],
SymbolOps USING [CtxLevel, SetCtxLevel, UnderType, TransferTypes],
Symbols USING [Base, bodyType, BTIndex, BTNull, ContextLevel, CSEIndex, CSENull, CTXIndex, CTXNull, ctxType, ISEIndex, ISENull, RecordSEIndex, RecordSENull, SEIndex, seType],
Tree USING [Base, Index, Link, Map, NodeName, Null, Scan, treeType],
TreeOps USING [FreeTree, GetNode, GetSe, MarkShared, ReverseUpdateList, ScanList, UpdateList];
Statement: PROGRAM
IMPORTS MPtr: ComData, CPtr: Code, Log, P5U, P5L, P5, P5S, SourceMap, Stack, SymbolOps, TreeOps
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: SourceMap.Loc = 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: SourceMap.Loc ← CPtr.inlineFileLoc;
node ← index;
IF fIndex = SourceMap.nullLoc THEN fIndex ← tb[node].info;
IF fIndex # SourceMap.nullLoc THEN
SELECT tb[node].name FROM
list, block, null => NULL; -- info is not a valid file index
ENDCASE =>
{CPtr.fileLoc ← 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 => GO TO unimplementedConstruct; -- added in Trinity
lste => 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
MarkShared[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..Byte.LAST] THEN Log.Error[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.inlineFileLoc = SourceMap.nullLoc THEN
CPtr.fileLoc ← MPtr.textIndex ← SourceMap.Up[bb[bti].sourceIndex]
ELSE bb[bti].sourceIndex ← CPtr.inlineFileLoc.Down;
P5U.OutSource[SourceMap.Up[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: BOOLFALSE;
signed, long: BOOLFALSE;
sSon, eSon: Tree.Link;
node, subNode: Tree.Index;
bti: BTIndex ← BTNull;
intType: Tree.NodeName;
indexLex: Lexeme.se;
endLex: Lexeme;
topLabel: LabelCCIndex = P5U.LabelAlloc[];
startLabel: LabelCCIndex;
finLabel: LabelCCIndex = P5U.LabelAlloc[];
endLabel, loopLabel: LabelCCIndex;
labelMark: LabelInfoIndex = P5.GetLabelMark[];
UpdateCV: PROC [loadLong: BOOL] =
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: BOOL = 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.index SELECT FROM
word => endLex ← Lexeme[literal[word[lti]]];
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 BOOL OF
ARRAY BOOL OF ARRAY BOOL 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, Lexeme.se]];
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: Lexeme.se;
saveActEnable: LabelCCIndex = CPtr.actenable;
tempState: FrameStateRecord;
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.PushFrameState[@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.PopFrameState[@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 = SymbolOps.UnderType[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 ← SymbolOps.CtxLevel[inCtx];
SymbolOps.SetCtxLevel[inCtx, CPtr.curctxlvl];
END;
IF CPtr.catchoutrecord # RecordSENull
THEN
BEGIN
outCtx ← seb[CPtr.catchoutrecord].fieldCtx;
saveOutCtxLevel ← SymbolOps.CtxLevel[outCtx];
SymbolOps.SetCtxLevel[outCtx, CPtr.curctxlvl];
END;
END;
P5.PopInVals[inRecord, TRUE];
tb[node].son[2] ← StatementTree[tb[node].son[2]];
IF inCtx # Symbols.CTXNull THEN SymbolOps.SetCtxLevel[inCtx, saveInCtxLevel];
IF outCtx # Symbols.CTXNull THEN SymbolOps.SetCtxLevel[outCtx, 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.