<> <> <> <> <> <> <> DIRECTORY Ascii USING [Lower], BasicTime USING [GMT, OutOfRange, Pack, Unpacked], Convert, IO, RefText, 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; <> 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.GetChar[ ! 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.Backup[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] = { buffer.length _ 0; DO char: CHAR _ stream.GetChar[ ! IO.EndOfStream => IF buffer.length > 0 THEN EXIT ELSE REJECT]; IF char # IO.CR THEN buffer _ RefText.InlineAppendChar[buffer, char] ELSE EXIT; ENDLOOP; RETURN [buffer]; }; GetLineRope: PUBLIC PROC [stream: STREAM] RETURNS [line: ROPE] = { buffer: REF TEXT = RefText.ObtainScratch[100]; { ENABLE UNWIND => RefText.ReleaseScratch[buffer]; line _ Rope.FromRefText[GetLine[stream, buffer]]; }; RefText.ReleaseScratch[buffer]; RETURN [line]; }; SkipWhitespace: PUBLIC PROC [stream: STREAM, flushComments: BOOL] RETURNS [charsSkipped: INT] = { char: CHAR; { charsSkipped _ 0; DO char _ stream.GetChar[ ! IO.EndOfStream => GOTO End]; SELECT char FROM IN [IO.NUL .. IO.SP] => charsSkipped _ charsSkipped + 1; '- => { IF NOT flushComments THEN GOTO Backup; char _ stream.GetChar[ ! IO.EndOfStream => {stream.Backup[char]; GOTO End}]; IF char # '- THEN { -- false alarm, first minus is not start of comment stream.Backup[char]; char _ '-; GOTO Backup } ELSE { -- start of comment, consume rest of comment charsSkipped _ charsSkipped + 2; DO SELECT (char _ stream.GetChar[ ! IO.EndOfStream => GOTO End]) FROM '\n => EXIT; '- => { charsSkipped _ charsSkipped + 1; IF stream.GetChar[ ! IO.EndOfStream => GOTO End] = '- THEN EXIT; }; ENDCASE => charsSkipped _ charsSkipped + 1; ENDLOOP; charsSkipped _ charsSkipped + 1; }; }; ENDCASE => GOTO Backup; ENDLOOP; EXITS Backup => { stream.Backup[char]; RETURN [charsSkipped] }; End => RETURN [charsSkipped]; }}; <> 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.GetChar[]; token _ RefText.InlineAppendChar[token, char]; RETURN[Ascii.Lower[char]] }; PutbackChar: PROC = { stream.Backup[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] => { -- white space charsSkipped _ charsSkipped + 1; token.length _ 0; }; '- => {-- minus or comment 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] => { -- identifier tokenKind _ $tokenID; DO SELECT NextChar[ ! IO.EndOfStream => GOTO Return] FROM IN ['a..'z], IN ['0..'9] => NULL; ENDCASE => GOTO PutbackReturn; ENDLOOP; }; IN ['0 .. '9] => { -- numeric literal, this gets hairy 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 } }; '. => {-- either a dotdot or a REAL or a dot 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; }; ',, ';, ':, '_, '#, '~, '+, '*, '/, '^, '@, '!, '(, '), '[, '], '{, '}, '| => { tokenKind _ $tokenSINGLE; GOTO Return }; '\' => { -- CHAR literal tokenKind _ $tokenCHAR; SELECT NextChar[ ! IO.EndOfStream => GOTO Illegal] FROM '\\ => IF NOT AcceptExtendedChar[] THEN GOTO ErrorReturn ELSE GOTO Return; IN [' ..'~] => GOTO Return; ENDCASE => GOTO Illegal; EXITS Illegal => { error _ $charLiteral; GOTO ErrorReturn }; }; '\" => { -- ROPE, REF TEXT, or STRING literal quoteSeen: BOOL _ FALSE; tokenKind _ $tokenROPE; DO SELECT NextChar[ ! IO.EndOfStream => IF quoteSeen THEN GOTO Return ELSE GOTO Illegal] FROM '\" => quoteSeen _ NOT quoteSeen; '\\ => IF quoteSeen THEN EXIT ELSE IF NOT AcceptExtendedChar[] THEN GOTO ErrorReturn; IN [' ..'~], '\n, '\t => IF quoteSeen THEN EXIT; ENDCASE => GOTO Illegal; ENDLOOP; SELECT Ascii.Lower[char] FROM 'l => GOTO Return; ENDCASE => GOTO PutbackReturn; EXITS Illegal => { error _ $stringLiteral; GOTO ErrorReturn }; }; '$ => { -- ATOM literal 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; }; '= => { -- either '=' or '=>' tokenKind _ $tokenSINGLE; IF NextChar[ ! IO.EndOfStream => GOTO Return] = '> THEN GOTO DoubleReturn ELSE GOTO PutbackReturn }; '>, '< => { -- either '>' 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, negative: BOOL] = { 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]; RETURN [card, negative]; 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 [REF ANY] = { RightParen: ERROR = CODE; Comma: ERROR = CODE; GetRefAny0: PROC [stream: STREAM, buffer: REF TEXT] RETURNS [REF ANY] = { 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 => ERROR IO.Error[$SyntaxError, stream]; tokenID => RETURN[ IF Rope.Equal[RefText.TrustTextAsRope[token], "NIL"] THEN NIL ELSE IF Rope.Equal[RefText.TrustTextAsRope[token], "TRUE"] THEN NEW[BOOL _ TRUE] ELSE IF Rope.Equal[RefText.TrustTextAsRope[token], "FALSE"] THEN NEW[BOOL _ FALSE] ELSE 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 ANY _ NIL; obj: REF ANY; UNTIL IO.EndOf[stream] DO obj _ GetRefAny0[stream, buffer ! RightParen, IO.EndOfStream => EXIT; Comma => LOOP]; IF tail # NIL THEN {tail.rest _ LIST[obj]; tail _ tail.rest} ELSE {tail _ LIST[obj]; lst _ tail}; ENDLOOP; RETURN[lst]; }; ') => ERROR RightParen; '^ => NULL; -- e.g. ^3, makes print and read be inverses. ', => ERROR Comma; '-, '+ => {obj: REF ANY = GetRefAny0[stream, buffer]; WITH obj SELECT FROM x: REF INT => IF c = '- THEN x^ _ -x^; x: REF REAL => IF c = '- THEN x^ _ -x^; ENDCASE => ERROR IO.Error[$SyntaxError, stream]; RETURN[obj]; }; ENDCASE => ERROR IO.Error[$SyntaxError, stream]; }; tokenDOUBLE => ERROR IO.Error[$SyntaxError, stream]; tokenCOMMENT => NULL; tokenEOF => ERROR IO.EndOfStream[stream]; ENDCASE => ERROR; ENDLOOP; }; object: REF ANY; buffer: REF TEXT = RefText.ObtainScratch[512]; { object _ GetRefAny0[stream, buffer ! RightParen => ERROR IO.Error[$SyntaxError, stream]; Comma => ERROR IO.Error[$SyntaxError, stream]]; }; RefText.ReleaseScratch[buffer]; RETURN [object]; }; GetRefAnyLine: PUBLIC PROC [stream: STREAM] RETURNS [LIST OF REF ANY] = { lst, tail: LIST OF REF ANY _ NIL; lst _ tail _ LIST[GetRefAny[stream]]; UNTIL stream.EndOf[] DO IF stream.PeekChar[] = IO.CR THEN { [] _ stream.GetChar[]; EXIT }; tail.rest _ LIST[GetRefAny[stream]]; tail _ tail.rest; ENDLOOP; RETURN[lst]; }; END. <> <> <>