Пример #1
0
        public NFA closure()
        {
            NFA ret = new NFA(this);
            //add new start state
            int oldStartState = ret.startState;
            int newStartState = ret.addState(false);

            ret.startState = newStartState;
            ret.connect(newStartState, oldStartState, new EpsilonConnection(0, 0));
            //add connections from old end states to old start state
            ret.addConnectionToEndStates(oldStartState, new EpsilonConnection(0, 0));
            //old start state is a valid end state
            ret.endStates.Add(newStartState);
            ret.hasEpsilons = true;
            return(ret);
        }
Пример #2
0
        public NFA toDFA()
        {
            NFA temp = new NFA(this);
            NFA ret  = new NFA();

            temp.deEpsilonate();
            List <HashSet <int> > newStates = new List <HashSet <int> >();

            newStates.Add(new HashSet <int>());
            Queue <HashSet <int> > statesThatNeedProcessing = new Queue <HashSet <int> >();
            HashSet <int>          startState = new HashSet <int>();

            startState.Add(temp.startState);
            ret.startState = ret.addState(temp.endStates.Contains(temp.startState));
            newStates.Add(startState);
            statesThatNeedProcessing.Enqueue(startState);
            while (statesThatNeedProcessing.Count > 0)
            {
                HashSet <int>     newState                 = statesThatNeedProcessing.Dequeue();
                int               hasState                 = newStates.FindIndex(h => newState.SetEquals(h));
                List <Connection> allConnections           = new List <Connection>();
                List <Connection> uninterestingConnections = new List <Connection>();
                HashSet <int>     anyReachable             = new HashSet <int>();
                foreach (int i in newState)
                {
                    allConnections.AddRange(temp.connectionPerState[i]);
                }
                HashSet <char> interestingChars = new HashSet <char>();
                foreach (Connection c in allConnections)
                {
                    if (c is AnythingConnection)
                    {
                        anyReachable.Add(c.end);
                    }
                    if (c is AnythingConnection || c is ConnectionAnythingBut)
                    {
                        uninterestingConnections.Add(c);
                    }
                    interestingChars.UnionWith(c.interestingCharacters());
                }
                foreach (char ch in interestingChars)
                {
                    HashSet <int> reachable = new HashSet <int>();
                    foreach (Connection c in allConnections)
                    {
                        if (c.accepts(ch))
                        {
                            reachable.Add(c.end);
                        }
                    }
                    int newAddIndex = newStates.FindIndex(h => reachable.SetEquals(h));
                    if (newAddIndex == -1)
                    {
                        bool endState = false;
                        foreach (int i in reachable)
                        {
                            if (temp.endStates.Contains(i))
                            {
                                endState = true;
                                break;
                            }
                        }
                        newAddIndex = ret.addState(endState);
                        newStates.Add(reachable);
                        statesThatNeedProcessing.Enqueue(reachable);
                    }
                    ret.connect(hasState, newAddIndex, new ConnectionExactCharacter(hasState, newAddIndex, ch));
                }
                if (uninterestingConnections.Count > 0)
                {
                    HashSet <int> reachable = new HashSet <int>();
                    foreach (Connection c in uninterestingConnections)
                    {
                        reachable.Add(c.end);
                    }
                    int newAddIndex = newStates.FindIndex(h => reachable.SetEquals(h));
                    if (newAddIndex == -1)
                    {
                        bool endState = false;
                        foreach (int i in reachable)
                        {
                            if (temp.endStates.Contains(i))
                            {
                                endState = true;
                                break;
                            }
                        }
                        newAddIndex = ret.addState(endState);
                        newStates.Add(reachable);
                        statesThatNeedProcessing.Enqueue(reachable);
                    }
                    if (interestingChars.Count > 0)
                    {
                        ret.connect(hasState, newAddIndex, new ConnectionAnythingBut(hasState, newAddIndex, interestingChars));
                    }
                    else
                    {
                        ret.connect(hasState, newAddIndex, new AnythingConnection(hasState, newAddIndex));
                    }
                }
            }
            int garbageState = ret.addState(false);

            ret.calculateConnectionPerState();
            for (int i = 1; i < ret.numStates; i++)
            {
                HashSet <char> unUsableConnections = new HashSet <char>();
                foreach (Connection c in ret.connectionPerState[i])
                {
                    unUsableConnections.UnionWith(c.acceptSet());
                }
                bool           canUseAll         = true;
                bool           canUseAny         = true;
                HashSet <char> usableConnections = new HashSet <char>();
                foreach (Connection c in ret.connectionPerState[i])
                {
                    if (c is AnythingConnection)
                    {
                        canUseAny = false;
                        break;
                    }
                    if (c is ConnectionAnythingBut)
                    {
                        if (canUseAll)
                        {
                            usableConnections = new HashSet <char>(((ConnectionAnythingBut)c).forbidden);
                            canUseAll         = false;
                        }
                        else
                        {
                            usableConnections.IntersectWith(((ConnectionAnythingBut)c).forbidden);
                        }
                    }
                }
                if (canUseAny)
                {
                    if (!canUseAll)
                    {
                        usableConnections.ExceptWith(unUsableConnections);
                        if (usableConnections.Count > 0)
                        {
                            ret.connect(i, garbageState, new ConnectionAnyOf(i, garbageState, usableConnections));
                        }
                    }
                    else
                    {
                        if (unUsableConnections.Count > 0)
                        {
                            ret.connect(i, garbageState, new ConnectionAnythingBut(i, garbageState, unUsableConnections));
                        }
                        else
                        {
                            ret.connect(i, garbageState, new AnythingConnection(i, garbageState));
                        }
                    }
                }
            }
            ret.connect(garbageState, garbageState, new AnythingConnection(garbageState, garbageState));
            ret.calculateConnectionPerState();
            return(ret);
        }