-- Expression.mesa, modified by Sweet, January 11, 1980 11:59 AM DIRECTORY AltoDefs: FROM "altodefs" USING [BYTE, BytesPerWord, wordlength], Code: FROM "code" USING [ caseCVState, CodeNotImplemented, dStar, mwCaseCV, xtracting, xtractlex], CodeDefs: FROM "codedefs" USING [Lexeme, VarComponent, VarIndex], ControlDefs: FROM "controldefs" USING [ ControlLink, EPRange, GFTNull, ProcDesc, SignalDesc], FOpCodes: FROM "fopcodes" USING [ qADD, qAND, qBNDCK, qDADD, qDDIV, qDESCB, qDESCBS, qDIV, qDMOD, qDMUL, qDSUB, qDUDIV, qDUMOD, qEXCH, qFADD, qFDIV, qFLOAT, qFMUL, qFSUB, qLI, qMUL, qNEG, qNILCK, qNILCKL, qPOP, qPUSH, qSDIV, qSHIFT, qSUB], InlineDefs: FROM "inlinedefs" USING [BITAND, BITSHIFT], Literals: FROM "literals" USING [LTIndex, ltType, MSTIndex, stType], OpCodeParams: FROM "opcodeparams" USING [GlobalHB, LocalHB], P5: FROM "p5" USING [ AllExp, CaseStmtExp, ConstructExp, FlowExp, GenTempLex, MoveToCodeWord, P5Error, RowConsExp, TTAssign, WriteCodeWord], P5L: FROM "p5l" USING [ AddrForVar, AdjustComponent, ComponentForLex, ComponentForSE, CopyLex, FieldOfVarOnly, GenVarItem, LoadBoth, LoadComponent, LoadVar, MakeComponent, OVarItem, TOSComponent, TOSLex, VarAlignment, VarForLex, Words], P5S: FROM "p5s" USING [ AssignExp, BodyInit, CallExp, DIndex, ErrExp, ForkExp, Index, JoinExp, New, PortInit, SeqIndex, SigExp, StartExp, StringInit, SubstExp, SysErrExp], P5U: FROM "p5u" USING [ OperandType, Out0, Out1, PushLitVal, TreeLiteral, TreeLiteralValue, WordsForOperand, WordsForSei], SDDefs: FROM "sddefs", Stack: FROM "stack" USING [Dump, Require], StringDefs: FROM "stringdefs" USING [StringHeaderSize], SymbolOps: FROM "symbolops" USING [ FnField, NormalType, UnderType, WordsForType, XferMode], Symbols: FROM "symbols" USING [ BitAddress, bodyType, BTIndex, BTNull, CBTIndex, ContextLevel, CSEIndex, CTXIndex, ctxType, HTIndex, ISEIndex, lZ, RecordSEIndex, SEIndex, seType], Table: FROM "table" USING [Base, Notifier], Tree: FROM "tree" USING [Index, Link, Null, treeType]; Expression: PROGRAM IMPORTS CPtr: Code, InlineDefs, P5, P5L, P5S, P5U, Stack, SymbolOps EXPORTS CodeDefs, P5 SHARES Literals, StringDefs = BEGIN OPEN FOpCodes, CodeDefs; -- imported definitions BYTE: TYPE = AltoDefs.BYTE; wordlength: CARDINAL = AltoDefs.wordlength; BytesPerWord: CARDINAL = AltoDefs.BytesPerWord; StringHeaderSize: CARDINAL = StringDefs.StringHeaderSize; MSTIndex: TYPE = Literals.MSTIndex; LocalHB: TYPE = OpCodeParams.LocalHB; GlobalHB: TYPE = OpCodeParams.GlobalHB; BitAddress: TYPE = Symbols.BitAddress; BTIndex: TYPE = Symbols.BTIndex; CBTIndex: TYPE = Symbols.CBTIndex; BTNull: BTIndex = Symbols.BTNull; ContextLevel: TYPE = Symbols.ContextLevel; CSEIndex: TYPE = Symbols.CSEIndex; RecordSEIndex: TYPE = Symbols.RecordSEIndex; CTXIndex: TYPE = Symbols.CTXIndex; HTIndex: TYPE = Symbols.HTIndex; ISEIndex: TYPE = Symbols.ISEIndex; lZ: ContextLevel = Symbols.lZ; SEIndex: TYPE = Symbols.SEIndex; LTIndex: TYPE = Literals.LTIndex; tb: Table.Base; -- tree base (local copy) seb: Table.Base; -- semantic entry base (local copy) ctxb: Table.Base; -- context entry base (local copy) bb: Table.Base; -- body entry base (local copy) cb: Table.Base; -- code base (local copy) stb: Table.Base; -- string base (local copy) ltb: Table.Base; -- literal base (local copy) ExpressionNotify: PUBLIC Table.Notifier = BEGIN -- called by allocator whenever table area is repacked stb ← base[Literals.stType]; seb ← base[Symbols.seType]; ctxb ← base[Symbols.ctxType]; bb ← base[Symbols.bodyType]; cb ← tb ← base[Tree.treeType]; ltb ← base[Literals.ltType]; RETURN END; recentExp: PUBLIC Tree.Link; -- for debugging Exp: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [l: Lexeme] = BEGIN -- generates code for an expression node: Tree.Index; WITH e: t SELECT FROM literal => WITH e.info SELECT FROM word => RETURN[Lexeme[literal[word[index]]]]; string => RETURN[Lexeme[literal[string[index]]]]; ENDCASE; symbol => BEGIN RETURN[Lexeme[se[e.index]]]; END; subtree => BEGIN recentExp ← t; IF e = Tree.Null THEN IF CPtr.xtracting THEN RETURN[CPtr.xtractlex] ELSE BEGIN SELECT CPtr.caseCVState FROM single => P5U.Out0[qPUSH]; singleLoaded => CPtr.caseCVState ← single; multi => RETURN [P5L.CopyLex[CPtr.mwCaseCV]]; ENDCASE => ERROR; RETURN [P5L.TOSLex[1]]; END; node ← e.index; SELECT tb[node].name FROM casex => BEGIN l ← P5.CaseStmtExp[node, TRUE]; END; assignx => l ← P5S.AssignExp[node]; plus => l ← Plus[node]; minus => l ← Minus[node]; div => l ← Div[node]; mod => l ← Mod[node]; times => l ← Times[node]; dot, uparrow => l ← DotOrUparrow[node]; reloc => l ← Reloc[node]; dollar => l ← Dollar[node]; uminus => l ← UMinus[node]; addr => l ← Addr[node]; index => l ← P5S.Index[node]; dindex => l ← P5S.DIndex[node]; construct => l ← P5.ConstructExp[Tree.Null, node]; arraydesc => l ← ArrayDesc[node]; length => l ← Length[node]; base => l ← Base[node]; portinit => l ← P5S.PortInit[node]; body => l ← P5S.BodyInit[node]; rowcons => l ← P5.RowConsExp[Tree.Null, node]; stringinit => l ← P5S.StringInit[node]; pad => BEGIN psei: SEIndex = tb[node].info; tlex: se Lexeme = P5.GenTempLex[SymbolOps.WordsForType[psei]]; P5.TTAssign[[symbol[tlex.lexsei]], t]; l ← tlex; END; cast => l ← Exp[tb[node].son[1]]; seqindex => l ← P5S.SeqIndex[node]; item => l ← Exp[tb[node].son[2]]; callx, portcallx => l ← P5S.CallExp[node]; substx => l ← P5S.SubstExp[node]; signalx => l ← P5S.SigExp[node]; errorx => l ← P5S.ErrExp[node]; syserrorx => l ← P5S.SysErrExp[node]; startx => l ← P5S.StartExp[node]; new => l ← P5S.New[node]; mwconst => l ← MwConst[node]; signalinit => l ← SignalInit[node]; fork => l ← P5S.ForkExp[node]; joinx => l ← P5S.JoinExp[node]; float => l ← Float[node]; check => BEGIN PushRhs[tb[node].son[1]]; PushRhs[tb[node].son[2]]; P5U.Out0[FOpCodes.qBNDCK]; l ← P5L.TOSLex[1]; END; chop => BEGIN len: CARDINAL ← P5U.WordsForSei[tb[node].info]; r: VarIndex ← P5L.VarForLex[Exp[tb[node].son[1]]]; P5L.FieldOfVarOnly[r: r, wSize: len]; l ← [bdo[r]]; END; all => BEGIN l ← P5.AllExp[Tree.Null, node]; END; ENDCASE => l ← P5.FlowExp[node]; END; ENDCASE; RETURN END; ConstOperand: PROCEDURE [t: Tree.Link] RETURNS [BOOLEAN, INTEGER] = BEGIN -- if t is a literal node, return [TRUE,val(t)] IF P5U.TreeLiteral[t] THEN RETURN [TRUE, P5U.TreeLiteralValue[t]] ELSE RETURN [FALSE, 0] END; Plus: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generate code for + real: BOOLEAN = tb[node].attr1; double: BOOLEAN = real OR tb[node].attr2; op1, op2: VarComponent; IF double THEN BEGIN IF ~CPtr.dStar OR real THEN Stack.Dump[]; END; op1 ← P5L.ComponentForLex[Exp[tb[node].son[1]]]; op2 ← P5L.ComponentForLex[Exp[tb[node].son[2]]]; P5L.LoadBoth[@op1, @op2, TRUE]; IF double THEN BEGIN P5U.Out0[IF real THEN qFADD ELSE qDADD]; RETURN[P5L.TOSLex[2]] END; P5U.Out0[qADD]; RETURN[P5L.TOSLex[1]] END; Minus: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generate code for - real: BOOLEAN = tb[node].attr1; double: BOOLEAN = real OR tb[node].attr2; IF double THEN BEGIN IF ~CPtr.dStar OR real THEN Stack.Dump[]; END; PushRhs[tb[node].son[1]]; PushRhs[tb[node].son[2]]; IF double THEN BEGIN P5U.Out0[IF real THEN qFSUB ELSE qDSUB]; RETURN[P5L.TOSLex[2]] END; P5U.Out0[qSUB]; RETURN[P5L.TOSLex[1]] END; UMinus: PROCEDURE [node: Tree.Index] RETURNS [l: Lexeme] = BEGIN -- generate code for unary minus tt: Tree.Link ← tb[node].son[1]; real: BOOLEAN = tb[node].attr1; double: BOOLEAN = real OR tb[node].attr2; WITH tt SELECT FROM subtree => IF tb[index].name = uminus THEN BEGIN PushRhs[tb[index].son[1]]; RETURN END; ENDCASE; IF double THEN BEGIN IF ~CPtr.dStar OR real THEN Stack.Dump[]; P5U.PushLitVal[0]; P5U.PushLitVal[0]; IF real THEN P5U.Out0[qFLOAT]; END; PushRhs[tt]; IF double THEN P5U.Out0[IF real THEN qFSUB ELSE qDSUB] ELSE P5U.Out0[qNEG]; RETURN [P5L.TOSLex[IF double THEN 2 ELSE 1]]; END; Times: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generates code for multiply real: BOOLEAN = tb[node].attr1; double: BOOLEAN = real OR tb[node].attr2; op1, op2: VarComponent; IF double THEN Stack.Require[0]; op1 ← P5L.ComponentForLex[Exp[tb[node].son[1]]]; op2 ← P5L.ComponentForLex[Exp[tb[node].son[2]]]; P5L.LoadBoth[@op1, @op2, TRUE]; IF double THEN BEGIN P5U.Out0[IF real THEN qFMUL ELSE qDMUL]; RETURN[P5L.TOSLex[2]]; END; P5U.Out0[qMUL]; RETURN[P5L.TOSLex[1]] END; Log2: PROCEDURE [i: INTEGER] RETURNS [BOOLEAN, [0..16]] = BEGIN OPEN InlineDefs; shift: [0..16]; IF i = 0 THEN RETURN [FALSE, 0]; i ← ABS[i]; IF BITAND[i, i-1] # 0 THEN RETURN [FALSE, 0]; FOR shift IN [0..16) DO IF BITAND[i,1] = 1 THEN RETURN[TRUE, shift]; i ← BITSHIFT[i, -1]; ENDLOOP; ERROR; -- can't get here, but it makes the compiler happy END; Div: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generate code for divide real: BOOLEAN = tb[node].attr1; double: BOOLEAN = real OR tb[node].attr2; signed: BOOLEAN = tb[node].attr3; rand2lit, powerof2: BOOLEAN; rand2val: INTEGER; shift: [0..16]; IF double THEN Stack.Require[0]; PushRhs[tb[node].son[1]]; IF ~double AND ~signed THEN BEGIN [rand2lit, rand2val] ← ConstOperand[tb[node].son[2]]; IF rand2lit AND rand2val > 0 THEN BEGIN [powerof2, shift] ← Log2[rand2val]; IF powerof2 THEN BEGIN P5U.PushLitVal[-shift]; P5U.Out0[qSHIFT]; RETURN [P5L.TOSLex[1]] END; END; END; PushRhs[tb[node].son[2]]; IF double THEN BEGIN P5U.Out0[IF real THEN qFDIV ELSE IF signed THEN qDDIV ELSE qDUDIV]; RETURN [P5L.TOSLex[2]]; END; IF signed THEN P5U.Out0[qSDIV] ELSE P5U.Out0[qDIV]; RETURN [P5L.TOSLex[1]]; END; Mod: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generate code for MOD real: BOOLEAN = tb[node].attr1; double: BOOLEAN = real OR tb[node].attr2; signed: BOOLEAN = tb[node].attr3; rand2lit, powerof2: BOOLEAN; rand2val: INTEGER; IF double THEN BEGIN IF real THEN SIGNAL CPtr.CodeNotImplemented; Stack.Dump[]; END; PushRhs[tb[node].son[1]]; IF ~double AND ~signed THEN BEGIN [rand2lit, rand2val] ← ConstOperand[tb[node].son[2]]; IF rand2lit AND rand2val > 0 THEN BEGIN [powerof2, ] ← Log2[rand2val]; IF powerof2 THEN BEGIN P5U.PushLitVal[rand2val-1]; P5U.Out0[qAND]; RETURN [P5L.TOSLex[1]]; END; END; END; PushRhs[tb[node].son[2]]; IF double THEN BEGIN P5U.Out0[IF signed THEN qDMOD ELSE qDUMOD]; RETURN [P5L.TOSLex[2]]; END; P5U.Out0[IF signed THEN qSDIV ELSE qDIV]; P5U.Out0[qPUSH]; P5U.Out0[qEXCH]; P5U.Out0[qPOP]; RETURN [P5L.TOSLex[1]]; END; Float: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN Stack.Dump[]; PushRhs[tb[node].son[1]]; P5U.Out0[qFLOAT]; RETURN[P5L.TOSLex[2]]; END; Addr: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generates code for "@" r: VarIndex; avar: VarComponent; r ← P5L.VarForLex[Exp[tb[node].son[1]]]; avar ← P5L.AddrForVar[r]; RETURN[[bdo[P5L.OVarItem[avar]]]] END; ArrayDesc: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- pushes two components of an array descriptor onto stack size: CARDINAL; WITH tb[node].son[1] SELECT FROM subtree => BEGIN size ← SPushRhs[tb[index].son[1]]; size ← SPushRhs[tb[index].son[2]] + size; END; ENDCASE; RETURN[P5L.TOSLex[size]] END; Length: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generates code to extract length from array descriptor -- relocs need not apply t1: Tree.Link = tb[node].son[1]; pW: CARDINAL = P5U.WordsForOperand[t1] - 1; r: VarIndex ← P5L.VarForLex[Exp[t1]]; P5L.FieldOfVarOnly[r: r, wd: pW, wSize: 1]; RETURN [[bdo[r]]]; END; Base: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generates code to extract base from array descriptor -- relocs get converted to addr t1: Tree.Link = tb[node].son[1]; pW: CARDINAL = P5U.WordsForOperand[t1] - 1; r: VarIndex ← P5L.VarForLex[Exp[t1]]; P5L.FieldOfVarOnly[r: r, wSize: pW]; RETURN [[bdo[r]]]; END; DotOrUparrow: PROCEDURE [mainnode: Tree.Index] RETURNS [Lexeme] = BEGIN -- generate code for "exp.field" t1: Tree.Link ← tb[mainnode].son[1]; sei: ISEIndex; r: VarIndex; long: BOOLEAN = tb[mainnode].attr2; nilCheck: BOOLEAN = tb[mainnode].attr1; base: VarComponent; offset: VarComponent; -- fields of code data are dollar nodes IF tb[mainnode].name = uparrow THEN sei ← tb[mainnode].info ELSE WITH tb[mainnode].son[2] SELECT FROM symbol => sei ← index; ENDCASE; BEGIN -- to set up useBdo label IF nilCheck THEN BEGIN PushRhs[t1]; P5U.Out0[IF long THEN FOpCodes.qNILCKL ELSE FOpCodes.qNILCK]; base ← P5L.TOSComponent[IF long THEN 2 ELSE 1]; END ELSE WITH t1 SELECT FROM subtree => BEGIN stnode: Tree.Index = index; SELECT tb[stnode].name FROM plus => BEGIN disp: VarComponent; base ← P5L.ComponentForLex[Exp[tb[stnode].son[1]]]; disp ← P5L.ComponentForLex[Exp[tb[stnode].son[2]]]; r ← P5L.GenVarItem[bdo]; cb[r] ← [body: bdo[base: base, disp: disp, offset: NULL]]; GO TO useBdo; END; ENDCASE; END; ENDCASE; base ← P5L.ComponentForLex[Exp[t1]]; r ← P5L.GenVarItem[bo]; cb[r] ← [body: bo[base: base, offset: NULL]]; EXITS useBdo => NULL; END; IF tb[mainnode].name = uparrow THEN offset ← [wSize: P5U.WordsForSei[sei], space: frame[wd: 0]] ELSE IF seb[sei].constant THEN BEGIN -- procedure or signal from pointer to frame RETURN[ConstantField[@base, sei]] END ELSE BEGIN psei: CSEIndex = SymbolOps.NormalType[P5U.OperandType[tb[mainnode].son[1]]]; offset ← P5L.ComponentForSE[sei]; WITH offset SELECT FROM frame => level ← lZ; -- to take care of pointer to frame ENDCASE => ERROR; WITH seb[psei] SELECT FROM pointer => BEGIN OPEN SymbolOps; rcsei: CSEIndex ← UnderType[refType]; -- if we point to a type, it fills a number of full words WITH seb[rcsei] SELECT FROM record => P5L.AdjustComponent[var: @offset, rSei: LOOPHOLE[rcsei], fSei: sei, tBits: WordsForType[rcsei]*wordlength]; ENDCASE; END; ENDCASE => P5.P5Error[642]; END; WITH cc: cb[r] SELECT FROM bo => cc.offset ← offset; bdo => cc.offset ← offset; ENDCASE => ERROR; RETURN[[bdo[r]]] END; Reloc: PUBLIC PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generates code for "baseptr[relptr]" rd, rr: VarIndex; base, disp: VarComponent; base ← P5L.ComponentForLex[Exp[tb[node].son[1]]]; rd ← P5L.VarForLex[Exp[tb[node].son[2]]]; IF tb[node].attr1 THEN BEGIN -- reloc of an array descriptor dsize: CARDINAL = P5U.WordsForOperand[tb[node].son[2]] - 1; P5L.FieldOfVarOnly[r: rd, wSize: dsize]; END; disp ← P5L.MakeComponent[rd]; rr ← P5L.GenVarItem[bdo]; cb[rr] ← [body: bdo[base: base, disp: disp, offset: [wSize: SymbolOps.WordsForType[tb[node].info], space: frame[]]]]; RETURN[[bdo[rr]]]; END; ConstantField: PROCEDURE [ var: POINTER TO VarComponent, sei: ISEIndex] RETURNS [Lexeme] = BEGIN p: ControlDefs.ProcDesc; bti: CBTIndex; SELECT SymbolOps.XferMode[seb[sei].idType] FROM procedure => BEGIN IF seb[sei].extended THEN SIGNAL CPtr.CodeNotImplemented; bti ← seb[sei].idInfo; IF bti = BTNull THEN BEGIN RETURN [[bdo[ P5L.OVarItem[ [wSize: 1, space: const[d1: seb[sei].idValue]]]]]]; END; IF var.wSize > 1 THEN SIGNAL CPtr.CodeNotImplemented; P5L.LoadComponent[var↑]; WITH bb[bti] SELECT FROM Inner => BEGIN -- could happen with pointer to procedure frame P5U.Out1[FOpCodes.qLI, frameOffset]; P5U.Out0[FOpCodes.qADD]; END; Outer => BEGIN OPEN ControlDefs; p.gfi ← entryIndex/EPRange; p.ep ← entryIndex MOD EPRange; p.tag ← procedure; P5U.Out1[qDESCBS, LOOPHOLE[p]]; END; ENDCASE; END; signal, error => BEGIN p ← seb[sei].idValue; p.gfi ← p.gfi-1; IF var.wSize > 1 THEN SIGNAL CPtr.CodeNotImplemented; P5L.LoadComponent[var↑]; P5U.Out1[qDESCBS, LOOPHOLE[p]]; END; ENDCASE => P5.P5Error[643]; RETURN [P5L.TOSLex[1]]; END; Dollar: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN -- generates code for "exp$field" sei: ISEIndex; r: VarIndex; recsei: RecordSEIndex ← LOOPHOLE[P5U.OperandType[tb[node].son[1]]]; functionCall: BOOLEAN; tBits, twSize: CARDINAL; tbSize: [0..wordlength); foffset: frame VarComponent; functionCall ← seb[recsei].argument; r ← P5L.VarForLex[Exp[tb[node].son[1]]]; [wSize: twSize, bSize: tbSize] ← P5L.VarAlignment[r, load]; tBits ← twSize*wordlength + tbSize; WITH tb[node].son[2] SELECT FROM symbol => BEGIN sei ← index; IF seb[sei].constant THEN BEGIN fpvar: VarComponent; WITH tb[node].son[1] SELECT FROM subtree => BEGIN node: Tree.Index = index; IF tb[node].name # uparrow THEN P5.P5Error[645]; fpvar ← P5L.ComponentForLex[Exp[tb[node].son[1]]]; END; ENDCASE => P5.P5Error[646]; RETURN [ConstantField[@fpvar, sei]]; END; IF functionCall THEN BEGIN fSize: CARDINAL; fAddr: BitAddress; [fAddr,fSize] ← SymbolOps.FnField[sei]; foffset ← [wSize: fSize / wordlength, bSize: fSize MOD wordlength, space: frame[wd: fAddr.wd, bd: fAddr.bd]]; END ELSE foffset ← LOOPHOLE[P5L.ComponentForSE[sei]]; IF tBits <= wordlength THEN P5L.AdjustComponent[var: @foffset, rSei: recsei, fSei: sei, tBits: tBits]; P5L.FieldOfVarOnly[r: r, wSize: foffset.wSize, bSize: foffset.bSize, wd: foffset.wd, bd: foffset.bd]; RETURN [[bdo[r]]]; END; ENDCASE => ERROR; END; MwConst: PROCEDURE [node: Tree.Index] RETURNS [l: Lexeme] = BEGIN -- puts multi-word constant out to code stream lti: LTIndex; WITH tb[node].son[1] SELECT FROM literal => WITH info SELECT FROM word => lti ← index; ENDCASE => P5.P5Error[647]; ENDCASE => P5.P5Error[648]; WITH ll:ltb[lti] SELECT FROM short => RETURN [[literal[word[lti]]]]; long => BEGIN var: VarComponent; SELECT ll.length FROM 0 => P5.P5Error[649]; 1 => var ← [wSize: 1, space: const[d1: ll.value[0]]]; 2 =>var ← [wSize: 2, space: const[d1: ll.value[0], d2: ll.value[1]]]; ENDCASE => BEGIN nwords: CARDINAL ← ll.length; i: CARDINAL; IF ll.codeIndex = 0 THEN BEGIN ll.codeIndex ← P5.MoveToCodeWord[]; FOR i IN [0..nwords) DO P5.WriteCodeWord[ll.value[i]]; ENDLOOP; END; var ← [wSize: nwords, space: code[wd: ll.codeIndex]]; END; RETURN[[bdo[P5L.OVarItem[var]]]]; END; ENDCASE => ERROR; -- to keep the compiler happy END; DoubleZero: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [BOOLEAN] = BEGIN node: Tree.Index; lti: LTIndex; WITH t SELECT FROM subtree => node ← index; ENDCASE => GO TO retFalse; IF tb[node].name # mwconst THEN GO TO retFalse; WITH tb[node].son[1] SELECT FROM literal => WITH info SELECT FROM word => lti ← index; ENDCASE => GO TO retFalse; ENDCASE => GO TO retFalse; WITH ll:ltb[lti] SELECT FROM long => SELECT ll.length FROM 2 => IF ll.value[0] = 0 AND ll.value[1] = 0 THEN RETURN[TRUE]; ENDCASE; ENDCASE; GO TO retFalse; EXITS retFalse => RETURN[FALSE]; END; LPushRhs: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [Lexeme] = BEGIN -- forces a value onto the stack wSize: CARDINAL ← SPushRhs[t]; RETURN [P5L.TOSLex[wSize]]; END; PushRhs: PUBLIC PROCEDURE [t: Tree.Link] = BEGIN -- forces a value onto the stack [] ← SPushRhs[t]; RETURN END; SPushRhs: PROCEDURE [t: Tree.Link] RETURNS [wSize: CARDINAL] = BEGIN -- forces a value onto the stack RETURN[SPushLex[Exp[t]]]; END; SPushLex: PROCEDURE [l: Lexeme] RETURNS [wSize: CARDINAL] = BEGIN -- forces a lexeme onto the stack r: VarIndex = P5L.VarForLex[l]; ws, bs: CARDINAL; [wSize: ws, bSize: bs] ← P5L.VarAlignment[r,load]; wSize ← P5L.Words[ws, bs]; P5L.LoadVar[r]; END; PushLex: PUBLIC PROCEDURE [l: Lexeme] = BEGIN [] ← SPushLex[l]; END; LPushLex: PUBLIC PROCEDURE [l: Lexeme] RETURNS [Lexeme] = BEGIN wSize: CARDINAL ← SPushLex[l]; RETURN [P5L.TOSLex[wSize]]; END; PushLProcDesc: PUBLIC PROCEDURE [bti: CBTIndex] = BEGIN -- pushes a descriptor for local procedure on stack WITH bb[bti] SELECT FROM Inner => PushNestedProcDesc[bti]; Outer => PushNonnestedProcDesc[entryIndex]; ENDCASE; RETURN END; PushNestedProcDesc: PUBLIC PROCEDURE [bti: CBTIndex] = BEGIN -- pushes a descriptor for nested local procedure on stack v: ContextLevel ← bb[bti].level - 1; WITH bb[bti] SELECT FROM Inner => BEGIN avar: VarComponent = [wSize: 1, space: faddr[wd: frameOffset, level: v]]; P5L.LoadComponent[avar]; RETURN END; ENDCASE END; PushNonnestedProcDesc: PUBLIC PROCEDURE [n: CARDINAL] = BEGIN -- pushes a descriptor for local procedure n on stack OPEN ControlDefs; p: ProcDesc; p.gfi ← n/EPRange; p.ep ← n MOD EPRange; p.tag ← procedure; P5U.Out1[qDESCB, LOOPHOLE[p]]; RETURN END; PushLSigDesc: PROCEDURE [desc: ControlDefs.SignalDesc] = BEGIN IF desc.gfi # ControlDefs.GFTNull THEN BEGIN desc.gfi ← desc.gfi-1; P5U.Out1[qDESCB, LOOPHOLE[desc]]; END ELSE P5U.PushLitVal[desc]; RETURN END; SignalInit: PROCEDURE [node: Tree.Index] RETURNS [Lexeme] = BEGIN OPEN ControlDefs; v: CARDINAL ← tb[node].info; P5U.Out1[qDESCB, LOOPHOLE[ControlLink[procedure[ gfi: v/EPRange, ep: v MOD EPRange, tag: procedure]]]]; RETURN [P5L.TOSLex[1]] END; END...