-- file Pass3S.Mesa -- last modified by Satterthwaite, October 31, 1979 1:54 PM DIRECTORY ComData: FROM "comdata" USING [ bodyIndex, mainBody, monitored, nTypeCodes, stopping, textIndex, typeBOOLEAN, typeMap], Copier: FROM "copier" USING [CopyXferType], InlineDefs: FROM "inlinedefs" USING [BITAND], Log: FROM "log" USING [Error, ErrorTree, Warning, WarningTree], Pass3: FROM "pass3" USING [ continued, currentBody, implicitAttr, implicitTree, implicitType, enclosingBody, lockHeld, lockNode, markCatch], P3: FROM "p3" USING [ Attr, BodyData, NPUse, BoundNP, SequenceNP, phraseNP, --And,-- Apply, Assignment, BumpCount, CanonicalType, CheckDisjoint, CloseBase, ClearRefStack, CopyLock, DeclList, Discrimination, Exp, Extract, FindLockParams, IdentifiedType, LockVar, MatchFields, MiscStmt, OpenBase, OperandLhs, OrderedType, PopCtx, PushCtx, Range, RAttr, RecordMention, Rhs, RPop, RPush, RType, SealRefStack, TargetType, TypeForTree, UnsealRefStack, UpdateTreeAttr, InsertCatchLabel], Symbols: FROM "symbols" USING [seType, ctxType, mdType, bodyType, ContextLevel, SEIndex, ISEIndex, CSEIndex, RecordSEIndex, CTXIndex, BTIndex, CBTIndex, HTNull, SENull, CSENull, RecordSENull, CTXNull, BTNull, lG, typeANY], SymbolOps: FROM "symbolops" USING [FirstCtxSe, NextSe, TransferTypes, UnderType], SystemDefs: FROM "systemdefs" USING [AllocateHeapNode], Table: FROM "table" USING [Base, Notifier], Tree: FROM "tree" USING [treeType, Index, Link, Map, Null, Scan, NullId], TreeOps: FROM "treeops" USING [ FreeNode, GetNode, MakeList, PopTree, PushTree, PushNode, ReverseScanList, ScanList, SetAttr, SetInfo, UpdateList]; Pass3S: PROGRAM IMPORTS InlineDefs, Copier, Log, P3, SymbolOps, SystemDefs, TreeOps, dataPtr: ComData, passPtr: Pass3 EXPORTS P3 = BEGIN OPEN SymbolOps, Symbols, P3, TreeOps; And: PROCEDURE [Attr, Attr] RETURNS [Attr] = LOOPHOLE[InlineDefs.BITAND]; tb: Table.Base; -- tree base address (local copy) seb: Table.Base; -- se table base address (local copy) ctxb: Table.Base; -- context table base (local copy) mdb: Table.Base; -- module table base (local copy) bb: Table.Base; -- body table base (local copy) StmtNotify: PUBLIC Table.Notifier = BEGIN -- called by allocator whenever table area is repacked tb ← base[Tree.treeType]; seb ← base[seType]; ctxb ← base[ctxType]; mdb ← base[mdType]; bb ← base[bodyType]; END; -- parameter usage pathNP: PUBLIC NPUse; -- bodies and blocks current: POINTER TO P3.BodyData = @passPtr.currentBody; currentArgCtx: PUBLIC CTXIndex; exits: BOOLEAN; BodyList: PUBLIC PROCEDURE [firstBti: BTIndex] = BEGIN bti: BTIndex; IF (bti ← firstBti) # BTNull THEN DO WITH bb[bti] SELECT FROM Callable => Body[LOOPHOLE[bti, CBTIndex]]; ENDCASE => NULL; IF bb[bti].link.which = parent THEN EXIT; bti ← bb[bti].link.index; ENDLOOP; END; Body: PROCEDURE [bti: CBTIndex] = BEGIN item: Tree.Index; -- item designates a declitem with body as last son saved: P3.BodyData = current↑; saveIndex: CARDINAL = dataPtr.textIndex; saveBodyIndex: CBTIndex = dataPtr.bodyIndex; saveEnclosing: BTIndex = passPtr.enclosingBody; saveLockHeld: BOOLEAN = passPtr.lockHeld; node: Tree.Index; lockVar: ISEIndex; lockBit: BOOLEAN; bodyType: SEIndex; inRecord, outRecord: RecordSEIndex; dataPtr.bodyIndex ← passPtr.enclosingBody ← bti; WITH bb[bti].info SELECT FROM Internal => BEGIN dataPtr.textIndex ← sourceIndex; item ← bodyTree; current.bodyNode ← node ← GetNode[tb[item].son[3]]; bodyTree ← node; END; ENDCASE => ERROR; current.level ← bb[bti].level; current.entry ← bb[bti].entry ← tb[node].attr1; bb[bti].internal ← tb[node].attr2; bb[bti].resident ← FALSE; passPtr.lockHeld ← bb[bti].entry OR bb[bti].internal; bodyType ← TypeForTree[tb[item].son[2]]; bb[bti].ioType ← SELECT seb[bodyType].seTag FROM cons => LOOPHOLE[bodyType, CSEIndex], ENDCASE => Copier.CopyXferType[UnderType[bodyType]]; [inRecord, outRecord] ← TransferTypes[bb[bti].ioType]; IF inRecord = SENull THEN currentArgCtx ← CTXNull ELSE ctxb[currentArgCtx←seb[inRecord].fieldCtx].level ← bb[bti].level; IF outRecord # SENull THEN ctxb[seb[outRecord].fieldCtx].level ← bb[bti].level; IF current.level = lG AND dataPtr.nTypeCodes # 0 THEN BEGIN dataPtr.typeMap ← DESCRIPTOR [ SystemDefs.AllocateHeapNode[dataPtr.nTypeCodes*SIZE[SEIndex]], dataPtr.nTypeCodes]; dataPtr.nTypeCodes ← 0; END; PushArgCtx[current.inputRecord ← inRecord]; BumpArgRefs[current.inputRecord, TRUE]; PushArgCtx[current.returnRecord ← outRecord]; ClearRefStack[]; -- initialize computed attributes current.labelList ← Tree.Null; current.loopDepth ← 0; current.catchDepth ← 0; current.unwindEnabled ← FALSE; current.resumeRecord ← RecordSENull; current.resumeFlag ← FALSE; IF ~current.entry THEN pathNP ← none ELSE BEGIN IF (lockVar ← FindLockParams[].actual) # SENull THEN BEGIN lockBit ← seb[lockVar].immutable; seb[lockVar].immutable ← TRUE; END; tb[node].son[4] ← CopyLock[]; pathNP ← phraseNP; END; BEGIN ENABLE InsertCatchLabel => BEGIN Log.Error[catchLabel]; RESUME END; ScanList[tb[node].son[1], OpenItem]; IF inRecord # SENull THEN CheckDisjoint[seb[inRecord].fieldCtx, bb[bti].localCtx]; IF outRecord # SENull THEN CheckDisjoint[seb[outRecord].fieldCtx, bb[bti].localCtx]; PushCtx[bb[bti].localCtx]; IF bti = dataPtr.mainBody AND dataPtr.monitored THEN BEGIN DeclList[tb[passPtr.lockNode].son[1]]; PushCtx[tb[passPtr.lockNode].info]; IF (lockVar ← FirstCtxSe[tb[passPtr.lockNode].info]) # SENull THEN BumpCount[lockVar]; tb[passPtr.lockNode].son[2] ← LockVar[tb[passPtr.lockNode].son[2]]; PopCtx[]; ClearRefStack[]; END; DeclList[tb[node].son[2]]; END; current.reachable ← TRUE; tb[node].son[3] ← UpdateList[tb[node].son[3], Stmt ! InsertCatchLabel => BEGIN IF ~catchSeen THEN Log.Error[catchLabel]; RESUME END]; IF current.reachable THEN tb[node].son[3] ← ImpliedReturn[tb[node].son[3]]; BodyList[bb[bti].firstSon]; PopCtx[]; ReverseScanList[tb[node].son[1], CloseItem]; bb[bti].stopping ← dataPtr.stopping AND bb[bti].level = lG; bb[bti].hints ← [ -- temporary safe: FALSE, argUpdated: inRecord # SENull AND ctxb[seb[inRecord].fieldCtx].varUpdated, nameSafe: pathNP # unsafe, attr4: FALSE, attr5: FALSE]; PopArgCtx[outRecord]; PopArgCtx[inRecord]; IF current.entry AND lockVar # SENull THEN seb[lockVar].immutable ← lockBit; current↑ ← saved; passPtr.lockHeld ← saveLockHeld; passPtr.enclosingBody ← saveEnclosing; dataPtr.bodyIndex ← saveBodyIndex; dataPtr.textIndex ← saveIndex; END; Block: PROCEDURE [node: Tree.Index] = BEGIN OPEN tb[node]; bti: BTIndex = info; saveIndex: CARDINAL = dataPtr.textIndex; saveEnclosing: BTIndex = passPtr.enclosingBody; WITH bb[bti].info SELECT FROM Internal => dataPtr.textIndex ← sourceIndex; ENDCASE => ERROR; passPtr.enclosingBody ← bti; PushCtx[bb[bti].localCtx]; DeclList[son[1] ! InsertCatchLabel => BEGIN Log.Error[catchLabel]; RESUME END]; son[2] ← UpdateList[son[2], Stmt]; BodyList[bb[bti].firstSon]; PopCtx[]; passPtr.enclosingBody ← saveEnclosing; dataPtr.textIndex ← saveIndex; END; PushArgCtx: PROCEDURE [sei: RecordSEIndex] = BEGIN IF sei # SENull THEN PushCtx[seb[sei].fieldCtx]; END; PopArgCtx: PROCEDURE [sei: RecordSEIndex] = BEGIN IF sei # SENull THEN PopCtx[]; END; -- statements Stmt: PUBLIC PROCEDURE [stmt: Tree.Link] RETURNS [val: Tree.Link] = BEGIN node: Tree.Index; saveIndex: CARDINAL = dataPtr.textIndex; saveMark: BOOLEAN = passPtr.markCatch; saveContinued: BOOLEAN = passPtr.continued; IF stmt = Tree.Null THEN RETURN [Tree.Null]; WITH stmt SELECT FROM subtree => BEGIN node ← index; dataPtr.textIndex ← tb[node].info; IF ~current.reachable AND tb[node].name # list THEN BEGIN Log.Warning[unreachable]; current.reachable ← TRUE END; val ← stmt; -- the default passPtr.markCatch ← passPtr.continued ← FALSE; SELECT tb[node].name FROM assign => BEGIN Assignment[node]; RPop[]; pathNP ← SequenceNP[pathNP][phraseNP]; END; extract => BEGIN Extract[node]; pathNP ← SequenceNP[pathNP][phraseNP] END; apply => BEGIN Apply[node, typeANY, TRUE]; SELECT tb[node].name FROM wait => Log.ErrorTree[typeClash, tb[node].son[1]]; error => current.reachable ← FALSE; ENDCASE; SELECT RType[] FROM CSENull, typeANY => NULL; ENDCASE => Log.Error[nonVoidStmt]; RPop[]; pathNP ← SequenceNP[pathNP][phraseNP]; END; block => Block[node]; if => BEGIN OPEN tb[node]; saveReachable: BOOLEAN; entryNP, saveNP: NPUse; son[1] ← Rhs[son[1], dataPtr.typeBOOLEAN]; RPop[]; pathNP ← entryNP ← SequenceNP[pathNP][phraseNP]; ClearRefStack[]; son[2] ← UpdateList[son[2], Stmt]; saveReachable ← current.reachable; saveNP ← pathNP; current.reachable ← TRUE; pathNP ← entryNP; son[3] ← UpdateList[son[3], Stmt]; IF saveReachable THEN current.reachable ← TRUE; pathNP ← BoundNP[saveNP][pathNP]; END; case => SelectStmt[node, Case]; bind => SelectStmt[node, Discrimination]; do => DoStmt[node]; label => BEGIN OPEN tb[node]; InsertLabels[son[2]]; son[1] ← UpdateList[son[1], Stmt]; DeleteLabels[son[2]]; LabelList[son[2]]; END; goto => BEGIN ValidateLabel[tb[node].son[1]]; current.reachable ← FALSE; END; return => Return[node]; exit, loop => BEGIN IF tb[node].name = exit THEN exits ← TRUE; IF current.loopDepth = 0 THEN Log.Error[exit]; current.reachable ← FALSE; END; null => NULL; syserror => current.reachable ← FALSE; open => BEGIN OPEN tb[node]; ScanList[son[1], OpenItem]; son[2] ← UpdateList[son[2], Stmt]; ReverseScanList[son[1], CloseItem]; END; list => val ← UpdateList[val, Stmt]; ENDCASE => val ← MiscStmt[node]; END; ENDCASE => ERROR; IF passPtr.markCatch THEN BEGIN PushTree[val]; PushNode[catchmark,1]; SetInfo[dataPtr.textIndex]; val ← PopTree[]; IF passPtr.continued THEN current.reachable ← TRUE; pathNP ← unsafe; END; passPtr.markCatch ← saveMark; passPtr.continued ← saveContinued; ClearRefStack[]; dataPtr.textIndex ← saveIndex; RETURN END; -- case driver Case: PUBLIC PROCEDURE [node: Tree.Index, selection: Tree.Map] = BEGIN OPEN tb[node]; saveType: CSEIndex = passPtr.implicitType; saveAttr: Attr = passPtr.implicitAttr; saveTree: Tree.Link = passPtr.implicitTree; entryNP: NPUse; attr: Attr; eqTests: BOOLEAN; CaseItem: Tree.Scan = BEGIN switchable: BOOLEAN; saveIndex: CARDINAL = dataPtr.textIndex; CaseTest: Tree.Map = BEGIN node: Tree.Index = GetNode[t]; BEGIN OPEN tb[node]; SELECT name FROM relE => BEGIN type: CSEIndex; son[2] ← Rhs[son[2], TargetType[passPtr.implicitType]]; type ← RType[]; info ← dataPtr.typeBOOLEAN; SELECT seb[type].typeTag FROM long => BEGIN attr1 ← FALSE; attr2 ← TRUE END; real => BEGIN attr1 ← TRUE; attr2 ← FALSE END; ENDCASE => attr1 ← attr2 ← FALSE; switchable ← switchable AND RAttr[].const; v ← t; END; ENDCASE => BEGIN v ← Rhs[t, dataPtr.typeBOOLEAN]; eqTests ← switchable ← FALSE; END; attr ← And[RAttr[], attr]; RPop[]; entryNP ← SequenceNP[entryNP][phraseNP]; END; RETURN END; node: Tree.Index = GetNode[t]; dataPtr.textIndex ← tb[node].info; BEGIN OPEN tb[node]; switchable ← TRUE; son[1] ← UpdateList[son[1], CaseTest]; attr1 ← switchable; phraseNP ← entryNP; son[2] ← selection[son[2]]; END; dataPtr.textIndex ← saveIndex; END; SealRefStack[]; son[1] ← Exp[son[1], typeANY]; passPtr.implicitType ← CanonicalType[RType[]]; passPtr.implicitAttr ← attr ← RAttr[]; RPop[]; entryNP ← phraseNP; IF ~IdentifiedType[passPtr.implicitType] THEN Log.ErrorTree[relationType, son[1]]; passPtr.implicitTree ← son[1]; eqTests ← TRUE; UnsealRefStack[]; ScanList[son[2], CaseItem]; attr1 ← eqTests; phraseNP ← entryNP; son[3] ← selection[son[3]]; RPush[CSENull, attr]; passPtr.implicitAttr ← saveAttr; passPtr.implicitType ← saveType; passPtr.implicitTree ← saveTree; END; -- selection SelectStmt: PROCEDURE [node: Tree.Index, driver: PROCEDURE [Tree.Index, Tree.Map]] = BEGIN newReachable: BOOLEAN; newNP: NPUse; saveNP: NPUse = pathNP; Selection: Tree.Map = BEGIN current.reachable ← TRUE; pathNP ← SequenceNP[saveNP][phraseNP]; v ← Stmt[t]; IF current.reachable THEN newReachable ← TRUE; newNP ← BoundNP[newNP][pathNP]; END; newReachable ← FALSE; newNP ← none; driver[node, Selection]; RPop[]; current.reachable ← newReachable; pathNP ← newNP; END; -- iteration DoStmt: PROCEDURE [node: Tree.Index] = BEGIN OPEN tb[node]; forNode: Tree.Index; cvType: CSEIndex; controlled, cvUpdate, newReachable, saveExits: BOOLEAN; saveNP, exitNP: NPUse; newReachable ← controlled ← cvUpdate ← FALSE; IF son[1] # Tree.Null THEN BEGIN forNode ← GetNode[son[1]]; IF tb[forNode].son[1] = Tree.Null THEN RPush[typeANY, [noXfer:TRUE, noAssign:TRUE, const:FALSE]] ELSE BEGIN tb[forNode].son[1] ← Exp[tb[forNode].son[1], typeANY]; IF ~OperandLhs[tb[forNode].son[1]] THEN Log.ErrorTree[nonLHS, tb[forNode].son[1]]; WITH tb[forNode].son[1] SELECT FROM symbol => BEGIN -- account for implicit references BumpCount[index]; BumpCount[index]; END; ENDCASE => Log.ErrorTree[controlId, tb[forNode].son[1]]; END; cvType ← TargetType[RType[]]; RPop[]; SELECT tb[forNode].name FROM forseq => BEGIN -- sequencing using a generator OPEN seq: tb[forNode]; seq.son[2] ← Rhs[seq.son[2], cvType]; RPop[]; cvUpdate ← TRUE; END; upthru, downthru => BEGIN -- stepping through an interval controlled ← TRUE; IF ~OrderedType[cvType] AND cvType # typeANY THEN Log.Error[nonOrderedType]; tb[forNode].son[2] ← Range[tb[forNode].son[2], cvType]; RPop[]; END; ENDCASE => ERROR; pathNP ← SequenceNP[pathNP][phraseNP]; ClearRefStack[]; END; saveNP ← pathNP; pathNP ← none; IF son[2] # Tree.Null THEN BEGIN controlled ← TRUE; son[2] ← Rhs[son[2], dataPtr.typeBOOLEAN]; RPop[]; pathNP ← SequenceNP[pathNP][phraseNP]; ClearRefStack[]; END; ScanList[son[3], OpenItem]; InsertLabels[son[5]]; current.loopDepth ← current.loopDepth + 1; saveExits ← exits; exits ← FALSE; son[4] ← UpdateList[son[4], Stmt]; IF exits THEN newReachable ← TRUE; exits ← saveExits; DeleteLabels[son[5]]; current.loopDepth ← current.loopDepth - 1; IF cvUpdate THEN BEGIN tb[forNode].son[3] ← Rhs[tb[forNode].son[3], cvType]; RPop[]; pathNP ← SequenceNP[pathNP][phraseNP]; ClearRefStack[]; END; IF pathNP = refset THEN pathNP ← unsafe; saveNP ← pathNP ← SequenceNP[saveNP][pathNP]; IF son[5] # Tree.Null THEN BEGIN current.reachable ← FALSE; LabelList[son[5]]; IF current.reachable THEN newReachable ← TRUE; END; exitNP ← pathNP; IF son[6] # Tree.Null THEN BEGIN current.reachable ← controlled; pathNP ← saveNP; son[6] ← UpdateList[son[6], Stmt]; IF current.reachable THEN newReachable ← TRUE; exitNP ← BoundNP[exitNP][pathNP]; END ELSE IF controlled THEN newReachable ← TRUE; ReverseScanList[son[3], CloseItem]; current.reachable ← newReachable; pathNP ← exitNP; END; -- labels LabelList: PROCEDURE [t: Tree.Link] = BEGIN newReachable: BOOLEAN; saveNP, newNP: NPUse; LabelItem: PROCEDURE [item: Tree.Link] = BEGIN node: Tree.Index = GetNode[item]; current.reachable ← tb[node].attr1; pathNP ← saveNP; tb[node].son[2] ← UpdateList[tb[node].son[2], Stmt]; IF current.reachable THEN newReachable ← TRUE; newNP ← BoundNP[newNP][pathNP]; END; newReachable ← current.reachable; saveNP ← pathNP; newNP ← none; ScanList[t, LabelItem]; current.reachable ← newReachable; pathNP ← newNP; END; InsertLabels: PROCEDURE [t: Tree.Link] = BEGIN labelMark: Tree.Link = current.labelList; InsertLabel: PROCEDURE [labeled: Tree.Link] = BEGIN node: Tree.Index = GetNode[labeled]; saveIndex: CARDINAL = dataPtr.textIndex; dataPtr.textIndex ← tb[node].info; ScanList[tb[node].son[1], StackLabel]; dataPtr.textIndex ← saveIndex; END; StackLabel: PROCEDURE [id: Tree.Link] = BEGIN t: Tree.Link; node: Tree.Index; FOR t ← current.labelList, tb[node].son[2] UNTIL t = labelMark DO node ← GetNode[t]; IF tb[node].son[1] = id AND id # Tree.NullId THEN Log.ErrorTree[duplicateLabel, id]; ENDLOOP; PushTree[id]; PushTree[current.labelList]; PushNode[item, 2]; SetAttr[1, FALSE]; current.labelList ← PopTree[]; END; ScanList[t, InsertLabel]; END; ValidateLabel: PROCEDURE [id: Tree.Link] = BEGIN t: Tree.Link; node: Tree.Index; FOR t ← current.labelList, tb[node].son[2] UNTIL t = Tree.Null DO node ← GetNode[t]; IF tb[node].son[1] = id THEN BEGIN tb[node].attr1 ← TRUE; RETURN END; ENDLOOP; Log.ErrorTree[unknownLabel, id]; END; DeleteLabels: PROCEDURE [t: Tree.Link] = BEGIN anyReachable: BOOLEAN; DeleteLabel: PROCEDURE [labeled: Tree.Link] = BEGIN node: Tree.Index = GetNode[labeled]; saveIndex: CARDINAL = dataPtr.textIndex; dataPtr.textIndex ← tb[node].info; anyReachable ← FALSE; ReverseScanList[tb[node].son[1], UnstackLabel]; tb[node].attr1 ← anyReachable; dataPtr.textIndex ← saveIndex; END; UnstackLabel: PROCEDURE [id: Tree.Link] = BEGIN node: Tree.Index; node ← GetNode[current.labelList]; IF tb[node].attr1 THEN anyReachable ← TRUE ELSE Log.WarningTree[unusedId, tb[node].son[1]]; current.labelList ← tb[node].son[2]; tb[node].son[2] ← Tree.Null; FreeNode[node]; END; ReverseScanList[t, DeleteLabel]; END; -- control transfers BumpArgRefs: PUBLIC PROCEDURE [record: RecordSEIndex, write: BOOLEAN] = BEGIN sei: ISEIndex; IF record # SENull THEN FOR sei ← FirstCtxSe[seb[record].fieldCtx], NextSe[sei] UNTIL sei = SENull DO IF write THEN BumpCount[sei] ELSE RecordMention[sei]; ENDLOOP; END; CheckLocals: PUBLIC PROCEDURE [t: Tree.Link] RETURNS [localsOnly: BOOLEAN] = BEGIN level: ContextLevel = bb[dataPtr.bodyIndex].level; CheckElement: Tree.Scan = BEGIN sei: ISEIndex; WITH t SELECT FROM literal => NULL; symbol => BEGIN sei ← index; IF ~seb[sei].constant AND ctxb[seb[sei].idCtx].level # level THEN localsOnly ← FALSE; END; ENDCASE => localsOnly ← FALSE; END; localsOnly ← TRUE; ScanList[t, CheckElement]; RETURN END; Return: PROCEDURE [node: Tree.Index] = BEGIN OPEN tb[node]; rSei: RecordSEIndex = current.returnRecord; IF current.catchDepth # 0 OR (dataPtr.bodyIndex = dataPtr.mainBody AND rSei = SENull) THEN Log.Error[misplacedReturn]; IF rSei # SENull AND son[1] = Tree.Null THEN BEGIN BumpArgRefs[rSei, FALSE]; IF seb[ctxb[seb[rSei].fieldCtx].seList].hash = HTNull THEN Log.Error[illDefinedReturn]; attr2 ← TRUE; END ELSE BEGIN son[1] ← MatchFields[rSei, son[1], FALSE]; RPop[]; pathNP ← SequenceNP[pathNP][phraseNP]; IF current.entry THEN attr2 ← CheckLocals[son[1]]; END; IF (attr1 ← current.entry) THEN BEGIN [] ← UpdateTreeAttr[tb[current.bodyNode].son[4]]; pathNP ← SequenceNP[pathNP][phraseNP]; END; current.reachable ← FALSE; END; ImpliedReturn: Tree.Map = BEGIN IF current.returnRecord # SENull OR current.entry THEN BEGIN PushTree[Tree.Null]; PushNode[return, 1]; SetInfo[dataPtr.textIndex]; PushTree[Stmt[PopTree[]]]; PushTree[t]; v ← MakeList[-2]; END ELSE v ← t; RETURN END; -- basing OpenItem: Tree.Scan = BEGIN node: Tree.Index = GetNode[t]; saveIndex: CARDINAL = dataPtr.textIndex; dataPtr.textIndex ← tb[node].info; WITH tb[node].son[1] SELECT FROM hash => tb[node].son[2] ← OpenBase[tb[node].son[2], index ! InsertCatchLabel => BEGIN Log.Error[catchLabel]; RESUME END]; ENDCASE => ERROR; ClearRefStack[]; dataPtr.textIndex ← saveIndex; END; CloseItem: Tree.Scan = BEGIN node: Tree.Index = GetNode[t]; WITH tb[node].son[1] SELECT FROM hash => CloseBase[tb[node].son[2], index]; ENDCASE => ERROR; END; END.