continue;
forward.add(epsilon.from, epsilon.to);
backward.add(epsilon.to, epsilon.from);
StatePair pair = new StatePair(epsilon.from, epsilon.to);
if (!all.containsKey(pair))
all.put(pair, new TreeSet<Character>(epsilon.illegalCharacters()));
else
all.get(pair).retainAll(epsilon.illegalCharacters());
workset.add(pair);
}
// calculate the transitive closure.
// for every eps.tr. (s1,s2), we find a transition (s2,s3), and create (s1,s3).
// workset contains the (s1,s2) pairs that may yield a new transition like above.
while (!workset.isEmpty()) {
Iterator<StatePair> it = workset.iterator();
StatePair pair = it.next();
it.remove();
State s1 = pair.getFirstState();
State s2 = pair.getSecondState();
for (State s3 : forward.getView(s2)) {
// do not create degenerate epsilons
if (s1 == s3)
continue;
assert s1 != s2 && s2 != s3;
TreeSet<Character> illegal = new TreeSet<Character>(all.get(pair));
illegal.addAll(all.get(new StatePair(s2, s3)));
boolean changed;
StatePair p2 = new StatePair(s1, s3);
if (!all.containsKey(p2)) {
all.put(p2, illegal);
forward.add(s1, s3); // note: we are not modifying the view being iterated because s1!=s2
backward.add(s3, s1);
changed = true;
} else {
changed = all.get(p2).retainAll(illegal);
}
if (changed) {
workset.add(p2);
for (State s0 : backward.getView(s1)) {
workset.add(new StatePair(s0, s1));
}
}
}
}
// closure completed, time to add the transitions
LinkedList<StateTransitionPair> transitions = new LinkedList<StateTransitionPair>();
for (Map.Entry<StatePair, TreeSet<Character>> entry : all.entrySet()) {
StatePair pair = entry.getKey();
for (Transition tr : pair.getSecondState().getTransitions()) {
char ch = tr.getMin();
// TreeSet is sorted, so we visit the illegal characters in increasing order
// at every illegal character, we add the interval below, since it must be a legal interval
for (Character illegal : entry.getValue()) {
if (illegal < ch)
continue;
if (illegal > tr.getMax())
break;
if (illegal > ch) {
transitions.add(new StateTransitionPair(pair.getFirstState(), new Transition(ch, (char)(illegal - 1), tr.getDest())));
}
ch = (char)(illegal + 1);
}
if (ch <= tr.getMax()) {
transitions.add(new StateTransitionPair(pair.getFirstState(), new Transition(ch, tr.getMax(), tr.getDest())));
}
}
}
for (StateTransitionPair pair : transitions) {
pair.state.addTransition(pair.transition);