-- DIMath.mesa Edited by Bruce, Oct 16, 1980 11:47 PM DIRECTORY ComData USING [typeCARDINAL, typeINT], DebugOps USING [Foo, InvalidNumber, Lengthen], DI USING [ AbortWithError, Foo, Format, GetNumber, GetValue, LongNumFormat, MakeLongType, NumAddr, Number, NumberType, NumFormat, SEIndex, TypeForSe], DIActions USING [ CheckLength, NumberLength, Pop, Push, PushLongVal, PushVal, Son, Tos], DOutput USING [Char, LongNumber, Number, Text], Dump USING [Char], DHeap USING [FreeLong], MachineDefs USING [BYTE], Storage USING [Node], Symbols USING [CSEIndex, CSENull, SEIndex, seType, typeANY], Table USING [Base, Bounds], Tree USING [Link, NodeName]; DIMath: PROGRAM IMPORTS com: ComData, DebugOps, DI, DIActions, Dump, DOutput, DHeap, Storage, Table EXPORTS DIActions = BEGIN OPEN DI, DIActions; LengtheningGarbage: ERROR = CODE; CompType: TYPE = {min, max}; PutReps: PUBLIC PROCEDURE [n: UNSPECIFIED] = BEGIN OPEN DOutput, LOOPHOLE[n,NumFormat]; Cardinal[c]; Equals[]; Hex[c]; Equals[]; Integer[i]; IF b1 # 0 THEN BEGIN Equals[]; Bytes[b1,b2]; IF b1 > 15 OR b2 > 15 THEN BEGIN Equals[]; Number[b1, [base: 8, zerofill: FALSE, unsigned: TRUE, columns: 0]]; IF b1 > 7 THEN Char['B]; Text[",,"L]; Number[b2, [base: 8, zerofill: FALSE, unsigned: TRUE, columns: 0]]; IF b2 > 7 THEN Char['B]; END; IF b1 < 128 AND b2 < 128 THEN BEGIN Equals[]; Dump.Char[b1]; Text[",,"L]; Dump.Char[b2]; END; END ELSE IF b2 IN [1..127] THEN BEGIN Equals[]; Dump.Char[b2]; END; IF n1 # 0 OR n3 # 0 THEN BEGIN Equals[]; IF b1 # 0 THEN BEGIN IF n1 # 0 THEN BEGIN Number[n1, [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 0]]; Char[':]; END; Number[n2, [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 0]]; Text[",,"L]; END; IF n3 # 0 THEN BEGIN Number[n3, [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 0]]; Char[':]; END; Number[n4, [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 0]]; END; END; Equals: PROCEDURE = BEGIN DOutput.Text[" = "L]; END; Cardinal: PROCEDURE [c: CARDINAL] = INLINE BEGIN OPEN DOutput; Number[c, [base: 8, zerofill: FALSE, unsigned: TRUE, columns: 0]]; IF c > 7 THEN Char['B]; END; Hex: PROCEDURE [c: CARDINAL] = INLINE BEGIN OPEN DOutput; Number[c, [base: 16, zerofill: FALSE, unsigned: TRUE, columns: 0]]; IF c > 7 THEN Char['X]; END; Integer: PROCEDURE [i: INTEGER] = BEGIN OPEN DOutput; Number[i, [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 0]]; IF i < 0 THEN BEGIN Equals[]; Number[i, [base: 10, zerofill: FALSE, unsigned: FALSE, columns: 0]]; END; END; Bytes: PROCEDURE [b1, b2: MachineDefs.BYTE] = BEGIN OPEN DOutput; Number[b1, [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 0]]; Text[",,"L]; Number[b2, [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 0]]; END; PutLongReps: PUBLIC PROCEDURE [n: LONG UNSPECIFIED] = BEGIN OPEN DOutput, LOOPHOLE[n,LongNumFormat]; LongNumber[c, [base: 8, zerofill: FALSE, unsigned: TRUE, columns: 0]]; IF c > 7 THEN Char['B]; Equals[]; LongNumber[c, [base: 16, zerofill: FALSE, unsigned: TRUE, columns: 0]]; IF c > 7 THEN Char['X]; Equals[]; LongNumber[c, [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 0]]; IF i < 0 THEN BEGIN Equals[]; LongNumber[c, [base: 10, zerofill: FALSE, unsigned: FALSE, columns: 0]]; END; Equals[]; Cardinal[w1]; Char[' ]; Cardinal[w2]; Equals[]; Bytes[b1,b2]; Char[' ]; Bytes[b3,b4]; END; LengthenFob: PUBLIC PROCEDURE [f: Foo] = BEGIN GetValue[f]; IF ~CheckLength[f,1] THEN AbortWithError[cantLengthen]; WITH Format[f.tsei].vf SELECT FROM int => Long[f, TRUE]; card => Long[f, FALSE]; string, pointer => BEGIN new: POINTER TO LONG UNSPECIFIED ← Storage.Node[SIZE[LONG POINTER]]; new↑ ← DebugOps.Lengthen[f.addr.base↑]; DHeap.FreeLong[f.addr.base]; f.addr.base ← new; f.words ← 2; END; ENDCASE; f.tsei ← MakeLongType[TypeForSe[f.tsei]]; END; Abs: PUBLIC PROCEDURE [t: Tree.Link, target: Symbols.SEIndex] = BEGIN f: Foo ← Son[t,target]; p: NumAddr; GetValue[f]; p ← LOOPHOLE[f.addr.base]; f.tsei ← com.typeINT; SELECT NumberLength[f] FROM nogood => AbortWithError[invalidNumber]; one => p.pi↑ ← ABS[p.pi↑]; two => p.pli↑ ← ABS[p.pli↑] ENDCASE; END; Long: PUBLIC PROCEDURE [f: Foo, signed: BOOLEAN] = BEGIN new: NumAddr ← LOOPHOLE[LONG[Storage.Node[SIZE[LONG UNSPECIFIED]]]]; old: NumFormat ← LOOPHOLE[f.addr.base↑]; IF f.there THEN ERROR LengtheningGarbage; IF signed THEN new.pli↑ ← LONG[old.i] ELSE new.plc↑ ← LONG[old.c]; DHeap.FreeLong[f.addr.base]; f.addr.base ← LOOPHOLE[new]; f.words ← 2; END; Compare: PROC [f1, f2: Foo, size: NumberType, compare: CompType, signed: BOOLEAN] RETURNS [Foo] = BEGIN addr1: NumAddr ← LOOPHOLE[f1.addr.base]; addr2: NumAddr ← LOOPHOLE[f2.addr.base]; firstSmallest: BOOLEAN; SELECT NIL FROM f1 => RETURN[f2]; f2 => RETURN[f1]; ENDCASE; IF signed THEN SELECT size FROM one => firstSmallest ← addr1.pi↑ < addr2.pi↑; two => firstSmallest ← addr1.pli↑ < addr2.pli↑; ENDCASE => ERROR DebugOps.InvalidNumber[f1] ELSE SELECT size FROM one => firstSmallest ← addr1.pc↑ < addr2.pc↑; two => firstSmallest ← addr1.plc↑ < addr2.plc↑; ENDCASE => ERROR DebugOps.InvalidNumber[f1]; SELECT compare FROM min => IF firstSmallest THEN RETURN[f1] ELSE RETURN[f2]; max => IF firstSmallest THEN RETURN[f2] ELSE RETURN[f1]; ENDCASE => ERROR; END; MinMax: PROC [ size: NumberType, cnt: CARDINAL, signed: BOOLEAN, comp: CompType] = BEGIN i: CARDINAL; f, current: Foo ← NIL; FOR i IN [0..cnt) DO f ← Pop[]; IF ~CheckLength[f,LOOPHOLE[size]] THEN Long[f, signed]; current ← Compare[f,current,size,comp,signed]; ENDLOOP; Push[current]; END; Max: PUBLIC PROCEDURE [size: NumberType, cnt: CARDINAL, signed: BOOLEAN] = BEGIN MinMax[size,cnt,signed,max]; END; Min: PUBLIC PROCEDURE [size: NumberType, cnt: CARDINAL, signed: BOOLEAN] = BEGIN MinMax[size,cnt,signed,min]; END; Inc: PUBLIC PROC [f: Foo, size: NumberType, signed: BOOLEAN] = BEGIN num: NumAddr ← LOOPHOLE[f.addr.base]; IF signed THEN SELECT size FROM one => num.pi↑ ← num.pi↑ + 1; two => num.pli↑ ← num.pli↑ + 1; ENDCASE => ERROR DebugOps.InvalidNumber[f] ELSE SELECT size FROM one => num.pc↑ ← num.pc↑ + 1; two => num.plc↑ ← num.plc↑ + 1; ENDCASE => ERROR DebugOps.InvalidNumber[f]; END; Dec: PUBLIC PROC [f: Foo, size: NumberType, signed: BOOLEAN] = BEGIN num: NumAddr ← LOOPHOLE[f.addr.base]; IF signed THEN SELECT size FROM one => num.pi↑ ← num.pi↑ - 1; two => num.pli↑ ← num.pli↑ - 1; ENDCASE => ERROR DebugOps.InvalidNumber[f] ELSE SELECT size FROM one => num.pc↑ ← num.pc↑ - 1; two => num.plc↑ ← num.plc↑ - 1; ENDCASE => ERROR DebugOps.InvalidNumber[f]; END; MakeCnt: PUBLIC PROC [top, sub: Foo, size: NumberType, signed: BOOLEAN] = BEGIN res: NumAddr ← LOOPHOLE[top.addr.base]; num: NumAddr ← LOOPHOLE[sub.addr.base]; IF signed THEN SELECT size FROM one => res.pi↑ ← res.pi↑ - num.pi↑ + 1; two => res.pli↑ ← res.pli↑ - num.pli↑ + 1; ENDCASE => ERROR DebugOps.InvalidNumber[top] ELSE SELECT size FROM one => res.pc↑ ← res.pc↑ - num.pc↑ + 1; two => res.plc↑ ← res.plc↑ - num.plc↑ + 1; ENDCASE => ERROR DebugOps.InvalidNumber[top]; END; Repr: TYPE = [none..all]; signed: CARDINAL = 1; unsigned: CARDINAL = 2; long: CARDINAL = 4; other: CARDINAL = 8; none: CARDINAL = 0; both: CARDINAL = signed+unsigned; all: CARDINAL = other+long+both; -- literals TreeLiteralValue: PROC [f: Foo] RETURNS [WORD] = BEGIN n: Number = GetNumber[f]; SELECT n.type FROM one => RETURN[n.u]; ENDCASE => AbortWithError[sizeMismatch]; ERROR; END; LongLiteralValue: PROC [f: Foo] RETURNS [LONG UNSPECIFIED] = BEGIN n: Number = GetNumber[f]; SELECT n.type FROM one => {LengthenFob[f]; RETURN[LongLiteralValue[f]]}; two => RETURN[n.lu]; ENDCASE => AbortWithError[sizeMismatch]; ERROR; END; MakeTreeLiteral: PROC [u: UNSPECIFIED, signed: BOOLEAN] = BEGIN PushVal[u, IF signed THEN com.typeINT ELSE com.typeCARDINAL]; END; MakeLongLiteral: PROC [lu: LONG UNSPECIFIED, signed: BOOLEAN] = BEGIN PushLongVal[lu, IF signed THEN com.typeINT ELSE com.typeCARDINAL]; END; AddRep: PROCEDURE [f: Foo, op: Tree.NodeName, csei: Symbols.CSEIndex, rep: Repr] RETURNS [Symbols.CSEIndex, Repr] = BEGIN new: Repr ← GetRep[f,op].rep; islong: BOOLEAN ← new > long OR rep > long; IF new > long AND rep < long THEN csei ← MakeLongType[csei]; new ← new MOD long; rep ← rep MOD long; SELECT TRUE FROM rep = both => rep ← new; rep = signed => NULL; new = signed => rep ← signed; ENDCASE => rep ← unsigned; IF islong THEN rep ← rep + long; RETURN[csei,rep]; END; GetRep: PROC [f: Foo, op: Tree.NodeName] RETURNS [csei: Symbols.CSEIndex, rep: Repr] = BEGIN subtraction: BOOLEAN ← op = minus OR op = uminus; n: Number ← GetNumber[f]; signedNum: BOOLEAN ← IF n.type = one THEN n.sign ELSE n.lsign; [csei,rep] ← TypedRep[f]; IF subtraction THEN csei ← IF n.type = one THEN com.typeINT ELSE MakeLongType[com.typeINT]; SELECT rep MOD long FROM none => NULL; unsigned => IF subtraction THEN rep ← rep - 1; signed => IF ~subtraction AND ~signedNum THEN rep ← rep + 2; -- make it both both => IF subtraction THEN rep ← rep - 2 ELSE IF signedNum THEN rep ← rep - 1; -- make it unsigned ENDCASE; IF n.type = two AND rep < long THEN rep ← rep + long; END; TypedRep: PROC [f: Foo] RETURNS [csei: Symbols.CSEIndex, rep: Repr] = BEGIN seb: Table.Base ← Table.Bounds[Symbols.seType].base; save: Symbols.CSEIndex ← Symbols.CSENull; csei ← LOOPHOLE[f.tsei]; rep ← none; DO SELECT csei FROM com.typeCARDINAL => rep ← rep + unsigned; com.typeINT => rep ← rep + signed; Symbols.typeANY => rep ← rep + both; ENDCASE => { csei ← TypeForSe[csei]; WITH seb[csei] SELECT FROM long => {rep ← long; save ← csei; csei ← TypeForSe[rangeType]; LOOP}; subrange => {save ← csei; csei ← TypeForSe[rangeType]; LOOP}; ref => rep ← rep + unsigned; ENDCASE => rep ← rep + both}; IF save # Symbols.CSENull THEN csei ← save; EXIT; ENDLOOP; END; -- dispatch Mode: TYPE = {ss, su, ls, lu, other}; ModeMap: ARRAY Repr OF Mode = [ss, ss, su, su, ls, ls, lu, lu, other, ss, su, su, other, ls, lu, lu]; UnaryOp: ARRAY Mode OF PROC [node: Foo] = [UnarySS, UnarySU, UnaryLS, UnaryLU, UnaryOpError]; BinaryOp: ARRAY Mode OF PROC [node: Foo, op: Tree.NodeName] = [BinarySS, BinarySU, BinaryLS, BinaryLU, OpError]; FoldExpr: PUBLIC PROC [op: Tree.NodeName] = BEGIN left: Foo ← Pop[]; tos: Foo; rep: Repr; csei: Symbols.CSEIndex; [csei, rep] ← GetRep[left, op]; SELECT op FROM plus, minus, times, div, mod => { [csei, rep] ← AddRep[Tos[], op, csei, rep]; BinaryOp[ModeMap[rep]][left,op]}; uminus => UnaryOp[ModeMap[rep]][left]; ENDCASE; tos ← Tos[]; tos.tsei ← csei; END; -- operations MinSS: INTEGER = FIRST[INTEGER]; MaxSS: INTEGER = LAST[INTEGER]; UnarySS: PROC [node: Foo] = BEGIN v: INTEGER; v1: INTEGER = TreeLiteralValue[node]; IF v1 # MinSS THEN v ← -v1 ELSE AbortWithError[overflow]; MakeTreeLiteral[v,TRUE]; END; BinarySS: PROC [node: Foo, op: Tree.NodeName] = BEGIN v: INTEGER; v1: INTEGER = TreeLiteralValue[node]; v2: INTEGER = TreeLiteralValue[Pop[]]; SELECT op FROM plus => IF (IF v1 >= 0 THEN v2 <= MaxSS-v1 ELSE v2 >= MinSS-v1) THEN v ← v1 + v2 ELSE GO TO Overflow; minus => IF (IF v1 >= 0 THEN v1-MaxSS <= v2 ELSE v1-MinSS >= v2) THEN v ← v1 - v2 ELSE GO TO Overflow; times => IF (SELECT TRUE FROM (v1 > 0) AND (v2 > 0) => v2 <= MaxSS / v1, (v1 > 0) AND (v2 < 0) => v2 >= MinSS / v1, (v1 < 0) AND (v2 > 0) => v1 >= MinSS / v2, (v1 < 0) AND (v2 < 0) => v1 # MinSS AND v2 # MinSS AND v2 >= MaxSS / v1, ENDCASE => TRUE) THEN v ← v1 * v2 ELSE GO TO Overflow; div => IF v2 # 0 AND (v2 # -1 OR v1 # MinSS) THEN v ← v1 / v2 ELSE GO TO Overflow; mod => IF v2 # 0 THEN v ← v1 MOD v2 ELSE GO TO Overflow; ENDCASE => ERROR; MakeTreeLiteral[v,TRUE]; EXITS Overflow => AbortWithError[overflow]; END; MaxSU: CARDINAL = LAST[CARDINAL]; UnarySU: PROC [node: Foo] = BEGIN v1: CARDINAL = TreeLiteralValue[node]; IF v1 # 0 THEN AbortWithError[overflow]; MakeTreeLiteral[v1,FALSE]; END; BinarySU: PROC [node: Foo, op: Tree.NodeName] = BEGIN v: CARDINAL; v1: CARDINAL = TreeLiteralValue[node]; v2: CARDINAL = TreeLiteralValue[Pop[]]; SELECT op FROM plus => IF v2 <= MaxSU-v1 THEN v ← v1 + v2 ELSE GO TO Overflow; minus => IF v1 >= v2 THEN v ← v1 - v2 ELSE GO TO Overflow; times => IF v1 = 0 OR v2 <= MaxSU/v1 THEN v ← v1 * v2 ELSE GO TO Overflow; div => IF v2 # 0 THEN v ← v1 / v2 ELSE GO TO Overflow; mod => IF v2 # 0 THEN v ← v1 MOD v2 ELSE GO TO Overflow; ENDCASE => ERROR; MakeTreeLiteral[v,FALSE]; EXITS Overflow => AbortWithError[overflow]; END; MinLS: LONG INTEGER = FIRST[LONG INTEGER]; MaxLS: LONG INTEGER = LAST[LONG INTEGER]; UnaryLS: PROC [node: Foo] = BEGIN v: LONG INTEGER; v1: LONG INTEGER = LongLiteralValue[node]; IF v1 # MinLS THEN v ← -v1 ELSE AbortWithError[overflow]; MakeLongLiteral[v, TRUE]; END; BinaryLS: PROC [node: Foo, op: Tree.NodeName] = BEGIN v: LONG INTEGER; v1: LONG INTEGER = LongLiteralValue[node]; v2: LONG INTEGER = LongLiteralValue[Pop[]]; SELECT op FROM plus => IF (IF v1 >= 0 THEN v2 <= MaxLS-v1 ELSE v2 >= MinLS-v1) THEN v ← v1 + v2 ELSE GO TO Overflow; minus => IF (IF v1 >= 0 THEN v1-MaxLS <= v2 ELSE v1-MinLS >= v2) THEN v ← v1 - v2 ELSE GO TO Overflow; times => IF (SELECT TRUE FROM (v1 > 0) AND (v2 > 0) => v2 <= MaxLS / v1, (v1 > 0) AND (v2 < 0) => v2 >= MinLS / v1, (v1 < 0) AND (v2 > 0) => v1 >= MinLS / v2, (v1 < 0) AND (v2 < 0) => v1 # MinLS AND v2 # MinLS AND v2 >= MaxLS / v1, ENDCASE => TRUE) THEN v ← v1 * v2 ELSE GO TO Overflow; div => IF v2 # 0 AND (v2 # -1 OR v1 # MinLS) THEN v ← v1 / v2 ELSE GO TO Overflow; mod => IF v2 # 0 THEN v ← v1 MOD v2 ELSE GO TO Overflow; ENDCASE => ERROR; MakeLongLiteral[v, TRUE]; EXITS Overflow => AbortWithError[overflow]; END; MaxLU: LONG CARDINAL = LAST[LONG CARDINAL]; UnaryLU: PROC [node: Foo] = BEGIN v1: LONG CARDINAL = LongLiteralValue[node]; IF v1 # 0 THEN AbortWithError[overflow]; MakeLongLiteral[v1,FALSE]; END; BinaryLU: PROC [node: Foo, op: Tree.NodeName] = BEGIN v: LONG CARDINAL; v1: LONG CARDINAL = LongLiteralValue[node]; v2: LONG CARDINAL = LongLiteralValue[Pop[]]; SELECT op FROM plus => IF v2 <= MaxLU-v1 THEN v ← v1 + v2 ELSE GO TO Overflow; minus => IF v1 >= v2 THEN v ← v1 - v2 ELSE GO TO Overflow; times => IF v1 = 0 OR v2 <= MaxLU/v1 THEN v ← v1 * v2 ELSE GO TO Overflow; div => IF v2 # 0 THEN v ← v1 / v2 ELSE GO TO Overflow; mod => IF v2 # 0 THEN v ← v1 MOD v2 ELSE GO TO Overflow; ENDCASE => ERROR; MakeLongLiteral[v,FALSE]; EXITS Overflow => AbortWithError[overflow]; END; OpError: PROC [node: Foo, op: Tree.NodeName] = {AbortWithError[overflow]}; UnaryOpError: PROC [node: Foo] = {AbortWithError[overflow]}; END.