X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;ds=sidebyside;f=src%2Fedu%2Fberkeley%2Fsbp%2FGSS.java;h=3843f57020efe11b1df60b4612e8c818e89ddb91;hb=ebb5fe5647046306f415e31e4967b23169c9004e;hp=0d343a9fa93498a41792cafa3a83de951f603b34;hpb=b2d396676e77fb8777865258f84dfb8f8a2dbcad;p=sbp.git diff --git a/src/edu/berkeley/sbp/GSS.java b/src/edu/berkeley/sbp/GSS.java index 0d343a9..3843f57 100644 --- a/src/edu/berkeley/sbp/GSS.java +++ b/src/edu/berkeley/sbp/GSS.java @@ -1,27 +1,11 @@ package edu.berkeley.sbp; import edu.berkeley.sbp.*; -import edu.berkeley.sbp.*; -import edu.berkeley.sbp.*; import edu.berkeley.sbp.util.*; +import edu.berkeley.sbp.Sequence.Position; import java.io.*; import java.util.*; import java.lang.reflect.*; -////////////////////////////////////////////////////////////////////////////// -// TODO: -// -// - fix public/package/private status -// - -////////////////////////////////////////////////////////////////////////////// -// Optimizations to add -// -// ** NOTE: not all of these are appropriate for this class -- it is -// simply a list of optimizations not implemented. This -// class is meant to remain simple and easy to understand; -// optimizations which obscure that do not belong here (they -// should go into the compiled version instead) - /** implements Tomita's Graph Structured Stack */ class GSS { @@ -30,7 +14,7 @@ class GSS { private Phase.Node[] reducing_list = null; /** corresponds to a positions between tokens the input stream; same as Tomita's U_i's */ - public class Phase { + public class Phase implements Invokable { /** the token immediately after this phase */ public final Token token; @@ -44,7 +28,7 @@ class GSS { public Forest.Ref finalResult = null; /** all nodes, keyed by the value returned by code() */ - private HashMap hash = new HashMap(); /* ALLOC */ + /*private*/ HashMap hash = new HashMap(); /* ALLOC */ /** the number of nodes in this phase */ private int numNodes = 0; @@ -58,13 +42,87 @@ class GSS { this.location = location; } - public boolean isDone() { return token == null; } + public void complain(Node n, HashMap> errors, boolean force) { + if (n.touched) return; + n.touched = true; + for(Position p : n.state) { + //if (!p.isLast()) { + if (((p.isFirst() || p.isLast()) && !force) || p.owner().name==null) { + for(Node n2 : n.parents()) + complain(n2, errors, force | p.isFirst()); + } else { + String seqname = p.owner().name; + HashSet hs = errors.get(seqname); + if (hs==null) errors.put(seqname, hs = new HashSet()); + hs.add(p.element()+""); + //String s = " while parsing " + seqname + ": expected a " + p.element(); + //"\n"; + /* + s += " parsed: "; + for(Position p2 = p.owner().firstp(); p2 != null && p2 != p && !p2.isLast(); p2 = p2.next()) s += (p2.element() + " "); + s += "\n"; + s += " expected: "; + for(Position p2 = p; p2 != null && !p2.isLast(); p2 = p2.next()) s += (p2.element() + " "); + */ + //s += "\n"; + //errors.add(s); + } + } + } - private String error = "generic syntax error"; - public void checkFailure() throws Parser.Failed { - if (numNodes <= 0) - throw new Parser.Failed(error, getLocation()); + public String black(Object o) { return "\033[30m"+o+"\033[0m"; } + public String red(Object o) { return "\033[31m"+o+"\033[0m"; } + public String green(Object o) { return "\033[32m"+o+"\033[0m"; } + public String yellow(Object o) { return "\033[33m"+o+"\033[0m"; } + public String blue(Object o) { return "\033[34m"+o+"\033[0m"; } + public String purple(Object o) { return "\033[35m"+o+"\033[0m"; } + public String cyan(Object o) { return "\033[36m"+o+"\033[0m"; } + public String el(Object e) { + String s = e.toString(); + if (s.length()==0 || s.charAt(0)!='\"' || s.charAt(s.length()-1)!='\"') return yellow(s); + s = s.substring(1); + s = s.substring(0, s.length()-1); + StringBuffer ret = new StringBuffer(); + for(int i=0; i" : token.toString(); + StringBuffer ret = new StringBuffer(); + ret.append("\n "); + ret.append(message); + HashMap> errors = new HashMap>(); + for(Node n : hash.values()) complain(n, errors, false); + for(String s : errors.keySet()) { + ret.append(" while parsing " + yellow(s)); + HashSet hs = errors.get(s); + if (hs.size()==1) ret.append(" expected " + yellow(el(hs.iterator().next())) + "\n"); + else { + ret.append(" expected "); + boolean first = true; + for(String s2 : hs) { + if (!first) ret.append(" or "); + first = false; + ret.append(yellow(el(s2))); + } + ret.append("\n"); + } + } + return ret.toString(); + } + + public boolean isDone() throws Parser.Failed { + if (token != null) return false; + if (token==null && finalResult==null) + throw new Parser.Failed(error(red("unexpected end of file\n")), + getLocation()); + return true; + } + + private String error = "generic syntax error"; public Token.Location getLocation() { return location; } @@ -75,34 +133,36 @@ class GSS { * @param fromEmptyReduction true iff this node is being created as a result of a reduction of length zero (see GRMLR paper) * @param start the earliest part of the input contributing to this node (used to make merging decisions) */ - public void newNode(Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction, Phase start) { - Node p = hash.get(code(state, start)); - if (p != null) newNode2(p, parent, pending, state, fromEmptyReduction, start); - else newNode3(parent, pending, state, fromEmptyReduction, start); + public boolean newNode(Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction) { + Node p = hash.get(code(state, parent==null?null:parent.phase())); + if (p != null) return newNode2(p, parent, pending, state, fromEmptyReduction); + else return newNode3(parent, pending, state, fromEmptyReduction); } - private void newNode2(Node p, Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction, Phase start) { + private boolean newNode2(Node p, Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction) { p.holder.merge(pending); - if (p.parents().contains(parent)) return; - p.addParent(parent, fromEmptyReduction); + if (p.parents().contains(parent)) return true; + //if (p.fe && p.phase() != parent.phase()) throw new Error("yep yep"); + //if (!p.fe && p.phase() == parent.phase()) throw new Error("yep yep2"); + p.parents().add(parent, true); + if (p!=parent && !fromEmptyReduction) p.queueReductions(parent); + return true; } - private void newNode3(Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction, Phase start) { + private boolean newNode3(Node parent, Forest pending, Parser.Table.State state, boolean fromEmptyReduction) { do { if (token != null && state.canShift(token)) break; if (state.isAccepting()) break; if (token==null) break; - int count = 0; - Parser.Table.Reduction r = null; - for(Parser.Table.Reduction red : token==null ? state.getEofReductions() : state.getReductions(token)) { r = red; count++; } - if (count==0) return; // BEWARE! this optimization is suspected to cause really nasty heisenbugs + //if (!state.canReduce(token)) return false; //if (count > 1) break; //if (r.numPop == 0) break; //r.reduce(pending, parent, null, Phase.this, null); //return; } while(false); - Node n = new Node(parent, pending, state, start); // ALLOC + Node n = new Node(parent, pending, state, fromEmptyReduction); // ALLOC n.queueEmptyReductions(); if (!fromEmptyReduction) n.queueReductions(parent); + return true; } @@ -122,13 +182,19 @@ class GSS { for(int i=0; inext */ - public void shift(Phase next, Forest result) { + public void shift(Phase next, Forest result) throws Parser.Failed { + this.next = next; closed = true; Forest res = null; boolean ok = false; @@ -136,38 +202,20 @@ class GSS { if (n.holder==null) continue; n.holder.resolve(); if (token == null && n.state.isAccepting()) { - ok = true; if (finalResult==null) finalResult = new Forest.Ref(); finalResult.merge(n.holder); } if (!n.holder.valid()) continue; if (token == null) continue; - for(Parser.Table.State st : n.state.getShifts(token)) { - if (res == null) res = result; - next.newNode(n, res, st, true, this); - ok = true; - } + n.state.invokeShifts(token, this, result, n); } - if (!ok && token != null) { - StringBuffer error = new StringBuffer(); - error.append("error: unable to shift token \"" + token + "\"\n"); - //error.append(" before: " +pendingReductions+ "\n"); - //error.append(" before: " +totalReductions+ "\n"); - //for(Phase.Node n : hash.values()) { - //n.queueReductions(); - //n.queueEmptyReductions(); - //} - //error.append(" after: " +pendingReductions+ "\n"); - //error.append(" candidate states:\n"); - //for(Phase.Node n : hash.values()) { - //for(Sequence.Position p : n.state) error.append(" " + p + "\n"); - //error.append(" --\n"); - //for(Parser.Table.Reduction r : n.state.getReductions(token)) error.append(" " + r + "\n"); - //error.append(" ==\n"); - //} - next.error = error.toString(); - } + if (!good && token!=null) + throw new Parser.Failed(error(red("unexpected character")+" "+purple(token)+" encountered at "+green(getLocation())+"\n"), + getLocation()); + if (token==null && finalResult==null) + throw new Parser.Failed(error(red("unexpected end of file\n")), + getLocation()); // this massively improves GC performance hash = null; @@ -177,83 +225,54 @@ class GSS { // GSS Nodes ////////////////////////////////////////////////////////////////////////////// /** a node in the GSS */ - public final class Node extends FastSet { - - public void addParent(Node parent, boolean fromEmptyReduction) { - parents().add(parent, true); - if (this!=parent && !fromEmptyReduction) queueReductions(parent); - } + public final class Node extends FastSet implements Invokable { + public boolean touched = false; private Forest.Ref holder = null; private boolean allqueued = false; - private HashMap cache = null; - - /** the set of nodes to which there is an edge starting at this node */ - //public final FastSet parents = new FastSet(); /* ALLOC */ - /** what state this node is in */ public final Parser.Table.State state; /** which Phase this Node belongs to (node that Node is also a non-static inner class of Phase) */ public Phase phase() { return Phase.this; } - public HashMap cache() { - return cache==null ? (cache = new HashMap()) : cache; - } public Forest.Ref holder() { return holder==null ? (holder = new Forest.Ref()) : holder; } public Forest pending() { return Phase.this.closed ? holder().resolve() : holder; } public FastSet parents() { return this; } - /** FIXME */ public void queueReductions() { + if (!reducing) return; if (allqueued) return; allqueued = true; int where = parents().size(); - for(Parser.Table.Reduction r : token==null ? state.getEofReductions() : state.getReductions(token)) - if (r.numPop >= 1) - r.reduce(this, null, null); + state.invokeReductions(token, this, this, null); } - /** FIXME */ - public void queueReductions(Node n2) { queueReductions(n2, true); } - public void queueReductions(Node n2, boolean includeLongs) { + public void queueReductions(Node n2) { if (!allqueued) { queueReductions(); return; } - Node n = this; - for(Parser.Table.Reduction r : token==null ? n.state.getEofReductions() : n.state.getReductions(token)) { - - // UGLY HACK - // The problem here is that a "reduction of length 1" - // performed twice with different values of n2 needs - // to only create a *single* new result, but must add - // multiple parents to the node holding that result. - // The current reducer doesn't differentiate between - // the next node of an n-pop reduction and the - // ultimate parent of the last pop, so we need to - // cache instances here as a way of avoiding - // recreating them. - if (r.numPop <= 0) continue; - if (r.numPop == 1) { - Forest ret = n.cache().get(r); - if (ret != null) r.reduce(this, n2, ret); - else n.cache().put(r, r.reduce(this, n2, null)); - } else { - r.reduce(this, n2, null); - } - } + state.invokeReductions(token, this, this, n2); } - - /** FIXME */ + public final void invoke(Parser.Table.Reduction r, Node n, Node n2) { + if (n==null) { + if (r.numPop==0) r.reduce(this); + return; + } + if (r.numPop==0) return; + if (n2==null) r.reduce(n); + else r.reduce(n, n2); + } public void queueEmptyReductions() { - if (reducing) - for(Parser.Table.Reduction r : token==null ? state.getEofReductions() : state.getReductions(token)) - if (r.numPop==0) - r.reduce(this, null, r.zero()); + if (!reducing) return; + state.invokeReductions(token, this, null, null); } - private Node(Node parent, Forest pending, Parser.Table.State state, Phase start) { + private boolean fe; + private Node(Node parent, Forest pending, Parser.Table.State state, boolean fe) { + this.fe = fe; this.state = state; + Phase start = parent==null ? null : parent.phase(); if (pending != null) this.holder().merge(pending); if (parent != null) parents().add(parent, true); if (Phase.this.hash.get(code(state, start)) != null) throw new Error("severe problem!"); @@ -274,6 +293,6 @@ class GSS { /** this is something of a hack right now */ private static long code(Parser.Table.State state, Phase start) { - return (((long)state.idx) << 32) | (start==null ? 0 : start.pos); + return (((long)state.idx) << 32) | (start==null ? 0 : (start.pos+1)); } }