X-Git-Url: http://git.megacz.com/?p=sbp.git;a=blobdiff_plain;f=src%2Fedu%2Fberkeley%2Fsbp%2Fmeta%2FGrammarBuilder.java;h=f38bd8e11e25f837ae6e2425ddf25fd5d253615c;hp=3651be36cbefc55bbafdf517920da51471aee8d5;hb=65c42fc8ec481eb1305a1f6bc005737b0870bc91;hpb=dc9bb3a45ed306e2e35549076842b3e74efecb48 diff --git a/src/edu/berkeley/sbp/meta/GrammarBuilder.java b/src/edu/berkeley/sbp/meta/GrammarBuilder.java index 3651be3..f38bd8e 100644 --- a/src/edu/berkeley/sbp/meta/GrammarBuilder.java +++ b/src/edu/berkeley/sbp/meta/GrammarBuilder.java @@ -85,7 +85,9 @@ public class GrammarBuilder { public Object walk(Tree t) { String head = (String)t.head(); - while(head.indexOf('.') != -1) head = head.substring(head.indexOf('.')+1); + if (head.indexOf('.') != 0) + while(head.indexOf('.') != -1) + head = head.substring(head.indexOf('.')+1); if (head==null) throw new RuntimeException("head is null: " + t); if (head.equals("|")) return walkChildren(t); if (head.equals("RHS")) return walkChildren(t); @@ -98,6 +100,7 @@ public class GrammarBuilder { 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))); @@ -108,6 +111,11 @@ public class GrammarBuilder { 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("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))); @@ -153,8 +161,7 @@ public class GrammarBuilder { File file = new File(f.getAbsolutePath()+File.separatorChar+fileName); if (!file.exists()) continue; try { - String newPrefix = (String)walk(t.child(1)); - if (newPrefix.length() > 0) newPrefix += "."; + String newPrefix = t.size()<2 ? "" : ((String)walk(t.child(1))+"."); FileInputStream fis = new FileInputStream(file); Tree tr = new CharParser(MetaGrammar.newInstance()).parse(fis).expand1(); return (GrammarNode)new GrammarBuilder(includes, newPrefix).walk(tr); @@ -164,7 +171,7 @@ public class GrammarBuilder { } throw new RuntimeException("unable to find #include file \""+fileName+"\""); } - throw new RuntimeException("unknown head: " + head + "\n"+t); + throw new RuntimeException("unknown head: \"" + head + "\" => " + (head.equals("..."))); } /** A grammar (a set of nonterminals) */ @@ -264,7 +271,7 @@ public class GrammarBuilder { public class NonTerminalNode extends UnionNode { public boolean alwaysDrop; public String name = null; - public boolean drop() { return alwaysDrop; } + public boolean drop(Context cx) { return alwaysDrop; } public NonTerminalNode(String name, Seq[][] sequences, boolean rep, String sep, boolean alwaysDrop) { super(sequences, rep, sep==null?null:(prefix + sep)); this.name = prefix + name; @@ -275,7 +282,7 @@ public class GrammarBuilder { public class Seq { public boolean alwaysDrop = false; - public boolean drop() { return alwaysDrop; } + public boolean drop(Context cx) { return alwaysDrop; } HashSet and = new HashSet(); HashSet not = new HashSet(); ElementNode[] elements; @@ -326,13 +333,10 @@ public class GrammarBuilder { public Sequence build0(Context cx, NonTerminalNode cnt, boolean dropall) { boolean[] drops = new boolean[elements.length]; Element[] els = new Element[elements.length]; - dropall |= drop(); + dropall |= drop(cx); for(int i=0; i 0 && elements[0].lifted) + lift = true; if (!multiNonDrop) { if (idx == -1) ret = tag==null ? Sequence.create(els, illegalTag) - : Sequence.create(tag, els, drops, false); + : Sequence.createLeft(tag, els, drops, lift); else if (tag==null) ret = Sequence.create(els, idx); - else ret = Sequence.create(tag, els, drops, false); + else ret = Sequence.createLeft(tag, els, drops, lift); } if (multiNonDrop) - ret = Sequence.create(tag, els, drops, false); + ret = Sequence.createLeft(tag, els, drops, lift); if (this.follow != null) ret = ret.followedBy(this.follow.toAtom(cx)); return ret; @@ -371,9 +378,14 @@ public class GrammarBuilder { public class ReferenceNode extends ElementNode { public String nonTerminal; public ReferenceNode() { } - public NonTerminalNode resolve(Context cx) { return cx.grammar.get(nonTerminal); } + public NonTerminalNode resolve(Context cx) { + NonTerminalNode ret = cx.grammar.get(nonTerminal); + if (ret==null) throw new RuntimeException("undefined nonterminal: " + nonTerminal); + return ret; + } public ReferenceNode(String nonTerminal) { this.nonTerminal = prefix + nonTerminal; } public Atom toAtom(Context cx) { return cx.grammar.get(nonTerminal).toAtom(cx); } + public boolean drop(Context cx) { return resolve(cx).drop(cx); } public Element build(Context cx, NonTerminalNode cnt, boolean dropall) { if (!this.nonTerminal.startsWith(prefix)) nonTerminal = prefix + nonTerminal; Element ret = cx.get(nonTerminal); @@ -393,7 +405,7 @@ public class GrammarBuilder { } public String getOwnerTag() { return caret ? thePrefix+string : super.getOwnerTag(); } public String toString() { return "\""+string+"\""; } - public boolean drop() { return true; } + public boolean drop(Context cx) { return true; } public Atom toAtom(Context cx) { if (string.length()!=1) return super.toAtom(cx); edu.berkeley.sbp.util.Range.Set set = new edu.berkeley.sbp.util.Range.Set(); @@ -405,6 +417,7 @@ public class GrammarBuilder { public class AtomNode extends ElementNode { AtomNodeRange[] ranges; + public AtomNode() { this(new AtomNodeRange[0]); } public AtomNode(AtomNodeRange[] ranges) { this.ranges = ranges; } public AtomNode(AtomNodeRange range) { this.ranges = new AtomNodeRange[] { range }; } public Element build(Context cx, NonTerminalNode cnt, boolean dropall) { return toAtom(cx); } @@ -423,14 +436,20 @@ public class GrammarBuilder { public class RepeatNode extends ElementNode { public ElementNode e, sep; - public boolean zero, many, max; + public final boolean zero, many, max; public RepeatNode(ElementNode e, ElementNode sep, boolean zero, boolean many, boolean max) { - this.e = e; this.sep = sep; this.zero = zero; this.many = many; this.max = max;} + this.e = e; this.sep = sep; this.zero = zero; this.many = many; this.max = max; + } public Atom toAtom(Context cx) { return sep==null ? e.toAtom(cx) : super.toAtom(cx); } + public boolean drop(Context cx) { return e.drop(cx); } public Element build(Context cx, NonTerminalNode cnt, boolean dropall) { - if (!dropall && !drop() && !e.drop()) - throw new Error("you need a tag on this repetition: " + build(cx, cnt, dropall, "")); - return build(cx, cnt, dropall, illegalTag); + Element ret = build(cx, cnt, dropall, illegalTag); + String must = "must be tagged unless they appear within a dropped expression or their contents are dropped: "; + if (!dropall && !drop(cx) && !e.drop(cx)) + if (!many) throw new RuntimeException("options (?) " + must + ret); + else if (zero) throw new RuntimeException("zero-or-more repetitions (*) " + must + ret); + else throw new RuntimeException("one-or-more repetitions (+) " + must + ret); + return ret; } public Element build(Context cx, NonTerminalNode cnt, boolean dropall, Object repeatTag) { return (!max) @@ -442,8 +461,9 @@ public class GrammarBuilder { } public abstract class ElementNode { + public boolean lifted = false; public String getOwnerTag() { return null; } - public boolean drop() { return false; } + public boolean drop(Context cx) { return false; } public Atom toAtom(Context cx) { throw new Error("can't convert a " + this.getClass().getName() + " to an atom: " + this); } public abstract Element build(Context cx, NonTerminalNode cnt, boolean dropall); } @@ -452,7 +472,7 @@ public class GrammarBuilder { protected ElementNode _e; public ElementNodeWrapper(ElementNode e) { this._e = e; } public String getOwnerTag() { return _e.getOwnerTag(); } - public boolean drop() { return _e.drop(); } + public boolean drop(Context cx) { return _e.drop(cx); } public Atom toAtom(Context cx) { return _e.toAtom(cx); } public Element build(Context cx, NonTerminalNode cnt, boolean dropall) { return _e.build(cx, cnt, dropall); } } @@ -465,7 +485,7 @@ public class GrammarBuilder { public class DropNode extends ElementNodeWrapper { public DropNode(ElementNode e) { super(e); } - public boolean drop() { return true; } + public boolean drop(Context cx) { return true; } } public Seq and2(Seq s, Seq a) { a.alwaysDrop = true; return s.and(a); } @@ -482,7 +502,7 @@ public class GrammarBuilder { public ElementNode star(final ElementNode e) { return new RepeatNode(e, null, true, true, false); } public ElementNode starmaxfollow(final ElementNode e, final ElementNode sep) { return new RepeatNode(e, sep, true, true, true); } public ElementNode starfollow(final ElementNode e, final ElementNode sep) { return new RepeatNode(e, sep, true, true, false); } - public ElementNode question(final ElementNode e) { return new RepeatNode(e, null, true, true, false); } + public ElementNode question(final ElementNode e) { return new RepeatNode(e, null, true, false, false); } ////////////////////////////////////////////////////////////////////////////// @@ -511,7 +531,7 @@ public class GrammarBuilder { } else { ret = new Union(name, false); map.put(name, ret); - nt.buildIntoPreallocatedUnion(this, nt, nt.drop(), ret); + nt.buildIntoPreallocatedUnion(this, nt, nt.drop(this), ret); } return ret; } @@ -527,11 +547,9 @@ public class GrammarBuilder { Union u2 = new Union(null, false); u2.add(Sequence.create(new Element[] { CharAtom.leftBrace, - cx.get("ws"), u, - cx.get("ws"), CharAtom.rightBrace - }, 2)); + }, 1)); return u2; } }