-- VarBasics.mesa -- last edited by Sweet, 5-Aug-82 14:10:10 -- last edited by Satterthwaite, January 11, 1983 5:14 pm DIRECTORY Alloc: TYPE USING [Notifier], Code: TYPE USING [CodeNotImplemented, curctxlvl], CodeDefs: TYPE USING [ Base, BoVarIndex, BYTE, codeType, DataStackIndex, Lexeme, NullLex, StackBackup, StackLocRec, VarComponent, VarIndex, VarNull, wordlength], FOpCodes: TYPE USING [ qACD, qADC, qADD, qAMUL, qAND, qBLT, qBLTC, qBLTCL, qBLTL, qDADD, qDIS, qLI, qLL, qLLK, qLP, qMUL, qR, qRC, qRCFS, qREC, qSHIFTSB], Inline: TYPE USING [LongNumber], LiteralOps: TYPE USING [FindDescriptor], Literals: TYPE USING [Base, LTIndex, ltType], P5: TYPE USING [MoveToCodeWord, WriteCodeWord], P5L: TYPE USING [ AllLoaded, CopyToTemp, CopyVarItem, EasilyLoadable, FieldOfVar, GenVarItem, LoadComponent, LoadVar, ModComponent, LongVarAddress, OVarItem, ReleaseVarItem, ReusableCopies, StoreVar, TOSComponent, TOSLex, VarAddressEasy, VarAlignment], P5U: TYPE USING [Out0, Out1, RecordConstant], PrincOps: TYPE USING [FieldDescriptor, framelink, localbase], Stack: TYPE USING [ Above, Also, DataIndex, Forget, Load, Loc, Pop, TempStore, Top], Symbols: TYPE USING [Base, ContextLevel, ctxType, lG, lZ, seType]; VarBasics: PROGRAM IMPORTS CPtr: Code, LiteralOps, P5, P5U, P5L, Stack EXPORTS P5L, CodeDefs = BEGIN OPEN FOpCodes, CodeDefs, Symbols; cb: CodeDefs.Base; seb, ctxb: Symbols.Base; ltb: Literals.Base; VarBasicsNotify: PUBLIC Alloc.Notifier = BEGIN -- called by allocator whenever table area is repacked seb ← base[Symbols.seType]; ctxb ← base[Symbols.ctxType]; cb ← base[codeType]; ltb ← base[Literals.ltType]; END; AddrComponent: PUBLIC PROC [var: VarComponent] RETURNS [avar: VarComponent] = BEGIN WITH vv: var SELECT FROM code => RETURN [[wSize: 1, space: caddr[wd: vv.wd]]]; frame => RETURN [[wSize: 1, space: faddr[level: vv.level, wd: vv.wd]]]; frameup => BEGIN base: VarComponent = [wSize: vv.pwSize, space: frame[wd: vv.wd, level: vv.level, immutable: vv.immutable]]; IF vv.delta = 0 THEN RETURN [base]; P5L.LoadComponent[base]; GenAdd[vv.delta, base.wSize > 1]; RETURN [P5L.TOSComponent[base.wSize]] END; linkup => BEGIN IF vv.delta = 0 THEN RETURN [[wSize: 1, space: link[wd: vv.wd]]]; P5U.Out1[qLLK, vv.wd]; GenAdd[vv.delta]; RETURN [P5L.TOSComponent[1]] END; stack => IF vv.wd = 0 AND vv.bd = 0 THEN BEGIN loc: StackLocRec = Stack.Loc[vv.sti, var.wSize]; WITH ll: loc SELECT FROM contig => WITH bb: ll.place SELECT FROM frame => BEGIN Stack.Forget[vv.sti, var.wSize]; RETURN [[wSize: 1, space: faddr[level: bb.tLevel, wd: bb.tOffset]]] END; ENDCASE; ENDCASE; END; caddr => ERROR; -- nobody should be taking the address of a code address ENDCASE; -- faddr, link, const, pdesc -- put it in a temp, generate addr of temp RETURN [AddrComponent[P5L.CopyToTemp[P5L.OVarItem[var]].var]] END; AddrForVar: PUBLIC PROC [r: VarIndex, codeOk: BOOL←FALSE] RETURNS [avar: VarComponent] = BEGIN WITH cc: cb[r] SELECT FROM o => BEGIN IF ~codeOk AND cc.var.tag = code THEN ERROR; avar ← AddrComponent[cc.var]; END; bo => BEGIN WITH oo: cc.offset SELECT FROM frame => IF oo.level = lZ AND oo.wd = 0 THEN avar ← cc.base ELSE WITH vv: cc.base SELECT FROM faddr => {vv.wd ← vv.wd + oo.wd; avar ← vv}; ENDCASE => GO TO loadIt; code => IF codeOk AND oo.wd = 0 THEN avar ← cc.base ELSE GO TO loadIt; ENDCASE => ERROR; END; ENDCASE => GO TO loadIt; P5L.ReleaseVarItem[r]; EXITS loadIt => BEGIN long: BOOL = LoadAddress[r, codeOk]; avar ← P5L.TOSComponent[IF long THEN 2 ELSE 1]; END; END; BaseComponent: PUBLIC PROC [lvl: ContextLevel] RETURNS [VarComponent] = BEGIN IF lvl >= CPtr.curctxlvl THEN ERROR; IF lvl + 1 = CPtr.curctxlvl THEN RETURN [[wSize: 1, space: frame[ immutable: TRUE, wd: PrincOps.framelink, level: CPtr.curctxlvl]]]; P5U.Out1[qLL, PrincOps.framelink]; THROUGH (lvl..CPtr.curctxlvl) DO P5U.Out1[qR, PrincOps.framelink - PrincOps.localbase]; ENDLOOP; RETURN [P5L.TOSComponent[1]] END; GenAdd: PUBLIC PROC [delta: UNSPECIFIED, long: BOOL←FALSE] = BEGIN n: [1..2] = IF long THEN 2 ELSE 1; Stack.Load[Stack.Top[n],n]; P5U.Out1[qLI, LOOPHOLE[delta, CARDINAL]]; P5U.Out0[IF long THEN qADC ELSE qADD]; END; GenAnd: PUBLIC PROC [delta: UNSPECIFIED] = BEGIN P5U.Out1[qLI, LOOPHOLE[delta, CARDINAL]]; P5U.Out0[qAND]; END; GenRFC: PUBLIC PROC [wd: CARDINAL, bd: [0..16), len: [1..16]] = BEGIN IF bd = 0 AND len = 16 THEN { IF wd > BYTE.LAST THEN {GenAdd[wd-BYTE.LAST]; wd ← BYTE.LAST}; P5U.Out1[qRC, wd]} ELSE { IF wd > BYTE.LAST THEN {GenAdd[wd-BYTE.LAST]; wd ← BYTE.LAST}; P5U.Out1[qLI, LOOPHOLE[PrincOps.FieldDescriptor[offset: wd, posn: bd, size: len]]]; P5U.Out0[qRCFS]}; END; GenShift: PUBLIC PROC [delta: UNSPECIFIED] = BEGIN IF INTEGER[delta] IN [-15..15] THEN P5U.Out1[qSHIFTSB, delta] ELSE { P5U.Out0[qDIS]; P5U.Out1[qLI, 0]}; END; LoadAddress: PUBLIC PROC [r: VarIndex, codeOk: BOOL←FALSE] RETURNS [long: BOOL] = BEGIN bor: BoVarIndex; base, offset: VarComponent; owd: CARDINAL; WITH cc: cb[r] SELECT FROM o => BEGIN avar: VarComponent ← AddrComponent[cc.var]; P5L.ReleaseVarItem[r]; IF avar.tag = caddr AND ~codeOk THEN ERROR; P5L.LoadComponent[avar]; RETURN [FALSE] END; ENDCASE; bor ← MakeBo[r]; IF bor = VarNull THEN SIGNAL CPtr.CodeNotImplemented; base ← cb[bor].base; offset ← cb[bor].offset; P5L.ReleaseVarItem[bor]; long ← Words[base.wSize, base.bSize] > 1; WITH oo: offset SELECT FROM frame => BEGIN IF oo.level # lZ THEN ERROR CPtr.CodeNotImplemented; owd ← oo.wd; END; code => BEGIN IF ~codeOk OR long THEN ERROR; owd ← oo.wd; END; ENDCASE => ERROR; WITH vv: base SELECT FROM faddr => IF vv.wd + owd IN BYTE THEN BEGIN vv.wd ← vv.wd + owd; owd ← 0; END; ENDCASE; P5L.LoadComponent[base]; IF owd # 0 THEN GenAdd[owd, long]; END; LoadBoth: PUBLIC PROC [atC1, atC2: POINTER TO VarComponent, abelian: BOOL] = BEGIN [] ← LoadBothInternal[atC1, atC2, abelian]; END; LoadBothInternal: PRIVATE PROC [atC1, atC2: POINTER TO VarComponent, abelian: BOOL] RETURNS [s1Size, s2Size: CARDINAL] = BEGIN c1: VarComponent ← atC1↑; c2: VarComponent ← atC2↑; c1Loaded, c2Loaded: BOOL ← FALSE; c1Depth, c2Depth: CARDINAL; c1Size: CARDINAL = Words[c1.wSize, c1.bSize]; c2Size: CARDINAL = Words[c2.wSize, c2.bSize]; WITH cc: c1 SELECT FROM stack => IF cc.bd = 0 AND c1.bSize = 0 THEN BEGIN loc: StackLocRec = Stack.Loc[cc.sti, c1Size]; WITH loc SELECT FROM onStack => {c1Depth ← depth; c1Loaded ← TRUE}; ENDCASE; END; ENDCASE; WITH cc: c2 SELECT FROM stack => IF cc.bd = 0 AND c2.bSize = 0 THEN BEGIN loc: StackLocRec = Stack.Loc[cc.sti, c2Size]; WITH loc SELECT FROM onStack => {c2Depth ← depth; c2Loaded ← TRUE}; ENDCASE; END; ENDCASE; BEGIN -- to set up loadBoth label IF ~(c1Loaded OR c2Loaded) THEN GO TO loadBoth; IF c1Loaded AND c2Loaded THEN SELECT TRUE FROM (c1Depth = c2Size AND c2Depth = 0) => RETURN [c1Size, c2Size]; (abelian AND c2Depth = c1Size AND c1Depth = 0) => RETURN [c2Size, c1Size]; ENDCASE => GO TO loadBoth; -- considered unlikely IF c1Loaded THEN BEGIN IF c1Depth # 0 THEN P5L.LoadComponent[c1]; P5L.LoadComponent[c2]; RETURN [c1Size, c2Size]; END ELSE -- c2Loaded BEGIN IF c2Depth # 0 THEN {P5L.LoadComponent[c2]; c2 ← P5L.TOSComponent[c2Size]}; IF ~abelian AND (c1Size>1 OR c2Size>1) THEN c2 ← Stack.TempStore[c2Size]; P5L.LoadComponent[c1]; IF ~abelian THEN P5L.LoadComponent[c2]; IF abelian THEN RETURN[c2Size, c1Size] ELSE RETURN [c1Size, c2Size]; END; EXITS loadBoth => {P5L.LoadComponent[c1]; P5L.LoadComponent[c2]; RETURN [c1Size, c2Size]}; END; END; LoadSum: PUBLIC PROC [atB, atD: POINTER TO VarComponent] RETURNS [bpSize: [1..2]] = BEGIN -- atB and atD are of size IN [1..2] s1Size, s2Size: [1..2]; AddOp: ARRAY [1..2] OF ARRAY [1..2] OF BYTE = [ [FOpCodes.qADD, FOpCodes.qACD], [FOpCodes.qADC, FOpCodes.qDADD]]; [s1Size, s2Size] ← LoadBothInternal[atB, atD, TRUE]; P5U.Out0[AddOp[s1Size][s2Size]]; RETURN [MAX[s1Size, s2Size]]; END; MakeBo: PUBLIC PROC [r: VarIndex] RETURNS [bor: BoVarIndex] = BEGIN base, disp, offset: VarComponent; bpSize: [1..2]; WITH cb[r] SELECT FROM bo => RETURN [LOOPHOLE[r]]; ENDCASE; bor ← LOOPHOLE[P5L.GenVarItem[bo]]; cb[bor] ← [body: bo[base: NULL, offset: NULL]]; -- set tag WITH cc: cb[r] SELECT FROM o => BEGIN var: VarComponent ← cc.var; vbSize: [0..16) = var.bSize; vwSize: CARDINAL = var.wSize; wS: CARDINAL = Words[vwSize, vbSize]; P5L.ReleaseVarItem[r]; WITH vv: var SELECT FROM frameup => BEGIN cb[bor].base ← [wSize: vv.pwSize, space: frame[wd: vv.wd, level: vv.level, immutable: vv.immutable]]; cb[bor].offset ← [wSize: vwSize, space: frame[wd: vv.delta]]; RETURN END; linkup => BEGIN cb[bor].base ← [wSize: 1, space: link[wd: vv.wd]]; cb[bor].offset ← [wSize: vwSize, space: frame[wd: vv.delta]]; RETURN END; code => cb[bor].offset ← [wSize: NULL, bSize: NULL, space: code[bd: vv.bd]]; frame => cb[bor].offset ← [wSize: NULL, bSize: NULL, space: frame[bd: vv.bd]]; stack => { cb[bor].offset ← [wSize: NULL, bSize: NULL, space: frame[bd: vv.bd]]; var.wSize ← wS; var.bSize ← 0; vv.bd ← 0}; const => BEGIN IF wS = 1 THEN { cb[bor].offset ← -- can't index packed in code anyway [wSize: NULL, bSize: NULL, space: frame[bd: vv.bd]]; var.wSize ← wS; var.bSize ← 0; vv.bd ← 0} ELSE BEGIN -- wS = 2 const: ARRAY [0..1] OF CARDINAL ← [vv.d1, vv.d2]; lti: Literals.LTIndex = LiteralOps.FindDescriptor[DESCRIPTOR[const]].lti; cb[bor].offset ← [wSize: NULL, bSize: NULL, space: code[bd: vv.bd]]; WITH ll: ltb[lti] SELECT FROM long => BEGIN IF ll.codeIndex = 0 THEN BEGIN ll.codeIndex ← P5.MoveToCodeWord[]; P5.WriteCodeWord[const[0]]; P5.WriteCodeWord[const[1]]; P5U.RecordConstant[ll.codeIndex, 2]; END; var ← [wSize: 2, space: code[wd: ll.codeIndex]]; END; ENDCASE => ERROR; END; END; ENDCASE => ERROR; cb[bor].base ← AddrComponent[var]; cb[bor].offset.wSize ← vwSize; cb[bor].offset.bSize ← vbSize; RETURN END; bdo => {disp ← cc.disp; base ← cc.base; offset ← cc.offset}; ind => BEGIN eWords: CARDINAL; base ← cc.base; disp ← cc.index; offset ← cc.offset; WITH pp: cc SELECT FROM packed => {P5L.ReleaseVarItem[bor]; RETURN [LOOPHOLE[VarNull]]}; notPacked => eWords ← pp.eWords; ENDCASE; IF eWords # 1 THEN BEGIN WITH vv: disp SELECT FROM const => BEGIN ld: Inline.LongNumber; ld.lc ← LONG[CARDINAL[vv.d1]] * LONG[eWords]; vv.d1 ← ld.lowbits; IF ld.highbits # 0 THEN {vv.wSize ← 2; vv.d2 ← ld.highbits}; GO TO const; END; ENDCASE; P5L.LoadComponent[disp]; P5U.Out1[qLI, eWords]; IF cc.simple THEN BEGIN P5U.Out0[qMUL]; disp ← P5L.TOSComponent[1]; END ELSE BEGIN P5U.Out0[qAMUL]; P5U.Out0[qREC]; disp ← P5L.TOSComponent[2]; END; EXITS const => NULL; END; END; ENDCASE; P5L.ReleaseVarItem[r]; WITH vv: disp SELECT FROM const => IF vv.wSize = 1 AND vv.bSize = 0 THEN BEGIN ld: Inline.LongNumber; owd: CARDINAL; WITH oo: offset SELECT FROM frame => owd ← oo.wd; code => owd ← oo.wd; ENDCASE => ERROR; ld.lc ← LONG[owd] + LONG[CARDINAL[vv.d1]]; IF ld.highbits = 0 THEN BEGIN P5L.ModComponent[var: @offset, wd: vv.d1]; cb[bor].base ← base; cb[bor].offset ← offset; RETURN END; END; ENDCASE; bpSize ← LoadSum[@base, @disp]; cb[bor].base ← P5L.TOSComponent[bpSize]; cb[bor].offset ← offset; END; MakeComponent: PUBLIC PROC [r: VarIndex, allowFields: BOOL ← FALSE] RETURNS [var: VarComponent] = BEGIN wS: CARDINAL; WITH cc: cb[r] SELECT FROM o => {var ← cc.var; GO TO freer}; bo => BEGIN WITH oo: cc.offset SELECT FROM code => WITH bb: cc.base SELECT FROM caddr => BEGIN var ← [wSize: cc.offset.wSize, bSize: cc.offset.bSize, space: code[wd: bb.wd + oo.wd, bd: oo.bd]]; GO TO freer; END; ENDCASE; frame => WITH bb: cc.base SELECT FROM faddr => SELECT bb.level FROM lG, CPtr.curctxlvl => BEGIN var ← [ wSize: cc.offset.wSize, bSize: cc.offset.bSize, space: frame[level: bb.level, wd: bb.wd + oo.wd, bd: oo.bd]]; GO TO freer; END; ENDCASE; frame => IF ~allowFields AND cc.base.bSize = 0 AND cc.base.wSize IN [1..2] AND cc.offset.bSize = 0 AND cc.offset.wSize = 1 AND oo.level = lZ THEN BEGIN var ← [ wSize: cc.offset.wSize, space: frameup[ level: bb.level, wd: bb.wd, pwSize: cc.base.wSize, delta: oo.wd, immutable: bb.immutable]]; GO TO freer; END; link => IF ~allowFields AND cc.offset.bSize = 0 AND cc.offset.wSize IN [1..2] AND oo.level = lZ THEN BEGIN var ← [ wSize: cc.offset.wSize, space: linkup[wd: bb.wd, delta: oo.wd]]; GO TO freer; END; ENDCASE; ENDCASE => ERROR; wS ← Words[cc.offset.wSize, cc.offset.bSize]; END; bdo => wS ← Words[cc.offset.wSize, cc.offset.bSize]; ind => wS ← Words[cc.offset.wSize, cc.offset.bSize]; ENDCASE; IF wS > 2 THEN var ← P5L.CopyToTemp[r].var ELSE {P5L.LoadVar[r]; var ← P5L.TOSComponent[wS]}; EXITS freer => P5L.ReleaseVarItem[r]; END; VarVarAssign: PUBLIC PROC [to, from: VarIndex, isexp: BOOL] RETURNS [l: Lexeme] = BEGIN bSize, tbd: [0..wordlength); wSize, wS: CARDINAL; trashOnStack: CARDINAL ← 0; l ← NullLex; [bd: tbd, bSize: bSize, wSize: wSize] ← P5L.VarAlignment[to, store]; wS ← Words[wSize, bSize]; WITH cc: cb[from] SELECT FROM o => WITH vv: cc.var SELECT FROM stack => IF vv.wd # 0 THEN IF isexp THEN BEGIN P5L.LoadVar[from]; -- causing from to be freed from ← P5L.OVarItem[P5L.TOSComponent[wS]]; END ELSE BEGIN tvar: VarComponent; trashOnStack ← vv.wd; vv.wd ← 0; tvar ← cc.var; -- to avoid passing address of chunk P5L.ModComponent[var: @tvar, wd: trashOnStack]; cc.var ← tvar; END; ENDCASE; ENDCASE; IF wS <= 2 THEN BEGIN -- it's 2 words at most alsoLink: BOOL ← FALSE; tLevel: Symbols.ContextLevel ← Symbols.lZ; backup1, backup2: StackBackup ← [none[]]; IF ~P5L.AllLoaded[from] THEN -- anything above it is part of "to" BEGIN P5L.LoadVar[from]; from ← P5L.OVarItem[P5L.TOSComponent[wS]]; END; IF isexp THEN BEGIN -- locate a backup site for stack model after PUSH -- "from" is a stack o varitem, see if it is alsotemp -- otherwise, see if "to" is a friendly frame loc (doesn't -- have to be immutable in this case WITH cb[from] SELECT FROM o => WITH vv: var SELECT FROM stack => BEGIN vsti: DataStackIndex = Stack.DataIndex[vv.sti]; backup1 ← cb[vsti].backup; IF wS = 2 THEN BEGIN nsti: DataStackIndex = Stack.DataIndex[Stack.Above[vsti]]; backup2 ← cb[nsti].backup; END; END; ENDCASE; ENDCASE; IF backup1.where = none OR (wS = 2 AND backup2.where = none) THEN WITH cb[to] SELECT FROM o => WITH vv: var SELECT FROM frame => IF vv.bSize = 0 AND vv.bd = 0 THEN BEGIN level: Symbols.ContextLevel = vv.level; SELECT level FROM lG, CPtr.curctxlvl => { backup1 ← [frame[tLevel: level, tOffset: vv.wd]]; backup2 ← [frame[tLevel: level, tOffset: vv.wd+1]]}; ENDCASE; END; ENDCASE; ENDCASE; END; P5L.ReleaseVarItem[from]; P5L.StoreVar[to]; IF isexp THEN BEGIN P5U.Out0[qREC]; IF backup1.where # none THEN Stack.Also[backup1]; IF wS = 2 THEN { P5U.Out0[qREC]; IF backup2.where # none THEN Stack.Also[backup2]}; l ← P5L.TOSLex[wS]; END; END ELSE IF P5L.AllLoaded[from] THEN BEGIN -- large thing, all on stack IF isexp THEN BEGIN tr: VarIndex; [first: to, next: tr] ← P5L.ReusableCopies[to, store, FALSE]; l ← [bdo[tr]]; END; P5L.StoreVar[to]; END ELSE IF bSize = 0 THEN BEGIN fromCode: BOOL; longDest: BOOL ← P5L.LongVarAddress[to]; longSource: BOOL ← P5L.LongVarAddress[from]; sourceAddr, destAddr: VarComponent; destInTemp: BOOL ← FALSE; expBase: {unknown, source, dest} ← unknown; BltOp: ARRAY BOOL OF ARRAY BOOL OF BYTE = [[qBLT, qBLTL], [qBLTC, qBLTCL]]; WITH ff: cb[from] SELECT FROM o => fromCode ← ff.var.tag = code; bo => fromCode ← ff.offset.tag = code; bdo => fromCode ← ff.offset.tag = code; ind => fromCode ← ff.offset.tag = code; ENDCASE => ERROR; IF isexp AND longDest = longSource AND P5L.VarAddressEasy[from] AND ~P5L.VarAddressEasy[to] THEN expBase ← source; sourceAddr ← AddrForVar[r: from, codeOk: TRUE]; IF longDest AND ~longSource THEN BEGIN IF isexp THEN BEGIN sourceAddr ← P5L.EasilyLoadable[sourceAddr, store]; expBase ← source; END; P5L.LoadComponent[sourceAddr]; IF ~fromCode THEN P5U.Out0[qLP]; END ELSE P5L.LoadComponent[sourceAddr]; P5U.Out1[qLI, wSize]; destAddr ← AddrForVar[to]; IF longSource AND ~longDest THEN BEGIN IF isexp THEN BEGIN destAddr ← P5L.EasilyLoadable[destAddr, store]; expBase ← dest; END; P5L.LoadComponent[destAddr]; P5U.Out0[qLP]; longDest ← TRUE; END ELSE BEGIN IF isexp AND expBase = unknown THEN BEGIN destAddr ← P5L.EasilyLoadable[destAddr, store]; expBase ← dest; END; P5L.LoadComponent[destAddr]; END; P5U.Out0[BltOp[fromCode][longDest]]; IF isexp THEN BEGIN tr: BoVarIndex = LOOPHOLE[P5L.GenVarItem[bo]]; SELECT expBase FROM source => NULL; dest => sourceAddr ← destAddr; ENDCASE => ERROR; cb[tr] ← [body: bo[base: sourceAddr, offset: NULL]]; IF expBase = source AND fromCode THEN cb[tr].offset ← [wSize: wSize, space: code[wd: 0]] ELSE cb[tr].offset ← [wSize: wSize, space: frame[wd: 0]]; l ← [bdo[tr]]; END; END ELSE BEGIN -- vars are ragged on at most one end; i.e., if wSize # 0 and bSize # 0 -- then bd = 0 or bd+bSize = wordlength, also bd # 0 implies bSize # 0 fMain, fNub: VarIndex; tMain, tNub: VarIndex; [first: fMain, next: fNub] ← P5L.ReusableCopies[from, store, TRUE]; [first: tMain, next: tNub] ← P5L.ReusableCopies[to, store, FALSE]; IF tbd = 0 THEN BEGIN tr: VarIndex ← tMain; tMain ← tNub; tNub ← tr; tr ← fMain; fMain ← fNub; fNub ← fMain; END; IF isexp THEN l ← [bdo[P5L.CopyVarItem[tMain]]]; -- has been rendered reusable IF tbd = 0 THEN BEGIN P5L.FieldOfVar[r: fMain, wSize: wSize]; P5L.FieldOfVar[r: fNub, wd: wSize, bSize: bSize]; P5L.FieldOfVar[r: tMain, wSize: wSize]; P5L.FieldOfVar[r: tNub, wd: wSize, bSize: bSize]; [] ← VarVarAssign[to: tNub, from: fNub, isexp: FALSE]; [] ← VarVarAssign[to: tMain, from: fMain, isexp: FALSE]; END ELSE BEGIN IF tbd + bSize # wordlength THEN ERROR; P5L.FieldOfVar[r: fMain, wSize: wSize, bd: bSize]; P5L.FieldOfVar[r: fNub, bSize: bSize]; P5L.FieldOfVar[r: tMain, wSize: wSize, bd: bSize]; P5L.FieldOfVar[r: tNub, bSize: bSize]; [] ← VarVarAssign[to: tMain, from: fMain, isexp: FALSE]; [] ← VarVarAssign[to: tNub, from: fNub, isexp: FALSE]; END; END; THROUGH [0..trashOnStack) DO Stack.Pop[]; ENDLOOP; END; Words: PUBLIC PROC [w, b: CARDINAL] RETURNS [CARDINAL] = BEGIN RETURN [w + ((b+15)/16)]; END; END.