import java.util.*;
/** if ambiguity checking is enabled, this exception is thrown to signal that the parse was ambiguous */
-public class Ambiguous extends RuntimeException {
+public class Ambiguous extends Exception {
public final Forest<?> ambiguity;
public Ambiguous(Forest<?> ambiguity) { this.ambiguity = ambiguity; }
public String toString() {
+ // FEATURE: more legible printout desperately needed
StringBuffer sb = new StringBuffer();
- sb.append("unresolved ambiguity "/*"at " + ambiguity.getLocation() + ":"*/);
- for(Tree<?> result : ambiguity.expand(false))
- sb.append("\n\n" + result.toPrettyString());
+ sb.append("unresolved ambiguity ");
+ for(Tree<?> result : ambiguity.expand(false)) {
+ sb.append("\n\n");
+ result.toPrettyString(sb);
+ }
return sb.toString();
}
}
abstract StringBuffer toString(StringBuffer sb);
- /** if this element always matches exactly one token, return a topology covering exactly those possible tokens, otherwise <tt>null</tt> */
- Forest epsilonForm() { return null; }
+ /** returns the Forest resulting from matching this element against the empty string */
+ Forest epsilonForm() { throw new Error("element " + this + " has no epsilon form"); }
}
/** assume that this forest contains exactly one tree and return it; otherwise throw an exception */
public final Tree<T> expand1() throws Ambiguous, ParseFailed {
- Iterator<Tree<T>> it = expand(true).iterator();
- if (!it.hasNext()) throw new ParseFailed();
- return it.next();
+ try {
+ Iterator<Tree<T>> it = expand(true).iterator();
+ if (!it.hasNext()) throw new ParseFailed();
+ return it.next();
+ } catch (InnerAmbiguous ia) { throw new Ambiguous(ia.f); }
}
/** expand this forest into a set of trees */
public HashSet<Tree<T>> expand(boolean toss) {
final HashSetTreeConsumer<T> ret = new HashSetTreeConsumer<T>();
visit(new TreeMaker2<T>(toss, ret), null, null);
- if (toss && ret.size() > 1) throw new Ambiguous(this);
+ if (toss && ret.size() > 1) throw new InnerAmbiguous(this);
return ret;
}
+ private static class InnerAmbiguous extends RuntimeException {
+ public final Forest<?> f;
+ public InnerAmbiguous(Forest<?> f) { this.f = f; }
+ }
+
public static interface TreeConsumer<T> {
public void addTree(Tree<T> t);
}
this.synthetic = synthetic;
}
- /** display form for the Union (ie not including the RHS) */
final String shortForm;
-
- /** this is just a hint to use when printing out the grammar in visual form */
final boolean synthetic;
-
- /** the actual alternatives */
private final List<Sequence> alternatives = new ArrayList<Sequence>();
public Iterator<Sequence> iterator() { return alternatives.iterator(); }
if (alternatives.size()==0) {
sb.append(StringUtil.pad(15, shortForm) + " = ");
} else for(Sequence s : this) {
+ // FIXME: what to do here about printing out negated sequences?
sb.append(StringUtil.pad(15, first ? shortForm : "") + (first ? " = " : " | "));
first = false;
sb.append(s.toString());
private boolean basic() { return toString().length() < MAXCHARS; }
public String toPrettyString() { return toPrettyString("\n"); }
+ public StringBuffer toPrettyString(StringBuffer sb) { sb.append(this); return sb; }
private String toPrettyString(String nl) {
String str = toString();
if (str.length() < MAXCHARS) return str;