-- FlowExpression.mesa, modified by Sweet, January 17, 1980 5:29 PM

DIRECTORY
AltoDefs: FROM "altodefs" USING [BYTE, wordlength],
Code: FROM "code" USING [CodeNotImplemented, dStar, ZEROlexeme],
CodeDefs: FROM "codedefs" USING [
JumpType, LabelCCIndex, Lexeme, NullLex, VarComponent, VarIndex],
ComData: FROM "comdata" USING [switches],
FOpCodes: FROM "fopcodes" USING [
qDCOMP, qDSUB, qDUCOMP, qDUP, qEXCH, qFCOMP, qFLOAT, qFSUB, qLI, qLINT,
qLP, qNEG, qPOP, qPUSH, qRF, qXOR],
P5: FROM "p5" USING [
Exp, FlowIn, FlowTree, GenTempLex, LogHeapFree, PushLex, PushRhs,
ReleaseTempLex, SAssign],
P5L: FROM "p5l" USING [
AllLoaded, EasilyLoadable, FieldOfVar, LoadComponent, LoadVar,
MakeComponent, NormalizeExp, NormalLex, ReusableCopies, TOSLex,
VarAlignment, VarForLex],
P5U: FROM "p5u" USING [
InsertLabel, LabelAlloc, LongTreeAddress, Out0, Out1, Out2, OutJump,
PushLitVal, TreeLiteral],
SDDefs: FROM "sddefs",
Stack: FROM "stack" USING [
Decr, DeleteToMark, Dump, Mark, Off, On, ResetToMark, TempStore, UnMark],
Symbols: FROM "symbols" USING [
CTXIndex, HTIndex, ISEIndex, ISENull, SEIndex, seType],
Table: FROM "table" USING [Base, Notifier],
Tree: FROM "tree" USING [Index, Link, NodeName, treeType],
TreeOps: FROM "treeops" USING [ListLength, ScanList];


FlowExpression: PROGRAM
IMPORTS CPtr: Code, MPtr: ComData, P5U, P5L, P5, Stack, TreeOps
EXPORTS CodeDefs, P5 =
BEGIN
OPEN FOpCodes, CodeDefs;

-- imported definitions

BYTE: TYPE = AltoDefs.BYTE;
wordlength: CARDINAL = AltoDefs.wordlength;

CTXIndex: TYPE = Symbols.CTXIndex;
HTIndex: TYPE = Symbols.HTIndex;
ISEIndex: TYPE = Symbols.ISEIndex;
SEIndex: TYPE = Symbols.SEIndex;
ISENull: ISEIndex = Symbols.ISENull;

tb: Table.Base; -- tree base (local copy)
seb: Table.Base; -- semantic entry base (local copy)
cb: Table.Base; -- code base (local copy)

FlowExpressionNotify: PUBLIC Table.Notifier =
BEGIN -- called by allocator whenever table area is repacked
seb ← base[Symbols.seType];
cb ← tb ← base[Tree.treeType];
RETURN
END;

JumpNN: ARRAY Tree.NodeName[relE..relLE] OF JumpType = [
JumpE, JumpN, JumpL, JumpGE, JumpG, JumpLE];

UJumpNN: ARRAY Tree.NodeName[relE..relLE] OF JumpType ← [
JumpE, JumpN, UJumpL, UJumpGE, UJumpG, UJumpLE];

CNN: ARRAY Tree.NodeName[relE..relLE] OF Tree.NodeName = [
relN, relE, relGE, relL, relLE, relG];

RNN: ARRAY Tree.NodeName[relE..relLE] OF Tree.NodeName = [
relE, relN, relG, relLE, relL, relGE];

PushOnly: PROCEDURE [t: Tree.Link] =
BEGIN
IF ~CPtr.dStar THEN Stack.Dump[]; -- should never see Case CV
P5.PushRhs[t];
RETURN
END;

FlowExp: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [l: Lexeme] =
BEGIN -- generates code for a flow expression

