-- DIInterpret.mesa last edit: Bruce May 20, 1980 6:12 PM DIRECTORY Actions, ComData, CompilerUtil USING [PrintTree], CoreSwapDefs, Debug, DebugOps, DebugFormat, DebugUsefulDefs, DI, DIActions, DOutput, Dump, Frames, Gf, Heap, Init, Inline, Lf, Literals, Lookup, MachineDefs, P1 USING [DParse], Pc, PrincOps, State USING [Get, GetGS, GSHandle, Handle, Stack], Storage, String, SymbolOps, SymbolPack, Symbols, SymbolSegment, SymbolTable USING [Base], Table USING [AddNotify, Base, DropNotify, Notifier], Tree, TreeOps, Types; DIInterpret: PROGRAM IMPORTS Actions, com: ComData, CompilerUtil, Debug, DebugOps, DI, DIActions, DOutput, Dump, Frames, Gf, Heap, Init, Lf, Lookup, Pc, P1, State, Storage, String, MyBase: SymbolPack, SymbolOps, Table, TreeOps, Types EXPORTS DebugOps, DebugUsefulDefs, DIActions SHARES Debug = BEGIN OPEN DI, DIActions; Underflow: PUBLIC ERROR = CODE; StackNotEmptyAtStatement: PUBLIC ERROR = CODE; NotImplemented: PUBLIC SIGNAL [msg: STRING] = CODE; DIAbort: PUBLIC ERROR = CODE; DerefError: ERROR = CODE; BadTree: ERROR = CODE; WhosBeenScanningMyTree: ERROR = CODE; CantAssignInDebuggerImage: ERROR = CODE; seb: Table.Base; tb: Table.Base; data: State.GSHandle ← State.GetGS[]; Interpreter: PUBLIC PROC [exp: STRING] = {Interpret[exp,NIL]}; Interpret: PUBLIC PROC [ exp: STRING, results: DebugOps.FooProc ← DebugOps.DisplayFoo] = 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 Table.DropNotify[Notify]; [] ← 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]; Table.AddNotify[Notify]; State.Get[].h.proc ← results; ProcessTree[t ! UNWIND => Cleanup[]]; Cleanup[]; END; StringExpToNum: PUBLIC PROC [s: STRING] RETURNS [u: UNSPECIFIED] = BEGIN OPEN DebugOps; Result: FooProc = BEGIN u ← ProcessNum[f, one].n.u END; Interpret[s,Result ! ParseError, SyntaxError, InvalidCharacter => ERROR InvalidNumber[NIL]]; END; StringExpToLNum: PUBLIC PROC [s: STRING] RETURNS [u: LONG UNSPECIFIED] = BEGIN OPEN DebugOps; Result: FooProc = BEGIN u ← ProcessNum[f, two].n.lu END; Interpret[s,Result ! ParseError, SyntaxError, InvalidCharacter => ERROR InvalidNumber[NIL]]; END; ProcessNum: PROC [f: DebugOps.Foo, size: DI.NumberType] RETURNS [n: Number]= BEGIN i: NumberType; p: LONG POINTER TO Words; IF f.bits # 0 OR f.addr.offset # 0 THEN GOTO invalid; n.type ← LOOPHOLE[f.words]; SELECT n.type FROM size => NULL; one => IF size # two THEN GOTO invalid; two => {IF size = one THEN Error[sizeMismatch]; GOTO invalid}; ENDCASE => GOTO invalid; GetValue[f]; p ← f.addr.base; FOR i IN [nogood..n.type) DO n.w[i] ← p[i]; ENDLOOP; IF n.type # size THEN n.w[one] ← 0; RETURN; EXITS invalid => SIGNAL DebugOps.InvalidNumber[f] END; ProcessTree: Tree.Scan = BEGIN OPEN TreeOps; IF t = Tree.Null THEN RETURN; t ← CheckNode[t,rowcons]; t ← CheckNode[t,block]; IF OpName[t] = list THEN ScanList[t,Exp] ELSE Exp[t]; DOutput.EOL[]; CheckForStackEmpty[]; END; CheckNode: PROCEDURE [t: Tree.Link, name: Tree.NodeName] RETURNS [son1: Tree.Link] = BEGIN IF TreeOps.OpName[t] # name THEN ERROR BadTree; WITH t SELECT FROM subtree => son1 ← tb[index].son[1]; ENDCASE => ERROR BadTree; END; CheckLink: PROC [t: Tree.Link, type: {subtree, hash, symbol, literal}] 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; Notify: Table.Notifier = BEGIN tb ← base[Tree.treeType]; seb ← base[SymbolSegment.seType]; END; Exp: Tree.Scan = BEGIN ENABLE DIAbort => GOTO cleanExit; son1: Foo; IF t = Tree.Null THEN RETURN; WITH t SELECT FROM subtree => BEGIN OPEN TreeOps; SELECT tb[index].name FROM exit => BEGIN son1 ← FirstSon[index]; State.Get[].h.proc[son1]; END; open => BEGIN son1 ← FirstSon[index]; DumpMemory[son1]; END; label => BEGIN n: Number; son1 ← FirstSon[index]; n ← GetNumber[son1]; SELECT n.type FROM one => PutReps[n.u]; two => PutLongReps[n.lu]; ENDCASE; END; assign => BEGIN son1 ← FirstSon[index]; TargetTypeWork[tb[index].son[2], son1.tsei]; Assign[son1] END; rowcons => {Exp[tb[index].son[1]]; DOutput.EOL[]; CheckForStackEmpty[]}; ENDCASE => ERROR WhosBeenScanningMyTree; END; ENDCASE => ERROR BadTree; EXITS cleanExit => {ResetStack[]; RETURN}; END; FirstSon: PROC [index: Tree.Index, type: SEIndex ← Symbols.typeANY] RETURNS [f: Foo] = BEGIN Work[tb[index].son[1], type]; f ← Pop[]; END; Work: 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: 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]; RETURN}; hash => f ← HashWork[index,type]; literal => f ← FindLiteral[info]; ENDCASE => ERROR BadTree; LoopHole[f,type,TRUE]; Push[f]; END; TargetTypeWork: 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]; RETURN}; hash => f ← HashWork[index,type]; literal => f ← FindLiteral[info]; ENDCASE => ERROR BadTree; Assignable[f,TypeForSe[type]]; Push[f]; END; SymbolWork: PROC [index: Symbols.SEIndex] RETURNS [f: Foo] = INLINE BEGIN f ← Heap.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 BEGIN OPEN Symbols; WITH seb[TypeForSe[hint]] SELECT FROM enumerated => f ← Lookup.InCtx[index, valueCtx]; ENDCASE; IF f # NIL THEN RETURN; END; 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]; Work[tb[index].son[2]]; Push[f]; FoldExpr[tb[index].name]; 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 => Push[FindLiteral[CheckLink[tb[index].son[1], literal]]]; dollar => 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]; IF ~f.typeOnly THEN Error[notType, id]; Push[f]; END; addr => TakeAddress[Son[tb[index].son[1],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 => IF tb[index].son[2] = Tree.Null THEN {Work[tb[index].son[1],type]; LoopHole[Tos[],Symbols.typeANY]} ELSE BEGIN f: Foo; Work[tb[index].son[2],type]; f ← Pop[]; IF ~f.typeOnly THEN Error[notType, f.hti]; LoopHoleWork[tb[index].son[1],f.tsei]; END; cdot => 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]; Push[f]; END; index => BEGIN id: Symbols.HTIndex ← CheckLink[tb[index].son[2], hash]; f: Foo ← FindLiteral[CheckLink[tb[index].son[1], literal]]; Push[Lookup.InLF[id,f.addr.base↑]]; END; openx => Memory[tb[index].son[1],type]; longTC => BEGIN f: Foo ← Tos[]; f.tsei ← MakeLongType[f.tsei]; END; pointerTC => BEGIN f: Foo ← Tos[]; 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]; cast => Interval[t: tb[index].son[1], type: type, cntOnly: TRUE]; ENDCASE => NotImpl[tb[index].name]; END; NotImpl: PROC [name: Tree.NodeName] = BEGIN Debug.LockStringTable[]; Debug.WriteNodeName[name]; Debug.UnlockStringTable[]; SIGNAL NotImplemented[" "L]; END; Interval: PROC [ t: Tree.Link, type: Symbols.SEIndex, openLow, openHigh, cntOnly: BOOLEAN ← FALSE] = BEGIN index: Tree.Index ← CheckLink[t,subtree]; f1, f2: Foo; size, size2: NumberType; signed, signed2: BOOLEAN; [f1,size,signed] ← MinimalRep[tb[index].son[1],type]; [f2,size2,signed2] ← MinimalRep[tb[index].son[2],type]; IF size # size2 THEN BEGIN SIGNAL NotImplemented["DoubleWord array indexes"L]; size ← two; IF size = one THEN Long[f1,signed]; IF size2 = one THEN Long[f2,signed2]; END; IF cntOnly THEN RETURN; IF openLow THEN Inc[f1,size,signed]; IF openHigh THEN Dec[f2,size,signed2]; MakeCnt[f2,f1,size,signed OR signed2]; END; Base: PROC [f: Foo, sei: SEIndex] = BEGIN WITH seb[TypeForSe[f.tsei]] SELECT FROM long => LongBase[f,sei]; ENDCASE => ShortBase[f,sei]; END; ShortBase: PROC [f: Foo, sei: SEIndex] = BEGIN asei: Symbols.ArraySEIndex; lp: LONG POINTER TO POINTER; d: Desc; [d,asei] ← GetDesc[f ! NotAnArray => {AbortWithError[typeMismatch,f.hti]; ERROR}]; lp ← Storage.Node[1]; lp↑ ← d.base; f.addr.base ← lp; f.addr.offset ← f.bits ← 0; f.words ← 1; f.there ← FALSE; f.hti ← Symbols.HTNull; f.tsei ← MakePointerType[Symbols.typeANY]; Push[f]; END; LongBase: PROC [f: Foo, sei: SEIndex] = BEGIN asei: Symbols.ArraySEIndex; lp: LONG POINTER TO LONG POINTER; d: LongDesc; [d,asei] ← GetLongDesc[f ! NotAnArray => {AbortWithError[typeMismatch,f.hti]; ERROR}]; lp ← Storage.Node[2]; lp↑ ← d.base; f.addr.base ← lp; f.addr.offset ← f.bits ← 0; f.words ← 2; f.bits ← 0; f.there ← FALSE; f.hti ← Symbols.HTNull; f.tsei ← MakeLongType[MakePointerType[Symbols.typeANY]]; Push[f]; END; Length: PROC [f: Foo, sei: SEIndex] = BEGIN long: BOOLEAN; asei: Symbols.ArraySEIndex; len: LONG POINTER TO CARDINAL; WITH seb[TypeForSe[f.tsei]] SELECT FROM long => long ← TRUE; ENDCASE => long ← FALSE; len ← Storage.Node[1]; IF long THEN BEGIN ld: LongDesc; [ld,asei] ← GetLongDesc[f ! NotAnArray => {AbortWithError[typeMismatch,f.hti]; ERROR}]; len↑ ← ld.length; END ELSE BEGIN d: Desc; [d,asei] ← GetDesc[f ! NotAnArray => {AbortWithError[typeMismatch,f.hti]; ERROR}]; len↑ ← d.length; END; f.addr.base ← len; f.addr.offset ← f.bits ← 0; f.words ← 1; f.there ← FALSE; f.hti ← Symbols.HTNull; f.tsei ← com.typeCARDINAL; Push[f]; END; Deref: PUBLIC PROC [f: Foo] RETURNS [success: BOOLEAN] = BEGIN tsei: Symbols.CSEIndex ← TypeForSe[f.tsei]; ref: SEIndex; n: Number; DO WITH seb[tsei] SELECT FROM ref => BEGIN IF basing THEN RETURN[FALSE]; ref ← refType; EXIT END; long => tsei ← TypeForSe[rangeType]; ENDCASE => RETURN[FALSE]; ENDLOOP; n ← GetNumber[f, invalidPointer]; Heap.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.bits ← 0; f.there ← TRUE; RETURN[TRUE]; END; Qualify: PROC [f: Foo, hti: Symbols.HTIndex] = BEGIN OPEN Symbols; rsei: RecordSEIndex; WHILE Deref[f] DO NULL ENDLOOP; rsei ← CheckClass[record,f]; IF SearchCtx[f, rsei, hti] THEN RETURN; IF seb[rsei].hints.variant AND SearchVariants[f,hti,rsei] THEN RETURN; AbortWithError[notValidField,hti]; END; SearchCtx: PROC [f: Foo, rsei: RecordSEIndex, hti: HTIndex] RETURNS [BOOLEAN] = BEGIN OPEN Symbols; isei: ISEIndex ← SearchCtxList[hti,seb[rsei].fieldCtx]; field: Foo; IF isei = ISENull THEN RETURN [FALSE]; field ← FindField[f, DI.Pad[f,rsei], isei]; IF field = NIL THEN RETURN [FALSE]; Push[field]; RETURN[TRUE]; END; SearchVariants: PROC [f: Foo, hti: HTIndex, rsei: RecordSEIndex] RETURNS [BOOLEAN] = BEGIN OPEN Symbols; usei: UnionSEIndex ← LOOPHOLE[VariantUnionType[rsei]]; IF usei = typeANY THEN RETURN [FALSE]; SELECT VariantType[usei] FROM controlled => BEGIN isei: ISEIndex ← TagIsei[f,DI.Pad[f,rsei],usei]; IF isei = ISENull THEN RETURN [FALSE]; RETURN[SearchCtx[f,seb[isei].idInfo,hti]]; END; overlaid => BEGIN OPEN SymbolOps, seb[usei]; isei: ISEIndex; Lookup.Complete[caseCtx]; FOR isei ← FirstCtxSe[caseCtx], NextSe[isei] UNTIL isei = ISENull DO IF SearchCtx[f,seb[isei].idInfo,hti] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; END; computed => BEGIN OPEN SymbolOps, seb[usei]; isei: ISEIndex; cnt: CARDINAL ← 0; Lookup.Complete[caseCtx]; FOR isei ← FirstCtxSe[caseCtx], NextSe[isei] UNTIL isei = ISENull DO IF SearchCtx[f,seb[isei].idInfo,hti] THEN cnt ← cnt + 1; IF cnt > 1 THEN AbortWithError[notUniqueField,hti]; ENDLOOP; RETURN[cnt = 1]; END; ENDCASE => ERROR; END; TakeAddress: PROC [f: Foo] = BEGIN p: LONG POINTER TO LONG POINTER; IF f.addr.offset # 0 THEN AbortWithError[invalidAddress,f.hti]; IF ~f.there THEN ERROR WhosBeenScanningMyTree; f.tsei ← MakePointerType[f.tsei]; f.hti ← Symbols.HTNull; f.there ← FALSE; p ← Storage.Node[(f.words ← SIZE[LONG POINTER])]; p↑ ← f.addr.base; f.addr.base ← p; END; Memory: PROC [t: Tree.Link, type: Symbols.SEIndex] = BEGIN f: Foo ← Son[t,type]; lp: LONG POINTER; n: Number ← GetNumber[f, invalidAddress]; IF f.there THEN AbortWithError[invalidAddress]; f.hti ← Symbols.HTNull; f.tsei ← Symbols.typeANY; lp ← Storage.Node[1]; SELECT n.type FROM one => lp↑ ← DebugOps.ShortREAD[n.u]; two => lp↑ ← DebugOps.LongREAD[n.u]; ENDCASE; Heap.FreeLong[f.addr.base]; f.addr.base ← lp; f.words ← 1; END; DoApply: PUBLIC PROC[t: Tree.Link, target: Foo] = BEGIN uniOperand: BOOLEAN ← TreeOps.OpName[t] # list; long: BOOLEAN; targetType: CSEIndex; IF target = NIL THEN RETURN; WHILE DIActions.Deref[target] DO ENDLOOP; targetType ← TypeForSe[target.tsei]; WITH seb[targetType] SELECT FROM long => {long ← TRUE; targetType ← TypeForSe[rangeType]}; ENDCASE => long ← FALSE; WITH seb[targetType] SELECT FROM record => AbortWithError[constructor]; array => BEGIN start: CARDINAL; IF ~uniOperand THEN SIGNAL NotImplemented["Array intervals"L]; start ← GetStart[t, indexType]; DoArray[target,start,start]; END; arraydesc => BEGIN start: CARDINAL; asei: Symbols.ArraySEIndex; IF ~uniOperand THEN SIGNAL NotImplemented["Array descriptor intervals"L]; asei ← LOOPHOLE[SymbolOps.UnderType[describedType]]; start ← GetStart[t, seb[asei].indexType]; IF long THEN DoLongDesc[target,start,start] ELSE DoDesc[target,start,start]; END; transfer => BEGIN tm: Symbols.TransferMode = SymbolOps.XferMode[targetType]; IF tm # proc THEN ApplyError[tm]; ProcedureCall[t,target]; END; ref => BEGIN tos: Foo; IF ~basing THEN ERROR DerefError; Work[t]; tos ← Tos[]; IF ~uniOperand THEN AbortWithError[notRelative,tos.hti]; Reloc[target,tos]; END; ENDCASE; END; GetStart: PROC [t: Tree.Link, target: Symbols.SEIndex] RETURNS [CARDINAL] = BEGIN f: Foo; n: Number; TargetTypeWork[t,target]; IF ~CheckLength[(f ← Pop[]),1] THEN AbortWithError[indexTooBig]; n ← GetNumber[f]; RETURN[n.c]; END; DoLongDesc: PROC [f: Foo, start, stop: CARDINAL] = BEGIN sei: Symbols.ArraySEIndex; d: LongDesc; ai: Dump.ArrayInfo; [d,sei] ← GetLongDesc[f]; IF d.base = NIL THEN AbortWithError[nilChk]; ai ← [start: start, stop: stop, addr: [d.base,0], length: d.length, packing: SymbolOps.BitsPerElement[sei], type: seb[sei].componentType]; IF start = stop THEN GetElement[@ai] ELSE Dump.Elements[@ai]; END; DoDesc: PROC [f: Foo, start, stop: CARDINAL] = BEGIN sei: Symbols.ArraySEIndex; d: Desc; ai: Dump.ArrayInfo; [d,sei] ← GetDesc[f]; IF d.base = NIL THEN AbortWithError[nilChk]; ai ← [start: start, stop: stop, addr: [DebugOps.Lengthen[d.base],0], length: d.length, packing: SymbolOps.BitsPerElement[sei], type: seb[sei].componentType]; IF start = stop THEN GetElement[@ai] ELSE Dump.Elements[@ai]; END; DoArray: PROC [f: Foo, start, stop: CARDINAL] = BEGIN ai: Dump.ArrayInfo; d: Desc; sei: Symbols.ArraySEIndex; [d,sei] ← GetDesc[f]; ai ← [ start: start, stop: stop, length: d.length, addr: f.addr, packing: SymbolOps.BitsPerElement[sei], type: seb[sei].componentType]; IF start = stop THEN GetElement[@ai] ELSE Dump.Elements[@ai]; END; GetElement: PUBLIC PROCEDURE [ai: Dump.ArrayHandle] = BEGIN OPEN DOutput; f: Foo ← Heap.AllocFob[]; f↑ ← [hti: Symbols.HTNull, indent:, xfer:, tsei: ai.type, typeOnly: FALSE, there: TRUE, addr:, words:, bits:]; [f.words, f.bits] ← Normalize[ai.packing]; f.addr ← Dump.CalculateAddr[ai, ai.start]; Push[f]; END; Reloc: PROC [base, rel: Foo] = BEGIN csei: CSEIndex ← TypeForSe[rel.tsei]; lp: LONG POINTER TO LONG CARDINAL; WITH seb[csei] SELECT FROM relative => BEGIN IF TypeForSe[baseType] # TypeForSe[base.tsei] THEN AbortWithError[wrongBase, base.hti]; rel.tsei ← resultType; GetValue[rel]; -- round to one word IF ~CheckLength[rel,1] THEN AbortWithError[notRelative,rel.hti]; lp ← Add[base,rel]; Heap.FreeLong[rel.addr.base]; rel.addr.base ← lp; rel.addr.offset ← rel.bits ← 0; rel.words ← SymbolOps.WordsForType[resultType]; rel.there ← FALSE; rel.hti ← Symbols.HTNull; IF ~Deref[rel] THEN AbortWithError[notRelative]; END; ENDCASE => AbortWithError[notRelative,rel.hti]; END; Add: PROC [f1,f2: Foo] RETURNS [lp: LONG POINTER TO LONG CARDINAL] = BEGIN n: Number; lc: LONG CARDINAL; n ← GetNumber[f1, invalidAddress]; IF n.type = one THEN lc ← n.c ELSE lc ← n.lc; n ← GetNumber[f2, invalidAddress]; IF n.type = one THEN lc ← lc + n.c ELSE lc ← lc + n.lc; lp ← Storage.Node[SIZE[LONG CARDINAL]]; lp↑ ← lc; END; ProcedureCall: PUBLIC PROCEDURE [args: Tree.Link, proc: Foo] = BEGIN OPEN SymbolOps; cnt: CARDINAL ← 0; in: Symbols.RecordSEIndex; isei: ISEIndex ← Symbols.ISENull; cl: PrincOps.ControlLink; state: PrincOps.StateVector; cbti: Symbols.CBTIndex; sv: PrincOps.SVPointer; Collect: Tree.Scan = BEGIN f: Foo; words: CARDINAL; p: LONG POINTER TO ARRAY [0..0) OF UNSPECIFIED; isei ← IF cnt = 0 THEN FirstCtxSe[seb[in].fieldCtx] ELSE NextSe[isei]; IF isei = Symbols.ISENull THEN AbortWithError[wrongNumberArgs,proc.hti]; TargetTypeWork[t,isei]; words ← TotalWords[(f←Pop[])]; GetValue[f]; cnt ← cnt + words; IF state.stkptr + words > PrincOps.MaxParamsInStack THEN AbortWithError[tooManyArgs,proc.hti]; p ← LOOPHOLE[f.addr.base]; FOR i: CARDINAL IN [0..words) DO state.stk[state.stkptr] ← p[state.stkptr]; state.stkptr ← state.stkptr + 1; ENDLOOP; END; IF data.worryEntry THEN AbortWithError[worryCall]; in ← TransferTypes[TypeForSe[proc.tsei]].typeIn; state.instbyte ← state.stkptr ← 0; TreeOps.ScanList[args,Collect]; IF cnt#WordsForType[in] OR (cnt#0 AND NextSe[isei]#Symbols.ISENull) THEN AbortWithError[wrongNumberArgs,proc.hti]; cl ← DerefProcDesc[GetControlLink[proc ! NotAProcedure => GOTO inline] ! NotAProcedure => GOTO inline]; cbti ← Pc.LinkToCbti[cl]; IF cbti = Symbols.CBTNull THEN AbortWithError[callingInline]; state.source ← NIL; state.dest ← Gf.OldLink[cl]; sv ← @LOOPHOLE[data.ESV.parameter, CoreSwapDefs.CallDP].sv; DebugOps.ShortCopyWRITE[ to: sv, from: @state, nwords: SIZE[PrincOps.StateVector]]; Init.CoreSwap[call]; sv ← @LOOPHOLE[data.ESV.parameter, CoreSwapDefs.CallDP].sv; DebugOps.ShortCopyREAD[ from: sv, to: @state, nwords: SIZE[PrincOps.StateVector]]; Lf.DisplayResults[state.source]; EXITS inline => AbortWithError[callingInline]; END; ApplyError: PROC [tm: Symbols.TransferMode] = BEGIN OPEN DOutput; Text[" can't call a"L]; IF tm = error THEN Char['n]; Blanks[1]; Dump.ModeName[tm]; Char['!]; EOL[]; ERROR DIAbort; END; LoopHole: PROC [f: Foo, type: Symbols.SEIndex, lengthen: BOOLEAN ← FALSE] = BEGIN tSize: CARDINAL; SELECT TRUE FROM f = NIL => RETURN; f.tsei = type => RETURN; TotalWords[f] = (tSize ← SymbolOps.WordsForType[type]) => NULL; ~lengthen => AbortWithError[sizeMismatch]; tSize # 2 => AbortWithError[sizeMismatch]; ~CheckLength[f,1] => AbortWithError[sizeMismatch]; ENDCASE => LengthenFob[f]; f.tsei ← type; END; Size: PROC [f: Foo] = BEGIN f1: Foo ← Heap.AllocFob[]; lp: LONG POINTER TO CARDINAL ← Storage.Node[SIZE[CARDINAL]]; IF ~f.typeOnly THEN AbortWithError[notType]; lp↑ ← SymbolOps.WordsForType[f.tsei]; f1.addr.base ← lp; f1.words ← 1; f1.tsei ← com.typeCARDINAL; Push[f1]; END; Assign: PUBLIC PROCEDURE [lhs: Foo] = BEGIN rhs: Foo = Pop[]; Assignable[rhs, TypeForSe[lhs.tsei]]; PutValue[lhs,rhs.addr.base] END; Assignable: PROCEDURE [f: Foo, csei: CSEIndex] = BEGIN left: Types.Handle ← [LOOPHOLE[MyBase],csei]; right: Types.Handle ← [LOOPHOLE[MyBase],TypeForSe[f.tsei]]; IF ~Types.Assignable[typeL: left, typeR: right] THEN AbortWithError[typeMismatch, f.hti]; DI.GetValue[f]; -- so I can check sizes LoopHole[f,csei,TRUE]; IF SymbolOps.WordsForType[csei] # TotalWords[f] THEN AbortWithError[sizeMismatch, f.hti]; END; TotalWords: PROC [f: Foo] RETURNS [cnt: CARDINAL] = BEGIN cnt ← f.words; IF f.bits # 0 THEN cnt ← cnt + 1; END; DumpMemory: PROCEDURE [fcnt: Foo] = BEGIN fstart: Foo ← Pop[]; start: LONG POINTER; cnt: CARDINAL; n: Number; n ← GetNumber[fstart]; SELECT n.type FROM one => start ← DebugOps.Lengthen[n.p]; two => start ← n.lp; ENDCASE => AbortWithError[invalidAddress]; n ← GetNumber[fcnt]; SELECT n.type FROM one => cnt ← n.c; two => AbortWithError[wontDump]; ENDCASE => AbortWithError[invalidNumber]; Actions.DoRead[start,cnt, Actions.ReadUser]; RETURN END; GetSize: PROCEDURE [index: Tree.Index, type: Symbols.SEIndex] RETURNS [size: NumberType, cnt: CARDINAL, signed: BOOLEAN] = BEGIN Process: Tree.Scan = BEGIN tosSize: NumberType; int: BOOLEAN; IF t = Tree.Null THEN ERROR BadTree; cnt ← cnt + 1; [,tosSize,int] ← GetRep[t, type]; IF int THEN signed ← TRUE; IF tosSize = size THEN RETURN; size ← two; END; cnt ← 0; size ← one; signed ← FALSE; TreeOps.ScanList[tb[index].son[1],Process]; END; MinimalRep: PROCEDURE [t: Tree.Link, type: Symbols.SEIndex] RETURNS [f: Foo, size: NumberType, signed: BOOLEAN] = BEGIN p: LONG POINTER TO Inline.LongNumber; [f,size,signed] ← GetRep[t,type]; IF size = one THEN RETURN; p ← f.addr.base; IF p.highbits # 0 THEN RETURN; size ← one; f.words ← 1; END; GetRep: PROCEDURE [t: Tree.Link, type: Symbols.SEIndex] RETURNS [f: Foo, size: NumberType, signed: BOOLEAN] = BEGIN n: Number; f ← Son[t, type]; n ← GetNumber[f]; size ← n.type; WITH Format[f.tsei].vf SELECT FROM int => {signed ← TRUE; RETURN}; ENDCASE; SELECT size FROM one => signed ← ~n.sign; two => signed ← ~n.lsign; ENDCASE => ERROR DebugOps.InvalidNumber[f]; 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; FindLiteral: PROCEDURE [info: Literals.LitRecord] RETURNS [f: Foo] = BEGIN f ← Heap.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 i: NumberType; p: LONG POINTER TO Words; IF (n.type ← NumberLength[f]) = nogood THEN AbortWithError[code]; GetValue[f]; p ← f.addr.base; FOR i IN [nogood..n.type) DO n.w[i] ← p[i]; ENDLOOP; END; LongRec: TYPE = RECORD [sei, lsei: Symbols.CSEIndex]; longs: ARRAY [0..3) OF LongRec; SetUpLongs: PROCEDURE = BEGIN longs[0] ← [com.typeINT, Symbols.CSENull]; longs[1] ← [com.typeCARDINAL, Symbols.CSENull]; longs[2] ← [Symbols.typeANY, Symbols.CSENull]; END; ResetLongs: PUBLIC PROC = BEGIN i: CARDINAL; FOR i IN [0..LENGTH[longs]) DO longs[i].lsei ← Symbols.CSENull ENDLOOP; END; MakeLongType: PROC[rType: Symbols.SEIndex] RETURNS[type: Symbols.CSEIndex] = BEGIN OPEN SymbolOps, Symbols; i: CARDINAL; sei: CSEIndex ← UnderType[rType]; FOR i IN [0..LENGTH[longs]) DO IF longs[i].sei # sei THEN LOOP; IF longs[i].lsei # SENull THEN RETURN[longs[i].lsei]; longs[i].lsei ← type ← MakeNonCtxSe[SIZE[long cons SERecord]]; EXIT REPEAT FINISHED => type ← MakeNonCtxSe[SIZE[long cons SERecord]]; ENDLOOP; seb[type] ← SERecord[mark3: TRUE, mark4: TRUE, body: cons[long[rangeType: rType]]]; RETURN END; MakePointerType: PROC [cType: Symbols.SEIndex] RETURNS [type: Symbols.CSEIndex] = BEGIN OPEN SymbolOps, Symbols; type ← MakeNonCtxSe[SIZE[ref cons SERecord]]; seb[type] ← SERecord[mark3: TRUE, mark4: TRUE, body: cons[ref[ list: FALSE, counted: FALSE, ordered: FALSE, readOnly: FALSE, basing: FALSE, dereferenced: FALSE, refType: cType]]]; RETURN END; Stack: TYPE = State.Stack; 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; AbortWithError: PUBLIC PROC [ code: Err, hti: Symbols.HTIndex ← Symbols.HTNull] = BEGIN Error[code, hti]; ERROR DIAbort END; Error: PUBLIC PROC [code: Err, hti: Symbols.HTIndex ← Symbols.HTNull] = BEGIN s: STRING ← [40]; IF hti # Symbols.HTNull THEN {Lookup.HtiToString[hti,s]; DOutput.Text[s]}; DOutput.Line[SELECT code FROM callingInline => " can't call an INLINE!"L, cantLengthen => " can't lengthen!"L, constructor => " can't make a constructor!"L, indexTooBig => " double word array index!"L, invalidAddress => " has an invalid address!"L, invalidNumber => " is an invalid number!"L, invalidPointer => " is an invalid pointer!"L, nilChk => " pointer fault!"L, notFound => " not found!"L, notRelative => " is not a relative pointer!"L, notType => " is not a type!"L, notUniqueField => " is not a unique field selector!"L, notValidField => " is not a valid field selector!"L, overflow => " overflow!"L, sizeMismatch => " size mismatch!"L, tooManyArgs => " too many arguments for stack!"L, typeMismatch => " has incorrect type!"L, unknownVariant => " unknown variant!"L, wontDump => " Won't dump that much memory!"L, worryCall => " not permitted in wory mode!"L, wrongBase => " is the wrong base!"L, wrongNumberArgs => " has the wrong number of arguments!"L, ENDCASE => ERROR]; END; SetUpLongs[]; END.