-- 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.