<> <> <> DIRECTORY Ascii USING [Lower], BasicTime USING [GMT, OutOfRange, Pack, Unpacked], Convert USING [AtomFromRope, BoolFromRope, CardFromDecimalLiteral, CardFromHexLiteral, CardFromOctalLiteral, CharFromLiteral, Error, IntFromRope, RealFromLiteral, RopeFromLiteral], IO USING [BreakProc, CR, EndOf, EndOfStream, Error, GetUnpackedTime, NUL, PeekChar, SP, STREAM, TokenError, TokenKind], RefText USING [InlineAppendChar, New, ObtainScratch, ReleaseScratch, TrustTextAsRope], Rope USING [Concat, Equal, FromRefText, ROPE]; IOScanImpl: CEDAR PROGRAM IMPORTS Ascii, BasicTime, Convert, IO, Rope, RefText EXPORTS IO = BEGIN STREAM: TYPE = IO.STREAM; ROPE: TYPE = Rope.ROPE; BreakProc: TYPE = IO.BreakProc; TokenKind: TYPE = IO.TokenKind; XDEleftArrow: CHAR = 254C; XDEupArrow: CHAR = 255C; <> GetToken: PUBLIC PROC [stream: STREAM, breakProc: BreakProc, buffer: REF TEXT] RETURNS [token: REF TEXT, charsSkipped: INT] = { quit, include: BOOL _ FALSE; anySeen: BOOL _ FALSE; charsSkipped _ 0; buffer.length _ 0; DO char: CHAR _ stream.streamProcs.getChar[stream ! IO.EndOfStream => IF buffer.length > 0 THEN EXIT ELSE REJECT]; SELECT breakProc[char] FROM break => {include _ NOT anySeen; quit _ TRUE}; sepr => {include _ FALSE; quit _ anySeen }; other => {include _ TRUE; quit _ FALSE; anySeen _ TRUE}; ENDCASE => ERROR; SELECT TRUE FROM include => {buffer _ RefText.InlineAppendChar[buffer, char]; IF quit THEN EXIT}; quit => {stream.streamProcs.backup[stream, char]; EXIT}; ENDCASE => charsSkipped _ charsSkipped + 1; ENDLOOP; RETURN[buffer, charsSkipped]; }; GetTokenRope: PUBLIC PROC [stream: STREAM, breakProc: BreakProc] RETURNS [token: ROPE, charsSkipped: INT] = { buffer: REF TEXT = RefText.ObtainScratch[100]; { ENABLE UNWIND => RefText.ReleaseScratch[buffer]; tokenText: REF TEXT; [tokenText, charsSkipped] _ GetToken[stream, breakProc, buffer]; token _ Rope.FromRefText[tokenText]; }; RefText.ReleaseScratch[buffer]; RETURN [token, charsSkipped]; }; IDProc: PUBLIC BreakProc = { RETURN[SELECT char FROM IN [IO.NUL .. IO.SP] => sepr, ',, ':, '; => sepr, ENDCASE => other]; }; TokenProc: PUBLIC BreakProc = { RETURN [SELECT char FROM '[, '], '(, '), '{, '}, '", '+, '-, '*, '/, '@, '_ => break, IN [IO.NUL .. IO.SP] => sepr, ',, ':, '; => sepr, ENDCASE => other]; }; GetLine: PUBLIC PROC [stream: STREAM, buffer: REF TEXT] RETURNS [line: REF TEXT] = { maxLen: NAT = LAST[NAT]; IF buffer = NIL THEN buffer _ RefText.New[100]; buffer.length _ 0; DO char: CHAR _ stream.streamProcs.getChar[stream ! IO.EndOfStream => IF buffer.length > 0 THEN EXIT ELSE REJECT]; IF char = '\n OR buffer.length = maxLen THEN EXIT; buffer _ RefText.InlineAppendChar[buffer, char]; ENDLOOP; RETURN [buffer]; }; GetLineRope: PUBLIC PROC [stream: STREAM] RETURNS [line: ROPE _ NIL] = { bufMax: NAT = 256; buffer: REF TEXT = RefText.ObtainScratch[bufMax]; bLen: NAT _ 0; chars: INT _ 0; { ENABLE UNWIND => RefText.ReleaseScratch[buffer]; DO char: CHAR _ stream.streamProcs.getChar[stream ! IO.EndOfStream => IF chars > 0 THEN EXIT ELSE REJECT]; IF char = '\n THEN EXIT; chars _ chars + 1; IF bLen = bufMax THEN { buffer.length _ bLen; line _ Rope.Concat[line, Rope.FromRefText[buffer]]; bLen _ 0; }; buffer[bLen] _ char; bLen _ bLen+1; ENDLOOP; }; buffer.length _ bLen; IF bLen # 0 THEN line _ Rope.Concat[line, Rope.FromRefText[buffer]]; RefText.ReleaseScratch[buffer]; RETURN [line]; }; SkipWhitespace: PUBLIC PROC [stream: STREAM, flushComments: BOOL] RETURNS [charsSkipped: INT _ 0] = { char: CHAR; charsSkipped _ 0; DO char _ stream.streamProcs.getChar[stream ! IO.EndOfStream => GOTO Done]; SELECT char FROM IN [IO.NUL .. IO.SP] => charsSkipped _ charsSkipped + 1; '- => { IF NOT flushComments THEN EXIT; char _ stream.streamProcs.getChar[stream ! IO.EndOfStream => EXIT]; IF char # '- THEN { <> stream.streamProcs.backup[stream, char]; char _ '-; EXIT} ELSE { <> charsSkipped _ charsSkipped + 2; DO char _ stream.streamProcs.getChar[stream ! IO.EndOfStream => GOTO Done]; SELECT char FROM '\n => EXIT; '- => { charsSkipped _ charsSkipped + 1; char _ stream.streamProcs.getChar[stream ! IO.EndOfStream => GOTO Done]; IF char = '- THEN EXIT; }; ENDCASE => charsSkipped _ charsSkipped + 1; ENDLOOP; charsSkipped _ charsSkipped + 1; }; }; ENDCASE => EXIT; ENDLOOP; stream.streamProcs.backup[stream, char]; EXITS Done => {}; }; <> GetCedarToken: PUBLIC PROC [stream: STREAM, buffer: REF TEXT, flushComments: BOOL _ FALSE] RETURNS [tokenKind: TokenKind, token: REF TEXT, charsSkipped: INT, error: IO.TokenError] = { char: CHAR; NextChar: PROC RETURNS [CHAR] = { char _ stream.streamProcs.getChar[stream]; token _ RefText.InlineAppendChar[token, char]; RETURN[Ascii.Lower[char]] }; PutbackChar: PROC = { stream.streamProcs.backup[stream, token[token.length _ token.length - 1]]; }; <> AcceptExtendedChar: PROC RETURNS [success: BOOL] = { <> ENABLE IO.EndOfStream => GOTO Failure; SELECT NextChar[] FROM 'n, 'r, 't, 'b, 'f, 'l, '\', '\", '\\ => RETURN[TRUE]; IN ['0..'9] => { THROUGH [1..2] DO IF NextChar[] NOT IN ['0..'9] THEN GOTO Failure ENDLOOP; RETURN[TRUE]; }; ENDCASE EXITS Failure => { error _ $extendedChar; RETURN[FALSE] } }; AcceptRealTail: PROC [] = { <> DO SELECT NextChar[ ! IO.EndOfStream => GOTO Accept] FROM IN ['0..'9] => NULL; 'e => { [] _ AcceptExponent[]; RETURN }; ENDCASE => { PutbackChar[]; RETURN }; ENDLOOP; EXITS Accept => RETURN }; AcceptExponent: PROC RETURNS [success: BOOL] = { <> SELECT NextChar[ ! IO.EndOfStream => GOTO Failure] FROM '-, '+ => [] _ NextChar[ ! IO.EndOfStream => GOTO Failure]; ENDCASE => NULL; IF char NOT IN ['0..'9] THEN GOTO Failure; DO IF NextChar[ ! IO.EndOfStream => GOTO Success] NOT IN ['0..'9] THEN { PutbackChar[]; GOTO Success } ENDLOOP; EXITS Success => RETURN [TRUE]; Failure => { error _ $numericLiteral; RETURN [FALSE] }; }; AcceptHexTail: PROC [] RETURNS [success: BOOL] = { <> <> length: NAT = token.length; { DO SELECT NextChar[ ! IO.EndOfStream => GOTO Undo] FROM IN ['0..'9], IN ['a..'f] => NULL; 'h => EXIT; ENDCASE => GOTO Undo; ENDLOOP; WHILE NextChar[ ! IO.EndOfStream => GOTO Accept] IN ['0..'9] DO ENDLOOP; GOTO PutbackAccept; EXITS Accept => { tokenKind _ $tokenHEX; RETURN [TRUE] }; PutbackAccept => { PutbackChar[]; tokenKind _ $tokenHEX; RETURN [TRUE] }; Undo => { FOR i: NAT DECREASING IN [length .. token.length) DO PutbackChar[] ENDLOOP; token.length _ length; RETURN [FALSE] } } }; error _ $none; token _ buffer; token.length _ 0; charsSkipped _ 0; { -- EXITS ErrorReturn, DoubleReturn, Return, PutbackReturn, EOFReturn DO -- first arm loops, second may loop; others terminate SELECT NextChar[ ! IO.EndOfStream => GOTO EOFReturn] FROM IN [IO.NUL .. IO.SP] => { <> charsSkipped _ charsSkipped + 1; token.length _ 0; }; '- => { <> prev: CHAR _ IO.CR; endOfComment: BOOL _ FALSE; tokenKind _ $tokenSINGLE; IF NextChar[ ! IO.EndOfStream => GOTO Return] # '- THEN GOTO PutbackReturn; tokenKind _ $tokenCOMMENT; IF flushComments THEN { charsSkipped _ charsSkipped + 1; token.length _ 0 }; DO { SELECT NextChar[ ! IO.EndOfStream => GOTO EndOfStream] FROM IO.CR => endOfComment _ TRUE; '- => IF prev = '- THEN endOfComment _ TRUE; ENDCASE; IF flushComments THEN { charsSkipped _ charsSkipped + 1; token.length _ 0 }; EXITS EndOfStream => endOfComment _ TRUE }; IF endOfComment THEN IF flushComments THEN EXIT ELSE GOTO Return; prev _ char; ENDLOOP; }; IN ['a .. 'z] => { <> tokenKind _ $tokenID; DO SELECT NextChar[ ! IO.EndOfStream => GOTO Return] FROM IN ['a..'z], IN ['0..'9] => NULL; ENDCASE => GOTO PutbackReturn; ENDLOOP; }; IN ['0 .. '9] => { <> tokenKind _ $tokenDECIMAL; WHILE NextChar[ ! IO.EndOfStream => GOTO Return] IN ['0..'9] DO ENDLOOP; SELECT Ascii.Lower[char] FROM '. => { IF NextChar[ ! IO.EndOfStream => GOTO Invalid] IN ['0 .. '9] THEN { -- REAL tokenKind _ $tokenREAL; AcceptRealTail[]; GOTO Return } ELSE { -- DECIMAL followed by dotdot PutbackChar[]; GOTO PutbackReturn } }; 'a, 'f => { IF AcceptHexTail[] THEN GOTO Return ELSE GOTO Invalid; }; 'b, 'd => { IF Ascii.Lower[char] = 'b THEN tokenKind _ $tokenOCTAL; IF AcceptHexTail[] THEN GOTO Return; WHILE NextChar[ ! IO.EndOfStream => GOTO Return] IN ['0..'9] DO ENDLOOP; GOTO PutbackReturn; }; 'c => { IF AcceptHexTail[] THEN GOTO Return; tokenKind _ $tokenCHAR; GOTO Return; }; 'e => { IF AcceptHexTail[] THEN GOTO Return; IF AcceptExponent[] THEN { tokenKind _ $tokenREAL; GOTO Return } ELSE GOTO ErrorReturn; }; 'h => { tokenKind _ $tokenHEX; WHILE NextChar[ ! IO.EndOfStream => GOTO Return] IN ['0..'9] DO ENDLOOP; GOTO PutbackReturn; }; ENDCASE => GOTO PutbackReturn; EXITS Invalid => { error _ $numericLiteral; GOTO ErrorReturn } }; '. => { <> tokenKind _ $tokenSINGLE; SELECT NextChar[ ! IO.EndOfStream => GOTO Return] FROM '. => GOTO DoubleReturn; -- dotdot IN ['0..'9] => NULL; -- REAL ENDCASE => GOTO PutbackReturn; -- dot tokenKind _ $tokenREAL; AcceptRealTail[]; GOTO Return; }; ',, ';, ':, '_, '#, '~, '+, '*, '/, '^, '@, '!, '(, '), '[, '], '{, '}, '|, XDEleftArrow, XDEupArrow => { tokenKind _ $tokenSINGLE; GOTO Return }; '\' => { <> tokenKind _ $tokenCHAR; SELECT NextChar[ ! IO.EndOfStream => GOTO Illegal] FROM '\\ => IF NOT AcceptExtendedChar[] THEN GOTO ErrorReturn ELSE GOTO Return; IN [' ..'~], XDEleftArrow, XDEupArrow => GOTO Return; ENDCASE => GOTO Illegal; EXITS Illegal => { error _ $charLiteral; GOTO ErrorReturn }; }; '\" => { <> quoteSeen: BOOL _ FALSE; tokenKind _ $tokenROPE; DO c: CHAR _ NextChar[ ! IO.EndOfStream => IF quoteSeen THEN GOTO Return ELSE GOTO Illegal]; SELECT c FROM '\" => quoteSeen _ NOT quoteSeen; '\\ => IF quoteSeen THEN EXIT ELSE IF NOT AcceptExtendedChar[] THEN GOTO ErrorReturn; IN [' ..'~], '\n, '\t, XDEleftArrow, XDEupArrow => IF quoteSeen THEN EXIT; ENDCASE => GOTO Illegal; ENDLOOP; SELECT char FROM 'l, 'L => GOTO Return; ENDCASE => GOTO PutbackReturn; EXITS Illegal => { error _ $stringLiteral; GOTO ErrorReturn }; }; '$ => { <> tokenKind _ $tokenATOM; { SELECT NextChar[ ! IO.EndOfStream => GOTO Invalid] FROM IN ['a..'z] => NULL; ENDCASE => GOTO Invalid; EXITS Invalid => { error _ $atomLiteral; GO TO ErrorReturn }; }; DO SELECT NextChar[ ! IO.EndOfStream => GOTO Return] FROM IN ['a..'z], IN ['0..'9] => NULL; ENDCASE => GOTO PutbackReturn; ENDLOOP; }; '= => { <'>> tokenKind _ $tokenSINGLE; IF NextChar[ ! IO.EndOfStream => GOTO Return] = '> THEN GOTO DoubleReturn ELSE GOTO PutbackReturn }; '>, '< => { <' or '>=' (or '<' or '<=')>> tokenKind _ $tokenSINGLE; IF NextChar[ ! IO.EndOfStream => GOTO Return] = '= THEN GOTO DoubleReturn ELSE GOTO PutbackReturn }; ENDCASE => { error _ $singleChar; GOTO ErrorReturn }; ENDLOOP; EXITS Return => { RETURN }; PutbackReturn => { PutbackChar[]; RETURN }; DoubleReturn => { tokenKind _ $tokenDOUBLE; RETURN }; EOFReturn => { tokenKind _ $tokenEOF; RETURN }; ErrorReturn => { tokenKind _ $tokenERROR; RETURN }; } }; GetCedarTokenRope: PUBLIC PROC [stream: STREAM, flushComments: BOOL] RETURNS [tokenKind: TokenKind, token: ROPE, charsSkipped: INT] = { buffer: REF TEXT = RefText.ObtainScratch[100]; { ENABLE UNWIND => RefText.ReleaseScratch[buffer]; tokenText: REF TEXT; [tokenKind: tokenKind, token: tokenText, charsSkipped: charsSkipped] _ GetCedarToken[stream, buffer, flushComments]; SELECT tokenKind FROM tokenEOF => ERROR IO.EndOfStream[stream]; tokenERROR => ERROR IO.Error[$SyntaxError, stream]; ENDCASE; token _ Rope.FromRefText[tokenText]; }; RefText.ReleaseScratch[buffer]; RETURN [tokenKind, token, charsSkipped]; }; <>> GetInt: PUBLIC PROC [stream: STREAM] RETURNS [INT] = { LastInt: LONG CARDINAL = INT.LAST; card: LONG CARDINAL; negative: BOOL; [card, negative] _ GetNumber[stream, TRUE]; IF negative THEN { IF card <= LastInt+1 THEN RETURN[-card] } ELSE { IF card <= LastInt THEN RETURN[card] }; ERROR IO.Error[$Overflow, stream]; }; GetCard: PUBLIC PROC [stream: STREAM] RETURNS [LONG CARDINAL] = { RETURN[GetNumber[stream, FALSE].card]; }; GetNumber: PUBLIC PROC [stream: STREAM, negativeOK: BOOL] RETURNS [card: LONG CARDINAL _ 0, negative: BOOL _ FALSE] = { tokenKind: TokenKind; token: REF TEXT; signSeen: BOOL _ FALSE; buffer: REF TEXT = RefText.ObtainScratch[100]; negative _ FALSE; { ENABLE Convert.Error => IF reason = $overflow THEN GOTO Overflow; <> DO -- executed once or twice [tokenKind: tokenKind, token: token] _ GetCedarToken[stream, buffer, TRUE]; SELECT tokenKind FROM tokenDECIMAL => { card _ Convert.CardFromDecimalLiteral[RefText.TrustTextAsRope[token]]; EXIT }; tokenOCTAL => { card _ Convert.CardFromOctalLiteral[RefText.TrustTextAsRope[token]]; EXIT }; tokenHEX => { card _ Convert.CardFromHexLiteral[RefText.TrustTextAsRope[token]]; EXIT }; tokenSINGLE => { IF signSeen THEN GOTO SyntaxError; signSeen _ TRUE; SELECT token[0] FROM '- => IF negativeOK THEN negative _ TRUE ELSE GOTO SyntaxError; '+ => NULL; ENDCASE => GOTO SyntaxError; }; tokenEOF => IF signSeen THEN GOTO SyntaxError ELSE GOTO EndOfStream; ENDCASE => GOTO SyntaxError; ENDLOOP; RefText.ReleaseScratch[buffer]; EXITS EndOfStream => { RefText.ReleaseScratch[buffer]; ERROR IO.EndOfStream[stream] }; SyntaxError => { RefText.ReleaseScratch[buffer]; ERROR IO.Error[$SyntaxError, stream] }; Overflow => { RefText.ReleaseScratch[buffer]; ERROR IO.Error[$Overflow, stream] }; }; }; GetReal: PUBLIC PROC [stream: STREAM] RETURNS [REAL] = { tokenKind: TokenKind; token: REF TEXT; signSeen, negative: BOOL _ FALSE; real: REAL; buffer: REF TEXT = RefText.ObtainScratch[100]; { DO -- executed once or twice <> [tokenKind: tokenKind, token: token] _ GetCedarToken[stream, buffer, TRUE]; SELECT tokenKind FROM tokenDECIMAL => { real _ Convert.CardFromDecimalLiteral[RefText.TrustTextAsRope[token]]; EXIT }; tokenOCTAL => { real _ Convert.CardFromOctalLiteral[RefText.TrustTextAsRope[token]]; EXIT }; tokenHEX => { real _ Convert.CardFromHexLiteral[RefText.TrustTextAsRope[token]]; EXIT }; tokenREAL => { real _ Convert.RealFromLiteral[RefText.TrustTextAsRope[token]]; EXIT }; tokenSINGLE => { IF signSeen THEN GOTO SyntaxError; signSeen _ TRUE; SELECT token[0] FROM '- => negative _ TRUE; '+ => NULL; ENDCASE => GOTO SyntaxError; }; tokenEOF => IF signSeen THEN GOTO SyntaxError ELSE GOTO EndOfStream; ENDCASE => GOTO SyntaxError; ENDLOOP; RefText.ReleaseScratch[buffer]; RETURN [IF negative THEN -real ELSE real]; EXITS EndOfStream => { RefText.ReleaseScratch[buffer]; ERROR IO.EndOfStream[stream] }; SyntaxError => { RefText.ReleaseScratch[buffer]; ERROR IO.Error[$SyntaxError, stream] }; }; }; GetTime: PUBLIC PROC [stream: STREAM] RETURNS [BasicTime.GMT] = { RETURN[BasicTime.Pack[stream.GetUnpackedTime[] ! BasicTime.OutOfRange => ERROR IO.Error[$Overflow, stream]]]; }; GetBool: PUBLIC PROC [stream: STREAM] RETURNS [bool: BOOL] = { tokenKind: TokenKind; token: REF TEXT; buffer: REF TEXT = RefText.ObtainScratch[100]; [tokenKind: tokenKind, token: token] _ GetCedarToken[stream, buffer, TRUE]; SELECT tokenKind FROM tokenID => NULL; tokenEOF => ERROR IO.EndOfStream[stream]; ENDCASE => ERROR IO.Error[$SyntaxError, stream]; bool _ Convert.BoolFromRope[RefText.TrustTextAsRope[token] ! Convert.Error => IF reason = $syntax THEN ERROR IO.Error[$SyntaxError, stream]]; RefText.ReleaseScratch[buffer]; }; GetAtom: PUBLIC PROC [stream: STREAM] RETURNS [atom: ATOM] = { tokenKind: TokenKind; token: REF TEXT; buffer: REF TEXT = RefText.ObtainScratch[100]; [tokenKind: tokenKind, token: token] _ GetCedarToken[stream, buffer, TRUE]; SELECT tokenKind FROM tokenID => NULL; tokenATOM => NULL; tokenEOF => ERROR IO.EndOfStream[stream]; ENDCASE => ERROR IO.Error[$SyntaxError, stream]; atom _ Convert.AtomFromRope[RefText.TrustTextAsRope[token] ! Convert.Error => IF reason = $syntax THEN ERROR IO.Error[$SyntaxError, stream]]; RefText.ReleaseScratch[buffer]; }; GetRopeLiteral: PUBLIC PROC [stream: STREAM] RETURNS [r: ROPE] = { tokenKind: TokenKind; token: REF TEXT; buffer: REF TEXT = RefText.ObtainScratch[100]; [tokenKind: tokenKind, token: token] _ GetCedarToken[stream, buffer, TRUE]; SELECT tokenKind FROM tokenROPE => NULL; tokenEOF => ERROR IO.EndOfStream[stream]; ENDCASE => ERROR IO.Error[$SyntaxError, stream]; r _ Convert.RopeFromLiteral[RefText.TrustTextAsRope[token]]; RefText.ReleaseScratch[buffer]; }; GetCharLiteral: PUBLIC PROC [stream: STREAM] RETURNS [c: CHAR] = { tokenKind: TokenKind; token: REF TEXT; buffer: REF TEXT = RefText.ObtainScratch[100]; [tokenKind: tokenKind, token: token] _ GetCedarToken[stream, buffer, TRUE]; SELECT tokenKind FROM tokenCHAR => NULL; tokenEOF => ERROR IO.EndOfStream[stream]; ENDCASE => ERROR IO.Error[$SyntaxError, stream]; c _ Convert.CharFromLiteral[RefText.TrustTextAsRope[token] ! Convert.Error => IF reason = $overflow THEN ERROR IO.Error[$Overflow, stream]]; RefText.ReleaseScratch[buffer]; }; GetID: PUBLIC PROC [stream: STREAM] RETURNS [r: ROPE] = { tokenKind: TokenKind; token: REF TEXT; buffer: REF TEXT = RefText.ObtainScratch[100]; [tokenKind: tokenKind, token: token] _ GetCedarToken[stream, buffer, TRUE]; SELECT tokenKind FROM tokenID => NULL; tokenEOF => ERROR IO.EndOfStream[stream]; ENDCASE => ERROR IO.Error[$SyntaxError, stream]; r _ Rope.FromRefText[token]; RefText.ReleaseScratch[buffer]; }; <> GetRefAny: PUBLIC PROC [stream: STREAM] RETURNS [object: REF _ NIL] = { RightParen: ERROR = CODE; Comma: ERROR = CODE; GetRefAny0: PROC [stream: STREAM, buffer: REF TEXT] RETURNS [REF] = { ENABLE Convert.Error => IF reason = $syntax THEN ERROR IO.Error[$SyntaxError, stream] ELSE IF reason = $overflow THEN ERROR IO.Error[$Overflow, stream]; tokenKind: IO.TokenKind; token: REF TEXT; DO [tokenKind: tokenKind, token: token] _ GetCedarToken[stream, buffer, TRUE]; SELECT tokenKind FROM tokenERROR => GO TO syntax; tokenID => { SELECT TRUE FROM Rope.Equal[RefText.TrustTextAsRope[token], "NIL"] => RETURN [NIL]; Rope.Equal[RefText.TrustTextAsRope[token], "TRUE"] => RETURN[NEW[BOOL _ TRUE]]; Rope.Equal[RefText.TrustTextAsRope[token], "FALSE"] => RETURN[NEW[BOOL _ FALSE]]; ENDCASE => RETURN [Convert.AtomFromRope[RefText.TrustTextAsRope[token]]]; }; IN [tokenDECIMAL .. tokenHEX] => RETURN[ NEW[INT _ Convert.IntFromRope[RefText.TrustTextAsRope[token]]]]; tokenREAL => RETURN[ NEW[REAL _ Convert.RealFromLiteral[RefText.TrustTextAsRope[token]]]]; tokenROPE => RETURN[Convert.RopeFromLiteral[RefText.TrustTextAsRope[token]]]; tokenCHAR => RETURN[ NEW[CHAR _ Convert.CharFromLiteral[RefText.TrustTextAsRope[token]]]]; tokenATOM => RETURN[Convert.AtomFromRope[RefText.TrustTextAsRope[token]]]; tokenSINGLE => { c: CHAR = token[0]; SELECT c FROM '( => { lst, tail: LIST OF REF _ NIL; obj: REF; UNTIL IO.EndOf[stream] DO new: LIST OF REF _ NIL; obj _ GetRefAny0[stream, buffer ! RightParen, IO.EndOfStream => EXIT; Comma => LOOP]; new _ LIST[obj]; IF tail # NIL THEN tail.rest _ new ELSE lst _ new; tail _ new; ENDLOOP; RETURN[lst]; }; ') => ERROR RightParen; '^ => NULL; -- e.g. ^3, makes print and read be inverses. ', => ERROR Comma; '-, '+ => { obj: REF = GetRefAny0[stream, buffer]; WITH obj SELECT FROM x: REF INT => IF c = '- THEN x^ _ -x^; x: REF REAL => IF c = '- THEN x^ _ -x^; ENDCASE => GO TO syntax; RETURN[obj]; }; ENDCASE => GO TO syntax; }; tokenDOUBLE => GO TO syntax; tokenCOMMENT => NULL; tokenEOF => ERROR IO.EndOfStream[stream]; ENDCASE => ERROR; ENDLOOP; EXITS syntax => ERROR IO.Error[$SyntaxError, stream]; }; buffer: REF TEXT = RefText.ObtainScratch[100]; object _ GetRefAny0[stream, buffer ! RightParen, Comma => { RefText.ReleaseScratch[buffer]; ERROR IO.Error[$SyntaxError, stream]}]; RefText.ReleaseScratch[buffer]; }; GetRefAnyLine: PUBLIC PROC [stream: STREAM] RETURNS [LIST OF REF] = { lst, tail: LIST OF REF _ NIL; lst _ tail _ LIST[GetRefAny[stream]]; UNTIL stream.EndOf[] DO IF stream.PeekChar[] = IO.CR THEN { [] _ stream.streamProcs.getChar[stream]; EXIT }; tail.rest _ LIST[GetRefAny[stream]]; tail _ tail.rest; ENDLOOP; RETURN[lst]; }; END. <> <> <<>> <<>>