}
/** the start state */
- public final State<Tok> start;
+ public final State<Tok> start;
+
+ /** the state from which no reductions can be done */
+ private final State<Tok> dead_state;
/** used to generate unique values for State.idx */
private int master_state_idx = 0;
cache.ys.addAll(e, new Walk.YieldSet(e, cache).walk());
HashSet<Position> hp = new HashSet<Position>();
reachable(start0, hp);
+
+ this.dead_state = new State<Tok>(new HashSet<Position>(), all_states, all_elements);
this.start = new State<Tok>(hp, all_states, all_elements);
// for each state, fill in the corresponding "row" of the parse table
// Interface Methods //////////////////////////////////////////////////////////////////////////////
- boolean isAccepting() { return accept; }
- public Iterator<Position> iterator() { return hs.iterator(); }
+ boolean isAccepting() { return accept; }
+ public Iterator<Position> iterator() { return hs.iterator(); }
- boolean canShift(Tok t) { return oshifts.contains(t); }
+ boolean canShift(Tok t) { return oshifts!=null && oshifts.contains(t); }
<B,C> void invokeShifts(Tok t, Invokable<State<Tok>,B,C> irbc, B b, C c) {
oshifts.invoke(t, irbc, b, c);
}
- boolean canReduce(Tok t) { return t==null ? eofReductions.size()>0 : oreductions.contains(t); }
+ boolean canReduce(Tok t) { return oreductions != null && (t==null ? eofReductions.size()>0 : oreductions.contains(t)); }
<B,C> void invokeReductions(Tok t, Invokable<Position,B,C> irbc, B b, C c) {
if (t==null) for(Position r : eofReductions) irbc.invoke(r, b, c);
else oreductions.invoke(t, irbc, b, c);
// "yields" [in one or more step] is used instead of "produces" [in exactly one step]
// to avoid having to iteratively construct our set of States as shown in most
// expositions of the algorithm (ie "keep doing XYZ until things stop changing").
+
HashMapBag<Element,Position> move = new HashMapBag<Element,Position>();
for(Position p : hs) {
Element e = p.element();
for(Element y : move) {
HashSet<Position> h = move.getAll(y);
State<Tok> s = all_states.get(h) == null ? new State<Tok>(h, all_states, all_elements) : all_states.get(h);
- gotoSetNonTerminals.put(y, s);
+ // if a reduction is "lame", it should wind up in the dead_state after reducing
+ if (y instanceof Sequence && ((Sequence)y).lame)
+ ((HashMap)gotoSetNonTerminals).put(y, dead_state);
+ else
+ gotoSetNonTerminals.put(y, s);
}
}