DIRECTORY
BasicTime USING [GMT],
IO USING [int, Put, rope, STREAM],
RobotDefs USING [Robot, RobotRec],
RobotEvaluator,
RobotHardware USING [InstallStandardSymbols],
RobotInstruction USING [EncodeStatement],
RobotScanner,
RobotTParser,
Rope USING [Cat, Concat, Equal, ROPE];
AssembleRobot:
PUBLIC
PROC [file: Rope.
ROPE, err:
IO.
STREAM ←
NIL]
RETURNS [r: RobotDefs.Robot ←
NEW[RobotDefs.RobotRec], valid:
BOOL ←
FALSE, s: RobotEvaluator.SymbolTable ← RobotEvaluator.NewSymbolTable[]] ~ {
Process is as follows:
1. Tokenize the given file
2. Parse the tokens in Pass 1 to define all the symbols
3. Resolve the value of all the symbols
4. Parse the tokens in Pass 2 to generate the code.
See Robot.grammar (generated by PGS) for the grammar in use.
OPEN RobotEvaluator;
tokens: RobotScanner.ScannedProgram;
rVal: REF ARRAY [0..256) OF Value ← NEW[ARRAY [0..256) OF Value ← ALL[NIL]];--The pass1 values
i: INTEGER ← 0; --The next token
lastLoc, curLoc: INTEGER ← 16; --The current memory location
pass: [1..2] ← 1; --We'll make 2 passes at the tokens
parseError: BOOLEAN ← FALSE; --Detect any error throughout the parse
Type:
PROC [index:
INTEGER]
RETURNS [RobotScanner.RTknClass] ~
INLINE {
RETURN[tokens.token[index].class]};
Error:
PROC [error: Rope.
ROPE, pos:
INTEGER ← tokens.token[i-1].pc] ~ {
OPEN IO;
msg: Rope.ROPE ← Rope.Cat[error, " at Error["];
parseError ← TRUE;
Put[err, rope[msg], int[pos], rope["]\n"]];
};
Complain:
PROC [error: Rope.
ROPE] ~ {
OPEN IO;
Put[err, rope[error], rope["\n"]];
};
StartsExp:
PROC [i: Index]
RETURNS [result:
BOOLEAN] ~ {
result ←
SELECT Type[i]
FROM
tknID => TRUE,
tknNum => TRUE,
tknIF => TRUE,
tknLParen => TRUE,
tknAddop => TRUE,
tknLBracket => TRUE,
ENDCASE => FALSE;
};
AssembleModule:
PROC
RETURNS [error:
BOOLEAN] ~ {
AssembleCreateTime[];
AssemblePicdescript[];
AssembleBody[];
error ← parseError;
};
AssembleCreateTime:
PROC ~ {
t: REF BasicTime.GMT;
IF Type[i]#time THEN Error["Expected create time"];
TRUSTED {t ← LOOPHOLE[tokens.token[i].data]}; --WON'T LET ME DO NARROW!!!
r.timeOfSource ← t^;
i ← i+1;
};
AssemblePicdescript:
PROC ~ {
};
AssembleBody:
PROC ~ {
WHILE StartsExp[i]
OR Type[i]=tknInstruction
DO
AssembleLine[];
ENDLOOP;
};
AssembleLine:
PROC ~ {
SELECT
TRUE
FROM
Type[i]=tknID AND Type[i+1]=tknColon => {AssembleLabel[]; RETURN};
Type[i]=tknID
AND Type[i+1]=tknAssign => {
AssembleAssignment[];
IF Type[i]=tknSemiColon THEN i←i+1 ELSE Error["Expected ;"];
RETURN;
};
Type[i]=tknInstruction => {
rVal[curLoc] ← AssembleStatement[];
curLoc ← curLoc+1;
IF Type[i]=tknSemiColon THEN i←i+1 ELSE Error["Expected ;"];
RETURN;
};
StartsExp[i] => {
rVal[curLoc] ← AssembleExp[];
curLoc ← curLoc+1;
IF Type[i]=tknSemiColon THEN i←i+1 ELSE Error["Expected ;"];
};
ENDCASE => Error["Expect start of line"];
};
AssembleAssignment:
PROC ~ {
index: Index; --Index into symbol table
IF Type[i]#tknID OR Type[i+1]#tknAssign THEN {Error["Assignment expected"];RETURN};
index ← RobotEvaluator.RopeToSymbolIndex[r: NARROW[tokens.token[i].data], s: s]; --Get the index to this symbol
i ← i+2; --Skip the id and ←
RobotEvaluator.AssignValueToSymbol[v: AssembleExp[], index: index, s: s];
};
AssembleLabel:
PROC ~ {
index: Index; --Index into symbol table
IF Type[i]#tknID OR Type[i+1]#tknColon THEN {Error["Label expected"]; RETURN};
index ← RobotEvaluator.RopeToSymbolIndex[r: NARROW[tokens.token[i].data], s: s];
i ← i+2; --Skip the id and ←
RobotEvaluator.AssignValueToSymbol[v: RobotEvaluator.NewValueFromInteger[curLoc], index: index, s:s];
};
AssembleStatement:
PROC
RETURNS [v: Value] ~ {
tag: Value;
immediate, indirect, indexed: BOOL ← FALSE;
opCodeNum: INTEGER;
IF Type[i]#tknInstruction THEN {Error["OpCode expected"]; RETURN};
opCodeNum ← NARROW[tokens.token[i].data, REF INTEGER]^; i←i+1;
IF Type[i]=tknImmediate THEN {immediate←TRUE; i←i+1};
tag ← AssembleExp[];
IF Type[i]=tknIndirect THEN {indirect←TRUE; i←i+1};
IF Type[i]=tknComma
THEN {
i←i+1; --Gobble comma
IF Type[i]#tknID
THEN Error["Expected I"]
ELSE {
IF ~Rope.Equal[NARROW[tokens.token[i].data],"I"] THEN Error["Expected I"];
i←i+1; --Gobble it whether it was right or not...
};
indexed←TRUE;
};
v ← RobotInstruction.EncodeStatement[opCodeNum, tag, immediate, indirect, indexed];
};
AssembleExp:
PROC
RETURNS [v: Value] ~ {
WHILE ~StartsExp[i] AND Type[i]~=tknEOF DO i←i+1 ENDLOOP;
IF Type[i]=tknIF
THEN {
cond, exp1, exp2: Value;
i←i+1;
cond ← AssembleDisjunct[];
IF Type[i]=tknTHEN THEN i←i+1 ELSE Error["Expected THEN"];
exp1 ← AssembleExp[];
IF Type[i]=tknELSE THEN i←i+1 ELSE Error["Expected ELSE"];
exp2 ← AssembleExp[];
v ← ApplyTrinaryFcn[opIfThenElse, cond, exp1, exp2];
}
ELSE {
v ← AssembleSum[];
};
};
AssembleSum:
PROC
RETURNS [v: Value] ~ {
sum: Value ← AssembleProduct[];
addop: RobotEvaluator.BinOp;
WHILE Type[i]=tknAddop
DO
addop ← NARROW[tokens.token[i].data, RobotEvaluator.BinOp]; i←i+1;
sum ← RobotEvaluator.ApplyBinaryFcn[addop, sum, AssembleProduct[]];
ENDLOOP;
v ← sum;
};
AssembleProduct:
PROC
RETURNS [v: Value] ~ {
product: Value ← AssembleFactor[];
multop: RobotEvaluator.BinOp;
WHILE Type[i]=tknMulop
DO
multop ← NARROW[tokens.token[i].data]; i←i+1;
product ← RobotEvaluator.ApplyBinaryFcn[multop, product, AssembleFactor[]];
ENDLOOP;
v ← product;
};
AssembleDisjunct:
PROC
RETURNS [v: Value] ~ {
disjunct: Value ← AssembleConjunct[];
or: RobotEvaluator.BinOp;
WHILE Type[i]=tknOR
DO
or ← NARROW[tokens.token[i].data]; i←i+1;
disjunct ← RobotEvaluator.ApplyBinaryFcn[or, disjunct, AssembleConjunct[]];
ENDLOOP;
v ← disjunct;
};
AssembleConjunct:
PROC
RETURNS [v: Value] ~ {
conjunct: Value ← AssembleNegation[];
and: RobotEvaluator.BinOp;
WHILE Type[i]=tknAND
DO
and ← NARROW[tokens.token[i].data]; i←i+1;
conjunct ← RobotEvaluator.ApplyBinaryFcn[and, conjunct, AssembleNegation[]];
ENDLOOP;
v ← conjunct;
};
AssembleNegation:
PROC
RETURNS [v: Value] ~ {
IF Type[i]=tknNOT
THEN {
i←i+1;
RETURN[RobotEvaluator.ApplyUnaryFcn[NARROW[tokens.token[i].data], AssembleRelation[]]];
};
v ← AssemblePrimary[];
};
AssembleRelation:
PROC
RETURNS [v: Value] ~ {
relation: Value ← AssembleExp[];
relop: RobotEvaluator.BinOp;
IF Type[i]#tknRelop
THEN {
Error["Expected Relational Operator"];
RETURN[NewUnassignedValue[]];
};
relop ← NARROW[tokens.token[i].data]; i←i+1;
relation ← RobotEvaluator.ApplyBinaryFcn[relop, relation, AssembleExp[]];
v ← relation;
};
AssembleFactor:
PROC
RETURNS [v: Value] ~ {
IF Type[i]=tknAddop
AND RobotEvaluator.opMinus=
NARROW[tokens.token[i].data, RobotEvaluator.BinOp]
THEN {
i←i+1;
RETURN[RobotEvaluator.ApplyUnaryFcn[RobotEvaluator.opUMinus, AssembleFactor[]]];
};
IF Type[i]=tknAddop THEN i←i+1;
v ← AssemblePrimary[];
};
AssemblePrimary:
PROC
RETURNS [v: Value] ~ {
OPEN RobotEvaluator;
SELECT Type[i]
FROM
tknID => {
v ← ValueOfSymbol[RopeToSymbolIndex[NARROW[tokens.token[i].data], s], s];
i ← i+1;
};
tknNum => {
vval: INTEGER ← NARROW[tokens.token[i].data, REF INT]^;
v ← NewValueFromInteger[vval];
i ← i+1;
};
tknLParen => {
i ← i+1; --Skip the paren
v ← AssembleExp[];
IF Type[i]=tknRParen THEN i←i+1 ELSE Error["Expected Right Parenthesis"];
};
tknLBracket => {
i ← i+1;
v ← AssembleStatement[];
IF Type[i]=tknRBracket THEN i←i+1 ELSE Error["Expected Right Bracket"];
};
ENDCASE => {
Error["Expected id"];
v ← NewUnassignedValue[];
};
};
ResolveSymbols:
PROC
RETURNS [error:
BOOLEAN] ~ {
error ← RobotEvaluator.ResolveSymbolTable[s];
IF error
THEN {
FOR i: RobotEvaluator.Index
IN Index
DO
IF s[i]#
NIL
AND s[i].value.type#integer
THEN
Complain[Rope.Concat[s[i].name, " undefined."]];
ENDLOOP;
};
};
ResolveCode:
PROC
RETURNS [error:
BOOLEAN ←
FALSE] ~ {
lastLoc ← curLoc-1;
FOR i:
INTEGER
IN [0..256)
DO
r.code[i] ← 0;
ENDLOOP;
FOR i:
INTEGER
IN [16..lastLoc]
DO
rVal[i] ← Eval[rVal[i], s];
IF rVal[i].type=integer
THEN r.code[i]←rVal[i].value
ELSE {
error←TRUE;
Error["instruction SYSERR",i];
};
ENDLOOP;
};
Main routine for AssembleRobot starts here!!!
Note that in the binding, we have already gotten a list of tokens.
RobotHardware.InstallStandardSymbols[s]; --Define AC, I, etc...
tokens ← RobotScanner.GetTokensFromFile[file];
r.pic[0][0]←TRUE; r.pic[0][15]←TRUE; r.pic[15][0]←TRUE; r.pic[15][15]←TRUE;
SELECT
TRUE
FROM
AssembleModule[] => Complain["Parsing Errors"];
ResolveSymbols[] => Complain["Undefined or circularly defined symbols"];
ResolveCode[] => Complain["SYSTEM ERROR while resolving code"];
ENDCASE => valid ← TRUE; --Nothing went wrong
};
}.