+// Copyright 2006-2007 all rights reserved; see LICENSE file for BSD-style license
+
package edu.berkeley.sbp;
-import edu.berkeley.sbp.*;
-import edu.berkeley.sbp.Sequence.Position;
import edu.berkeley.sbp.util.*;
import java.io.*;
import java.util.*;
-import java.lang.reflect.*;
/**
* <font color=blue>
* shared packed parse forest).
* </font>
*/
-public abstract class Forest<T> implements GraphViz.ToGraphViz {
+public abstract class Forest<NodeType> implements GraphViz.ToGraphViz {
/** assume that this forest contains exactly one tree and return it; otherwise throw an exception */
- public abstract Tree<T> expand1() throws Ambiguous;
+ public abstract Tree<NodeType> expand1() throws Ambiguous;
/** expand this forest into a set of trees */
- public void expand(HashSet<Tree<T>> ht) { expand(ht, new HashSet<Forest<T>>(), null); }
-
- static <T> Forest<T> create(Input.Region loc, T head, Forest<T>[] children, boolean lift) {
- return new One<T>(loc, head, children, lift);
+ public Iterable<Tree<NodeType>> expand() {
+ HashSet<Tree<NodeType>> ht = new HashSet<Tree<NodeType>>();
+ expand(ht, new HashSet<Forest<NodeType>>(), null);
+ return ht;
}
- /** create a new forest */
- public static <T> Forest<T> create(Input.Region loc, T head, Forest<T>[] children) {
- return Forest.create(loc, head, children, false); }
+ /** returns the input Region which this Forest was parsed from */
+ public abstract Input.Region getRegion();
// Package-Private //////////////////////////////////////////////////////////////////////////////
- abstract void expand(HashSet<Tree<T>> ht, HashSet<Forest<T>> ignore, Tree<T> bogus);
- abstract void gather(HashSet<Forest<T>> ignore);
- abstract void edges(GraphViz.Node n);
- boolean ambiguous() { return false; }
-
+ public static <NodeType> Forest<NodeType> create(Input.Region region, NodeType head, Forest<NodeType>[] children) {
+ return create(region, head, children, new boolean[children==null ? 0 : children.length]); }
+ public static <NodeType> Forest<NodeType> create(Input.Region region, NodeType head, Forest<NodeType>[] children, boolean[] lifts) {
+ if (region == null) throw new RuntimeException("invoked Forest.create(region=null) -- this should never happen");
+ return new One<NodeType>(region, head, children, lifts);
+ }
+ abstract void expand(HashSet<Tree<NodeType>> ht, HashSet<Forest<NodeType>> ignore, Tree<NodeType> bogus);
+ abstract void gather(HashSet<Forest<NodeType>> ignore);
+ abstract void edges(GraphViz.StateNode n);
+ boolean ambiguous() { return false; }
+
// One //////////////////////////////////////////////////////////////////////////////
/** A "single" forest with a head and child subforests */
- private static class One<T> extends Forest<T> {
+ private static class One<NodeType> extends Forest<NodeType> {
private final Input.Region location;
- private final T head;
- private final Forest<T>[] children;
+ private final NodeType head;
+ private final Forest<NodeType>[] children;
/** if true, the last child's children are considered children of this node */
- private final boolean lift;
+ private final boolean[] lifts;
- private One(Input.Region loc, T head, Forest<T>[] children, boolean lift) {
+ public Input.Region getRegion() { return location; }
+
+ private One(Input.Region loc, NodeType head, Forest<NodeType>[] children, boolean[] lifts) {
this.location = loc;
this.head = head;
+ if (head==null) throw new RuntimeException("invoked Forest.create(,null,,,) -- this should never happen");
this.children = children==null ? emptyForestArray : new Forest[children.length];
if (children != null) System.arraycopy(children, 0, this.children, 0, children.length);
if (children != null) for(int i=0; i<children.length; i++) if (children[i]==null) throw new Error(i+"");
- this.lift = lift;
+ this.lifts = lifts;
}
- public Tree<T> expand1() throws Ambiguous {
- Tree<T>[] ret = new Tree[children.length];
- for(int i=0; i<children.length; i++) ret[i] = children[i].expand1();
- return new Tree<T>(location, head, ret, lift);
+ public Tree<NodeType> expand1() throws Ambiguous {
+ if (children.length == 0)
+ return new Tree<NodeType>(location, head);
+ else
+ return expand1ForOneAndMany((Forest<NodeType>)this);
}
- void gather(HashSet<Forest<T>> hf) {
+ void gather(HashSet<Forest<NodeType>> hf) {
hf.add(this);
- for(Forest<T> f : children) f.gather(hf);
+ for(Forest<NodeType> f : children) f.gather(hf);
}
- void expand(HashSet<Tree<T>> ht, HashSet<Forest<T>> ignore, Tree<T> bogus) {
+ void expand(HashSet<Tree<NodeType>> ht, HashSet<Forest<NodeType>> ignore, Tree<NodeType> bogus) {
if (ignore.contains(this)) { ht.add(bogus); return; }
expand(0, new Tree[children.length], ht, ignore, bogus);
}
- private void expand(final int i, Tree<T>[] ta, HashSet<Tree<T>> ht, HashSet<Forest<T>> ignore, Tree<T> bogus) {
+ private void expand(final int i, Tree<NodeType>[] ta, HashSet<Tree<NodeType>> ht, HashSet<Forest<NodeType>> ignore,
+ Tree<NodeType> bogus) {
if (i==children.length) {
- ht.add(new Tree<T>(location, head, ta, lift));
+ ht.add(new Tree<NodeType>(location, head, ta, lifts));
} else {
- HashSet<Tree<T>> ht2 = new HashSet<Tree<T>>();
+ HashSet<Tree<NodeType>> ht2 = new HashSet<Tree<NodeType>>();
children[i].expand(ht2, ignore, bogus);
- for(Tree<T> tc : ht2) {
+ for(Tree<NodeType> tc : ht2) {
ta[i] = tc;
expand(i+1, ta, ht, ignore, bogus);
ta[i] = null;
public boolean isTransparent() { return false; }
public boolean isHidden() { return false; }
- public GraphViz.Node toGraphViz(GraphViz gv) {
+ public GraphViz.StateNode toGraphViz(GraphViz gv) {
if (gv.hasNode(this)) return gv.createNode(this);
- GraphViz.Node n = gv.createNode(this);
+ GraphViz.StateNode n = gv.createNode(this);
n.label = headToString()==null?"":headToString();
n.directed = true;
edges(n);
return n;
}
boolean edges = false; // FIXME ??
- public void edges(GraphViz.Node n) {
+ public void edges(GraphViz.StateNode n) {
if (edges) return;
edges = true;
for(int i=0; i<children.length; i++) {
- if (i==children.length-1 && lift && !children[i].ambiguous()) {
+ if (lifts[i] && !children[i].ambiguous()) {
children[i].edges(n);
} else {
n.edge(children[i], null);
// Many //////////////////////////////////////////////////////////////////////////////
/** An "ambiguity node"; this is immutable once it has been "looked at" */
- static class Many<T> extends Forest<T> {
+ static class Many<NodeType> extends Forest<NodeType> {
- HashSet<GSS.Phase.Node> parents = new HashSet<GSS.Phase.Node>();
- private FastSet<Forest<T>> hp = new FastSet<Forest<T>>();
+ private FastSet<Forest<NodeType>> hp = new FastSet<Forest<NodeType>>();
private boolean touched = false;
public Many() { }
- public Tree<T> expand1() throws Ambiguous {
+ public Input.Region getRegion() { return hp.iterator().next().getRegion(); } // all should be identical
+
+ Forest<NodeType> simplify() throws Ambiguous {
touched();
if (hp.size() > 1) {
- HashSet<Forest<T>> hf0 = new HashSet<Forest<T>>();
- Iterator<Forest<T>> ih = hp.iterator();
+ HashSet<Forest<NodeType>> hf0 = new HashSet<Forest<NodeType>>();
+ Iterator<Forest<NodeType>> ih = hp.iterator();
ih.next().gather(hf0);
- for(Forest<T> f : hp) {
- HashSet<Forest<T>> hf1 = new HashSet<Forest<T>>();
+ for(Forest<NodeType> f : hp) {
+ HashSet<Forest<NodeType>> hf1 = new HashSet<Forest<NodeType>>();
f.gather(hf1);
hf0.retainAll(hf1);
}
- HashSet<Tree<T>> ht = new HashSet<Tree<T>>();
+ HashSet<Tree<NodeType>> ht = new HashSet<Tree<NodeType>>();
expand(ht, hf0, new Tree(null, "*"));
throw new Ambiguous((Forest<?>)this,
(HashSet<Tree<?>>)(Object)ht);
}
- return hp.iterator().next().expand1();
+
+ return hp.iterator().next();
+ }
+
+ public Tree<NodeType> expand1() throws Ambiguous {
+ return simplify().expand1();
}
- void gather(HashSet<Forest<T>> ht) {
+ void gather(HashSet<Forest<NodeType>> ht) {
touched();
+
+ // FIXME: do something more sensible here
+ if (ht.contains(this)) {
+ System.err.println("WARNING: grammar produced a circular forest\n" + this);
+ //throw new Error("grammar produced a circular forest:\n" + this);
+ return;
+ }
+
ht.add(this);
- for(Forest<T> f : hp) f.gather(ht);
+ for(Forest<NodeType> f : hp) f.gather(ht);
}
private void touched() {
if (touched) return;
touched = true;
/*
- FastSet<Forest<T>> f2 = new FastSet<Forest<T>>();
+ FastSet<Forest<NodeType>> f2 = new FastSet<Forest<NodeType>>();
for(Forest f : hp)
if (f instanceof Forest.One) f2.add(f);
- else for(Forest ff : ((Forest.Many<T>)f))
+ else for(Forest ff : ((Forest.Many<NodeType>)f))
f2.add(ff);
hp = f2;
*/
return true;
}
- void expand(HashSet<Tree<T>> ht, HashSet<Forest<T>> ignore, Tree<T> bogus) {
+ void expand(HashSet<Tree<NodeType>> ht, HashSet<Forest<NodeType>> ignore, Tree<NodeType> bogus) {
touched();
if (ignore.contains(this)) { ht.add(bogus); return; }
- for (Forest<T> f : hp) f.expand(ht, ignore, bogus);
+ for (Forest<NodeType> f : hp) f.expand(ht, ignore, bogus);
}
public boolean isTransparent() { return hp.size()==1; }
public boolean isHidden() { return hp.size()==0; }
- public void edges(GraphViz.Node n) {
+ public void edges(GraphViz.StateNode n) {
if (hp.size()==1) { hp.iterator().next().edges(n); return; }
for(Forest f : hp) f.edges(n);
}
- public GraphViz.Node toGraphViz(GraphViz gv) {
+ public GraphViz.StateNode toGraphViz(GraphViz gv) {
if (hp.size()==1) return hp.iterator().next().toGraphViz(gv);
if (gv.hasNode(this)) return gv.createNode(this);
- GraphViz.Node n = gv.createNode(this);
+ GraphViz.StateNode n = gv.createNode(this);
n.label = "?";
n.color = "red";
for(Forest f : hp) n.edge(f, null);
}
}
+
// Statics //////////////////////////////////////////////////////////////////////////////
+ /** Depth-first expansion, handling .One and .Many without recursion. */
+ private static <NodeType> Tree<NodeType> expand1ForOneAndMany(
+ Forest<NodeType> forest) throws Ambiguous {
+ List<Tree<NodeType>> nodes = new ArrayList<Tree<NodeType>>();
+ List<Tree<NodeType>> build = new ArrayList<Tree<NodeType>>();
+
+ // path stack
+ List<Forest.One<NodeType>> path = new ArrayList<Forest.One<NodeType>>();
+ List<Integer> sizes = new ArrayList<Integer>(),
+ poss = new ArrayList<Integer>();
+
+ // handle the left-most leaf
+ expand1Descend(path, nodes, sizes, poss, forest);
+
+ for (Forest.One<NodeType> f; path.size() > 0;) {
+ // up one
+ f = pop(path);
+ int size = pop(sizes) + 1;
+ int pos = pop(poss) + 1;
+ Forest<NodeType>[] children = f.children;
+ if (pos < children.length) {
+ // down the next branch
+ path.add(f);
+ sizes.add(new Integer(size));
+ poss.add(new Integer(pos));
+
+ // handle the left-most leaf
+ expand1Descend(path, nodes, sizes, poss, children[pos]);
+ } else {
+ if (path.size() > 0 && peek(path).lifts[peek(poss)]) {
+ // skip assembling this node, lift children
+ sizes.add(pop(sizes) + size - 1);
+ continue;
+ }
+ // assemble this node
+ for (int i=size; i > 0; i--)
+ build.add(nodes.remove(nodes.size() - i));
+ nodes.add(new Tree<NodeType>(f.location, f.head, build));
+ build.clear();
+ }
+ }
+
+ return pop(nodes);
+ }
+
+ /** Descend to the left-most leaf, building the path. */
+ private static <NodeType> void expand1Descend(
+ List<Forest.One<NodeType>> path, List<Tree<NodeType>> nodes,
+ List<Integer> sizes, List<Integer> poss, Forest<NodeType> f)
+ throws Ambiguous {
+ while (true) {
+ if (f instanceof Forest.Many)
+ f = ((Forest.Many<NodeType>)f).simplify();
+ else if (f instanceof Forest.One) {
+ Forest.One<NodeType> one = (Forest.One<NodeType>)f;
+ if (one.children.length == 0)
+ break;
+ path.add(one);
+ sizes.add(0);
+ poss.add(0);
+ f = one.children[0];
+ } else {
+ nodes.add(f.expand1());
+ return;
+ }
+ }
+
+ if (path.size() > 0 && peek(path).lifts[peek(poss)])
+ sizes.add(pop(sizes) - 1); // ignore lifted leafs
+ else
+ nodes.add(f.expand1());
+ }
+
+ private static <T> T pop(List<T> list) {
+ return list.remove(list.size() - 1); }
+ private static <T> T peek(List<T> list) {
+ return list.get(list.size() - 1); }
+
private static Tree[] tree_hint = new Tree[0];
private static String[] string_hint = new String[0];
private static final Forest[] emptyForestArray = new Forest[0];