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