SELECT tb[node].name FROM
ifx => l ← IfExp[node];
or => l ← Or[node];
and => l ← And[node];
not => l ← Not[node];
relE,relN,relL,relGE,relG,relLE => l ← Rel[node, TRUE];
in => l ← In[node, TRUE];
notin => l ← In[node, FALSE];
abs => l ← Abs[node];
lengthen => l ← Lengthen[node];
min => l ← Min[node];
max => l ← Max[node];
ENDCASE =>
BEGIN
SIGNAL CPtr.CodeNotImplemented;
l ← CPtr.ZEROlexeme;
END;
RETURN
END;


Abs: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] =
BEGIN -- generate code for ABS
poslabel, donelabel: LabelCCIndex;

IF tb[node].attr1 THEN RETURN[RealAbs[node]];
IF tb[node].attr2 THEN RETURN [LongAbs[node]];
IF CPtr.dStar THEN RETURN [DAbs[node]];
poslabel ← P5U.LabelAlloc[];
donelabel ← P5U.LabelAlloc[];
Stack.Dump[]; Stack.Mark[];
P5.PushRhs[tb[node].son[1]];
P5U.PushLitVal[0];
P5U.OutJump[JumpGE, poslabel];
P5U.Out0[qPUSH];
P5U.Out0[qNEG];
Stack.ResetToMark[];
P5U.OutJump[Jump, donelabel];
P5U.InsertLabel[poslabel];
P5U.Out0[qPUSH];
Stack.UnMark[];
P5U.InsertLabel[donelabel];
RETURN[P5L.TOSLex[1]]
END;

DAbs: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] =
BEGIN
poslabel: LabelCCIndex ← P5U.LabelAlloc[];
P5.PushRhs[tb[node].son[1]];
P5U.Out0[qDUP]; -- don’t use Stack.Dup since Neg will clear info
P5U.PushLitVal[0];
P5U.OutJump[JumpGE, poslabel];
P5U.Out0[qNEG];
P5U.InsertLabel[poslabel];
RETURN [P5L.TOSLex[1]];
END;


LongAbs: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] =
BEGIN
pos, done: LabelCCIndex;
var: VarComponent;
IF ~CPtr.dStar THEN Stack.Dump[];
Stack.Mark[];
var ← P5L.MakeComponent[P5L.VarForLex[P5.Exp[tb[node].son[1]]]];
var ← P5L.EasilyLoadable[var, load];
P5L.LoadComponent[var];
P5U.Out1[qLI, 0];
P5U.Out1[qLI, 0];
P5U.Out0[qDCOMP];
P5U.PushLitVal[0];
P5U.OutJump[JumpGE, pos ← P5U.LabelAlloc[]];
P5U.Out1[qLI, 0];
P5U.Out1[qLI, 0];
P5L.LoadComponent[var];
P5U.Out0[qDSUB];
Stack.ResetToMark[];
P5U.OutJump[Jump, done ← P5U.LabelAlloc[]];
P5U.InsertLabel[pos];
P5L.LoadComponent[var];
Stack.UnMark[];
P5U.InsertLabel[done];
RETURN [P5L.TOSLex[2]]
END;

RealAbs: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] =
BEGIN
pos, done: LabelCCIndex;
var, zero: VarComponent;
Stack.Dump[];
IF ~MPtr.switches[’f] THEN
BEGIN
P5U.PushLitVal[0];
P5U.PushLitVal[0];
P5U.Out0[qFLOAT];
zero ← Stack.TempStore[2];
END
ELSE zero ← [wSize: 2, space: const[d1: 0, d2: 0]];
var ← P5L.MakeComponent[P5L.VarForLex[P5.Exp[tb[node].son[1]]]];
var ← P5L.EasilyLoadable[var, load];
Stack.Mark[];
P5L.LoadComponent[var];
P5L.LoadComponent[zero];
P5U.Out0[qFCOMP];
P5U.PushLitVal[0];
P5U.OutJump[JumpGE, pos ← P5U.LabelAlloc[]];
P5L.LoadComponent[zero];
P5L.LoadComponent[var];
P5U.Out0[qFSUB];
Stack.ResetToMark[];
P5U.OutJump[Jump, done ← P5U.LabelAlloc[]];
P5U.InsertLabel[pos];
P5L.LoadComponent[var];
Stack.UnMark[];
P5U.InsertLabel[done];
RETURN [P5L.TOSLex[2]]
END;

