X-Git-Url: http://git.megacz.com/?p=sbp.git;a=blobdiff_plain;f=src%2Fedu%2Fberkeley%2Fsbp%2Fmeta%2FMetaGrammarBindings.java;h=742918be276d99ebe85ae3157ceaf93f423e57af;hp=0fc7c71599520e2f70e5a3ca4f4e9ad4d4bf8515;hb=1e8506b9723a432c2c010b0f91b17cd0b68f6f68;hpb=f56263f0f1cf0c01dfbd8ea7bd1ba8a9c6bd8042 diff --git a/src/edu/berkeley/sbp/meta/MetaGrammarBindings.java b/src/edu/berkeley/sbp/meta/MetaGrammarBindings.java index 0fc7c71..742918b 100644 --- a/src/edu/berkeley/sbp/meta/MetaGrammarBindings.java +++ b/src/edu/berkeley/sbp/meta/MetaGrammarBindings.java @@ -9,30 +9,69 @@ import java.lang.annotation.*; import java.lang.reflect.*; import java.io.*; -/** The java classes typically used to represent a parsed grammar AST */ +/** The java classes typically used to represent a parsed grammar AST; each inner class is a type of AST node. */ public class MetaGrammarBindings { + // FIXME ugly ugly ugly scary dangerous + public static String prefix = ""; + /** A grammar (a set of nonterminals) */ - public static class Grammar extends HashMap { - public @bind Grammar(NonTerminal[] nonterminals) { - for(NonTerminal nt : nonterminals) this.put(nt.name, nt); } + public static class GrammarNode extends HashMap implements NonTerminalSource { + public NonTerminalNode[] getNonTerminals() { + return (NonTerminalNode[])values().toArray(new NonTerminalNode[0]); + } + public GrammarNode(NonTerminalNode[] nonterminals) { + for(NonTerminalNode nt : nonterminals) { + if (nt==null) continue; + if (this.get(nt.name)!=null) + throw new RuntimeException("duplicate definition of nonterminal \""+nt.name+"\""); + this.put(nt.name, nt); + } + } + public @bind.as("Grammar") GrammarNode(Object[] nt) { + add(nt); + } + private void add(Object[] obs) { + for(Object o : obs) { + if (o==null) continue; + else if (o instanceof Object[]) add((Object[])o); + else if (o instanceof NonTerminalNode) { + NonTerminalNode nt = (NonTerminalNode)o; + if (this.get(nt.name)!=null) + throw new RuntimeException("duplicate definition of nonterminal \""+nt.name+"\""); + this.put(nt.name, nt); + } + else if (o instanceof NonTerminalSource) add(((NonTerminalSource)o).getNonTerminals()); + } + } public String toString() { String ret = "[ "; - for(NonTerminal nt : values()) ret += nt + ", "; + for(NonTerminalNode nt : values()) ret += nt + ", "; return ret + " ]"; } + public Union build(String s, GrammarBindingResolver rm) { + Context cx = new Context(this,rm); + Union u = null; + for(MetaGrammarBindings.NonTerminalNode nt : values()) { + Union el = (Union)cx.get(nt.name); + StringBuffer st = new StringBuffer(); + el.toString(st); + if (nt.name.equals(s)) u = el; + } + return u; + } } - public abstract static class Un extends El { + public abstract static class UnionNode extends ElementNode { public Seq[][] sequences; - public void build(MetaGrammar.Context cx, Union u) { + public void build(Context cx, Union u, NonTerminalNode cnt) { HashSet bad2 = new HashSet(); for(int i=0; i red = (Tree.TreeFunctor)t.head(); + String oldprefix = prefix; + prefix = as; + GrammarNode gn = (GrammarNode)red.invoke(t); + prefix = oldprefix; + return gn; + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static interface NonTerminalSource { + public NonTerminalNode[] getNonTerminals(); + } + + public static class NonTerminalNode extends UnionNode implements NonTerminalSource { + public boolean rep; public String name = null; - public @bind NonTerminal(@bind.arg String name, - @bind.arg Seq[][] sequences) { - this.name = name; + public String sep = null; + public NonTerminalNode[] getNonTerminals() { return new NonTerminalNode[] { this }; } + public @bind.as("NonTerminal") NonTerminalNode(@bind.arg String name, @bind.arg Seq[][] sequences) { this(name, sequences, false); } + public NonTerminalNode(String name, Seq[][] sequences, boolean rep) { this(name, sequences, rep, null); } + public NonTerminalNode(String name, Seq[][] sequences, boolean rep, String sep) { + this.name = prefix + name; this.sequences = sequences; + this.rep = rep; + this.sep = prefix + sep; } - public Element build(MetaGrammar.Context cx) { return cx.get(name); } + public Element build(Context cx, NonTerminalNode cnt) { return cx.get(name); } + public void build(Context cx, Union u, NonTerminalNode cnt) { + if (!rep) { super.build(cx, u, this); return; } + HashSet bad2 = new HashSet(); + + Union urep = new Union(); + urep.add(Sequence.empty); + urep.add(Sequence.singleton(new Element[] { cx.get(sep), u }, 1)); + + for(int i=0; i and = new HashSet(); HashSet not = new HashSet(); - El[] elements; - El follow; + ElementNode[] elements; + ElementNode follow; String tag = null; boolean lame; - public Seq(El e) { this(new El[] { e }); } - public Seq(El[] elements) { this.elements = elements; } + public void append(ElementNode e) { + ElementNode[] elements = new ElementNode[this.elements.length+1]; + System.arraycopy(this.elements, 0, elements, 0, this.elements.length); + this.elements = elements; + elements[elements.length-1] = e; + } + public Seq(ElementNode e) { this(new ElementNode[] { e }); } + public Seq(ElementNode[] elements) { this.elements = elements; } public Seq tag(String tag) { this.tag = tag; return this; } - public Seq follow(El follow) { this.follow = follow; return this; } + public Seq follow(ElementNode follow) { this.follow = follow; return this; } public Seq dup() { Seq ret = new Seq(elements); ret.and.addAll(and); @@ -116,8 +226,8 @@ public class MetaGrammarBindings { } public Seq and(Seq s) { and.add(s); s.lame = true; return this; } public Seq andnot(Seq s) { not.add(s); s.lame = true; return this; } - public Seq separate(El sep) { - El[] elements = new El[this.elements.length * 2 - 1]; + public Seq separate(ElementNode sep) { + ElementNode[] elements = new ElementNode[this.elements.length * 2 - 1]; for(int i=0; i") Seq arrow(Seq s, El e) { return s.follow(e); } + public static @bind.as("->") Seq arrow(Seq s, ElementNode e) { return s.follow(e); } public static @bind.as("::") Seq tag(String tagname, Seq s) { return s.tag(tagname); } - public static @bind.as("/") Seq slash(Seq s, El e) { return s.separate(e); } + public static @bind.as("/") Seq slash(Seq s, ElementNode e) { return s.separate(e); } - public static Seq seq(El[] elements) { return new Seq(elements); } - public static @bind.as("Elements") Seq seq2(El[] elements) { return new Seq(elements); } + public static Seq seq(ElementNode[] elements) { return new Seq(elements); } + public static @bind.as("Elements") Seq seq2(ElementNode[] elements) { return new Seq(elements); } public static @bind.as Seq psx(Seq s) { return s; } - public static @bind.as(":") El colon(String s, El e) { return new Label(s, e); } + public static @bind.as(":") ElementNode colon(String s, ElementNode e) { return new Label(s, e); } public static @bind.as(")") void close(String foo) { throw new Error("not supported"); } - public static @bind.as("()") El epsilon() { return new Constant(Union.epsilon); } + public static @bind.as("()") ElementNode epsilon() { return new Constant(Union.epsilon); } - public static @bind class NonTerminalReference extends El { - public @bind.arg String nonTerminal; - public Element build(MetaGrammar.Context cx) { return cx.get(nonTerminal); } + public static class NonTerminalReferenceNode extends ElementNode { + public String nonTerminal; + public NonTerminalReferenceNode() { } + public @bind.as("NonTerminalReference") NonTerminalReferenceNode(String nonTerminal) { + this.nonTerminal = prefix + nonTerminal; + } + public Element build(Context cx, NonTerminalNode cnt) { + if (!this.nonTerminal.startsWith(prefix)) nonTerminal = prefix + nonTerminal; + Element ret = cx.get(nonTerminal); + if (ret == null) throw new RuntimeException("unknown nonterminal \""+nonTerminal+"\""); + return ret; + } } public static class Literal extends Constant { @@ -195,10 +307,10 @@ public class MetaGrammarBindings { public boolean drop() { return true; } } - public static class CharClass extends El { + public static class CharClass extends ElementNode { Range[] ranges; public @bind.as("[") CharClass(Range[] ranges) { this.ranges = ranges; } - public Element build(MetaGrammar.Context cx) { + public Element build(Context cx, NonTerminalNode cnt) { edu.berkeley.sbp.util.Range.Set set = new edu.berkeley.sbp.util.Range.Set(); for(Range r : ranges) set.add(r.first, r.last); @@ -206,74 +318,135 @@ public class MetaGrammarBindings { } } - public static @bind.as("{") class XTree extends El { + public static @bind.as("{") class XTree extends ElementNode { public @bind.arg Seq body; - public Element build(MetaGrammar.Context cx) { - throw new Error(); + public Element build(Context cx, NonTerminalNode cnt) { + Union u = new Union(); + Sequence s = body.build(cx, u, false, null); + Union u2 = new Union(); + u2.add(Sequence.singleton(new Element[] { + CharRange.leftBrace, + cx.get("ws"), + u, + cx.get("ws"), + CharRange.rightBrace + }, 2)); + return u2; } } - public static class Rep extends El { - public El e, sep; + public static class Rep extends ElementNode { + public ElementNode e, sep; public boolean zero, many, max; - public Rep(El e, El sep, boolean zero, boolean many, boolean max) { + public Rep(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;} - public Element build(MetaGrammar.Context cx) { + public Element build(Context cx, NonTerminalNode cnt) { return (!max) - ? Sequence.repeat(e.build(cx), zero, many, sep==null ? null : sep.build(cx), cx.rm.repeatTag()) + ? Sequence.repeat(e.build(cx, null), zero, many, sep==null ? null : sep.build(cx, null), cx.rm.repeatTag()) : sep==null - ? Sequence.repeatMaximal(infer(e.build(cx)), zero, many, cx.rm.repeatTag()) - : Sequence.repeatMaximal(e.build(cx), zero, many, infer(sep.build(cx)), cx.rm.repeatTag()); + ? Sequence.repeatMaximal(infer(e.build(cx, null)), zero, many, cx.rm.repeatTag()) + : Sequence.repeatMaximal(e.build(cx, null), zero, many, infer(sep.build(cx, null)), cx.rm.repeatTag()); } } - public static class Constant extends El { + public static class Constant extends ElementNode { Element constant; public Constant(Element constant) { this.constant = constant; } - public Element build(MetaGrammar.Context cx) { return constant; } + public Element build(Context cx, NonTerminalNode cnt) { return constant; } } - public abstract static class PostProcess extends El { - El e; - public PostProcess(El e) { this.e = e; } - public Element build(MetaGrammar.Context cx) { return postProcess(e.build(cx)); } + public abstract static class PostProcess extends ElementNode { + ElementNode e; + public PostProcess(ElementNode e) { this.e = e; } + public Element build(Context cx, NonTerminalNode cnt) { return postProcess(e.build(cx, cnt)); } public abstract Element postProcess(Element e); } // FIXME: it would be nice if we could hoist this into "Rep" - public static @bind.as("++") El plusmax(final El e) { return new Rep(e, null, false, true, true); } - public static @bind.as("+") El plus(final El e) { return new Rep(e, null, false, true, false); } - public static @bind.as("++/") El plusmaxfollow(final El e, final El sep) { return new Rep(e, sep, false, true, true); } - public static @bind.as("+/") El plusfollow(final El e, final El sep) { return new Rep(e, sep, false, true, false); } - public static @bind.as("**") El starmax(final El e) { return new Rep(e, null, true, true, true); } - public static @bind.as("*") El star(final El e) { return new Rep(e, null, true, true, false); } - public static @bind.as("**/") El starmaxfollow(final El e, final El sep) { return new Rep(e, sep, true, true, true); } - public static @bind.as("*/") El starfollow(final El e, final El sep) { return new Rep(e, sep, true, true, false); } - public static @bind.as("?") El question(final El e) { return new Rep(e, null, true, true, false); } - - public static @bind.as("!") El bang(final El e) { return new Drop(e); } + public static @bind.as("++") ElementNode plusmax(final ElementNode e) + { return new Rep(e, null, false, true, true); } + public static @bind.as("+") ElementNode plus(final ElementNode e) + { return new Rep(e, null, false, true, false); } + public static @bind.as("++/") ElementNode plusmaxfollow(final ElementNode e, final ElementNode sep) + { return new Rep(e, sep, false, true, true); } + public static @bind.as("+/") ElementNode plusfollow(final ElementNode e, final ElementNode sep) + { return new Rep(e, sep, false, true, false); } + public static @bind.as("**") ElementNode starmax(final ElementNode e) + { return new Rep(e, null, true, true, true); } + public static @bind.as("*") ElementNode star(final ElementNode e) + { return new Rep(e, null, true, true, false); } + public static @bind.as("**/") ElementNode starmaxfollow(final ElementNode e, final ElementNode sep) + { return new Rep(e, sep, true, true, true); } + public static @bind.as("*/") ElementNode starfollow(final ElementNode e, final ElementNode sep) + { return new Rep(e, sep, true, true, false); } + public static @bind.as("?") ElementNode question(final ElementNode e) + { return new Rep(e, null, true, true, false); } + public static @bind.as("!") ElementNode bang(final ElementNode e) + { return new Drop(e); } - public static @bind.as("^") El caret(final String s) { + public static @bind.as("^") ElementNode caret(final String s) { return new Drop(new Constant(CharRange.string(s)) { public String getOwnerTag() { return s; } }); } - public static @bind.as("~") El tilde(final El e) { + public static @bind.as("~") ElementNode tilde(final ElementNode e) { return new PostProcess(e) { public Element postProcess(Element e) { - return infer((Topology)Atom.toAtom(e).complement()); + return infer((Topology)Atom.toAtom(e).complement().minus(CharRange.braces)); } }; } - public static @bind.as("^^") void doublecaret(final El e) { throw new Error("not implemented"); } - - //public static @bind.as("(") El subexpression(Seq[][] rhs) { return new NonTerminal(rhs); } - - public static @bind.as("Word") String word(String s) { return s; } - public static @bind.as("Quoted") String quoted(String s) { return s; } - public static @bind.as("escaped") String c(char c) { return c+""; } - public static @bind.as("EmptyString") String emptystring() { return ""; } - public static @bind.as("\n") String retur() { return "\n"; } - public static @bind.as("\r") String lf() { return "\r"; } + public static @bind.as("Word") String word(String s) { return s; } + public static @bind.as("Quoted") String quoted(String s) { return s; } + public static @bind.as("escaped") String c(char c) { return c+""; } + public static @bind.as("EmptyString") String emptystring() { return ""; } + public static @bind.as("\n") String retur() { return "\n"; } + public static @bind.as("\r") String lf() { return "\r"; } static Atom infer(Element e) { return infer((Topology)Atom.toAtom(e)); } static Atom infer(Topology t) { return new CharRange(new CharTopology(t)); } + + public static class Context { + public HashMap map = new HashMap(); + public GrammarNode grammar; + public String cnt = null; + public GrammarBindingResolver rm; + public Context(GrammarNode g, GrammarBindingResolver rm) { + this.grammar = g; + this.rm = rm; + } + public Union build() { + Union ret = null; + for(NonTerminalNode nt : grammar.values()) { + Union u = get(nt.name); + if ("s".equals(nt.name)) + ret = u; + } + return ret; + } + public Context(Tree t, GrammarBindingResolver rm) { + this.rm = rm; + Tree.TreeFunctor red = (Tree.TreeFunctor)t.head(); + this.grammar = (GrammarNode)red.invoke(t); + } + public Union peek(String name) { return map.get(name); } + public void put(String name, Union u) { map.put(name, u); } + public Union get(String name) { + Union ret = map.get(name); + if (ret != null) return ret; + ret = new Union(name); + map.put(name, ret); + NonTerminalNode nt = grammar.get(name); + if (nt==null) { + //System.err.println("*** warning could not find " + name); + throw new Error("warning could not find " + name); + } else { + String old = cnt; + cnt = name; + nt.build(this, ret, nt); + cnt = old; + } + return ret; + } + + } + }