-- VarBasics.mesa Edited by Sweet, January 15, 1980 5:10 PM DIRECTORY AltoDefs: FROM "altodefs" USING [BYTE, wordlength], Code: FROM "code" USING [CodeNotImplemented, curctxlvl, dStar, stking], CodeDefs: FROM "codedefs", ControlDefs: FROM "controldefs" USING [FieldDescriptor, framelink, localbase], FOpCodes: FROM "fopcodes" USING [qADD, qAMUL, qAND, qBLT, qBLTC, qBLTL, qDADD, qLI, qLL, qLLK, qLP, qMUL, qNOOP, qPUSH, qR, qRFC, qSHIFT], InlineDefs: FROM "inlinedefs" USING [LongNumber], LiteralOps: FROM "literalops" USING [FindDescriptor], Literals: FROM "literals" USING [LTIndex, ltType], P5: FROM "p5" USING [MoveToCodeWord, WriteCodeWord], P5L: FROM "p5l" USING [ AllLoaded, AddrComponent, AddrForVar, CopyToTemp, CopyVarItem, EasilyLoadable, FieldOfVar, GenAdd, GenVarItem, LoadAddress, LoadBoth, LoadComponent, LoadVar, LongVarAddress, ModComponent, OVarItem, ReleaseVarItem, ReusableCopies, StoreVar, TOSComponent, TOSLex, VarAddressEasy, VarAlignment, VarStackWords, Words], P5U: FROM "p5u" USING [Out0, Out1, Out2], Stack: FROM "stack" USING [Above, Also, Forget, Loc, Pop, Require, TempStore], Symbols: FROM "symbols" USING [ContextLevel, ctxType, lG, lZ, seType], Table: FROM "table" USING [Base, Notifier], Tree: FROM "tree" USING [treeType]; VarBasics: PROGRAM IMPORTS LCPtr: Code, LiteralOps, P5, P5U, P5L, Stack EXPORTS P5L, CodeDefs = BEGIN OPEN FOpCodes, CodeDefs, Symbols; CPtr: POINTER TO FRAME [Code] = LCPtr; wordlength: CARDINAL = AltoDefs.wordlength; BYTE: TYPE = AltoDefs.BYTE; cb, seb, ctxb, ltb: Table.Base; VarBasicsNotify: PUBLIC Table.Notifier = BEGIN -- called by allocator whenever table area is repacked seb _ base[Symbols.seType]; ctxb _ base[Symbols.ctxType]; cb _ base[Tree.treeType]; ltb _ base[Literals.ltType]; RETURN END; AddrComponent: PUBLIC PROCEDURE [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]; P5L.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]; P5L.GenAdd[vv.delta]; RETURN [P5L.TOSComponent[1]]; END; stack => BEGIN loc: StackLocRec = Stack.Loc[vv.sti, var.wSize]; WITH loc SELECT FROM inTemp => BEGIN Stack.Forget[vv.sti, var.wSize]; RETURN [[wSize: 1, space: faddr[level: tLevel, wd: tOffset]]]; END; ENDCASE; END; caddr => ERROR; -- nobody should be taking the address of a code address ENDCASE; -- faddr, link, const, pdesc BEGIN -- put it in a temp, generate addr of temp tvar: VarComponent _ P5L.CopyToTemp[P5L.OVarItem[var]].var; RETURN [P5L.AddrComponent[tvar]]; END; END; AddrForVar: PUBLIC PROCEDURE [r: VarIndex, codeOk: BOOLEAN _ FALSE] RETURNS [avar: VarComponent] = BEGIN BEGIN -- to set up "loadIt" label 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 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: BOOLEAN _ P5L.LoadAddress[r, codeOk]; avar _ P5L.TOSComponent[IF long THEN 2 ELSE 1]; END; END; END; BaseComponent: PUBLIC PROCEDURE [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: ControlDefs.framelink, level: CPtr.curctxlvl]]]; P5U.Out1[qLL, ControlDefs.framelink]; THROUGH (lvl..CPtr.curctxlvl) DO P5U.Out1[qR, ControlDefs.framelink - ControlDefs.localbase]; ENDLOOP; RETURN[P5L.TOSComponent[1]]; END; GenAdd: PUBLIC PROCEDURE [delta: UNSPECIFIED, long: BOOLEAN _ FALSE] = BEGIN P5U.Out1[qLI, LOOPHOLE[delta, CARDINAL]]; IF long THEN P5U.Out1[qLI, 0]; P5U.Out0[IF long THEN qDADD ELSE qADD]; END; GenAnd: PUBLIC PROCEDURE [delta: UNSPECIFIED] = BEGIN P5U.Out1[qLI, LOOPHOLE[delta, CARDINAL]]; P5U.Out0[qAND]; END; GenRFC: PUBLIC PROCEDURE [wd: CARDINAL, bd: [0..16), len: [1..16]] = BEGIN IF wd > LAST[BYTE] THEN BEGIN GenAdd[wd-LAST[BYTE]]; wd _ LAST[BYTE]; END; P5U.Out2[qRFC, wd, LOOPHOLE[ControlDefs.FieldDescriptor[offset: 0, posn: bd, size: len]]]; END; GenShift: PUBLIC PROCEDURE [delta: UNSPECIFIED] = BEGIN P5U.Out1[qLI, delta]; P5U.Out0[qSHIFT]; END; LoadAddress: PUBLIC PROCEDURE [r: VarIndex, codeOk: BOOLEAN _ FALSE] RETURNS [long: BOOLEAN] = BEGIN bor: BoVarIndex; base, offset: VarComponent; WITH cc: cb[r] SELECT FROM o => BEGIN avar: VarComponent _ AddrComponent[cc.var]; 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 _ P5L.Words[base.wSize, base.bSize] > 1; P5L.LoadComponent[base]; WITH oo: offset SELECT FROM frame => BEGIN IF oo.level # lZ THEN ERROR CPtr.CodeNotImplemented; IF oo.wd # 0 THEN BEGIN P5U.Out1[qLI, oo.wd]; IF long THEN P5U.Out1[qLI, 0]; -- lengthen P5U.Out0[IF long THEN qDADD ELSE qADD]; END; END; code => BEGIN IF ~codeOk OR long THEN ERROR; IF oo.wd # 0 THEN GenAdd[oo.wd]; END; ENDCASE => ERROR; END; LoadBoth: PUBLIC PROCEDURE [atC1, atC2: POINTER TO VarComponent, abelian: BOOLEAN] = BEGIN c1: VarComponent _ atC1^; c2: VarComponent _ atC2^; c1Loaded, c2Loaded: BOOLEAN _ 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 => BEGIN c1Depth _ depth; c1Loaded _ TRUE; END; 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 => BEGIN c2Depth _ depth; c2Loaded _ TRUE; END; ENDCASE; END; ENDCASE; BEGIN -- to set up loadBoth label IF ~(c1Loaded OR c2Loaded) THEN GO TO loadBoth; IF c1Loaded AND c2Loaded THEN IF (c1Depth = c2Size AND c2Depth = 0) OR (abelian AND c2Depth = c1Size AND c1Depth = 0) THEN RETURN ELSE GO TO loadBoth; -- considered unlikely IF c1Loaded THEN BEGIN IF c1Depth # 0 THEN P5L.LoadComponent[c1]; P5L.LoadComponent[c2]; END ELSE -- c2Loaded BEGIN IF c2Depth # 0 THEN P5L.LoadComponent[c2]; IF ~abelian AND (c1Size>1 OR c2Size>1) THEN c2 _ Stack.TempStore[c2Size]; P5L.LoadComponent[c1]; IF ~abelian THEN P5L.LoadComponent[c2]; END; EXITS loadBoth => BEGIN P5L.LoadComponent[c1]; P5L.LoadComponent[c2]; END; END; END; LoadSum: PUBLIC PROCEDURE [atB, atD: POINTER TO VarComponent] RETURNS [bpSize: [1..2]] = BEGIN base, disp: VarComponent; dpSize: [1..2]; alreadyOn: CARDINAL _ 0; BDCommute: PROCEDURE = BEGIN t: VarComponent = base; i: CARDINAL _ bpSize; base _ disp; disp _ t; bpSize _ dpSize; dpSize _ i; END; base _ atB^; disp _ atD^; bpSize _ Words[base.wSize, base.bSize]; dpSize _ Words[disp.wSize, disp.bSize]; WITH base SELECT FROM stack => alreadyOn _ alreadyOn + bpSize; ENDCASE; WITH disp SELECT FROM stack => alreadyOn _ alreadyOn + dpSize; ENDCASE; IF (bpSize = 2 OR dpSize = 2) AND ~CPtr.dStar THEN Stack.Require[alreadyOn]; -- could dump what was on BEGIN -- to set up "different" exit label SELECT bpSize FROM >dpSize => GO TO different; BEGIN BDCommute[]; GO TO different END; ENDCASE => P5L.LoadBoth[@base, @disp, TRUE]; EXITS different => BEGIN P5L.LoadComponent[disp]; P5U.Out1[qLI, 0]; --lengthen disp disp _ P5L.TOSComponent[2]; P5L.LoadBoth[@base, @disp, TRUE]; END; END; P5U.Out0[IF bpSize = 1 THEN qADD ELSE qDADD]; RETURN END; MakeBo: PUBLIC PROCEDURE [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; 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: var.wSize, space: frame[wd: vv.delta]]; RETURN END; linkup => BEGIN cb[bor].base _ [wSize: 1, space: link[wd: vv.wd]]; cb[bor].offset _ [wSize: var.wSize, 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]]; const => BEGIN wS: CARDINAL = P5L.Words[var.wSize, var.bSize]; IF wS = 1 THEN cb[bor].offset _ -- can't index packed in code anyway [wSize: NULL, bSize: NULL, space: frame[bd: vv.bd]] ELSE BEGIN -- wS = 2 const: ARRAY [0..1] OF CARDINAL _ [vv.d1, vv.d2]; lti: Literals.LTIndex; cb[bor].offset _ [wSize: NULL, bSize: NULL, space: code[bd: vv.bd]]; lti _ LiteralOps.FindDescriptor[DESCRIPTOR[const]]; 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]]; END; var _ [wSize: 2, space: code[wd: ll.codeIndex]]; END; ENDCASE => ERROR; END; END; ENDCASE => ERROR; cb[bor].base _ P5L.AddrComponent[var]; cb[bor].offset.wSize _ var.wSize; cb[bor].offset.bSize _ var.bSize; RETURN END; bdo => BEGIN disp _ cc.disp; base _ cc.base; offset _ cc.offset; END; ind => BEGIN eWords: CARDINAL; base _ cc.base; disp _ cc.index; offset _ cc.offset; WITH pp: cc SELECT FROM packed => BEGIN P5L.ReleaseVarItem[bor]; RETURN [LOOPHOLE[VarNull]] END; notPacked => eWords _ pp.eWords; ENDCASE; IF eWords # 1 THEN BEGIN WITH vv: disp SELECT FROM const => BEGIN ld: InlineDefs.LongNumber; ld.lc _ LONG[CARDINAL[vv.d1]] * LONG[eWords]; vv.d1 _ ld.lowbits; IF ld.highbits # 0 THEN BEGIN vv.wSize _ 2; vv.d2 _ ld.highbits; END; 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[qPUSH]; 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: InlineDefs.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 PROCEDURE [r: VarIndex, allowFields: BOOLEAN _ FALSE] RETURNS [var: VarComponent] = BEGIN wS: CARDINAL; WITH cb[r] SELECT FROM o => RETURN[var]; bo => BEGIN WITH oo: offset SELECT FROM code => WITH bb: base SELECT FROM caddr => BEGIN var _ [wSize: offset.wSize, bSize: offset.bSize, space: code[wd: bb.wd + oo.wd, bd: oo.bd]]; GO TO freer; END; ENDCASE; frame => WITH bb: base SELECT FROM faddr => SELECT bb.level FROM lG, CPtr.curctxlvl => BEGIN var _ [ wSize: offset.wSize, bSize: offset.bSize, space: frame[ level: bb.level, wd: bb.wd + oo.wd, bd: oo.bd]]; GO TO freer; END; ENDCASE; frame => IF ~allowFields AND base.bSize = 0 AND base.wSize IN [1..2] AND offset.bSize = 0 AND offset.wSize = 1 AND oo.level = lZ THEN BEGIN var _ [ wSize: offset.wSize, space: frameup[ level: bb.level, wd: bb.wd, pwSize: base.wSize, delta: oo.wd, immutable: bb.immutable]]; GO TO freer; END; link => IF ~allowFields AND offset.bSize = 0 AND offset.wSize IN [1..2] AND oo.level = lZ THEN BEGIN var _ [ wSize: offset.wSize, space: linkup[ wd: bb.wd, delta: oo.wd]]; GO TO freer; END; ENDCASE; ENDCASE => ERROR; wS _ Words[offset.wSize, offset.bSize]; END; bdo => wS _ Words[offset.wSize, offset.bSize]; ind => wS _ Words[offset.wSize, offset.bSize]; ENDCASE; IF wS > 2 THEN var _ P5L.CopyToTemp[r].var ELSE BEGIN P5L.LoadVar[r]; var _ P5L.TOSComponent[wS]; END; EXITS freer => P5L.ReleaseVarItem[r]; END; VarVarAssign: PUBLIC PROCEDURE [to, from: VarIndex, isexp: BOOLEAN] 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: BOOLEAN _ FALSE; tOffset: TempAddr; tLevel: Symbols.ContextLevel _ Symbols.lZ; 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: StackIndex = vv.sti; WITH sv: cb[vsti] SELECT FROM onStack => BEGIN IF sv.alsoLink OR sv.tLevel # lZ THEN BEGIN nsti: StackIndex; alsoLink _ sv.alsoLink; tOffset _ sv.tOffset; tLevel _ sv.tLevel; IF wS = 1 THEN GO TO foundOne; IF tLevel # lZ THEN BEGIN nsti _ Stack.Above[vsti]; WITH sv2: cb[nsti] SELECT FROM onStack => IF sv2.tLevel = tLevel AND sv2.tOffset = tOffset+1 THEN GO TO foundOne; ENDCASE; END; alsoLink _ FALSE; tLevel _ lZ; END; END; ENDCASE; END; ENDCASE; ENDCASE; WITH cb[to] SELECT FROM o => WITH vv: var SELECT FROM link => BEGIN alsoLink _ TRUE; tLevel _ vv.wd; END; frame => IF vv.bSize = 0 AND vv.bd = 0 THEN BEGIN level: Symbols.ContextLevel = vv.level; SELECT level FROM lG, CPtr.curctxlvl => BEGIN tLevel _ level; tOffset _ vv.wd; END; ENDCASE; END; ENDCASE; ENDCASE; EXITS foundOne => NULL; END; P5L.ReleaseVarItem[from]; P5L.StoreVar[to]; IF isexp THEN BEGIN THROUGH [0..wS) DO P5U.Out0[qPUSH]; ENDLOOP; IF (alsoLink OR tLevel # lZ) AND CPtr.stking THEN Stack.Also[n: wS, inLink: alsoLink, tOffset: tOffset, tLevel: tLevel]; l _ P5L.TOSLex[wS]; END; END ELSE IF P5L.AllLoaded[from] THEN BEGIN -- large thing, all on stack IF isexp THEN BEGIN tr: VarIndex; [to, tr] _ P5L.ReusableCopies[to, store, FALSE]; l _ [bdo[tr]]; END; P5L.StoreVar[to]; END ELSE IF bSize = 0 THEN BEGIN fromCode: BOOLEAN; longDest: BOOLEAN _ P5L.LongVarAddress[to]; longSource: BOOLEAN _ P5L.LongVarAddress[from]; sourceAddr, destAddr: VarComponent; expBase: {unknown, source, dest} _ unknown; BltOp: ARRAY BOOLEAN OF ARRAY BOOLEAN OF BYTE = [[qBLT, qBLTL], [qBLTC, qNOOP]]; -- peephole will choke on BLTCL -- but it shouldn't be generated, anyway 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 fromCode AND longDest THEN BEGIN tvar: VarComponent = P5L.CopyToTemp[from].var; [] _ VarVarAssign[to: to, from: P5L.OVarItem[tvar], isexp: FALSE]; IF isexp THEN l _ [bdo[P5L.OVarItem[tvar]]]; RETURN -- trashOnStack = 0 END; IF ~CPtr.dStar OR longSource OR longDest THEN Stack.Require[P5L.VarStackWords[from]+ P5L.VarStackWords[to]]; IF isexp AND longDest = longSource AND P5L.VarAddressEasy[from] AND ~P5L.VarAddressEasy[to] THEN expBase _ source; sourceAddr _ P5L.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]; P5U.Out0[qLP]; END ELSE P5L.LoadComponent[sourceAddr]; P5U.Out1[qLI, wSize]; destAddr _ P5L.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; [fMain, fNub] _ P5L.ReusableCopies[from, store]; [tMain, tNub] _ P5L.ReusableCopies[to, store]; 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 PROCEDURE [w: CARDINAL, b: [0..wordlength)] RETURNS [CARDINAL] = BEGIN RETURN [w + CARDINAL[b+15]/16]; END; END.