FILE: ParseImpl.mesa
Last edited by John Ousterhout, January 24, 1984 1:06 pm
Christian LeCocq April 29, 1986 1:08:52 pm PDT
DIRECTORY
Globals,
IO,
Parse,
Rope;
ParseImpl: CEDAR PROGRAM
IMPORTS
IO,
Rope
EXPORTS Parse =
BEGIN
OPEN Parse, Globals;
Args: PUBLIC PROC[line: Rope.ROPE] RETURNS [Arg] =
BEGIN
result: Arg ← NIL;
prev: Arg ← NIL;
cur: Arg;
stream: IO.STREAMNIL;
token1, token2: Rope.ROPE;
length: INT;
Turn the rope into a stream, then strip off the arguments one at a time.
stream ← IO.RIS[line];
WHILE TRUE DO
ENABLE IO.EndOfStream => EXIT;
token2 ← NIL;
[token: token1] ← IO.GetTokenRope[stream, WhiteSpace];
IF token1 = NIL THEN LOOP;
Things are a bit tricky if the first letter of the token is "-". In this case, the argument could be either a switch (like in Unix, remember?), or it could signify the beginning of a comment. If it's not a comment, make sure that the rope doesn't contain more than one more character, and if it does then chop off the stuff after the first character into a separate token.
length ← Rope.Length[token1];
IF length >= 2 THEN
IF (Rope.Fetch[token1, 0] = '-) AND (Rope.Fetch[token1, 1] = '-)
THEN EXIT;
IF (Rope.Fetch[token1, 0] = '-) AND (length > 2) THEN
BEGIN
token2 ← Rope.Substr[base: token1, start: 2, len: length-2];
token1 ← Rope.Substr[base: token1, start: 0, len: 2];
END;
Generate either one or two Arg objects for the token(s).
cur ← NEW[ArgRec];
cur.rope ← token1;
IF result = NIL THEN result ← cur;
IF prev # NIL THEN prev.next ← cur;
prev ← cur;
IF token2 # NIL THEN
BEGIN
cur ← NEW[ArgRec];
cur.rope ← token2;
prev.next ← cur;
prev ← cur;
END;
ENDLOOP;
RETURN [result];
END;
Real: PUBLIC PROC[arg: Arg] RETURNS [parseOK: BOOLEAN, val: REAL] =
BEGIN
ENABLE ANY =>
BEGIN
parseOK ← FALSE;
val ← 0.0;
CONTINUE;
END;
IF arg = NIL THEN RETURN [FALSE, 0.0];
val ← IO.GetReal[IO.RIS[arg.rope]];
RETURN [TRUE, val];
END;
Int: PUBLIC PROC[arg: Arg] RETURNS [parseOK: BOOLEAN, val: INT] =
BEGIN
ENABLE ANY =>
BEGIN
parseOK ← FALSE;
val ← 0;
CONTINUE;
END;
IF arg = NIL THEN RETURN [FALSE, 0];
val ← IO.GetInt[IO.RIS[arg.rope]];
RETURN [TRUE, val];
END;
Lookup: PUBLIC PROC[rope: Rope.ROPE,
table: DESCRIPTOR FOR ARRAY OF Rope.ROPE]
RETURNS [index: INT] =
TRUSTED BEGIN
botIndex: INTEGER ← 0;
topIndex: INTEGERLENGTH[table] - 1;
char: CHAR;
The search is carried out using two indices into the table. One index marches up from the start of the table, one marches down from the back of the table. The two indices delimit the entries of the table whose first characters match the part of rope that we've examined (this only works if the table is ordered monotonically). To do the match, we examine characters of rope one at a time, squeezing the indices together until we've got a match.
FOR i: INTEGER IN [0..1000) DO
IF i >= Rope.Length[rope] THEN
BEGIN
IF botIndex = topIndex THEN RETURN [botIndex];
RETURN [-1];
END;
char ← Rope.Fetch[rope, i];
Move botIndex up until we find a table entry that matches the current character of rope.
WHILE TRUE DO
IF Rope.Length[table[botIndex]] > i THEN
IF Rope.Fetch[table[botIndex], i] = char THEN EXIT;
IF botIndex = topIndex THEN RETURN [-2];
botIndex ← botIndex + 1;
ENDLOOP;
Move topIndex down until we find a table entry that matches the current character of rope.
WHILE TRUE DO
IF Rope.Length[table[topIndex]] > i THEN
IF Rope.Fetch[table[topIndex], i] = char THEN EXIT;
IF botIndex = topIndex THEN RETURN [-2];
topIndex ← topIndex - 1;
ENDLOOP;
ENDLOOP;
RETURN [-2];
END;
WhiteSpace: PUBLIC IO.BreakProc =
BEGIN
IF (char = IO.CR) OR (char = IO.TAB) OR (char = IO.LF)
OR (char = IO.SP) THEN RETURN [sepr]
ELSE RETURN[other];
END;
END.