Lengthen: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] =
BEGIN
r: VarIndex;
ime: BOOLEAN ← MPtr.switches[’x];
size: CARDINAL;

GenLP: PROCEDURE =
BEGIN -- short pointer only thing on stack
nilLabel, doneLabel: LabelCCIndex;
nilLabel ← P5U.LabelAlloc[];
doneLabel ← P5U.LabelAlloc[];
Stack.Mark[];
P5U.PushLitVal[0];
P5U.OutJump[JumpE, nilLabel];
P5U.Out0[qPUSH];
P5U.PushLitVal[177740B];
P5U.Out2[qRF, 0, 301B]; -- [12,1], a 2 bit field
Stack.ResetToMark[];
P5U.OutJump[Jump, doneLabel];
P5U.InsertLabel[nilLabel];
P5U.Out0[qPUSH];
P5U.Out0[qDUP];
Stack.UnMark[];
P5U.InsertLabel[doneLabel];
END;

IF ime THEN Stack.Dump[];
r ← P5L.VarForLex[P5.Exp[tb[node].son[1]]];
size ← P5L.VarAlignment[r, load].wSize;
IF size = 2 THEN -- array descriptor
BEGIN
IF P5L.AllLoaded[r] THEN
BEGIN
len: VarComponent ← Stack.TempStore[1];
IF ime THEN GenLP[] ELSE P5U.Out0[qLP];
P5L.LoadComponent[len];
END
ELSE
BEGIN
tr1, tr2: VarIndex;
[tr1, tr2] ← P5L.ReusableCopies[r, load];
P5L.FieldOfVar[r: tr1, wSize: 1];
P5L.FieldOfVar[r: tr2, wd: 1, wSize: 1];
P5L.LoadVar[tr1];
IF ime THEN GenLP[] ELSE P5U.Out0[qLP];
P5L.LoadVar[tr2];
END;
RETURN[P5L.TOSLex[3]]
END;
P5L.LoadVar[r];
IF tb[node].attr1 THEN IF ime THEN GenLP[] ELSE P5U.Out0[qLP]
ELSE IF tb[node].attr3 THEN P5U.Out0[qLINT]
ELSE P5U.Out1[qLI, 0];
RETURN [P5L.TOSLex[2]]
END;


And: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] =
BEGIN -- generate code for "AND"
t1: Tree.Link ← tb[node].son[1];
t2: Tree.Link ← tb[node].son[2];

RETURN[sCand[TRUE, t1, t2]]
END;


sCand: PROCEDURE [tf: BOOLEAN, t1, t2: Tree.Link] RETURNS [Lexeme] =
BEGIN -- main subroutine for Cand
label, elabel: LabelCCIndex;

label ← P5U.LabelAlloc[];
elabel ← P5U.LabelAlloc[];
Stack.Mark[];
BEGIN ENABLE P5.LogHeapFree => RESUME[FALSE, NullLex];
P5.FlowTree[t1, FALSE, label];
P5.FlowTree[t2, FALSE, label];
END;
P5U.PushLitVal[IF tf THEN 1 ELSE 0];
Stack.DeleteToMark[];
P5U.OutJump[Jump,elabel];
P5U.InsertLabel[label];
P5U.PushLitVal[IF tf THEN 0 ELSE 1];
P5U.InsertLabel[elabel];
RETURN[P5L.TOSLex[1]]
END;


Or: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] =
BEGIN -- generate code for "OR"
t1: Tree.Link ← tb[node].son[1];
t2: Tree.Link ← tb[node].son[2];

RETURN[sCor[TRUE, t1, t2]]
END;


sCor: PROCEDURE [tf: BOOLEAN, t1,t2: Tree.Link] RETURNS [Lexeme] =
BEGIN -- main subroutine for Cor
labelt, labelf, elabel: LabelCCIndex;

