-- DIHot.mesa last edit: -- Bruce October 28, 1980 12:14 PM -- Sandman July 18, 1980 8:05 AM DIRECTORY BP USING [Condition], ComData USING [typeCARDINAL, typeCHAR, typeINT, typeSTRING], CompilerUtil USING [PrintTree], DebugFormat USING [Foo, Fob, NullFob], DebugOps USING [ DisplayFoo, Foo, FooProc, Lengthen, SyntaxError], DebugUsefulDefs USING [], DI USING [ AbortWithError, CSEIndex, CTXIndex, DerefProcDesc, Err, Error, FindField, Foo, GetControlLink, GetValue, HTIndex, ISEIndex, MakeLongType, NotAProcedure, Number, NumberType, Pad, PutValue, RecordSEIndex, SearchCtxList, SEIndex, TagIsei, TypeForSe, UnionSEIndex, VariantType, Words], DIActions USING [ Abs, Assignable, Base, DoApply, DumpArray, DumpMemory, FoldExpr, GetSize, Interval, Length, LengthenFob, Long, MakePointerType, MakeXferType, Max, Memory, Min, nullError, nullProc, nullSig, PushNil, PutLongReps, PutReps, SelectVariantType, Size, TotalWords, TreeType, VariantUnionType, exp, memoryInt, arrayInt, conditionalBreak, eol, frameDollar, fileDollar, typeDollar, card, lcard, int, lint, bang, memory, reps], DOutput USING [EOL, NewLine], DSyms USING [GFHandle, GFrameHti, Shared], Frames USING [Type], Gf USING [FrameGfi, Handle, NewLink, Validate], DHeap USING [AllocFob, FreeLong], Inline USING [HighHalf, LowHalf], Lf USING [GF], Literals USING [LitRecord], Lookup USING [ Complete, CopyLiteral, HTIndex, InCtx, InLF, InMod, Mode, OnStack, Proc, Signal], MachineDefs USING [GFHandle], P1 USING [DParse, PrintNodeName], PrincOps USING [SignalDesc], State USING [Get, GetGS, GSHandle, Handle, Stack, top], Storage USING [Free, FreeString, Node, String], String USING [AppendChar, AppendString], SymbolOps USING [FirstCtxSe, NextSe, TypeRoot, UnderType, WordsForType], Symbols USING [ ArraySEIndex, CSEIndex, CTXIndex, HTIndex, HTNull, ISEIndex, ISENull, SEIndex, seType, typeANY], SymbolTable USING [Missing], Table USING [AddNotify, Base, DropNotify, Notifier], Tree USING [Index, Link, NodeName, Null, Scan, treeType], TreeOps USING [FreeTree, OpName, PopTree, ScanList]; DIHot: PROGRAM IMPORTS BP, com: ComData, CompilerUtil, DebugOps, DI, DIActions, DOutput, DSyms, Frames, Gf, DHeap, Inline, Lf, Lookup, P1, State, Storage, String, SymbolOps, SymbolTable, Table, TreeOps EXPORTS DebugOps, DebugUsefulDefs, DI, DIActions = BEGIN OPEN DI, DIActions; Underflow: PUBLIC ERROR = CODE; StackNotEmptyAtStatement: PUBLIC ERROR = CODE; NotImplemented: PUBLIC SIGNAL [msg: STRING] = CODE; DIAbort: PUBLIC ERROR = CODE; BadTree: ERROR = CODE; WhosBeenScanningMyTree: ERROR = CODE; CantAssignInDebuggerImage: ERROR = CODE; data: State.GSHandle ← State.GetGS[]; dereferenced: PUBLIC BOOLEAN; target: Symbols.CSEIndex; Interpreter: PUBLIC PROC [exp: STRING] = {Interpret[exp,NIL]}; Interpret: PUBLIC PROC [ exp: STRING, results: DebugOps.FooProc ← DebugOps.DisplayFoo, targetType: Symbols.CSEIndex ← Symbols.typeANY] = BEGIN t: Tree.Link; copy: BOOLEAN = exp.length = exp.maxlength; temp: STRING ← IF copy THEN Storage.String[exp.length+1] ELSE NIL; CleanupString: PROC = BEGIN IF copy THEN Storage.FreeString[temp] ELSE exp.length ← exp.length - 1; END; Cleanup: PROC = BEGIN Drop[]; [] ← TreeOps.FreeTree[t]; ResetStack[]; CleanupString[]; END; IF copy THEN {String.AppendString[temp,exp]; exp ← temp}; String.AppendChar[exp,'\]; IF ~P1.DParse[exp !UNWIND => CleanupString[]] THEN BEGIN CleanupString[]; SIGNAL DebugOps.SyntaxError[0] END; t ← TreeOps.PopTree[]; IF data.tree THEN CompilerUtil.PrintTree[t]; Add[]; State.Get[].h.proc ← results; target ← targetType; ProcessTree[t ! UNWIND => Cleanup[]]; Cleanup[]; END; ProcessTree: Tree.Scan = BEGIN OPEN TreeOps; IF t = Tree.Null THEN RETURN; t ← CheckNode[t,eol]; t ← CheckNode[t,block]; ScanList[t,Exp]; CheckForStackEmpty[]; END; CheckNode: PUBLIC PROCEDURE [t: Tree.Link, name: Tree.NodeName] RETURNS [son1: Tree.Link] = BEGIN IF TreeOps.OpName[t] # name THEN ERROR BadTree; Add[]; WITH t SELECT FROM subtree => son1 ← tb[index].son[1]; ENDCASE => {Drop[]; ERROR BadTree}; Drop[]; END; CheckLink: PUBLIC PROC [t: Tree.Link, type: TreeType] RETURNS [UNSPECIFIED] = BEGIN WITH t SELECT FROM subtree => IF type = subtree THEN RETURN[index]; hash => IF type = hash THEN RETURN[index]; symbol => IF type = symbol THEN RETURN[index]; literal => IF type = literal THEN RETURN[info]; ENDCASE => ERROR BadTree; ERROR WhosBeenScanningMyTree; END; seb: Table.Base; tb: Table.Base; hot: PUBLIC CARDINAL ← 0; Notify: Table.Notifier = BEGIN tb ← base[Tree.treeType]; seb ← base[Symbols.seType]; END; Add: PROCEDURE = BEGIN IF hot = 0 THEN Table.AddNotify[Notify]; hot ← hot + 1; END; Drop: PROCEDURE = BEGIN IF (hot ← hot-1) = 0 THEN Table.DropNotify[Notify]; END; Exp: Tree.Scan = BEGIN ENABLE {DIAbort => GOTO cleanExit; UNWIND => Drop[]}; son1: Foo; IF t = Tree.Null THEN RETURN; Add[]; WITH t SELECT FROM subtree => BEGIN OPEN TreeOps; SELECT tb[index].name FROM exp => BEGIN son1 ← FirstSon[index, target]; IF son1↑ # DebugFormat.NullFob THEN State.Get[].h.proc[son1]; END; memoryInt => BEGIN son1 ← FirstSon[index, MakeLongType[com.typeCARDINAL]]; DumpMemory[son1]; END; arrayInt => BEGIN son1 ← FirstSon[index, target]; Work[tb[index].son[2], seb[ArraySei[son1]].indexType]; DumpArray[son1]; END; reps => BEGIN n: Number; son1 ← FirstSon[index, target]; n ← GetNumber[son1]; SELECT n.type FROM one => PutReps[n.u]; two => PutLongReps[n.lu]; ENDCASE; END; assign => BEGIN rhs: Foo; son1 ← FirstSon[index, target]; TargetTypeWork[tb[index].son[2], son1.tsei]; rhs ← Pop[]; PutValue[son1,rhs.addr.base] END; eol => { IF ~DOutput.NewLine[] THEN DOutput.EOL[]; Exp[tb[index].son[1]]; DOutput.EOL[]; CheckForStackEmpty[]}; conditionalBreak => { IF State.Get[].h.howSet # break THEN AbortWithError[relation]; dereferenced ← FALSE; Work[tb[index].son[1]]}; ENDCASE => ERROR WhosBeenScanningMyTree; END; ENDCASE => ERROR BadTree; Drop[]; EXITS cleanExit => {ResetStack[]; RETURN}; END; ArraySei: PROC [f: Foo] RETURNS [asei: Symbols.ArraySEIndex] = BEGIN csei: CSEIndex ← TypeForSe[f.tsei]; DO WITH seb[csei] SELECT FROM array => {asei ← LOOPHOLE[csei]; EXIT}; arraydesc => {asei ← LOOPHOLE[SymbolOps.UnderType[describedType]]; EXIT}; ref => csei ← TypeForSe[refType]; long => csei ← TypeForSe[rangeType]; ENDCASE => AbortWithError[notArray,f.hti]; ENDLOOP; END; FirstSon: PUBLIC PROC [index: Tree.Index, type: SEIndex ← Symbols.typeANY] RETURNS [f: Foo] = BEGIN son: Tree.Link; Add[]; son ← tb[index].son[1]; Work[son, type ! UNWIND => Drop[]]; Drop[]; f ← IF son # Tree.Null THEN Pop[] ELSE NIL; END; Son: PUBLIC PROC [t: Tree.Link, target: Symbols.SEIndex] RETURNS [Foo] = BEGIN IF t = Tree.Null THEN ERROR WhosBeenScanningMyTree; Work[t, target]; RETURN[Tos[]]; END; NumberWork: PUBLIC PROC [t: Tree.Link, number, target: Symbols.SEIndex] = BEGIN csei: Symbols.SEIndex; target ← TypeForSe[target]; csei ← SELECT TRUE FROM target = Symbols.typeANY => number, SymbolOps.WordsForType[target] # 1 => number, ENDCASE => target; TargetTypeWork[t, csei]; END; Work: PUBLIC PROC [t: Tree.Link, type: Symbols.SEIndex ← Symbols.typeANY] = BEGIN IF t = Tree.Null THEN RETURN; WITH t SELECT FROM subtree => SubtreeWork[index,type]; hash => Push[HashWork[index,type]]; symbol => Push[SymbolWork[index]]; literal => Push[FindLiteral[info]]; ENDCASE => ERROR BadTree; END; LoopHoleWork: PUBLIC PROC [t: Tree.Link, type: Symbols.SEIndex] = BEGIN f: Foo ← NIL; literal: BOOLEAN ← FALSE; IF t = Tree.Null THEN RETURN; WITH t SELECT FROM subtree => { SubtreeWork[index,type]; f ← Pop[]; SELECT tb[index].name FROM int, card => literal ← TRUE; ENDCASE}; hash => f ← HashWork[index,type]; literal => {literal ← TRUE; f ← FindLiteral[info]}; ENDCASE => ERROR BadTree; IF literal AND (SELECT type FROM nullProc, nullSig, nullError => TRUE, ENDCASE => FALSE) THEN f.addr.base↑ ← Gf.NewLink[f.addr.base↑]; LoopHole[f,type,TRUE]; Push[f]; END; TargetTypeWork: PUBLIC PROC [t: Tree.Link, type: Symbols.SEIndex] = BEGIN f: Foo ← NIL; IF t = Tree.Null THEN RETURN; WITH t SELECT FROM subtree => {SubtreeWork[index,type]; f ← Pop[]}; hash => f ← HashWork[index,type]; literal => {f ← FindLiteral[info]; FixupLiteral[f,type]}; ENDCASE => ERROR BadTree; Assignable[f,TypeForSe[type]]; Push[f]; END; FixupLiteral: PROC [f: Foo, type: Symbols.SEIndex] = { csei: Symbols.CSEIndex ← TypeForSe[type]; f.tsei ← csei; SELECT csei FROM com.typeCARDINAL, Symbols.typeANY, com.typeINT => NULL; ENDCASE => { WITH seb[csei] SELECT FROM long => IF NumberLength[f] = one THEN Long[f, rangeType = com.typeINT]; ENDCASE } }; SymbolWork: PROC [index: Symbols.SEIndex] RETURNS [f: Foo] = INLINE BEGIN f ← DHeap.AllocFob[]; f.tsei ← index; f.typeOnly ← TRUE; END; HashWork: PROC [index: Symbols.HTIndex, hint: Symbols.SEIndex] RETURNS [f: Foo] = BEGIN f ← NIL; IF hint # Symbols.typeANY THEN { csei: Symbols.CSEIndex ← TypeForSe[hint]; DO WITH seb[csei] SELECT FROM enumerated => f ← Lookup.InCtx[index, valueCtx]; subrange => {csei ← TypeForSe[rangeType]; LOOP}; ENDCASE; IF f # NIL THEN RETURN ELSE EXIT; ENDLOOP}; f ← Lookup.OnStack[index]; IF f = NIL THEN AbortWithError[notFound, index]; END; SubtreeWork: PROC [index: Tree.Index, type: Symbols.SEIndex] = BEGIN OPEN TreeOps; SELECT tb[index].name FROM plus, minus, times, div, mod => BEGIN f: Foo ← FirstSon[index, type]; LoopHoleWork[tb[index].son[2], type]; Push[f]; FoldExpr[tb[index].name]; END; relE, relN, relL, relLE, relG, relGE => BEGIN f: Foo ← FirstSon[index]; TargetTypeWork[tb[index].son[2],TypeForSe[f.tsei]]; BP.Condition[left: f, rel: tb[index].name, right: Pop[]]; END; uminus => BEGIN Work[tb[index].son[1]]; FoldExpr[uminus]; END; base => Base[FirstSon[index],type]; length => Length[FirstSon[index], type]; size => Size[FirstSon[index]]; clit => BEGIN f: Foo ← FindLiteral[CheckLink[tb[index].son[1], literal]]; f.tsei ← com.typeCHAR; f.addr.offset ← 8; Push[f]; END; mwconst => BEGIN f: Foo ← FindLiteral[CheckLink[tb[index].son[1], literal]]; f.tsei ← type; Push[f]; END; lint => Work[tb[index].son[1], MakeLongType[com.typeINT]]; lcard => Work[tb[index].son[1], MakeLongType[com.typeCARDINAL]]; int => NumberWork[tb[index].son[1], com.typeINT, type]; card => NumberWork[tb[index].son[1], com.typeCARDINAL, type]; typeDollar => BEGIN id: Symbols.HTIndex ← CheckLink[tb[index].son[2], hash]; mod: Symbols.HTIndex ← CheckLink[tb[index].son[1], hash]; f: Foo ← Lookup.InMod[id,mod ! DSyms.Shared => AbortWithError[wrongDollar,mod]]; IF f = NIL THEN AbortWithError[notFound,id]; IF ~f.typeOnly THEN Error[notType, id]; Push[f]; END; addr => TakeAddress[FirstSon[index,type]]; uparrow => BEGIN f: Foo ← Son[tb[index].son[1],type]; IF ~Deref[f] THEN AbortWithError[invalidPointer, f.hti]; END; dot => Qualify[FirstSon[index],CheckLink[tb[index].son[2], hash]]; apply => DoApply[tb[index].son[2], FirstSon[index]]; loophole => { f: Foo; IF tb[index].son[2] = Tree.Null THEN { Work[tb[index].son[1], type]; f ← Tos[]; LoopHole[f, type]} ELSE BEGIN Work[tb[index].son[2],type]; f ← Pop[]; IF ~f.typeOnly THEN Error[notType, f.hti]; LoopHoleWork[tb[index].son[1],f.tsei]; END }; fileDollar => BEGIN id: Symbols.HTIndex ← CheckLink[tb[index].son[2], hash]; mod: Symbols.HTIndex ← CheckLink[tb[index].son[1], hash]; f: Foo ← Lookup.InMod[id,mod ! DSyms.Shared => AbortWithError[wrongDollar,mod]]; IF f = NIL THEN AbortWithError[notFound,id]; Push[f]; END; frameDollar => BEGIN id: Symbols.HTIndex ← CheckLink[tb[index].son[2], hash]; f: Foo ← FindLiteral[CheckLink[tb[index].son[1], literal]]; f ← Lookup.InLF[id,f.addr.base↑]; IF f = NIL THEN AbortWithError[notFound,id]; Push[f]; END; memory => Memory[tb[index].son[1],type]; nil => PushNil[FirstSon[index,type]]; procTC => BEGIN f: Foo ← DHeap.AllocFob[]; f.tsei ← MakeXferType[proc]; f.typeOnly ← TRUE; Push[f]; END; errorTC => BEGIN f: Foo ← DHeap.AllocFob[]; f.tsei ← MakeXferType[error]; f.typeOnly ← TRUE; Push[f]; END; signalTC => BEGIN f: Foo ← DHeap.AllocFob[]; f.tsei ← MakeXferType[signal]; f.typeOnly ← TRUE; Push[f]; END; longTC => BEGIN f: Foo ← Son[tb[index].son[1],type]; f.tsei ← MakeLongType[f.tsei]; END; pointerTC => BEGIN f: Foo ← Son[tb[index].son[1],type]; f.tsei ← MakePointerType[f.tsei]; END; discrimTC => BEGIN f: Foo ← Son[tb[index].son[1],type]; f.tsei ← SelectVariantType[f.tsei, CheckLink[tb[index].son[2],hash]]; END; lengthen => BEGIN f: Foo ← Son[tb[index].son[1],type]; LengthenFob[f]; END; abs => Abs[tb[index].son[1],type]; min => BEGIN size: NumberType; cnt: CARDINAL; signed: BOOLEAN; [size,cnt,signed] ← GetSize[index,type]; Min[size,cnt,signed]; END; max => BEGIN size: NumberType; cnt: CARDINAL; signed: BOOLEAN; [size,cnt,signed] ← GetSize[index,type]; Max[size,cnt,signed]; END; intOO => Interval[ t: tb[index].son[1], type: type, openLow: TRUE, openHigh: TRUE]; intOC => Interval[t: tb[index].son[1], type: type, openLow: TRUE]; intCO => Interval[t: tb[index].son[1], type: type, openHigh: TRUE]; intCC => Interval[t: tb[index].son[1], type: type]; bang => Interval[t: tb[index].son[1], type: type, cntOnly: TRUE]; ENDCASE => NotImpl[tb[index].name]; END; NotImpl: PROC [name: Tree.NodeName] = { P1.PrintNodeName[name]; SIGNAL NotImplemented[NIL]}; Deref: PUBLIC PROC [f: Foo] RETURNS [success: BOOLEAN] = BEGIN tsei: Symbols.CSEIndex ← TypeForSe[f.tsei]; ref: SEIndex; n: Number; Add[]; DO WITH seb[tsei] SELECT FROM ref => { dereferenced ← TRUE; IF ~f.typeOnly THEN {ref ← TypeForSe[refType]; EXIT} ELSE { f↑ ← DebugFormat.NullFob; f.tsei ← refType; f.typeOnly ← TRUE; WITH seb[refType] SELECT FROM id => f.hti ← hash; ENDCASE; Drop[]; RETURN[TRUE]}}; long => tsei ← TypeForSe[rangeType]; subrange => tsei ← TypeForSe[rangeType]; ENDCASE => GOTO cant; ENDLOOP; Drop[]; n ← GetNumber[f, invalidPointer]; DHeap.FreeLong[f.addr.base]; SELECT n.type FROM one => f.addr.base ← DebugOps.Lengthen[n.p]; two => f.addr.base ← n.lp; ENDCASE; IF f.addr.base = NIL THEN AbortWithError[nilChk,f.hti]; f.tsei ← ref; f.words ← SymbolOps.WordsForType[ref]; f.hti ← Symbols.HTNull; f.typeOnly ← FALSE; f.addr.offset ← 0; f.addr.useStack ← FALSE; f.bits ← 0; f.there ← TRUE; RETURN[TRUE]; EXITS cant => {Drop[]; RETURN[FALSE]}; END; Qualify: PUBLIC PROC [f: Foo, hti: Symbols.HTIndex] = BEGIN OPEN Symbols; original, root: CSEIndex; Add[]; WHILE Deref[f] DO NULL ENDLOOP; original ← TypeForSe[f.tsei]; root ← SymbolOps.TypeRoot[original]; SELECT TRUE FROM QualifyCsei[f,hti,original] => {Drop[]; RETURN}; root # original => IF QualifyCsei[f,hti,root] THEN {Drop[]; RETURN}; ENDCASE; Drop[]; AbortWithError[notValidField,hti]; END; QualifyCsei: PUBLIC PROC [f: Foo, hti: Symbols.HTIndex, csei: Symbols.CSEIndex] RETURNS [found: BOOLEAN] = BEGIN OPEN Symbols; pad: CARDINAL; WITH seb[csei] SELECT FROM record => BEGIN pad ← DI.Pad[f,LOOPHOLE[csei]]; IF SearchCtx[f, fieldCtx, hti, pad] THEN RETURN[TRUE]; IF hints.variant THEN RETURN[SearchVariants[ f,hti,pad,LOOPHOLE[VariantUnionType[LOOPHOLE[csei]]]]]; END; definition => { temp: DebugFormat.Fob ← DebugFormat.NullFob; p: POINTER ← State.Get[].h.interpretContext; isei: ISEIndex = SearchCtxList[hti,defCtx]; reallyThere: BOOLEAN; IF isei = ISENull THEN RETURN [FALSE]; temp.addr.base ← DebugOps.Lengthen[IF Frames.Type[p] = local THEN Lf.GF[p] ELSE p]; temp.tsei ← f.tsei; temp.there ← TRUE; temp.indent ← f.indent; reallyThere ← SELECT Lookup.Mode[isei] FROM refVal => TRUE, refProc => FALSE, ENDCASE => FALSE; found ← SearchCtx[@temp,defCtx,hti,0]; IF found THEN Tos[].f.there ← reallyThere; RETURN}; ENDCASE => {Drop[]; AbortWithError[typeMismatch,f.hti]}; RETURN[FALSE]; END; SearchCtx: PROC [f: Foo, ctx: CTXIndex, hti: HTIndex, pad: CARDINAL] RETURNS [BOOLEAN] = BEGIN OPEN Symbols; isei: ISEIndex ← SearchCtxList[hti,ctx]; field: Foo; IF isei = ISENull THEN RETURN [FALSE]; IF f.typeOnly THEN { field ← DHeap.AllocFob[]; field↑ ← f↑; field.hti ← seb[isei].hash; field.tsei ← isei} ELSE field ← FindField[f, pad, isei]; IF field = NIL THEN RETURN [FALSE]; Push[field]; RETURN[TRUE]; END; SearchRecord: PROC [ f: Foo, rsei: RecordSEIndex, hti: HTIndex, pad: CARDINAL] RETURNS [BOOLEAN] = INLINE BEGIN RETURN[SearchCtx[f,seb[rsei].fieldCtx,hti,pad]] END; SearchVariants: PROC [ f: Foo, hti: HTIndex, pad: CARDINAL, usei: UnionSEIndex] RETURNS [BOOLEAN] = BEGIN OPEN Symbols; isei: ISEIndex; IF usei = typeANY THEN RETURN [FALSE]; SELECT VariantType[usei] FROM controlled => BEGIN isei ← seb[usei].tagSei; IF seb[isei].hash = hti THEN { field: Foo ← FindField[f, pad, isei]; IF field = NIL THEN RETURN [FALSE]; Push[field]; RETURN[TRUE]}; isei ← TagIsei[f,pad,usei]; IF isei = ISENull THEN RETURN [FALSE]; RETURN[SearchRecord[f,seb[isei].idInfo,hti,pad]]; END; overlaid => BEGIN OPEN SymbolOps, seb[usei]; Lookup.Complete[caseCtx]; FOR isei ← FirstCtxSe[caseCtx], NextSe[isei] UNTIL isei = ISENull DO IF SearchRecord[f,seb[isei].idInfo,hti,pad] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; END; computed => BEGIN OPEN SymbolOps, seb[usei]; cnt: CARDINAL ← 0; Lookup.Complete[caseCtx]; FOR isei ← FirstCtxSe[caseCtx], NextSe[isei] UNTIL isei = ISENull DO IF SearchRecord[f,seb[isei].idInfo,hti,pad] THEN cnt ← cnt + 1; IF cnt > 1 THEN AbortWithError[notUniqueField,hti]; ENDLOOP; RETURN[cnt = 1]; END; ENDCASE => ERROR; END; TakeAddress: PROC [f: Foo] = BEGIN addr: LONG POINTER = f.addr.base; tsei: Symbols.SEIndex = MakePointerType[f.tsei]; IF f.addr.offset # 0 OR ~f.there THEN AbortWithError[invalidAddress,f.hti]; IF Inline.HighHalf[addr] = data.mds THEN PushVal[Inline.LowHalf[addr], tsei] ELSE PushLongVal[addr,tsei]; END; LoopHole: PUBLIC PROC [ f: Foo, type: Symbols.SEIndex, lengthen: BOOLEAN ← FALSE] = BEGIN tSize: CARDINAL; checkSize: BOOLEAN ← TRUE; csei: Symbols.CSEIndex = TypeForSe[type]; Add[]; WITH seb[csei] SELECT FROM subrange => checkSize ← range # 0; ENDCASE; Drop[]; SELECT TRUE FROM f = NIL => RETURN; f.tsei = type => RETURN; type = nullProc => type ← LoopHoleControlLink[f,Lookup.Proc ! NotAProcedure => GO TO notProc]; type = nullSig OR type = nullError => type ← LoopHoleControlLink[f,Lookup.Signal ! NotAProcedure => GO TO notProc]; ~checkSize => NULL; TotalWords[f] = (tSize ← SymbolOps.WordsForType[csei]) => NULL; ~lengthen => AbortWithError[sizeMismatch]; tSize # 2 => AbortWithError[sizeMismatch]; ~CheckLength[f,1] => AbortWithError[sizeMismatch]; ENDCASE => LengthenFob[f]; f.tsei ← type; EXITS notProc => AbortWithError[notProcDesc]; END; LoopHoleControlLink: PROC [ f: Foo, proc: PROC [PrincOps.SignalDesc] RETURNS [Symbols.ISEIndex]] RETURNS [Symbols.SEIndex] = BEGIN desc: PrincOps.SignalDesc = LOOPHOLE[DerefProcDesc[GetControlLink[f]]]; gf: MachineDefs.GFHandle = Gf.FrameGfi[desc.gfi]; isei: Symbols.ISEIndex ← Symbols.ISENull; IF ~Gf.Validate[gf] THEN AbortWithError[notProcDesc]; isei ← proc[desc ! SymbolTable.Missing => CONTINUE]; IF isei # Symbols.ISENull THEN RETURN[TypeForSe[isei]]; AbortWithError[notFound, DSyms.GFrameHti[gf]]; ERROR; END; FindLiteral: PROCEDURE [info: Literals.LitRecord] RETURNS [f: Foo] = BEGIN f ← DHeap.AllocFob[]; [f.addr.base, f.words] ← Lookup.CopyLiteral[info]; WITH info SELECT FROM string => f.tsei ← com.typeSTRING; ENDCASE => f.tsei ← Symbols.typeANY; END; CheckLength: PUBLIC PROC [f: Foo, size: CARDINAL] RETURNS [BOOLEAN] = BEGIN IF f.words # size OR f.bits # 0 OR f.addr.offset # 0 THEN RETURN[FALSE] ELSE RETURN[TRUE]; END; NumberLength: PUBLIC PROC [f: Foo] RETURNS [nt: NumberType] = BEGIN IF CheckLength[f,1] THEN RETURN[one]; IF CheckLength[f,2] THEN RETURN[two]; RETURN[nogood] END; GetNumber: PUBLIC PROC [f: Foo, code: Err ← invalidNumber] RETURNS [n: Number] = BEGIN p: LONG POINTER TO Words; size: CARDINAL = TotalWords[f]; csei: Symbols.CSEIndex; IF size ~IN[1..2] THEN AbortWithError[code] ELSE n.type ← LOOPHOLE[size]; GetValue[f]; p ← f.addr.base; FOR i: NumberType IN [nogood..n.type) DO n.w[i] ← p[i]; ENDLOOP; IF (csei ← TypeForSe[f.tsei]) = com.typeCARDINAL THEN RETURN; Add[]; WITH seb[csei] SELECT FROM subrange => IF n.type = one THEN n.i ← n.i + origin ELSE AbortWithError[invalidSubrange]; ENDCASE; Drop[]; END; Stack: TYPE = State.Stack; PushVal: PUBLIC PROC [u: UNSPECIFIED, tsei: Symbols.SEIndex] = BEGIN f: Foo ← DHeap.AllocFob[]; p: POINTER TO UNSPECIFIED; f.addr.base ← p ← Storage.Node[SIZE[UNSPECIFIED]]; p↑ ← u; f.words ← 1; f.tsei ← tsei; Push[f]; END; PushLongVal: PUBLIC PROC [lu: LONG UNSPECIFIED, tsei: Symbols.SEIndex] = BEGIN f: Foo ← DHeap.AllocFob[]; p: POINTER TO LONG UNSPECIFIED; f.addr.base ← p ← Storage.Node[SIZE[LONG UNSPECIFIED]]; p↑ ← lu; f.words ← 2; f.tsei ← MakeLongType[tsei]; Push[f]; END; Push: PUBLIC PROCEDURE [f: Foo] = BEGIN h: State.Handle ← State.Get[]; new: POINTER TO Stack ← Storage.Node[SIZE[Stack]]; new↑ ← [h.fooStack,f]; h.fooStack ← new; END; Pop: PUBLIC PROCEDURE RETURNS [f: Foo] = BEGIN h: State.Handle ← State.Get[]; old: POINTER TO Stack ← h.fooStack; IF old = NIL THEN ERROR Underflow; f ← old.foo; h.fooStack ← old.link; Storage.Free[old]; END; ResetStack: PROCEDURE = BEGIN h: State.Handle ← State.Get[]; top, next: POINTER TO Stack; FOR top ← h.fooStack, next UNTIL top = NIL DO next ← top.link; Storage.Free[top]; ENDLOOP; h.fooStack ← NIL; END; Tos: PUBLIC PROCEDURE RETURNS [f: Foo] = BEGIN h: State.Handle ← State.Get[]; old: POINTER TO Stack ← h.fooStack; IF old = NIL THEN ERROR Underflow; RETURN[old.foo]; END; CheckForStackEmpty: PUBLIC PROCEDURE = BEGIN IF State.Get[].h.fooStack # NIL THEN ERROR StackNotEmptyAtStatement; END; END.