<> <> <> DIRECTORY Ascii, Atom, BasicTime, Convert, EDIFfing, IO, RefText, Rope; EDIFLexing2: CEDAR PROGRAM IMPORTS Ascii, Atom, IO, RefText, Rope EXPORTS EDIFfing = {OPEN EDIFfing; LexError: PUBLIC ERROR [stream: IO.STREAM, index: INT, complaint: ROPE] = CODE; Digit: TYPE = INTEGER [0 .. 9]; LexEDIF: PUBLIC PROC [source: Source, from: IO.STREAM] RETURNS [pt: ParseTree] = { ENABLE IO.EndOfStream => IF stream = from THEN LexError[from, from.GetIndex[], "Incomplete something-or-other"]; ParseList: PROC RETURNS [pt: ParseTree] = { c: CHAR _ from.GetChar[]; f: REF list ParseTreePrivate = NEW [ParseTreePrivate.list _ [ origin: [ source: source, where: [start: from.GetIndex[]-1]], variant: list[ children: NIL ] ]]; tail: ParseTreeList _ NIL; Append: PROC [sub: ParseTree] = { this: ParseTreeList = LIST[sub]; IF f.children = NIL THEN f.children _ this ELSE tail.rest _ this; tail _ this; }; IF c # '( THEN ERROR; DO d: CHAR; [] _ from.SkipWhitespace[flushComments: FALSE]; SELECT d _ from.PeekChar[] FROM ') => {IF from.GetChar[] # ') THEN ERROR; EXIT}; '( => Append[ParseList[]]; IN ['a .. 'z], IN ['A .. 'Z] => Append[ParseIdentifier[]]; '-, '+, IN ['0 .. '9] => Append[ParseInt[]]; '" => Append[ParseString[]]; ENDCASE => Append[ParseIdentifier[]]; ENDLOOP; f.origin.where.endPlusOne _ from.GetIndex[]; pt _ f; }; ParseIdentifier: PROC RETURNS [pt: ParseTree] = { keyBuff: REFTEXT; where: PositionRange; [keyBuff, where] _ ParseAtom[]; pt _ NEW [ParseTreePrivate.identifier _ [ origin: [ source: source, where: where], variant: identifier[id: Atom.MakeAtomFromRefText[keyBuff]] ]]; }; ParseAtom: PROC RETURNS [buff: REFTEXT, where: PositionRange] = { oneCharOnly: BOOL = SELECT from.PeekChar[] FROM IN ['a .. 'z], IN ['A .. 'Z] => FALSE, ENDCASE => TRUE; first: BOOL _ TRUE; next: INT; buff _ RefText.New[10]; WHILE first OR NOT oneCharOnly DO c: CHAR = from.PeekChar[]; SELECT c FROM IN ['a .. 'z], IN ['A .. 'Z], IN ['0 .. '9], '_ => { IF c # from.GetChar[] THEN ERROR; next _ from.GetIndex[]; IF first THEN where.start _ next-1; buff _ RefText.InlineReserveChars[buff, 1]; buff _ RefText.InlineAppendChar[buff, c]; }; ENDCASE => EXIT; first _ FALSE; ENDLOOP; IF first THEN ERROR; where.endPlusOne _ next; buff _ buff; }; ParseInt: PROC RETURNS [pt: ParseTree] = { start: INT _ from.GetIndex[] --count on bug in PeekChar:-- -1; pt _ NEW [ParseTreePrivate.integer _ [ origin: [ source: source, where: [start: start]], variant: integer[ i: from.GetInt[!IO.Error => IF stream # from THEN NULL ELSE IF ec = SyntaxError THEN LexError[from, from.GetIndex[], "Syntax error while parsing integer"] ELSE IF ec = Overflow THEN LexError[from, from.GetIndex[], "EDIF integer out of range"] ] ] ]]; pt.origin.where.endPlusOne _ from.GetIndex[] --count on bug in PeekChar:-- -1; }; ParseString: PROC RETURNS [pt: ParseTree] = { buff: REF TEXT _ RefText.New[100]; Append: PROC [c: CHAR] = INLINE { buff _ RefText.InlineReserveChars[buff, 1]; buff _ RefText.InlineAppendChar[buff, c]; }; GetDigit: PROC RETURNS [d: Digit] = { c: CHAR = from.GetChar[]; IF c IN ['0 .. '9] THEN RETURN [c - '0] ELSE LexError[from, from.GetIndex[], IO.PutFR["Got [%c]=%03bC instead of a digit in an escape sequence in a string", [character[c]], [integer[c - 0C]]]]; }; start: INT; IF from.GetChar[] # '" THEN ERROR; start _ from.GetIndex[]-1; DO c: CHAR = from.GetChar[]; SELECT c FROM '" => EXIT; Ascii.TAB, '\n, '\012, '\015 => NULL; '% => { d100: Digit = GetDigit[]; d10: Digit = GetDigit[]; d1: Digit = GetDigit[]; code: INT = (d100*100 + d10*10 + d1) MOD 128; Append[0C + code]; }; ENDCASE => Append[c]; ENDLOOP; pt _ NEW [ParseTreePrivate.string _ [ origin: [ source: source, where: [start: start, endPlusOne: from.GetIndex[]] ], variant: string[s: Rope.FromRefText[buff]] ]]; }; [] _ from.SkipWhitespace[flushComments: FALSE]; IF from.PeekChar[] # '( THEN LexError[from, from.GetIndex[], "Not an EDIF statement"]; pt _ ParseList[]; }; LowercaseText: PROC [rt: REFTEXT] = { FOR i: INT IN [0 .. rt.length) DO rt[i] _ Ascii.Lower[rt[i]] ENDLOOP; }; FmtOrg: PUBLIC PROC [pt: ParseTree] RETURNS [rope: ROPE] = { SELECT TRUE FROM pt.origin # [] => { rope _ IO.PutFR["%g|%g..%g", [rope[pt.origin.source.description]], [integer[pt.origin.where.start]], [integer[pt.origin.where.endPlusOne-1]]]; }; pt.replacing=NIL AND pt.generator=NIL => rope _ "??"; ENDCASE => { rope _ Rope.Cat["(Repl ", FmtOrg[pt.replacing], " _ ", FmtOrg[pt.generator], ")"]; }; }; }.