ExpressTokenImpl.mesa
Implementation of tokens for the Express package
Created Tuesday, July 17, 1984 9:50 pm PDT
Last edited by Eric Nickell, July 18, 1984 2:32:31 am PDT
DIRECTORY
ExpressToken,
IO USING [BreakProc, EndOfStream, GetTokenRope],
Rope USING [Equal, Length];
ExpressTokenImpl: CEDAR PROGRAM
IMPORTS IO, Rope
EXPORTS ExpressToken
~ {
OPEN ExpressToken;
DefinedTokens: TYPE ~ LIST OF RECORD [rope: ROPE, kind: ATOM];
rope is the name found in the input stream. NIL means that there is no text string that can be placed in the input stream that implicitly convert to said operation.
kind is the actual operator
proc, if it is not NIL, means that the code generated by ExpressProc will be a procedure call, and proc is the procedure to call
definedTokens: DefinedTokens ← LIST[
["",   $],
[NIL,   $Id1],
[NIL,   $Id2],
[NIL,   $Id3],
[NIL,   $Id4],
[NIL,   $Id5],
[NIL,   $Constant],
["+",   $Add],
["-",   $Subtract],
["*",   $Multiply],
["/",   $Divide],
["(",   $LPar],
[")",   $RPar],
["[",   $LBracket],
["]",   $RBracket],
[",",   $Comma],
["IF",   $If],
["THEN",  $Then],
["ELSE",  $Else],
["min",  $min],
["max",  $max],
["or",   $or],
["and",  $and],
["xor",  $xor],
[">",   $GT],
["<",   $LT],
["=",   $EQ],
[">=",   $GE],
["<=",   $LE],
["#",   $NE],
["~",   $not]
];
GetNextToken: PUBLIC PROC [ts: TokenStream, symbols: Symbols, cProcs: ClientProcList] RETURNS [token: Token] ~ {
TokenBreak: IO.BreakProc ~ {
RETURN[SELECT char FROM
IN ['\000 .. ' ] => sepr,
'>, '<, '=, '#, '~, '[, '], '(, '), '+, '-, '*, '/, '^, ', => break,
ENDCASE => other
];
};
Pos: PROC [size: INT] RETURNS [INT] ~ {
ts.position ← ts.position+size;
RETURN[size];
};
ids: INT ← 1;       --Counts identifiers as they go by...
rope: ROPE;
size: INT;
First, see if there is anything in the buffer of the TokenStream
IF ts.buffer#NIL
THEN {token ← ts.buffer.first; ts.buffer ←ts.buffer.rest; []←Pos[token.size]; RETURN};
Nothing in buffer...build one from IO stream
[rope, size] ← IO.GetTokenRope[ts.stream, TokenBreak ! IO.EndOfStream => {
token ← ["<End of Stream>", $EndOfStream, Pos[size]];
GOTO ReturnEOS;
}];
size ← size+Rope.Length[rope];
Check against the client-supplied symbol table
FOR sym: Symbols ← symbols, sym.rest UNTIL sym=NIL DO
IF Rope.Equal[sym.first, rope, FALSE] THEN RETURN [[rope, SELECT ids FROM
1=>$Id1, 2=>$Id2, 3=>$Id3, 4=>$Id4, 5=>$Id5, ENDCASE=>ERROR, Pos[size]]];
ids ← ids+1;
ENDLOOP;
Check against the client-supplied proc names
FOR cProc: ClientProcList ← cProcs, cProc.rest UNTIL cProc=NIL DO
IF Rope.Equal[cProc.first.userRope, rope, FALSE] THEN RETURN [[rope, $CProc, Pos[size]]];
ENDLOOP;
Check against the built-in symbol table
FOR builtIn: DefinedTokens ← definedTokens, builtIn.rest UNTIL builtIn=NIL DO
IF Rope.Equal[builtIn.first.rope, rope, FALSE] THEN RETURN [[rope, builtIn.first.kind, Pos[size]]];
ENDLOOP;
The only other thing it could be is a number...assume so
RETURN[[rope, $Constant, Pos[size]]];
EXITS
ReturnEOS => RETURN;
};
PushToken: PUBLIC PROC [ts: TokenStream, token: Token] ~ {
ts.buffer ← CONS[token, ts.buffer];
ts.position ← ts.position - token.size;
};
RegisterToken: PUBLIC PROC [rope: ROPE, kind: ATOM] ~ {
Add a new token to the defined tokens list...
definedTokens ← CONS[ [rope, kind], definedTokens];
};
TokenStreamFromIOStream: PUBLIC PROC [s: STREAM] RETURNS [ts: TokenStream] ~ {
Turns a vanilla IO STREAM into a token stream. Wasn't that obvious already?
RETURN [NEW[TokenStreamRec ← [stream: s]]];
};
}.