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];
};
}.