-- FILE: ParseImpl.mesa -- Last edited by John Ousterhout, January 24, 1984 1:06 pm 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.STREAM ← NIL; 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: INTEGER ← LENGTH[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.