+ 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 (!grammar.isRightNullable(p)) continue;
+ Topology<Token> follow = grammar.follow(p.owner());
+ for(Pos 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(grammar.follow(s));
+ Topology<Token> set = grammar.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 Pos "p"
+ state.reductions.put(follow, p);
+ if (grammar.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());
+ }
+ }
+
+ // FIXME: this method needs to be cleaned up and documented
+ private void sortReductions(Grammar<Token> grammar) {
+ // crude algorithm to assing an ordinal ordering to every position
+ // al will be sorted in DECREASING order (al[0] >= al[1])
+ ArrayList<Sequence.Pos> al = new ArrayList<Sequence.Pos>();
+ for(State s : all_states) {
+ for(Object po : s.positions()) {
+ Sequence.Pos p = (Sequence.Pos)po;
+ if (al.contains(p)) continue;
+ int i=0;
+ for(; i<al.size(); i++) {
+ if (grammar.comparePositions(p, al.get(i)) < 0)
+ break;
+ }
+ al.add(i, p);
+ }
+ }
+ // FIXME: this actually pollutes the "pure" objects (the ones that should not be modified by the Parser)
+ // sort in increasing order...
+ OUTER: while(true) {
+ for(int i=0; i<al.size(); i++)
+ for(int j=i+1; j<al.size(); j++)
+ if (grammar.comparePositions(al.get(i), al.get(j)) > 0) {
+ Sequence.Pos p = al.remove(j);
+ al.add(i, p);
+ continue OUTER;
+ }
+ break;
+ }
+
+ int j = 1;
+ int pk = 0;
+ for(int i=0; i<al.size(); i++) {
+ boolean inc = false;
+ for(int k=pk; k<i; k++) {
+ if (grammar.comparePositions(al.get(k), al.get(i)) > 0)
+ { inc = true; break; }