@@ -0,0 +1,2894 @@
+/* This file is part of SableCC ( http://sablecc.org ).%0A * %0A * See the NOTICE file distributed with this work for copyright information.%0A *%0A * Licensed under the Apache License, Version 2.0 (the %22License%22);%0A * you may not use this file except in compliance with the License.%0A * You may obtain a copy of the License at%0A *%0A *     http://www.apache.org/licenses/LICENSE-2.0%0A *%0A * Unless required by applicable law or agreed to in writing, software%0A * distributed under the License is distributed on an %22AS IS%22 BASIS,%0A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.%0A * See the License for the specific language governing permissions and%0A * limitations under the License.%0A */%0A%0Apackage org.sablecc.sablecc.automaton;%0A%0Aimport java.util.Collections;%0Aimport java.util.HashMap;%0Aimport java.util.HashSet;%0Aimport java.util.Map;%0Aimport java.util.Set;%0A%0Aimport org.sablecc.sablecc.automaton.graph.State;%0Aimport org.sablecc.sablecc.automaton.graph.Transition;%0Aimport org.sablecc.sablecc.exception.InternalException;%0A%0Aclass EpsilonReach%3CT extends Comparable%3C? super T%3E%3E %7B%0A%0A    private NFA%3CT%3E nfa;%0A%0A    private final Map%3CState%3CT%3E, Set%3CState%3CT%3E%3E%3E reachMap = new HashMap%3CState%3CT%3E, Set%3CState%3CT%3E%3E%3E();%0A%0A    EpsilonReach(%0A            NFA%3CT%3E nfa) %7B%0A%0A        if (nfa == null) %7B%0A            throw new InternalException(%22nfa may not be null%22);%0A        %7D%0A%0A        this.nfa = nfa;%0A    %7D%0A%0A    Set%3CState%3CT%3E%3E getEpsilonReach(%0A            State%3CT%3E state) %7B%0A%0A        if (state == null) %7B%0A            throw new InternalException(%22state may not be null%22);%0A        %7D%0A%0A        if (!this.nfa.getStates().contains(state)) %7B%0A            throw new InternalException(%22invalid state%22);%0A        %7D%0A%0A        Set%3CState%3CT%3E%3E reach = this.reachMap.get(state);%0A%0A        if (reach == null) %7B%0A            reach = computeReach(state);%0A            this.reachMap.put(state, reach);%0A        %7D%0A%0A        return reach;%0A    %7D%0A%0A    private Set%3CState%3CT%3E%3E computeReach(%0A            State%3CT%3E state) %7B%0A%0A        Set%3CState%3CT%3E%3E reach = new HashSet%3CState%3CT%3E%3E();%0A%0A        visit(state, reach);%0A%0A        return Collections.unmodifiableSet(reach);%0A    %7D%0A%0A    private void visit(%0A            State%3CT%3E state,%0A            Set%3CState%3CT%3E%3E reach) %7B%0A%0A        // did we visit it before?%0A        if (!reach.contains(state)) %7B%0A%0A            // no, so add it%0A            reach.add(state);%0A%0A            // do we know its reach?%0A            Set%3CState%3CT%3E%3E stateReach = this.reachMap.get(state);%0A            if (stateReach != null) %7B%0A                // yes, use it!%0A                reach.addAll(stateReach);%0A            %7D%0A            else %7B%0A                // no, we need to visit%0A                for (Transition%3CT%3E transition : state.getForwardTransitions()) %7B%0A                    if (transition.getSymbol() == null) %7B%0A                        visit(transition.getDestination(), reach);%0A                    %7D%0A                %7D%0A            %7D%0A        %7D%0A    %7D%0A%7D%0A

Add class to compute transitive NFA epsilon transitions.