EDIFLexing2.Mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Spreitzer, February 23, 1986 3:37:27 pm PST
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: BOOLTRUE;
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], ")"];
};
};
}.