labelt ← P5U.LabelAlloc[];
labelf ← P5U.LabelAlloc[];
elabel ← P5U.LabelAlloc[];
Stack.Mark[];
BEGIN ENABLE P5.LogHeapFree => RESUME[FALSE, NullLex];
P5.FlowTree[t1, TRUE, labelt];
P5.FlowTree[t2, FALSE, labelf];
END;
P5U.InsertLabel[labelt];
P5U.PushLitVal[IF tf THEN 1 ELSE 0];
Stack.DeleteToMark[];
P5U.OutJump[Jump,elabel];
P5U.InsertLabel[labelf];
P5U.PushLitVal[IF tf THEN 0 ELSE 1];
P5U.InsertLabel[elabel];
RETURN[P5L.TOSLex[1]]
END;


Not: PROCEDURE [node: Tree.Index] RETURNS [l: Lexeme] =
BEGIN -- generate code for "NOT"
node1: Tree.Index;

BEGIN
WITH tb[node].son[1] SELECT FROM
subtree =>
BEGIN
node1 ← index;
SELECT tb[node1].name FROM
or => l ← sCor[FALSE, tb[node1].son[1], tb[node1].son[2]];
and => l ← sCand[FALSE, tb[node1].son[1], tb[node1].son[2]];
relE,relN,relL,relGE,relG,relLE => l ← Rel[node1, FALSE];
in => l ← In[node1, FALSE];
notin => l ← In[node1, TRUE];
not => P5.PushRhs[tb[node1].son[1]];
ENDCASE => GOTO VanillaNot;
RETURN [P5L.TOSLex[1]]
END;
ENDCASE;
EXITS
VanillaNot => NULL;
END;
P5.PushRhs[tb[node].son[1]];
P5U.PushLitVal[1];
P5U.Out0[qXOR];
RETURN[P5L.TOSLex[1]]
END;


Rel: PROCEDURE [node: Tree.Index, tf: BOOLEAN] RETURNS [Lexeme] =
BEGIN -- produces code for relationals outside flow
tlabel: LabelCCIndex ← P5U.LabelAlloc[];
elabel: LabelCCIndex ← P5U.LabelAlloc[];
P5.FlowTree[[subtree[node]], tf, tlabel];
P5U.PushLitVal[0];
P5U.OutJump[Jump, elabel];
P5U.InsertLabel[tlabel];
Stack.Off[];
P5U.PushLitVal[1];
Stack.On[];
P5U.InsertLabel[elabel];
RETURN[P5L.TOSLex[1]]
END;


In: PROCEDURE [node: Tree.Index, tf: BOOLEAN] RETURNS [Lexeme] =
BEGIN -- generates code for IN expression (outside flow)
label: LabelCCIndex ← P5U.LabelAlloc[];
elabel: LabelCCIndex ← P5U.LabelAlloc[];

Stack.Mark[];
P5.FlowIn[Tree.Link[subtree[node]], FALSE, label];
P5U.PushLitVal[IF tf THEN 1 ELSE 0];
P5U.OutJump[Jump, elabel];
Stack.DeleteToMark[];
P5U.InsertLabel[label];
P5U.PushLitVal[IF tf THEN 0 ELSE 1];
P5U.InsertLabel[elabel];
RETURN[P5L.TOSLex[1]]
END;


IfExp: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] =
BEGIN -- generates code for an IF expression
ilabel, elabel: LabelCCIndex;
t3: Tree.Link = tb[node].son[3];
t2: Tree.Link = tb[node].son[2];
nwords: CARDINAL;
tsei: ISEIndex ← ISENull;
bothConst: BOOLEAN ← P5U.TreeLiteral[t2] AND P5U.TreeLiteral[t3];
thenLong: BOOLEAN;
elseLong: BOOLEAN ← P5U.LongTreeAddress[t3];

