DIRECTORY
Alloc: TYPE USING [Notifier],
CatchFormat: TYPE USING [cEnable, cReject, defaultFsi],
Code:
TYPE
USING [
actenable, caseCVState, catchcount, catchoutrecord,
CodeNotImplemented, codeptr, codeStart, curctxlvl, enableLevel,
fileLoc, framesz,
inlineFileLoc, StackNotEmptyAtStatement, xtracting],
CodeDefs:
TYPE
USING [
Base, BYTE, CaseCVState, CCIndex, CCItem, codeType, EnableIndex, FrameStateRecord,
JumpType, LabelCCIndex, LabelCCNull, LabelInfoIndex, Lexeme,
NullLex, OtherCCIndex, StackIndex,
VarComponent, VarIndex],
ComData: TYPE USING [bodyIndex, switches, textIndex],
FOpCodes:
TYPE
USING [
qBC, qBNDCK, qCATCH, qCATCHFSI, qDADD, qDCMP, qDEC, qDSK, qDSUB,
qINC, qLP, qLST, qLSTE, qLSTF, qNC, qREC, qRET, qUDCMP],
Log: TYPE USING [Error, Warning],
P5:
TYPE
USING [
BindStmtExp, CaseStmtExp, CaseTest, Exp, FlowTree, GenAnonLex, GenHeapLex,
GetLabelMark, LabelCreate, LabelList, LogHeapFree, MakeExitLabel, P5Error,
PopInVals, PopFrameState, PurgeHeapList, PurgePendTempList, PushHeapList,
PushLex, PushRhs, PushFrameState, 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 [
BeginCatch, CCellAlloc, ComputeFrameSize, EndCatch, InsertLabel,
LabelAlloc, NewEnableItem, Out0, Out1, OutCatchMark, OutJump, OutSource,
PushLitVal, TreeLiteralValue, WordsForOperand],
PrincOps: TYPE USING [AVHeapSize, localbase],
SourceMap: TYPE USING [Loc, nullLoc, Down, Up],
Stack:
TYPE
USING [
Clear, Decr, Depth, Incr, Mark, New, Off, On, Pop,
Reset, Restore],
SymbolOps: TYPE USING [CtxLevel, SetCtxLevel, UnderType, TransferTypes],
Symbols:
TYPE
USING [
Base, bodyType, BTIndex, BTNull, CCBTIndex, CCBTNull, ContextLevel,
CSEIndex, CSENull, CTXIndex, CTXNull, ctxType,
ISEIndex, ISENull, RecordSEIndex, RecordSENull, seType],
Tree: TYPE USING [Base, Index, Link, Map, NodeName, Null, Scan, treeType],
TreeOps:
TYPE
USING [
FreeTree, GetNode, GetSe, MarkShared, ReverseUpdateList, ScanList, UpdateList];
DoStmt:
PROC [rootNode: Tree.Index] =
BEGIN -- generates code for all the loop statments
stepLoop, tempIndex, tempEnd, upLoop, forSeqLoop, bigForSeq: BOOL ← FALSE;
signed, long: BOOL ← FALSE;
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;
[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, FALSE];
SELECT tb[node].name
FROM
forseq =>
BEGIN
ENABLE P5.LogHeapFree => RESUME [FALSE, NullLex];
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[qREC]; P5U.Out0[qREC]};
P5.PushLex[endLex];
IF long
THEN
{P5U.Out0[IF signed THEN qDCMP ELSE qUDCMP]; P5U.PushLitVal[0]};
P5U.OutJump[TopTest[long OR signed][upLoop][intType = intOO], finLabel];
IF ~long THEN P5U.Out0[qREC];
END;
IF ~long THEN Stack.Decr[1];
P5U.OutJump[Jump, startLabel];
P5U.InsertLabel[topLabel];
IF ~long THEN P5U.Out0[qREC];
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;
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)
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[qREC]; P5U.Out0[qREC]};
ENDCASE;
P5.PushLex[endLex];
IF long
THEN
{P5U.Out0[IF signed THEN qDCMP ELSE qUDCMP]; 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
ENABLE P5.LogHeapFree => RESUME [FALSE, NullLex];
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[];
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
bti: CCBTIndex = tb[node].info;
CPtr.catchcount ← CPtr.catchcount + 1;
P5U.Out1[qCATCH, bb[bti].index];
SCatchPhrase[node];
CPtr.catchcount ← CPtr.catchcount - 1;
END;
SCatchPhrase:
PUBLIC
PROC [node: Tree.Index] =
BEGIN -- main subr for catchphrases and ENABLEs
first, cur: CCIndex;
saveCaseCVState: CaseCVState = CPtr.caseCVState;
saveEndLabel: LabelCCIndex = catchEndLabel;
oldStkPtr: StackIndex = Stack.New[];
saveActEnable: CCBTIndex = CPtr.actenable;
saveEnableLevel: CARDINAL = CPtr.enableLevel;
tempState: FrameStateRecord;
bti: CCBTIndex = tb[node].info;
initialFrameSize, cfsi: NAT;
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;
WITH bb[bti].info
SELECT
FROM
Internal => initialFrameSize ← frameSize;
ENDCASE => ERROR;
catchEndLabel ← P5U.LabelAlloc[];
CPtr.curctxlvl ← CPtr.curctxlvl + 1;
P5.PushFrameState[@tempState, initialFrameSize];
Stack.Incr[1]; -- signal code on stack
CPtr.caseCVState ← singleLoaded;
CPtr.actenable ← Symbols.CCBTNull;
[first: first, cur: cur] ← P5U.BeginCatch[];
EnterBlock[bti, TRUE];
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;
CPtr.enableLevel ← saveEnableLevel;
P5U.InsertLabel[catchEndLabel];
Stack.Off[];
IF CPtr.actenable # BTNull
THEN
BEGIN
P5U.PushLitVal[bb[CPtr.actenable].index];
P5U.PushLitVal[CatchFormat.cEnable];
P5U.Out0[qRET]; P5U.OutJump[JumpRet,LabelCCNull];
END
ELSE
BEGIN
P5U.PushLitVal[CatchFormat.cReject];
P5U.Out0[qRET]; P5U.OutJump[JumpRet,LabelCCNull];
END;
Stack.On[];
ExitBlock[bti];
CPtr.curctxlvl ← CPtr.curctxlvl-1;
CPtr.caseCVState ← saveCaseCVState;
catchEndLabel ← saveEndLabel;
cfsi ← P5U.ComputeFrameSize[CPtr.framesz];
P5.PopFrameState[@tempState];
IF bb[MPtr.bodyIndex].resident
THEN
cfsi ← cfsi + PrincOps.AVHeapSize;
IF cfsi > CatchFormat.defaultFsi
THEN {
CPtr.codeptr ← cb[CPtr.codeStart].flink; -- the startbody node
P5U.Out1[FOpCodes.qCATCHFSI, cfsi]};
P5U.EndCatch[oldfirst: first, oldcur: cur];
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 = 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;
P5.PopInVals[inRecord, TRUE];
END;
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;