<<>> <> <> <> <> <> <<>> DIRECTORY Atom, Convert, EBMesaLisp, EmbeddedButtons, IO, RefText, Rope, RuntimeError; EBMesaLispImpl: CEDAR PROGRAM IMPORTS Atom, Convert, EmbeddedButtons, IO, RefText, Rope, RuntimeError EXPORTS EBMesaLisp = BEGIN ROPE: TYPE = Rope.ROPE; Parse: PUBLIC PROC [stream: IO.STREAM] RETURNS [val: REF ¬ NIL, endOfStream: BOOL ¬ FALSE] = { tokenKind: IO.TokenKind; token, firstToken: REF TEXT; charsSkipped: INT; done: BOOL ¬ FALSE; error: IO.TokenError; IF IO.EndOf[stream] THEN RETURN[NIL, TRUE]; firstToken ¬ token ¬ RefText.ObtainScratch[nChars: 100]; [tokenKind, token, charsSkipped, error] ¬ IO.GetCedarToken[stream, token]; IF tokenKind = tokenEOF THEN done ¬ TRUE ELSE IF error # none THEN { EmbeddedButtons.Error[IO.PutFR1["IO Syntax error at character %g", [integer[stream.GetIndex[]]] ]]; done ¬ TRUE; }; IF done THEN { RefText.ReleaseScratch[firstToken]; RETURN[NIL, TRUE]; }; SELECT tokenKind FROM tokenERROR => ERROR; tokenID => { IF RefText.Equal[token, "TRUE"] THEN val ¬ NEW[BOOL ¬ TRUE] ELSE IF RefText.Equal[token, "FALSE"] THEN val ¬ NEW[BOOL ¬ FALSE] ELSE val ¬ Atom.MakeAtomFromRefText[token]; }; tokenDECIMAL => val ¬ NEW[INT ¬ Convert.IntFromRope[RefText.TrustTextAsRope[token], 10]]; tokenOCTAL => val ¬ NEW[INT ¬ Convert.IntFromRope[RefText.TrustTextAsRope[token], 8]]; tokenHEX => val ¬ NEW[INT ¬ Convert.IntFromRope[RefText.TrustTextAsRope[token], 16]]; tokenREAL => val ¬ NEW[REAL ¬ Convert.RealFromRope[RefText.TrustTextAsRope[token]]]; tokenROPE => { <> val ¬ Convert.RopeFromLiteral[RefText.TrustTextAsRope[token]]; }; tokenCHAR => { <> val ¬ Rope.FromChar[RefText.Fetch[token, 0 ! RuntimeError.BoundsFault => {val ¬ Rope.FromChar['Z]; CONTINUE}]]; }; tokenATOM => { <> val ¬ Convert.AtomFromRope[RefText.TrustTextAsRope[token]]; }; tokenSINGLE => { <> IF RefText.Equal[token, "("] THEN val ¬ GetList[stream, closeParenAtom] ELSE IF RefText.Equal[token, "["] THEN val ¬ GetList[stream, closeBracketAtom] ELSE IF RefText.Equal[token, "{"] THEN val ¬ GetList[stream, closeCurlyBracketAtom] ELSE IF RefText.Equal[token, "<"] THEN val ¬ GetExecuteList[stream] ELSE IF RefText.Equal[token, ")"] THEN val ¬ closeParenAtom ELSE IF RefText.Equal[token, "]"] THEN val ¬ closeBracketAtom ELSE IF RefText.Equal[token, "}"] THEN val ¬ closeCurlyBracketAtom ELSE IF RefText.Equal[token, ">"] THEN val ¬ closeAngleBracketAtom ELSE val ¬ Convert.AtomFromRope[RefText.TrustTextAsRope[token]]; -- should include *, /, + and - }; tokenDOUBLE => { <>> }; tokenCOMMENT => ERROR; tokenEOF => val ¬ NIL; ENDCASE => ERROR; RefText.ReleaseScratch[firstToken]; }; Unparse: PUBLIC PROC [object: REF ANY, prettyPrintList: LIST OF REF ANY ¬ NIL] RETURNS [result: ROPE] = { first: BOOL; listObject: LIST OF REF ANY; executeObject: BOOL ¬ FALSE; insert: ROPE ¬ NIL; insertFirst: BOOL ¬ FALSE; prettyPrintListRest: LIST OF REF ANY ¬ NIL; IF object = NIL THEN { result ¬ "()"; RETURN; } ELSE IF NOT ISTYPE[object, LIST OF REF ANY] THEN { result ¬ WITH object SELECT FROM v: REF BOOL => Convert.RopeFromBool[v­], v: REF INT => Convert.RopeFromInt[v­], v: REF REAL => Convert.RopeFromReal[v­], v: ATOM => Atom.GetPName[v], v: ROPE => Rope.Cat["\"", v, "\""], ENDCASE => ""; RETURN; }; listObject ¬ NARROW[object]; IF ISTYPE[listObject.first, ATOM] AND NARROW[listObject.first, ATOM] = $Execute THEN { listObject ¬ listObject.rest; result ¬ "<"; executeObject ¬ TRUE; } ELSE result ¬ "("; IF prettyPrintList # NIL THEN { IF ISTYPE[prettyPrintList.first, ROPE] THEN insert ¬ NARROW[prettyPrintList.first]; IF prettyPrintList.rest # NIL THEN { IF ISTYPE[prettyPrintList.rest.first, REF BOOL] THEN insertFirst ¬ NARROW[prettyPrintList.rest.first, REF BOOL]­; prettyPrintListRest ¬ prettyPrintList.rest.rest; }; }; first ¬ TRUE; FOR l: LIST OF REF ANY ¬ NARROW[listObject], l.rest UNTIL l = NIL DO IF insert # NIL AND (NOT first OR insertFirst) THEN result ¬ Rope.Concat[result, insert]; IF insert = NIL AND NOT first THEN result ¬ Rope.Concat[result, " "]; result ¬ Rope.Concat[result, Unparse[l.first, prettyPrintListRest]]; first ¬ FALSE; ENDLOOP; IF executeObject THEN result ¬ Rope.Concat[result, ">"] ELSE result ¬ Rope.Concat[result, ")"]; RETURN; }; ParseAborted: PUBLIC SIGNAL = CODE; SyntaxError: PUBLIC PROC [stream: IO.STREAM, msg: ROPE] = { EmbeddedButtons.Error[msg, NIL]; SIGNAL ParseAborted; }; <> GetList: PROC [stream: IO.STREAM, nestingAtom: ATOM] RETURNS [list: LIST OF REF ¬ NIL] = { <> val: REF ¬ NIL; endOfStream: BOOL ¬ FALSE; tail: LIST OF REF ¬ NIL; WHILE ~stream.EndOf[] DO [val, endOfStream] ¬ Parse[stream]; -- get the next token IF endOfStream THEN LOOP ELSE IF val = nestingAtom THEN EXIT; [list, tail] ¬ AddEntity[val, list, tail]; ENDLOOP; }; GetExecuteList: PROC [stream: IO.STREAM] RETURNS [list: LIST OF REF ¬ NIL] = { last: REF ANY ¬ NIL; endOfStream: BOOL ¬ FALSE; tail: LIST OF REF ANY ¬ NIL; [list, tail] ¬ AddEntity[$Execute, list, tail]; WHILE ~stream.EndOf[] DO [last, endOfStream] ¬ Parse[stream]; IF endOfStream THEN LOOP ELSE IF last = closeAngleBracketAtom THEN EXIT; [list, tail] ¬ AddEntity[last, list, tail]; ENDLOOP; }; Member: PUBLIC PROC [list: LIST OF ATOM, member: REF ANY] RETURNS[isMember: BOOL ¬ FALSE, tail: LIST OF ATOM] = { FOR l: LIST OF ATOM ¬ list, l.rest UNTIL l = NIL DO tail ¬ l; IF l.first = member THEN { isMember ¬ TRUE; RETURN; } ENDLOOP; }; AddEntity: PUBLIC PROC [entity: REF ANY, entityList, ptr: LIST OF REF ANY] RETURNS [newList, newPtr: LIST OF REF ANY] = { IF ptr = NIL THEN { IF NOT entityList = NIL THEN ERROR; newPtr ¬ newList ¬ CONS[entity, NIL]; RETURN; } ELSE { newList ¬ entityList; ptr.rest ¬ CONS[entity, NIL]; newPtr ¬ ptr.rest; }; }; <> ReadRopeInParens: PUBLIC PROC [stream: IO.STREAM] RETURNS [rope: ROPE ¬ NIL] = { level: NAT ¬ 1; scratch, text: REF TEXT; c: CHAR; scratch ¬ text ¬ RefText.ObtainScratch[512]; -- numbers larger than 512 always allocate (yuk!) c ¬ stream.GetChar[]; text ¬ RefText.InlineAppendChar[text, c]; UNTIL level = 0 OR stream.EndOf[] DO c ¬ stream.GetChar[]; text ¬ RefText.InlineAppendChar[text, c]; IF c = '( THEN level ¬ level + 1 ELSE IF c = ') THEN level ¬ level - 1; ENDLOOP; rope ¬ Rope.FromRefText[text]; RefText.ReleaseScratch[scratch]; }; ReadRopeInAngleBrackets: PUBLIC PROC [stream: IO.STREAM] RETURNS [rope: ROPE ¬ NIL] = { level: NAT ¬ 1; scratch, text: REF TEXT; c: CHAR; scratch ¬ text ¬ RefText.ObtainScratch[512]; -- numbers larger than 512 always allocate (yuk!) c ¬ stream.GetChar[]; text ¬ RefText.InlineAppendChar[text, c]; UNTIL level = 0 OR stream.EndOf[] DO c ¬ stream.GetChar[]; text ¬ RefText.InlineAppendChar[text, c]; IF c = '< THEN level ¬ level + 1 ELSE IF c = '> THEN level ¬ level - 1; ENDLOOP; rope ¬ Rope.FromRefText[text]; RefText.ReleaseScratch[scratch]; }; ReadChar: PUBLIC PROC [f: IO.STREAM, c: CHAR] = { streamC: CHAR; [] ¬ IO.SkipWhitespace[f, TRUE]; streamC ¬ IO.GetChar[f]; IF NOT c = streamC THEN { SyntaxError[f, IO.PutFR["Expected %g not %g", [character[c]], [character[streamC]]]]; }; }; ReadKeyword: PUBLIC PROC [stream: IO.STREAM] RETURNS [keyName: ROPE] = { <:". Returns . Strips the colon.>> <<[] _ IO.SkipWhitespace[stream, FALSE];>> <> keyName ¬ ReadWWord[stream]; ReadChar[stream, ':]; }; ReadWord: PUBLIC PROC [f: IO.STREAM] RETURNS [word: Rope.ROPE] = { <.>> WordBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = CHECKED { SELECT char FROM IO.TAB, IO.CR, IO.SP, IO.LF => RETURN [break]; ENDCASE => RETURN [wwordBreaks[char]]; }; [word, ----] ¬ IO.GetTokenRope[f, WordBreakProc !IO.EndOfStream => {word ¬ NIL; CONTINUE}]; }; ReadWWord: PUBLIC PROC [f: IO.STREAM] RETURNS [word: Rope.ROPE] = { <> WWordBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = { RETURN[wwordBreaks[char]]; }; <<[] _ IO.SkipWhitespace[f, TRUE];>> [word, ----] ¬ IO.GetTokenRope[f, WWordBreakProc !IO.EndOfStream => {word ¬ NIL; CONTINUE}]; }; <> <<>> closeParenAtom: ATOM ¬ Atom.MakeAtom[")"]; closeBracketAtom: ATOM ¬ Atom.MakeAtom["]"]; closeCurlyBracketAtom: ATOM ¬ Atom.MakeAtom["}"]; closeAngleBracketAtom: ATOM ¬ Atom.MakeAtom[">"]; wwordBreaks: PACKED ARRAY CHAR OF IO.CharClass ¬ ALL[other]; wwordBreaks[IO.TAB] ¬ wwordBreaks[IO.CR] ¬ wwordBreaks[IO.SP] ¬ wwordBreaks[IO.LF] ¬ sepr; wwordBreaks[',] ¬ wwordBreaks[']] ¬ wwordBreaks[')] ¬ wwordBreaks['}] ¬ wwordBreaks['>] ¬ wwordBreaks['=] ¬ wwordBreaks[':] ¬ wwordBreaks[';] ¬ break; END.