elabel ← P5U.LabelAlloc[];
Stack.Mark[];
P5.FlowTree[tb[node].son[1], FALSE, elabel];
BEGIN ENABLE
P5.LogHeapFree => RESUME[FALSE, NullLex];
[nwords: nwords, long: thenLong, tsei: tsei] ← P5L.NormalizeExp[
P5L.VarForLex[P5.Exp[t2]], tsei, bothConst];
IF elseLong AND ~thenLong THEN P5U.Out0[FOpCodes.qLP];
Stack.ResetToMark[];
P5U.OutJump[Jump, ilabel ← P5U.LabelAlloc[]];
P5U.InsertLabel[elabel];
[] ← P5L.NormalizeExp[
P5L.VarForLex[P5.Exp[t3]], tsei, bothConst];
Stack.UnMark[];
IF thenLong AND ~elseLong THEN
BEGIN P5U.Out0[qLP]; elseLong ← TRUE END;
P5U.InsertLabel[ilabel];
END;
IF tsei # ISENull THEN P5.ReleaseTempLex[[se[tsei]]];
RETURN [P5L.NormalLex[nwords, elseLong, bothConst]];
END;


Min: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] =
BEGIN -- generate code for "MIN[...]"
real: BOOLEAN = tb[node].attr1;
double: BOOLEAN = real OR tb[node].attr2;
signed: BOOLEAN = tb[node].attr3;
sCminmax[relL,tb[node].son[1],double, real, signed];
RETURN[P5L.TOSLex[IF double THEN 2 ELSE 1]]
END;


Max: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] =
BEGIN -- generates code for "MAX[...]"
real: BOOLEAN = tb[node].attr1;
double: BOOLEAN = real OR tb[node].attr2;
signed: BOOLEAN = tb[node].attr3;
sCminmax[relG,tb[node].son[1],double, real, signed];
RETURN[P5L.TOSLex[IF double THEN 2 ELSE 1]]
END;


sCminmax: PROCEDURE [n: Tree.NodeName, t: Tree.Link, double, real, signed: BOOLEAN] =
BEGIN -- common subroutine for Cmin and Cmax
node: Tree.Index;
label1, label2: LabelCCIndex;
tlex: se Lexeme;
firstson: BOOLEAN ← TRUE;
sscm: PROCEDURE [t: Tree.Link] =
BEGIN
label3: LabelCCIndex;
var: VarComponent;
IF firstson THEN BEGIN firstson ← FALSE; RETURN END;
label3 ← P5U.LabelAlloc[];
var ← P5L.MakeComponent[P5L.VarForLex[P5.Exp[t]]];
IF double THEN var ← P5L.EasilyLoadable[var, load];
P5L.LoadComponent[var];
P5.PushLex[tlex];
IF double THEN
BEGIN
P5U.Out0[IF real THEN qFCOMP
ELSE IF signed THEN qDCOMP ELSE qDUCOMP];
P5U.PushLitVal[0];
END;
P5U.OutJump[IF double OR signed THEN JumpNN[RNN[n]]
ELSE UJumpNN[RNN[n]], label3];
IF double THEN P5L.LoadComponent[var] ELSE P5U.Out0[qPUSH];
P5.SAssign[tlex.lexsei];
P5U.InsertLabel[label3];
RETURN
END;

WITH t SELECT FROM
subtree =>
BEGIN
node ← index;
IF ~CPtr.dStar THEN Stack.Dump[];
P5.PushRhs[tb[node].son[1]];
IF ~double AND TreeOps.ListLength[t] = 2 THEN
BEGIN
P5.PushRhs[tb[node].son[2]];
label1 ← P5U.LabelAlloc[]; label2 ← P5U.LabelAlloc[];
P5U.OutJump[IF signed THEN JumpNN[n] ELSE UJumpNN[n], label1];
P5U.Out0[qPUSH]; P5U.Out0[qPUSH]; P5U.Out0[qEXCH]; P5U.Out0[qPOP];
P5U.OutJump[Jump,label2];
Stack.Decr[1];
P5U.InsertLabel[label1];
P5U.Out0[qPUSH];
P5U.InsertLabel[label2];
RETURN;
END;
tlex ← P5.GenTempLex[IF double THEN 2 ELSE 1];
P5.SAssign[tlex.lexsei];
TreeOps.ScanList[t, sscm];
P5.PushLex[tlex];
END;
ENDCASE;
RETURN
END;


END...