+ state.shifts.addAll(state.gotoSetTerminals.subset(((Atom)p.element()).getTokenTopology()));
+
+ // RNGLR: we can potentially reduce from any "right-nullable" position -- that is,
+ // any position for which all Elements after it in the Sequence are capable of
+ // matching the empty string.
+ if (!isRightNullable(p)) continue;
+ Topology<Token> follow = follow(p.owner());
+ for(Position p2 = p; p2 != null && p2.element() != null; p2 = p2.next()) {
+ if (!(p2.element() instanceof Union))
+ throw new Error("impossible -- only Unions can be nullable");
+
+ // interesting RNGLR-followRestriction interaction: we must intersect
+ // not just the follow-set of the last non-nullable element, but the
+ // follow-sets of the nulled elements as well.
+ for(Sequence s : ((Union)p2.element()))
+ follow = follow.intersect(follow(s));
+ Topology<Token> set = epsilonFollowSet((Union)p2.element());
+ if (set != null) follow = follow.intersect(set);
+ }
+
+ // indicate that when the next token is in the set "follow", nodes in this
+ // state should reduce according to Position "p"
+ state.reductions.put(follow, p);
+ if (followEof.contains(p.owner())) state.eofReductions.add(p);
+ }
+
+ // optimize the reductions table
+ if (emptyTopology() instanceof IntegerTopology)
+ for(State<Token> state : all_states) {
+ // FIXME: this is pretty ugly
+ state.oreductions = state.reductions.optimize(((IntegerTopology)emptyTopology()).functor());
+ state.oshifts = state.shifts.optimize(((IntegerTopology)emptyTopology()).functor());