<> <> DIRECTORY Atom, EDIFAndCore, EDIFfing, EDIFParsing2, IO, Rope; EDIFParsing2Impl: CEDAR PROGRAM IMPORTS Atom, Rope EXPORTS EDIFParsing2 = {OPEN EDIFAndCore, EDIFfing, EDIFParsing2; ParseError : PUBLIC ERROR [ parseStack: ParseStack, nonTerminal: ATOM, syntaxRule: SyntaxRule] = CODE; Repeats: TYPE = REF SyntaxRuleList; NewRepeats: PROC RETURNS [r: Repeats] = {r _ NEW [SyntaxRuleList _ NIL]}; In: PROC [sr: SyntaxRule, rs: Repeats] RETURNS [in: BOOL] = { FOR srl: SyntaxRuleList _ rs^, srl.rest WHILE srl # NIL DO IF srl.first = sr THEN RETURN [TRUE]; ENDLOOP; }; Insert: PROC [sr: SyntaxRule, rs: Repeats] = {rs^ _ CONS[sr, rs^]}; Register : PUBLIC PROC [ outerKey: ATOM _ NIL, key: ATOM, start: PROC [outerKey, key: ATOM, name: NameStuff, outerConv: REF ANY] RETURNS [conv: REF ANY] _ NIL, finish: PROC [conv: REF ANY] _ NIL, rule: SyntaxRule ] = { }; FetchRule: PROC [category: ATOM] RETURNS [sr: SyntaxRule] = { ERROR --not yet implemented--; }; Check: PROC [ptl: ParseTreeList, rule: SyntaxRule, repeats: Repeats, insist: BOOL, nonTerminal: ATOM, ps: ParseStack] RETURNS [outsist, ok: BOOL, ptr: ParseTreeList] = { i0: INT = ps.first.index; outsist _ insist; WITH rule SELECT FROM x: REF SyntaxRulePrivate.terminal => { ok _ FALSE; WITH x SELECT FROM z: REF SyntaxRulePrivate.terminal.any => ok _ TRUE; z: REF SyntaxRulePrivate.terminal.string => ok _ ptl.first.type = string; z: REF SyntaxRulePrivate.terminal.identifier => ok _ ptl.first.type = identifier; z: REF SyntaxRulePrivate.terminal.integer => WITH ptl.first SELECT FROM y: REF ParseTreePrivate.integer => ok _ z.min <= y.i AND y.i <= z.max; ENDCASE; z: REF SyntaxRulePrivate.terminal.keyword => WITH ptl.first SELECT FROM y: REF ParseTreePrivate.identifier => ok _ z.key.Equal[Atom.GetPName[y.id], FALSE]; ENDCASE; ENDCASE => ERROR; IF ok THEN {ptr _ ptl.rest; ps.first.index _ ps.first.index + 1}; }; x: REF SyntaxRulePrivate.nonTerminal => { sr: SyntaxRule _ FetchRule[x.category]; [outsist, ok, ptr] _ Check[ptl, sr, repeats, insist, x.category, ps]; }; x: REF SyntaxRulePrivate.choice => { ok _ FALSE; FOR rl: SyntaxRuleList _ x.choices, rl.rest WHILE rl # NIL AND NOT ok DO [, ok, ptr] _ Check[ptl, rl.first, repeats, FALSE, nonTerminal, ps]; ENDLOOP; }; x: REF SyntaxRulePrivate.repeat => { once: BOOL _ FALSE; ptr _ ptl; ok _ TRUE; WHILE ptr # NIL AND ok DO [, ok, ptr] _ Check[ptr, x.r, repeats, insist AND x.atLeastOnce AND NOT once, nonTerminal, ps]; IF ok THEN once _ TRUE; ENDLOOP; ok _ once OR NOT x.atLeastOnce; }; x: REF SyntaxRulePrivate.series => { ptr _ ptl; ok _ TRUE; FOR rl: SyntaxRuleList _ x.elts, rl.rest WHILE rl # NIL AND ok DO [outsist, ok, ptr] _ Check[ptr, rl.first, NewRepeats[], outsist, nonTerminal, ps]; ENDLOOP; }; x: REF SyntaxRulePrivate.optional => { [outsist, ok, ptr] _ Check[ptl, x.r, repeats, FALSE, nonTerminal, ps]; IF NOT ok THEN {ok _ TRUE; outsist _ insist; ptr _ ptl}; }; x: REF SyntaxRulePrivate.nest => { WITH ptl.first SELECT FROM y: REF ParseTreePrivate.list => { sps: ParseStack = CONS[[y, 0], ps]; subl: ParseTreeList; --note that EDIF documents randomly allege that we can discard trailing stuff not consumed in currently understood grammar. [outsist, ok, subl] _ Check[y.children, x.r, NewRepeats[], insist, nonTerminal, sps]; IF ok THEN ptr _ ptl.rest; }; ENDCASE => ok _ FALSE; }; x: REF SyntaxRulePrivate.atMostOne => { SELECT In[x.r, repeats] FROM FALSE => { [outsist, ok, ptr] _ Check[ptl, x.r, NewRepeats[], insist, nonTerminal, ps]; IF ok THEN Insert[x.r, repeats]; }; TRUE => ok _ FALSE; ENDCASE => ERROR; }; x: REF SyntaxRulePrivate.cut => { ok _ outsist _ TRUE; ptr _ ptl; }; ENDCASE => ERROR; IF NOT ok THEN {ptr _ ptl; ps.first.index _ i0; outsist _ insist}; IF ok OR NOT insist THEN RETURN; ERROR ParseError[ parseStack: ps, nonTerminal: nonTerminal, syntaxRule: rule]; }; }.