JaMScanner2Impl.mesa
Original version by John Warnock, March 7, 1979
Paxton, 29-Jan-82 10:08:07
McGregor, September 10, 1982 11:27 am
Russ Atkinson, September 26, 1983 1:03 pm
DIRECTORY
Ascii USING [BS, CR, FF, LF, TAB],
Basics USING [BITSHIFT, LongNumber],
Convert USING [Error, RealFromRope],
JaMBasic USING [Object],
JaMInternal USING [Frame, Stack],
JaMOps USING
[Error, GetStream, KillStream, Pop, Push, PushBoolean, StreamToken, StringToken, SubString, Text, typechk],
JaMScanner,
JaMStorage,
JaMVM USING [GetChar, GetText],
Real USING [RealException],
Rope USING [ROPE, Translate],
StreamDefs USING [StreamHandle];
This program implements a very simple lexical scanner which works in the following way. When the routine "StreamToken" or "StringToken" is called then the first token is returned on the top of stack followed by the remainder of the source at next-on-stack.
JaMScanner2Impl: PROGRAM
IMPORTS Basics, Convert, JaMOps, JaMScanner, JaMVM, Real, Rope
EXPORTS JaMScanner = {
OPEN VM:JaMVM, JaMScanner, JaMStorage, JaMOps, JaMInternal, JaMBasic;
ROPE: TYPE = Rope.ROPE;
RemoveEscapes: PUBLIC PROC [text: Text] RETURNS [Text,BOOLEAN] = {
len: CARDINAL ← text.length;
read, write: CARDINAL ← 0;
char: CHARACTER;
error: BOOLEANFALSE;
Get: PROC RETURNS [ch: CHARACTER] = INLINE { ch ← text[read]; read ← read+1 };
WHILE read < len DO
IF (text[write] ← Get[]) = '\\ THEN {
SELECT char ← Get[] FROM
'n, 'N, 'r, 'R => char ← Ascii.CR;
't, 'T => char ← Ascii.TAB;
'b, 'B => char ← Ascii.BS;
'f, 'F => char ← Ascii.FF;
'l, 'L => char ← Ascii.LF;
'\\, '', '" => NULL;
IN ['0..'3] => {
d: CARDINAL ← char-'0;
IF read = len THEN error ← TRUE
ELSE {
IF (char ← Get[]) NOT IN ['0..'7] THEN error ← TRUE;
d ← d*8 + char-'0;
IF read = len THEN error ← TRUE
ELSE {
IF (char ← Get[]) NOT IN ['0..'7] THEN error ← TRUE;
d ← d*8 + char-'0 }};
char ← LOOPHOLE[d] };
ENDCASE => error ← TRUE;
text[write] ← char };
write ← write+1;
ENDLOOP;
text.length ← write;
RETURN [text,error] };
MakeOctal: PUBLIC PROC[text: LONG STRING] RETURNS[Object] = {
val: Basics.LongNumber ← [lc[0]];
neg: BOOLEANFALSE;
i: CARDINAL ← 0;
SELECT text[0] FROM '+ => { i ← 1 }; '- => { neg ← TRUE; i ← 1 }; ENDCASE;
FOR j: CARDINAL IN[i..text.length-1) DO
c: CHARACTER ← text[j];
use shifting to multiply by 8
val.highbits ← Basics.BITSHIFT[val.highbits,3] + Basics.BITSHIFT[val.lowbits,3-16];
val.lowbits ← Basics.BITSHIFT[val.lowbits,3];
IF c>'0 THEN val.lc ← val.lc + (c-'0);
ENDLOOP;
RETURN[[L,integer[IF neg THEN -val.li ELSE val.li]]];
};
MakeInteger: PUBLIC PROC[text: LONG STRING] RETURNS[Object] = {
val: LONG CARDINAL ← 0;
max: LONG CARDINAL = LAST[LONG CARDINAL];
lim: LONG CARDINAL = max/10; -- lim*10 <= max
int: LONG INTEGER;
neg: BOOLEANFALSE;
i: CARDINAL ← 0;
SELECT text[0] FROM '+ => { i ← 1 }; '- => { neg ← TRUE; i ← 1 }; ENDCASE;
FOR j: CARDINAL IN[i..text.length) WHILE val<max DO
c: CHARACTER ← text[j];
val ← IF val<=lim THEN val*10 ELSE max;
IF c>'0 THEN { d: CARDINAL ← c-'0; val ← IF d<(max-val) THEN val+d ELSE max };
ENDLOOP;
int ← LOOPHOLE[val]; IF neg THEN int ← -int;
IF (int<0)=neg THEN RETURN[[L,integer[int]]] ELSE RETURN[MakeReal[text]];
};
StringToRope: PROC
[text: LONG STRING, start: NAT ← 0, len: NATLAST[NAT]] RETURNS [ROPE] = {
IF text = NIL OR text.length = 0 THEN RETURN [NIL];
RETURN [Rope.Translate[LOOPHOLE[text], start, len, NIL]];
};
MakeReal: PUBLIC PROC[text: LONG STRING] RETURNS[Object] = {
ob: Object;
{ ENABLE Real.RealException, Convert.Error => TRUSTED { ob ← overflow; CONTINUE };
r: REAL ← Convert.RealFromRope[StringToRope[text]];
ob ← [L,real[r]] };
RETURN[ob];
};
StringToOctal: PUBLIC PROC[string: string Object] RETURNS[Object] = {
text: STRING ← [20];
IF string.length>text.maxlength THEN {
len: CARDINAL = text.maxlength;
VM.GetText[SubString[string,string.length-len,len],text];
text[0] ← VM.GetChar[string,0] } -- preserve sign
ELSE VM.GetText[string,text];
RETURN[MakeOctal[text]];
};
StringToInteger: PUBLIC PROC[string: string Object] RETURNS[Object] = {
text: STRING ← [20];
IF string.length>text.maxlength THEN RETURN[StringToReal[string]]
ELSE { VM.GetText[string,text]; RETURN[MakeInteger[text]] };
};
StringToReal: PUBLIC PROC[string: string Object] RETURNS[Object] = {
s: STRING ← [50];
JaMVM.GetText[string, s];
RETURN[MakeReal[s]];
};
One intrinsic
JToken: PUBLIC PROC[frame: Frame] = {
ob: Object ← Pop[frame.opstk];
found,error: BOOLEAN; tok,rem: Object;
WITH ob:ob SELECT FROM
string => [found,error,tok,rem] ← StringToken[frame,ob];
stream => {
s: StreamHandle ← GetStream[ob];
[found,error,tok] ← StreamToken[frame,s];
IF found THEN rem ← ob ELSE KillStream[ob];
};
ENDCASE => ERROR Error[typechk];
IF found THEN { Push[frame.opstk,rem]; Push[frame.opstk,tok] };
PushBoolean[frame.opstk, found];
ignores error flag
};
}...