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); }
public NFA or(NFA second) { NFA ret = new NFA(this); //add states ret.incrementIndices(second.numStates); foreach (int i in second.endStates) { ret.endStates.Add(i); } //add connections between newly added states foreach (Connection c in second.connections) { ret.connections.Add(c.copy()); } //connect new start states with old start state ret.connect(ret.startState, second.startState, new EpsilonConnection(-1, -1)); ret.hasEpsilons = true; ret.calculateConnectionPerState(); return(ret); }
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); }