-- VarUtils.mesa Edited by Sweet, January 16, 1980 1:07 PM DIRECTORY AltoDefs: FROM "altodefs" USING [BYTE, wordlength], Code: FROM "code" USING [catchcount, curctxlvl], CodeDefs: FROM "codedefs", ControlDefs: FROM "controldefs" USING [EPRange, GFTNull, ProcDesc, SignalDesc], InlineDefs: FROM "inlinedefs" USING [BITAND, BITSHIFT], LiteralOps: FROM "literalops" USING [MasterString, Value], Literals: FROM "literals" USING [MSTIndex, stType], P5: FROM "p5", P5L: FROM "p5l", P5U: FROM "p5u" USING [FreeChunk, GetChunk], Stack: FROM "stack" USING [Above, Forget, KeepOnly, Loc, TempStore, Top], SymbolOps: FROM "symbolops" USING [XferMode], Symbols: FROM "symbols" USING [BitAddress, bodyType, BTNull, CBTIndex, ContextLevel, ctxType, ISEIndex, ISENull, lG, lZ, RecordSEIndex, seType], Table: FROM "table" USING [Base, Notifier], Tree: FROM "tree" USING [treeType]; VarUtils: PROGRAM IMPORTS LCPtr: Code, InlineDefs, LiteralOps, P5, P5U, P5L, Stack, SymbolOps EXPORTS P5L, CodeDefs = BEGIN OPEN CodeDefs, Symbols; CPtr: POINTER TO FRAME [Code] = LCPtr; wordlength: CARDINAL = AltoDefs.wordlength; BYTE: TYPE = AltoDefs.BYTE; cb, seb, ctxb, bb, stb: Table.Base; VarUtilsNotify: PUBLIC Table.Notifier = BEGIN -- called by allocator whenever table area is repacked seb ← base[Symbols.seType]; ctxb ← base[Symbols.ctxType]; cb ← base[Tree.treeType]; bb ← base[Symbols.bodyType]; stb ← base[Literals.stType]; RETURN END; AdjustComponent: PUBLIC PROCEDURE [var: POINTER TO VarComponent, rSei: Symbols.RecordSEIndex, fSei: Symbols.ISEIndex, tBits: CARDINAL] = BEGIN length: CARDINAL = seb[rSei].length; first: BOOLEAN = (seb[fSei].idValue = 0); delta: CARDINAL; IF length < wordlength AND (delta ← tBits - length) # 0 THEN BEGIN IF first THEN BEGIN newB: CARDINAL = var.bSize + delta; var.bSize ← newB MOD wordlength; var.wSize ← newB / wordlength; END ELSE P5L.ModComponent[var: var, bd: delta]; END; END; AllLoaded: PUBLIC PROCEDURE [r: VarIndex, junkOk: BOOLEAN ← FALSE] RETURNS [BOOLEAN] = BEGIN -- is completely on stack (there may be stuff above it, tho) WITH cb[r] SELECT FROM o => WITH vv: var SELECT FROM stack => IF (junkOk OR vv.wd = 0) AND vv.bd = 0 THEN BEGIN sti: StackIndex ← IF vv.wd # 0 THEN Stack.Above[vv.sti, vv.wd] ELSE vv.sti; loc: StackLocRec ← Stack.Loc[sti, var.wSize]; IF loc.tag = onStack THEN RETURN[TRUE]; END; ENDCASE; ENDCASE; RETURN[FALSE]; END; ComponentForLex: PUBLIC PROCEDURE [l: Lexeme, allowFields: BOOLEAN ← FALSE] RETURNS [VarComponent] = BEGIN WITH ll: l SELECT FROM bdo => RETURN [P5L.MakeComponent[ll.lexbdoi, allowFields]]; se => RETURN [P5L.ComponentForSE[ll.lexsei]]; literal => BEGIN OPEN Literals; WITH ll SELECT FROM word => RETURN[ [wSize: 1, space: const[d1: LiteralOps.Value[lexlti]]]]; string => BEGIN msti: MSTIndex ← LiteralOps.MasterString[lexsti]; RETURN[[wSize: 1, space: faddr[ wd: stb[msti].info, level: IF stb[msti].local THEN CPtr.curctxlvl - CPtr.catchcount ELSE lG]]]; END; ENDCASE; END; stack => RETURN [[wSize: 1, space: stack[sti: ll.lexsti]]]; ENDCASE; ERROR; END; ComponentForSE: PUBLIC PROCEDURE [sei: ISEIndex] RETURNS [var: VarComponent] = BEGIN SELECT TRUE FROM sei = ISENull => ERROR; seb[sei].linkSpace => BEGIN a: BitAddress = seb[sei].idValue; var ← [wSize: 1, space: link[wd: a.wd]]; END; seb[sei].constant => SELECT SymbolOps.XferMode[seb[sei].idType] FROM procedure => BEGIN bti: CBTIndex = seb[sei].idInfo; IF bti = BTNull THEN RETURN [[ wSize: 1, space: const[d1: seb[sei].idValue]]] ELSE BEGIN WITH bb[bti] SELECT FROM Inner => RETURN [[wSize: 1, space: faddr[wd: frameOffset, level: bb[bti].level - 1]]]; Outer => BEGIN OPEN ControlDefs; p: ProcDesc; p.gfi ← entryIndex / EPRange; p.ep ← entryIndex MOD EPRange; p.tag ← procedure; RETURN [[wSize: 1, space: pdesc[p]]]; END; ENDCASE; END; END; signal, error => BEGIN OPEN ControlDefs; desc: SignalDesc ← seb[sei].idValue; IF desc.gfi # GFTNull THEN BEGIN desc.gfi ← desc.gfi-1; RETURN [[wSize: 1, space: pdesc[desc]]]; END ELSE RETURN [[wSize: 1, space: const[d1: desc]]]; END; ENDCASE => ERROR; ENDCASE => BEGIN a: Symbols.BitAddress ← seb[sei].idValue; s: CARDINAL = seb[sei].idInfo; RETURN [[wSize: s / wordlength, bSize: s MOD wordlength, space: frame[ wd: a.wd, bd: a.bd, immutable: seb[sei].immutable, level: ctxb[seb[sei].idCtx].level]]]; END; END; CopyLex: PUBLIC PROCEDURE [l: Lexeme] RETURNS [Lexeme] = BEGIN WITH l SELECT FROM bdo => RETURN [[bdo[CopyVarItem[lexbdoi]]]]; ENDCASE => RETURN [l]; END; CopyToTemp: PUBLIC PROCEDURE [r: VarIndex, tsei: ISEIndex ← ISENull] RETURNS [var: VarComponent, sei: ISEIndex] = BEGIN -- needs work for non aligned things bd, bSize: [0..wordlength); wSize, wS: CARDINAL; rr: VarIndex; sei ← tsei; [bd: bd, bSize: bSize, wSize: wSize] ← P5L.VarAlignment[r, load]; wS ← P5L.Words[wSize, bSize]; IF sei = ISENull THEN sei ← P5.GenTempLex[wS].lexsei; var ← P5L.ComponentForSE[sei]; IF wS > 1 THEN BEGIN var.wSize ← wSize; var.bSize ← bSize; WITH vv: var SELECT FROM frame => vv.bd ← bd; ENDCASE; END; rr ← P5L.OVarItem[var]; [] ← P5L.VarVarAssign[rr, r, FALSE]; END; CopyVarItem: PUBLIC PROCEDURE [r: VarIndex] RETURNS [rr: VarIndex] = BEGIN -- LOOPHOLEs can go away when the compiler gets smarter WITH cc: cb[r] SELECT FROM o => BEGIN tr: OVarIndex ← LOOPHOLE[P5L.GenVarItem[o]]; rr ← tr; cb[tr] ← cc; END; bo => BEGIN tr: BoVarIndex ← LOOPHOLE[P5L.GenVarItem[bo]]; rr ← tr; cb[tr] ← cc; END; bdo => BEGIN tr: BdoVarIndex ← LOOPHOLE[P5L.GenVarItem[bdo]]; rr ← tr; cb[tr] ← cc; END; ind => BEGIN tr: IndVarIndex ← LOOPHOLE[P5L.GenVarItem[ind]]; rr ← tr; cb[tr] ← cc; END; ENDCASE => ERROR; END; EasilyLoadable: PUBLIC PROCEDURE [var: VarComponent, dir: MoveDirection] RETURNS [evar: VarComponent] = BEGIN -- dir = store means it could be clobbered between loads size: CARDINAL = P5L.Words[var.wSize, var.bSize]; -- < 3 IF P5L.EasyToLoad[var, dir] THEN RETURN[var]; WITH vv: var SELECT FROM stack => BEGIN loc: StackLocRec ← Stack.Loc[vv.sti, size]; WITH loc SELECT FROM inTemp => BEGIN tvar: VarComponent ← [wSize: vv.wSize, bSize: vv.bSize, space: frame[ immutable: TRUE, level: tLevel, wd: tOffset, bd: vv.bd]]; Stack.Forget[vv.sti, size]; RETURN [EasilyLoadable[tvar, dir]]; END; inLink => BEGIN tvar: VarComponent ← [wSize: 1, space: link[wd: link]]; Stack.Forget[vv.sti, size]; RETURN [tvar]; END; ENDCASE; END; ENDCASE; P5L.LoadComponent[var]; RETURN[Stack.TempStore[size]]; END; EasyToLoad: PUBLIC PROCEDURE [var: VarComponent, dir: MoveDirection] RETURNS [BOOLEAN] = BEGIN -- dir = store means it could be clobbered between loads lvl: ContextLevel; WITH vv: var SELECT FROM const, link, linkup, caddr, code => RETURN[TRUE]; faddr => lvl ← vv.level; frame => BEGIN IF vv.bd # 0 OR var.bSize # 0 OR var.wSize ~IN [1..2] OR (dir = store AND ~vv.immutable) THEN RETURN[FALSE]; lvl ← vv.level; END; frameup => BEGIN IF dir = store AND ~vv.immutable THEN RETURN[FALSE]; lvl ← vv.level; END; ENDCASE => RETURN[FALSE]; SELECT lvl FROM lZ => ERROR; lG, CPtr.curctxlvl => RETURN[TRUE]; ENDCASE => RETURN[FALSE]; END; FieldOfComponent: PUBLIC PROCEDURE [var: POINTER TO VarComponent, wd, bd, wSize, bSize: CARDINAL ← 0] = BEGIN ModComponent[var, wd, bd]; IF wSize = 0 THEN WITH vv: var↑ SELECT FROM const => BEGIN OPEN InlineDefs; Mask: ARRAY [0..15] OF CARDINAL = [0B, 1B, 3B, 7B, 17B, 37B, 77B, 177B, 377B, 777B, 1777B, 3777B, 7777B, 17777B, 37777B, 77777B]; vv.d1 ← BITAND[BITSHIFT[vv.d1, vv.bd+bSize-wordlength], Mask[bSize]]; wSize ← 1; bSize ← 0; END; ENDCASE; var.wSize ← wSize; var.bSize ← bSize; END; FieldOfComponentOnly: PUBLIC PROCEDURE [var: POINTER TO VarComponent, wd, bd, wSize, bSize: CARDINAL ← 0] = BEGIN WITH vv: var↑ SELECT FROM stack => BEGIN -- throw away anything above this new field b: CARDINAL ← vv.bd + bd; ws: CARDINAL ← P5L.Words[wSize, bSize]; vv.wd ← vv.wd + wd + b/wordlength; vv.bd ← b MOD wordlength; Stack.KeepOnly[Stack.Above[vv.sti, vv.wd], ws]; var.wSize ← wSize; var.bSize ← bSize; END; ENDCASE => FieldOfComponent[var, wd, bd, wSize, bSize]; END; FieldOfVar: PUBLIC PROCEDURE [r: VarIndex, wd, bd, wSize, bSize: CARDINAL ← 0] = BEGIN ModField: PROCEDURE [var: POINTER TO VarComponent] = BEGIN -- had better not cause a compaction b: CARDINAL; WITH vv: var↑ SELECT FROM frame => BEGIN IF vv.level # lZ THEN ERROR; b ← vv.bd + bd; vv.wd ← vv.wd + wd + b/wordlength; vv.bd ← b MOD wordlength; END; code => BEGIN b ← vv.bd + bd; vv.wd ← vv.wd + wd + b/wordlength; vv.bd ← b MOD wordlength; END; ENDCASE => ERROR; var.wSize ← wSize; var.bSize ← bSize; END; WITH cb[r] SELECT FROM o => FieldOfComponent[@var, wd, bd, wSize, bSize]; bo => ModField[@offset]; bdo => ModField[@offset]; ind => ModField[@offset]; ENDCASE; END; FieldOfVarOnly: PUBLIC PROCEDURE [r: VarIndex, wd, bd, wSize, bSize: CARDINAL ← 0] = BEGIN WITH cb[r] SELECT FROM o => FieldOfComponentOnly[@var, wd, bd, wSize, bSize]; ENDCASE => FieldOfVar[r, wd, bd, wSize, bSize]; END; varCount, varMax: CARDINAL ← 0; GenVarItem: PUBLIC PROCEDURE [tag: VarTag] RETURNS [r: VarIndex] = BEGIN -- returns the cb-relative index of a VarItem varCount ← varCount + 1; varMax ← MAX[varMax, varCount]; r ← P5U.GetChunk[(SELECT tag FROM o => SIZE[o VarItem], bo => SIZE[bo VarItem], bdo => SIZE[bdo VarItem], ind => SIZE[ind VarItem], ENDCASE => ERROR)]; RETURN END; InCode: PUBLIC PROCEDURE [r: VarIndex] RETURNS [BOOLEAN] = BEGIN WITH cb[r] SELECT FROM o => RETURN [var.tag = code]; bo => RETURN [offset.tag = code]; bdo => RETURN [offset.tag = code]; ind => RETURN [offset.tag = code]; ENDCASE => ERROR; END; LongVarAddress: PUBLIC PROCEDURE [r: VarIndex] RETURNS [BOOLEAN] = BEGIN WITH cb[r] SELECT FROM o => RETURN[FALSE]; bo => RETURN [P5L.Words[base.wSize, base.bSize] > 1]; bdo => RETURN [P5L.Words[disp.wSize, disp.bSize] > 1 OR P5L.Words[base.wSize, base.bSize] > 1]; ind => RETURN [P5L.Words[base.wSize, base.bSize] > 1]; ENDCASE => ERROR; END; ModComponent: PUBLIC PROCEDURE [var: POINTER TO VarComponent, wd, bd: CARDINAL ← 0] = BEGIN b: CARDINAL; WITH vv: var↑ SELECT FROM stack => BEGIN nsti: StackIndex; b ← vv.bd + bd; nsti ← Stack.Above[vv.sti, wd + b/wordlength]; vv.sti ← nsti; vv.bd ← b MOD wordlength; END; frame => BEGIN b ← vv.bd + bd; vv.wd ← vv.wd + wd + b/wordlength; vv.bd ← b MOD wordlength; END; code => BEGIN -- lets hear it for cross jumping b ← vv.bd + bd; vv.wd ← vv.wd + wd + b/wordlength; vv.bd ← b MOD wordlength; END; const => BEGIN b ← vv.bd + bd; SELECT wd + b/wordlength FROM 0 => NULL; 1 => vv.d1 ← vv.d2; ENDCASE => ERROR; vv.bd ← b MOD wordlength; END; ENDCASE => ERROR; END; NormalizeExp: PUBLIC PROCEDURE [ r: VarIndex, tempsei: ISEIndex ← ISENull, codeOk: BOOLEAN ← FALSE] RETURNS [nwords: CARDINAL, long: BOOLEAN, tsei: ISEIndex] = BEGIN wSize: CARDINAL; bSize: [0..wordlength); tsei ← tempsei; [wSize: wSize, bSize: bSize] ← P5L.VarAlignment[r, load]; nwords ← P5L.Words[wSize, bSize]; IF nwords <= 2 THEN BEGIN P5L.LoadVar[r]; long ← FALSE END ELSE IF codeOk OR ~P5L.InCode[r] THEN long ← P5L.LoadAddress[r, codeOk] ELSE BEGIN tvar: VarComponent; IF tsei = ISENull THEN tsei ← P5.GenAnonLex[nwords].lexsei; [var: tvar, sei: tsei] ← P5L.CopyToTemp[r, tsei]; P5L.LoadComponent[P5L.AddrComponent[tvar]]; long ← FALSE; END; END; NormalLex: PUBLIC PROCEDURE [nwords: CARDINAL, long, code: BOOLEAN ← FALSE] RETURNS [Lexeme] = BEGIN IF nwords <= 2 THEN RETURN[P5L.TOSLex[nwords]] ELSE IF code THEN RETURN[P5L.TOSCodeAddrLex[nwords]] ELSE RETURN[P5L.TOSAddrLex[nwords, long]]; END; OVarItem: PUBLIC PROCEDURE [var: VarComponent] RETURNS [r: VarIndex] = BEGIN r ← P5L.GenVarItem[o]; cb[r] ← [body: o[var: var]]; END; ReleaseLex: PUBLIC PROCEDURE [lex: Lexeme] = BEGIN WITH lex SELECT FROM bdo => ReleaseVarItem[lexbdoi]; ENDCASE; END; PFSize: CARDINAL = 4; pendingFree: ARRAY [0..PFSize) OF VarIndex ← [VarNull, VarNull, VarNull, VarNull]; pfFirst, pfLast: CARDINAL ← 0; BadRelease: PUBLIC SIGNAL [badr: VarIndex] = CODE; ReleaseVarItem: PUBLIC PROCEDURE [r: VarIndex] = BEGIN i: CARDINAL; IF r = VarNull OR cb[r].free THEN GO TO bad; FOR i IN [0..PFSize) DO IF pendingFree[i] = r THEN GO TO bad; ENDLOOP; pfLast ← (pfLast+1) MOD PFSize; IF pfLast = pfFirst THEN BEGIN ReleaseReally[pendingFree[pfFirst]]; pfFirst ← (pfFirst+1) MOD PFSize; END; pendingFree[pfLast] ← r; RETURN; EXITS bad => SIGNAL BadRelease[r]; END; ReleaseReally: PROCEDURE [r: VarIndex] = BEGIN IF r = VarNull THEN RETURN; varCount ← varCount - 1; P5U.FreeChunk[r, (WITH cb[r] SELECT FROM o => SIZE[o VarItem], bo => SIZE[bo VarItem], bdo => SIZE[bdo VarItem], ind => SIZE[ind VarItem], ENDCASE => ERROR)]; RETURN END; ReusableCopies: PUBLIC PROCEDURE [r: VarIndex, dir: MoveDirection, stackOk: BOOLEAN ← TRUE] RETURNS [r1, r2: VarIndex] = BEGIN -- make sure r has reusable pointer parts BEGIN -- to set up "doBo" exit WITH cc: cb[r] SELECT FROM o => IF ~stackOk THEN WITH cc.var SELECT FROM stack => BEGIN tvar: VarComponent = CopyToTemp[r].var; r1 ← OVarItem[tvar]; END; frameup => IF ~immutable THEN GO TO doBo; ENDCASE; ind => IF cc.packtag = packed THEN BEGIN cc.base ← P5L.EasilyLoadable[cc.base, dir]; cc.index ← P5L.EasilyLoadable[cc.index, dir]; END ELSE GO TO doBo; ENDCASE => GO TO doBo; EXITS doBo => BEGIN bor: BoVarIndex = P5L.MakeBo[r]; cb[bor].base ← P5L.EasilyLoadable[cb[bor].base, dir]; r1 ← bor; END; END; r2 ← P5L.CopyVarItem[r1]; END; TOSAddrLex: PUBLIC PROCEDURE [size: CARDINAL, long: BOOLEAN ← FALSE] RETURNS [bdo Lexeme] = BEGIN r: VarIndex = P5L.GenVarItem[bo]; base: VarComponent = TOSComponent[IF long THEN 2 ELSE 1]; IF size = 0 THEN ERROR; cb[r] ← [body: bo[base: base, offset: [wSize: size, space: frame[]]]]; RETURN [[bdo[r]]]; END; TOSCodeAddrLex: PUBLIC PROCEDURE [size: CARDINAL] RETURNS [bdo Lexeme] = BEGIN r: VarIndex = P5L.GenVarItem[bo]; base: VarComponent = TOSComponent[1]; IF size = 0 THEN ERROR; cb[r] ← [body: bo[base: base, offset: [wSize: size, space: code[]]]]; RETURN [[bdo[r]]]; END; TOSComponent: PUBLIC PROCEDURE [size: CARDINAL ← 1] RETURNS [VarComponent] = BEGIN IF size = 0 THEN ERROR; RETURN [[wSize: size, space: stack[sti: Stack.Top[size]]]]; END; TOSLex: PUBLIC PROCEDURE [size: CARDINAL ← 1] RETURNS [Lexeme] = BEGIN r: VarIndex; SELECT size FROM 0 => ERROR; 1 => RETURN [[stack[Stack.Top[]]]]; ENDCASE; r ← P5L.GenVarItem[o]; cb[r] ← [body: o[var: [wSize: size, space: stack[sti: Stack.Top[size]]]]]; RETURN [[bdo[r]]]; END; VarAddressEasy: PUBLIC PROCEDURE [r: VarIndex] RETURNS [BOOLEAN] = BEGIN WITH cc: cb[r] SELECT FROM o => WITH vv: cc.var SELECT FROM code => RETURN [TRUE]; linkup => RETURN [vv.delta = 0]; frame => RETURN [vv.level = lG OR vv.level = CPtr.curctxlvl]; frameup => RETURN [vv.delta = 0 AND (vv.level = lG OR vv.level = CPtr.curctxlvl)]; ENDCASE; bo => WITH oo: cc.offset SELECT FROM frame => IF oo.wd = 0 AND oo.level = lZ THEN RETURN [P5L.EasyToLoad[cc.base, store]]; code => IF oo.wd = 0 THEN RETURN [P5L.EasyToLoad[cc.base, store]]; ENDCASE; ENDCASE; RETURN[FALSE]; END; VarAlignment: PUBLIC PROCEDURE [r: VarIndex, dir: MoveDirection] RETURNS [bd, bSize: [0..wordlength), wSize: CARDINAL] = BEGIN WITH cc: cb[r] SELECT FROM o => BEGIN WITH vv: cc.var SELECT FROM frame => bd ← vv.bd; code => BEGIN IF dir = store THEN ERROR; bd ← vv.bd; END; stack => BEGIN IF dir = store THEN ERROR; bd ← vv.bd; END; const => BEGIN IF dir = store THEN ERROR; bd ← vv.bd; END; ENDCASE => BEGIN IF dir = store THEN ERROR; bd ← 0; END; wSize ← cc.var.wSize; bSize ← cc.var.bSize; END; bo => BEGIN WITH oo: cc.offset SELECT FROM frame => bd ← oo.bd; code => BEGIN IF dir = store THEN ERROR; bd ← oo.bd; END; ENDCASE => ERROR; wSize ← cc.offset.wSize; bSize ← cc.offset.bSize; END; bdo => BEGIN WITH oo: cc.offset SELECT FROM frame => bd ← oo.bd; code => BEGIN IF dir = store THEN ERROR; bd ← oo.bd; END; ENDCASE => ERROR; wSize ← cc.offset.wSize; bSize ← cc.offset.bSize; END; ind => BEGIN WITH oo: cc.offset SELECT FROM frame => bd ← oo.bd; code => BEGIN IF dir = store THEN ERROR; bd ← oo.bd; END; ENDCASE => ERROR; wSize ← cc.offset.wSize; bSize ← cc.offset.bSize; END; ENDCASE => ERROR; END; VarFinal: PUBLIC PROCEDURE = BEGIN i: CARDINAL; FOR i IN [0..PFSize) DO IF pendingFree[i] # VarNull THEN BEGIN ReleaseReally[pendingFree[i]]; pendingFree[i] ← VarNull; END; ENDLOOP; END; VarForLex: PUBLIC PROCEDURE [l: Lexeme] RETURNS [r: VarIndex] = BEGIN var: VarComponent; WITH ll: l SELECT FROM bdo => RETURN [ll.lexbdoi]; ENDCASE => var ← ComponentForLex[l]; r ← P5L.GenVarItem[o]; cb[r] ← [body: o[var: var]]; END; VarStackWords: PUBLIC PROCEDURE [r: VarIndex] RETURNS [nW: CARDINAL] = BEGIN -- number of words on the virtual stack nW ← 0; WITH cb[r] SELECT FROM o => WITH vv: var SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; bo => WITH vv: base SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; bdo => BEGIN WITH vv: base SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; WITH vv: disp SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; END; ind => BEGIN WITH vv: base SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; WITH vv: index SELECT FROM stack => nW ← nW + P5L.Words[vv.wSize, vv.bSize]; ENDCASE; END; ENDCASE; RETURN END; END.