コード例 #1
0
        /// <summary>
        /// Create Deterministic Finite Automaton by lazy form of subset construction (Rabin and Scott, )
        /// </summary>
        /// <returns>Deterministic Finite Automaton created by lazy form of subset construction</returns>
        public LrItemsDfa <TTokenKind> ToDfa()
        {
            // The subset construction is an example of a fixed-point computation, where an application of a
            // monotone function to some collection of sets drawn from a domain whose structure is known is
            // performed iteratively. The computation will terminate when an iteration step produces a state
            // where further iteration produces the same answer — a “fixed point” in the space of successive
            // iterates.
            //
            // For the subset construction, the domain is the power set of all possible subsets of the NFA states.
            // The while loop adds elements (subsets) to Q; it cannot remove an element from Q. We can view
            // the while loop as a monotone increasing function f, which means that for a set x, f(x) ≥ x. (The
            // comparison operator ≥ is ⊇.) Since Q can have at most 2^N distinct elements, the while loop can iterate
            // at most 2^N times. It may, of course, reach a fixed point and halt more quickly than that.

            var newStartState = EpsilonClose(StartState.AsSingletonEnumerable());

            var newAcceptStates = new HashSet <ProductionItemSet <TTokenKind> >();
            var newTransitions  = new List <Transition <Symbol, ProductionItemSet <TTokenKind> > >();

            var newStates = new InsertionOrderedSet <ProductionItemSet <TTokenKind> > {
                newStartState
            };

            // Lazy form of Subset Construction where only reachable nodes
            // are added to the following work list of marked subsets
            var markedVisitedStates = new Queue <ProductionItemSet <TTokenKind> >(); // work list that preserves insertion order

            markedVisitedStates.Enqueue(newStartState);

            while (markedVisitedStates.Count != 0)
            {
                // subset S
                ProductionItemSet <TTokenKind> subsetSourceState = markedVisitedStates.Dequeue();

                if (subsetSourceState.Overlaps(GetAcceptStates()))
                {
                    newAcceptStates.Add(subsetSourceState);
                }

                // For all non-epsilon labels
                foreach (var label in GetAlphabet())
                {
                    // subset T
                    var subsetTargetState = new Set <ProductionItem <TTokenKind> >();

                    // kernel items: For all s in S, add all non-epsilon transitions (s, label) → t to T
                    foreach (ProductionItem <TTokenKind> s in subsetSourceState)
                    {
                        subsetTargetState.AddRange(Delta(Transition.FromPair(s, label)));
                    }

                    // Ignore empty subset (implicit transition to dead state in this case)
                    if (subsetTargetState.Count == 0)
                    {
                        continue;
                    }

                    // Closure Items: Epsilon-close all T such that (S, label) → T
                    var closure = EpsilonClose(subsetTargetState);

                    if (!newStates.Contains(closure))
                    {
                        newStates.Add(closure);
                        markedVisitedStates.Enqueue(closure);
                    }

                    // Add (S, label) → T transition
                    newTransitions.Add(Transition.Move(subsetSourceState, label, closure));
                }
            }

            return(new LrItemsDfa <TTokenKind>(newStates, GetAlphabet(), newTransitions, newStartState, newAcceptStates));
        }