RobotEvaluatorImpl.mesa
Created Monday, May 21, 1984 10:38 pm PDT
Last edited by Eric Nickell, October 25, 1984 9:49:23 pm PDT
DIRECTORY
RobotEvaluator,
Rope USING [ROPE, Equal, Fetch, Length];
RobotEvaluatorImpl: CEDAR PROGRAM
IMPORTS RobotEvaluator, Rope
EXPORTS RobotEvaluator
~ {
OPEN RobotEvaluator;
NewUnassignedValue: PUBLIC PROC RETURNS [z: Value] ~ {
Returns a new Value which is marked as being `unassigned'.
RETURN[NEW[ValueRec ← [type:unassigned] ]];
};
NewValueFromInteger: PUBLIC PROC [a: INTEGER] RETURNS [z: Value] ~ {
Returns a new Value which has the given INTEGER value.
RETURN[NEW[ValueRec ← [type:integer, value: a] ]];
};
ApplyUnaryFcn: PUBLIC PROC [fcn: UnOp, a: Value] RETURNS [z: Value] ~ {
Apply the specified function to the given value.
val: Value ← NIL;
val ← NEW[ValueRec ← [type: unExp, fcn: fcn, a: a]];
RETURN[Eval[val]];
};
ApplyBinaryFcn: PUBLIC PROC [fcn: BinOp, a,b: Value] RETURNS [z: Value] ~ {
Apply the specified function to the given values.
val: Value ← NIL;
val ← NEW[ValueRec ← [type: binExp, fcn: fcn, a: a, b: b]];
RETURN[Eval[val]];
};
ApplyTrinaryFcn: PUBLIC PROC [fcn: TrinOp, a,b,c: Value] RETURNS [z: Value] ~ {
Apply the specified function to the given values.
val: Value ← NIL;
val ← NEW[ValueRec ← [type: trinExp, fcn: fcn, a:a, b:b, c:c]];
RETURN[Eval[val]];
};
Eval: PUBLIC PROC [value: Value, s: SymbolTable ← NIL] RETURNS [z: Value] ~ {
Evaluate the value. Specifically, if the value was originally defined as a function of other values that were then unassigned, but are now at the time of the call to Eval, then Eval will return a Value that is an INTEGER rather than a complex type.
SELECT value.type FROM
unExp => {
a: Value ← Eval[value.a, s]; --Resolve the child first
unOp: UnOp ← NARROW[value.fcn];
If the child can be resolved, then really apply the function
IF IsInteger[a] THEN RETURN[NewValueFromInteger[unOp^[a.value]]];
RETURN[NEW[ValueRec ← [type: unExp, fcn: value.fcn, a: a]]];
};
binExp => {
a: Value ← Eval[value.a, s]; --Resolve the children first
b: Value ← Eval[value.b, s];
binOp: BinOp ← NARROW[value.fcn];
If the children can be resolved, then really apply the function
IF IsInteger[a] AND IsInteger[b] THEN RETURN[NewValueFromInteger[binOp^[a.value,b.value]]];
RETURN[NEW[ValueRec ← [type: binExp, fcn: value.fcn, a: a, b: b]]];
};
trinExp => {
a: Value ← Eval[value.a, s]; --Resolve the children first
b: Value ← Eval[value.b, s];
c: Value ← Eval[value.c, s];
trinOp: TrinOp ← NARROW[value.fcn];
If the children can be resolved, then really apply the function
IF IsInteger[a] AND IsInteger[b] AND IsInteger[c] THEN RETURN[NewValueFromInteger[trinOp^[a.value, b.value, c.value]]];
RETURN[NEW[ValueRec ← [type: binExp, fcn: value.fcn, a: a, b: b, c: c]]];
};
symbolRef => {
IF s#NIL AND s[value.value]#NIL AND s[value.value].value.type=integer THEN RETURN[s[value.value].value];
};   --ELSE just RETURN the symbolRef as we found it
ENDCASE;
If we get here, either (1) it was already an INTEGER, or (2) it is still unassigned. In both cases, however, we can just return what we received.
RETURN[value];
};
IsInteger: PRIVATE PROC [value: Value] RETURNS [BOOLEAN] ~ {
RETURN[value.type=integer];
};
NewSymbolTable: PUBLIC PROC RETURNS [s: SymbolTable] ~ {
RETURN [NEW[SymbolTableRec ← ALL[NIL]]];
};
RopeToSymbolIndex: PUBLIC PROC [r: Rope.ROPE, s: SymbolTable] RETURNS [index: Index] ~ {
Hash the rope into an index. Then, starting with that record, look for either a blank record or one where the name is equal to the ROPE passed to us.
i: Index ← HashRopeForSymbol[r];
count: INT ← 0;
DO
SELECT TRUE FROM
s[i]=NIL => {s[i]←NEW[SymbolRec ← [name: r, value: NewUnassignedValue[]]]; RETURN[i]};
Rope.Equal[s[i].name, r] => RETURN[i];
ENDCASE;  --Fall through
i ← NextIndex[i]; --Only get here if had a collision in hashing
IF (count ← count+1) > MaxSymbolIndex THEN ERROR; --Symbol Table full
ENDLOOP;
};
HashRopeForSymbol: PRIVATE PROC [r: Rope.ROPE] RETURNS [index: Index] ~ {
Hash the rope into a pseudo-random index into a symbol table
len: INTEGER ← Rope.Length[r];
raw: INT ← (7*len + 31*CharToInt[Rope.Fetch[r,0]] + 103*CharToInt[Rope.Fetch[r,len-1]]) MOD MaxSymbolIndex;
index ← raw;
};
CharToInt: PRIVATE PROC [c: CHAR] RETURNS [i: INT] ~ INLINE {
RETURN [ORD[c]];
};
ResolveSymbolTable: PUBLIC PROC [s: SymbolTable] RETURNS [unresolved: BOOLEAN] ~ {
AttemptResolve: PROC RETURNS [resolvedThisPass, stillUnresolved: BOOLEAN] ~ {
resolvedThisPass ← FALSE;
stillUnresolved ← FALSE;
FOR i: Index IN Index DO
IF s[i]#NIL AND s[i].value.type#integer THEN {
s[i].value ← Eval[s[i].value, s];
IF s[i].value.type=integer THEN resolvedThisPass ← TRUE ELSE stillUnresolved ← TRUE;
};
ENDLOOP;
};
resolvedThisPass, stillUnresolved: BOOLEANTRUE; --TRUE causes at least 1 iteration
WHILE resolvedThisPass AND stillUnresolved DO
[resolvedThisPass, stillUnresolved] ← AttemptResolve[];
ENDLOOP;
unresolved ← stillUnresolved;
};
Define the actual procs that do the work, when we have resolved the args to INTEGERs.
opIfThenElseRec: TrinOpRec ~ {z ← IF a=0 THEN b ELSE c};
opORRec: BinOpRec ~ {z ← IF a=0 OR b=0 THEN 0 ELSE 1};
opANDRec: BinOpRec ~ {z ← IF a=0 AND b=0 THEN 0 ELSE 1};
opNOTRec: UnOpRec ~ {z ← IF a=0 THEN 1 ELSE 0};
opMODRec: BinOpRec ~ {z ← a MOD b; IF z<0 THEN z←z+b};
opLTRec: BinOpRec ~ {z ← IF a<b THEN 0 ELSE 1};
opEQRec: BinOpRec ~ {z ← IF a=b THEN 0 ELSE 1};
opGTRec: BinOpRec ~ {z ← IF a>b THEN 0 ELSE 1};
opNERec: BinOpRec ~ {z ← IF a#b THEN 0 ELSE 1};
opGERec: BinOpRec ~ {z ← IF a>=b THEN 0 ELSE 1};
opLERec: BinOpRec ~ {z ← IF a<=b THEN 0 ELSE 1};
opPlusRec: BinOpRec ~ {z ← a+b};
opMinusRec: BinOpRec ~ {z ← a-b};
opTimesRec: BinOpRec ~ {z ← a*b};
opDivideRec: BinOpRec ~ {z ← a/b};
opUMinusRec: UnOpRec ~ {z ← -a};
opIfThenElse: PUBLIC TrinOp ← NEW[TrinOpRec ← opIfThenElseRec];
opOR: PUBLIC BinOp ← NEW[BinOpRec ← opORRec];
opAND: PUBLIC BinOp ← NEW[BinOpRec ← opANDRec];
opNOT: PUBLIC UnOp ← NEW[UnOpRec ← opNOTRec];
opMOD: PUBLIC BinOp ← NEW[BinOpRec ← opMODRec];
opLT: PUBLIC BinOp ← NEW[BinOpRec ← opLTRec];
opEQ: PUBLIC BinOp ← NEW[BinOpRec ← opEQRec];
opGT: PUBLIC BinOp ← NEW[BinOpRec ← opGTRec];
opNE: PUBLIC BinOp ← NEW[BinOpRec ← opNERec];
opGE: PUBLIC BinOp ← NEW[BinOpRec ← opGERec];
opLE: PUBLIC BinOp ← NEW[BinOpRec ← opLERec];
opPlus: PUBLIC BinOp ← NEW[BinOpRec ← opPlusRec];
opMinus: PUBLIC BinOp ← NEW[BinOpRec ← opMinusRec];
opTimes: PUBLIC BinOp ← NEW[BinOpRec ← opTimesRec];
opDivide: PUBLIC BinOp ← NEW[BinOpRec ← opDivideRec];
opUMinus: PUBLIC UnOp ← NEW[UnOpRec ← opUMinusRec];
}.