import java.lang.reflect.*;
import java.io.*;
-// FIXME: deal with question-marks
-
-// FIXME: put back in associativity: ^")"
-// A = A "->" (A)
-// means that the FIRST "A" cannot match the SAME sequence in
-// which the (A) occurs
-// -- and add a test case
-
-// FIXME: make it so that we can have multi-result nonterminals
-// so long as they always appear under double-colons?
-// auto-insert the unwrap?
-
-// FIXME: put associativity back in
-
-// FIXME: "flat" sequences (no subtrees contain "::"s?)
-
-// freezing problem is related to comments in grammar files
-
-/** The java classes typically used to represent a parsed grammar AST; each inner class is a type of AST node. */
-public class GrammarBuilder {
+/**
+ * The inner classes of this class represent nodes in the Abstract
+ * Syntax Tree of a grammar.
+ */
+public class GrammarAST {
/**
* Create a grammar from a parse tree and binding resolver
if (head.equals("Word")) return stringifyChildren(t);
if (head.equals("Elements")) return seq2((ElementNode[])Reflection.rebuild(walkChildren(t), ElementNode[].class));
if (head.equals("NonTerminalReference")) return new ReferenceNode(stringifyChildren(t.child(0)));
- //if (head.equals(")")) return new ReferenceNode(stringifyChildren(t.child(0)));
- if (head.equals("{")) return new XTree((Seq)walk(t.child(0)));
- if (head.equals("::")) return tag((String)walk(t.child(0)), (Seq)walk(t.child(1)));
- if (head.equals("++")) return plusmax((ElementNode)walk(t.child(0)));
- if (head.equals("...")) return star(new TildeNode(new AtomNode()));
- if (head.equals("+")) return plus((ElementNode)walk(t.child(0)));
- if (head.equals("++/")) return plusmaxfollow((ElementNode)walk(t.child(0)), (ElementNode)walk(t.child(1)));
- if (head.equals("+/")) return plusfollow((ElementNode)walk(t.child(0)), (ElementNode)walk(t.child(1)));
- if (head.equals("**")) return starmax((ElementNode)walk(t.child(0)));
- if (head.equals("*")) return star((ElementNode)walk(t.child(0)));
- if (head.equals("**/")) return starmaxfollow((ElementNode)walk(t.child(0)), (ElementNode)walk(t.child(1)));
- if (head.equals("*/")) return starfollow((ElementNode)walk(t.child(0)), (ElementNode)walk(t.child(1)));
- if (head.equals("?")) return question((ElementNode)walk(t.child(0)));
- if (head.equals("!")) return new DropNode((ElementNode)walk(t.child(0)));
- if (head.equals("^")) return new LiteralNode((String)walk(t.child(0)), true);
- if (head.equals("`")) {
- ElementNode ret = (ElementNode)walk(t.child(0));
- ret.lifted = true;
- return ret;
- }
+ if (head.equals(")")) return new ReferenceNode(stringifyChildren(t.child(0)), true);
+ if (head.equals("{")) return new BracedNode(walkSeq(t.child(0)));
+ if (head.equals("::")) return walkSeq(t.child(1)).tag(walkString(t.child(0)));
+ if (head.equals("...")) return new DropNode(new RepeatNode(new TildeNode(new AtomNode()), null, true, true, false));
+
+ if (head.equals("++")) return new RepeatNode(walkElement(t.child(0)), null, false, true, true);
+ if (head.equals("+")) return new RepeatNode(walkElement(t.child(0)), null, false, true, false);
+ if (head.equals("++/")) return new RepeatNode(walkElement(t.child(0)), walkElement(t.child(1)), false, true, true);
+ if (head.equals("+/")) return new RepeatNode(walkElement(t.child(0)), walkElement(t.child(1)), false, true, false);
+ if (head.equals("**")) return new RepeatNode(walkElement(t.child(0)), null, true, true, true);
+ if (head.equals("*")) return new RepeatNode(walkElement(t.child(0)), null, true, true, false);
+ if (head.equals("**/")) return new RepeatNode(walkElement(t.child(0)), walkElement(t.child(1)), true, true, true);
+ if (head.equals("*/")) return new RepeatNode(walkElement(t.child(0)), walkElement(t.child(1)), true, true, false);
+ if (head.equals("?")) return new RepeatNode(walkElement(t.child(0)), null, true, false, false);
+
+ if (head.equals("!")) return new DropNode(walkElement(t.child(0)));
+ if (head.equals("^")) return new LiteralNode(walkString(t.child(0)), true);
+ if (head.equals("`")) return walkElement(t.child(0)).lifted();
if (head.equals("Quoted")) return stringifyChildren(t);
- if (head.equals("Literal")) return new LiteralNode((String)walk(t.child(0)));
- if (head.equals("->")) return arrow((Seq)walk(t.child(0)), (ElementNode)walk(t.child(1)));
- if (head.equals("DropNT")) return new NonTerminalNode((String)walk(t.child(0)), (Seq[][])walkChildren(t.child(1)), false, null, true);
- if (head.equals("=") && t.size()==2) return new NonTerminalNode((String)walk(t.child(0)), (Seq[][])walk(t.child(1)), true, null, false);
- if (head.equals("=")) return new NonTerminalNode((String)walk(t.child(0)), (Seq[][])walk(t.child(2)), true, (String)walk(t.child(1)), false);
- if (head.equals("&")) return and2((Seq)walk(t.child(0)), (Seq)walk(t.child(1)));
- if (head.equals("&~")) return andnot2((Seq)walk(t.child(0)), (Seq)walk(t.child(1)));
- if (head.equals("/")) return ((Seq)walk(t.child(0))).separate((ElementNode)walk(t.child(1)));
- if (head.equals("()")) return epsilon;
- if (head.equals("[")) return new AtomNode((AtomNodeRange[])Reflection.rebuild(walkChildren(t), AtomNodeRange[].class));
- if (head.equals("\\{")) return new DropNode(new AtomNode(new AtomNodeRange(CharAtom.left, CharAtom.left)));
- if (head.equals("\\}")) return new DropNode(new AtomNode(new AtomNodeRange(CharAtom.right, CharAtom.right)));
- if (head.equals("~")) return new TildeNode((ElementNode)walk(t.child(0)));
- if (head.equals("~~")) {
- Seq seq = new Seq(star(new TildeNode(new AtomNode())));
- return seq.andnot((Seq)walk(t.child(0)));
- }
- if (head.equals("Range") && t.size()==1) return new AtomNodeRange(unescape(t).charAt(0));
- if (head.equals("Range")) return new AtomNodeRange(unescape(t).charAt(0), unescape(t).charAt(1));
+ if (head.equals("Literal")) return new LiteralNode(walkString(t.child(0)));
+ if (head.equals("->")) return walkSeq(t.child(0)).follow(walkElement(t.child(1)));
+ if (head.equals("DropNT")) return new NonTerminalNode(walkString(t.child(0)), (Seq[][])walkChildren(t.child(1)), false, null, true);
+ if (head.equals("=")) return new NonTerminalNode(walkString(t.child(0)), (Seq[][])walk(t.child(2)),
+ true, t.size()==2 ? null : walkString(t.child(1)), false);
+ if (head.equals("&")) return and2(walkSeq(t.child(0)), walkSeq(t.child(1)));
+ if (head.equals("&~")) return andnot2(walkSeq(t.child(0)), walkSeq(t.child(1)));
+ if (head.equals("/")) return (walkSeq(t.child(0))).separate(walkElement(t.child(1)));
+ if (head.equals("()")) return new LiteralNode("");
+ if (head.equals("[")) return new AtomNode((char[][])Reflection.rebuild(walkChildren(t), char[][].class));
+ if (head.equals("\\{")) return new DropNode(new AtomNode(new char[] { CharAtom.left, CharAtom.left }));
+ if (head.equals("\\}")) return new DropNode(new AtomNode(new char[] { CharAtom.right, CharAtom.right }));
+ if (head.equals(">>")) return new DropNode(new AtomNode(new char[] { CharAtom.left, CharAtom.left }));
+ if (head.equals("<<")) return new DropNode(new AtomNode(new char[] { CharAtom.right, CharAtom.right }));
+ if (head.equals("~")) return new TildeNode(walkElement(t.child(0)));
+ if (head.equals("~~")) return new Seq(new RepeatNode(new TildeNode(new AtomNode()), null, true, true, false)).andnot(walkSeq(t.child(0)));
+ if (head.equals("Range") && t.size()==2 && ">".equals(t.child(0).head()))
+ return new char[] { CharAtom.left, CharAtom.left };
+ if (head.equals("Range") && t.size()==2 && "<".equals(t.child(0).head()))
+ return new char[] { CharAtom.right, CharAtom.right };
+ if (head.equals("Range") && t.size()==1) return new char[] { unescape(t).charAt(0), unescape(t).charAt(0) };
+ if (head.equals("Range")) return new char[] { unescape(t).charAt(0), unescape(t).charAt(1) };
if (head.equals("\"\"")) return "";
if (head.equals("\n")) return "\n";
if (head.equals("\r")) return "\r";
public Union build(String rootNonterminal) {
Context cx = new Context(this);
Union u = null;
- for(GrammarBuilder.NonTerminalNode nt : values())
+ for(GrammarAST.NonTerminalNode nt : values())
if (nt.name.equals(rootNonterminal))
return (Union)cx.get(nt.name);
return null;
els[i] = elements[i].build(cx, cnt, dropall);
}
if (tag==null && multiNonDrop)
- throw new RuntimeException("multiple non-dropped elements in sequence: " + Sequence.create(els, ""));
- boolean lift = false;
- if (elements.length > 0 && elements[0].lifted)
- lift = true;
+ throw new RuntimeException("multiple non-dropped elements in sequence: " + Sequence.create("", els));
+ boolean[] lifts = new boolean[elements.length];
+ for(int i=0; i<elements.length; i++)
+ lifts[i] = elements[i].lifted;
if (!multiNonDrop) {
if (idx == -1)
ret = tag==null
- ? Sequence.create(els, illegalTag)
- : Sequence.createLeft(tag, els, drops, lift);
+ ? Sequence.create(illegalTag, els)
+ : Sequence.create(tag, els, drops, lifts);
else if (tag==null) ret = Sequence.create(els, idx);
- else ret = Sequence.createLeft(tag, els, drops, lift);
+ else ret = Sequence.create(tag, els, drops, lifts);
}
if (multiNonDrop)
- ret = Sequence.createLeft(tag, els, drops, lift);
+ ret = Sequence.create(tag, els, drops, lifts);
if (this.follow != null)
ret = ret.followedBy(this.follow.toAtom(cx));
return ret;