- Fix the metagrammar (really?)
- - Repeat, Sequence, Tree
- - simplify Forest (considerably)
-
- decent/better error messages
- fix the location stuff, it's broken
protected abstract Topology<T> top();
public abstract String toString();
- public Topology toAtom() { return this; }
-
// Topology Thunks //////////////////////////////////////////////////////////////////////////////
public Topology<T> unwrap() { return top().unwrap(); }
public static class Infer<T extends Input> extends Atom<T> {
private final Element e;
public Infer(Element e) { this.e = e; }
- public Topology<T> top() { return (Topology<T>)e.toAtom(); }
+ public Topology<T> top() { return (Topology<T>)toAtom(e); }
public String toString() { return e.toString(); /* FIXME should be toAtom() */ }
}
public Topology<T> top() { return ((Topology<T>)a.top()).complement(); }
public String toString() { return "~"+a; }
}
+
+ static Topology toAtom(Element e) {
+ if (e instanceof Atom) return (Atom)e;
+ if (e instanceof Sequence) return ((Sequence)e).toAtom();
+ Topology ret = null;
+ for(Sequence s : (Union)e)
+ ret = ret==null ? toAtom(s) : ret.union(s.toAtom());
+ return ret;
+ }
}
public abstract class Element {
/** if this element always matches exactly one token, return a topology covering exactly those possible tokens, otherwise <tt>null</tt> */
- abstract Topology toAtom();
- public Topology toAtom0() { return toAtom(); }
Forest epsilonForm() { throw new Error("no epsilon form: " + this); }
final boolean possiblyEpsilon(Walk.Cache cache) {
Boolean ret = cache==null ? null : cache.possiblyEpsilon.get(this);
if (touched.contains(n)) return;
touched.add(n);
for(Position p : n.state) {
- if (((p.isFirst() || p.isLast()) && !force) || p.owner().name==null) {
+ 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;
+ String seqname = p.owner()/*.name*/+"";
HashSet<String> hs = errors.get(seqname);
if (hs==null) errors.put(seqname, hs = new HashSet<String>());
hs.add(p.element()+"");
////////////////////////////////////////////////////////////////////////////////
public Element noFollow = null;
- public String name = null;
- public void setName(String name) { this.name = name; }
- public final Topology noFollow() { return noFollow==null ? null : noFollow.toAtom(); }
+ public final Topology noFollow() { return noFollow==null ? null : Atom.toAtom(noFollow); }
Topology toAtom() {
if (elements.length!=1) throw new RuntimeException("cannot invoke toAtom() on a Sequence with " + elements.length + " elements: " + this);
- return elements[0].toAtom();
+ return Atom.toAtom(elements[0]);
}
protected final Element[] elements;
/** an element which can produce one of several alternatives */
public class Union extends Element implements Iterable<Sequence> {
+ /** 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(); }
public boolean contains(Sequence s) { return alternatives.contains(s); }
- Topology toAtom() {
- if (alternatives.size()==0) throw new RuntimeException("cannot build an Atom from a Union with no productions");
- Topology ret = null;
- for(Sequence s : this) {
- Topology a = s.toAtom();
- if (ret==null) ret = a;
- else ret = ret.union(a);
- }
- if (ret==null) throw new RuntimeException("confusion on " + this);
- return ret;
- }
-
/** adds an alternative */
public void add(Sequence s) {
alternatives.add(s);
for(Sequence n : s.needs) add(n);
for(Sequence n : s.hates) add(n);
- if (/*!synthetic &&*/ shortForm!=null
- //&& Character.isUpperCase(shortForm.charAt(0))
- )
- s.setName(toString());
}
/**
else if ("psy".equals(head)) return (PreSequence)walk(tree, 0);
else if ("->".equals(head)) { PreSequence p = (PreSequence)walk(tree, 0); p.noFollow = (Element)walk(tree, 1); return p; }
else if ("/".equals(head)) return ((PreSequence)walk(tree, 0)).sparse((Element)walk(tree, 1));
+ else if (" /".equals(head)) return ((PreSequence)walk(tree, 0)).sparse((Element)walk(tree, 1));
else if ("~".equals(head)) return new Hack(new Atom.Invert(new Atom.Infer((Element)walk(tree, 0))));
else if ("ps".equals(head)) return new PreSequence((Object[])walk(tree,0), null);
else if (":".equals(head)) {
s = ws grammar:Grammar ws
Grammar = NonTerminal +/ ws
-NonTerminal = Word !wp ^"=" !wp RHS
+NonTerminal = Word ^"=" RHS /ws
RHS = (Sequence +/ (!ws "|" !ws)) +/ (!ws ">" !ws)
PreSequence = ps:: Elements
| (Quoted|Word) ^"::" PreSequence /ws
- > PreSequence !wp ^"/" !ws e
- | PreSequence ^"->" e /ws
+ > PreSequence ^"/" e /ws
+ | PreSequence ^"->" e /ws
Sequence = psx:: PreSequence
- | Sequence !ws ^"&" !ws Elements
- | Sequence !ws ^"&~" !ws Elements
+ | Sequence ^"&" Elements /ws
+ | Sequence ^"&~" Elements /ws
ec = ~[\-\]\\]
| escaped