/// <summary> /// Creates an automaton that repeats the sub-automaton a number of times in the given range [min, max] /// </summary> /// <param name="sub">The sub-automaton</param> /// <param name="min">The minimum (included) number of time to repeat</param> /// <param name="max">The maximum (included) number of time to repeat</param> /// <returns>The new automaton</returns> // TODO: should get rid of static methods public static NFA NewRepeatRange(NFA sub, int min, int max) { NFA final = NewMinimal(); NFAState last = final.StateEntry; for (int i = 0; i != min; i++) { NFA inner = sub.Clone(); final.states.AddRange(inner.states); last.AddTransition(NFA.EPSILON, inner.StateEntry); last = inner.StateExit; } for (int i = min; i != max; i++) { NFA inner = NewOptional(sub, true); final.states.AddRange(inner.states); last.AddTransition(NFA.EPSILON, inner.StateEntry); last = inner.StateExit; } last.AddTransition(NFA.EPSILON, final.StateExit); if (min == 0) { final.StateEntry.AddTransition(NFA.EPSILON, final.StateExit); } return(final); }
/// <summary> /// Clones this automaton /// </summary> /// <param name="keepFinals">Whether to keep the marks for the final states</param> /// <returns>The cloned automaton</returns> public NFA Clone(bool keepFinals) { NFA copy = new NFA(); // Create new states for copy, add marks and copy finals if required for (int i = 0; i != states.Count; i++) { NFAState state = new NFAState(); state.Mark = states[i].Mark; if (keepFinals) { state.AddItems(states[i].Items); } copy.states.Add(state); } // Make linkage for (int i = 0; i != states.Count; i++) { foreach (NFATransition transition in states[i].Transitions) { copy.states[i].AddTransition(transition.Span, copy.states[states.IndexOf(transition.Next)]); } } if (StateEntry != null) { copy.StateEntry = copy.states[states.IndexOf(StateEntry)]; } if (StateExit != null) { copy.StateExit = copy.states[states.IndexOf(StateExit)]; } return(copy); }
/// <summary> /// Creates and initializes a minimal automaton with an entry state and a separate exit state /// </summary> /// <returns>The created automaton</returns> public static NFA NewMinimal() { NFA result = new NFA(); result.StateEntry = result.AddNewState(); result.StateExit = result.AddNewState(); return(result); }
/// <summary> /// Initializes this dfa as equivalent to the given nfa /// </summary> /// <param name="nfa">A nfa</param> public DFA(NFA nfa) { states = new List <DFAState>(); List <NFAStateSet> nfaStateSets = new List <NFAStateSet>(); // Create the first NFA set, add the entry and close it NFAStateSet nfaInit = new NFAStateSet(); nfaStateSets.Add(nfaInit); nfaInit.Add(nfa.StateEntry); nfaInit.Close(); // Create the initial state for the DFA DFAState dfaInit = new DFAState(0); states.Add(dfaInit); // For each set in the list of the NFA states for (int i = 0; i != nfaStateSets.Count; i++) { // Normalize transitions nfaStateSets[i].Normalize(); // Get the transitions for the set Dictionary <CharSpan, NFAStateSet> transitions = nfaStateSets[i].GetTransitions(); // For each transition foreach (CharSpan value in transitions.Keys) { // The child by the transition NFAStateSet next = transitions[value]; // Search for the child in the existing sets bool found = false; for (int j = 0; j != nfaStateSets.Count; j++) { // An existing equivalent set is already present if (nfaStateSets[j].Equals(next)) { states[i].AddTransition(value, states[j]); found = true; break; } } // The child is not already present if (!found) { // Add to the sets list nfaStateSets.Add(next); // Create the corresponding DFA state DFAState newState = new DFAState(states.Count); states.Add(newState); // Setup transition states[i].AddTransition(value, newState); } } // Add finals states[i].AddItems(nfaStateSets[i].GetFinals()); } }
/// <summary> /// Creates an automaton that repeats the sub-automaton one or more times /// </summary> /// <param name="sub">The sub-automaton</param> /// <param name="useClones">True to completely clone the sub-automaton</param> /// <returns>The new automaton</returns> // TODO: should get rid of static methods public static NFA NewRepeatOneOrMore(NFA sub, bool useClones) { NFA final = NewMinimal(); if (useClones) { sub = sub.Clone(); } final.states.AddRange(sub.states); final.StateEntry.AddTransition(NFA.EPSILON, sub.StateEntry); sub.StateExit.AddTransition(NFA.EPSILON, final.StateExit); final.StateExit.AddTransition(NFA.EPSILON, sub.StateEntry); return(final); }
/// <summary> /// Creates an automaton that concatenates the two sub-automaton /// </summary> /// <param name="left">The left automaton</param> /// <param name="right">The right automaton</param> /// <param name="useClones">True to completely clone the sub-automata</param> /// <returns>The new automaton</returns> // TODO: should get rid of static methods public static NFA NewConcatenation(NFA left, NFA right, bool useClones) { NFA final = new NFA(); if (useClones) { left = left.Clone(true); right = right.Clone(true); } final.states.AddRange(left.states); final.states.AddRange(right.states); final.StateEntry = left.StateEntry; final.StateExit = right.StateExit; left.StateExit.AddTransition(NFA.EPSILON, right.StateEntry); return(final); }
/// <summary> /// Creates an automaton that is the union of the two sub-automaton /// </summary> /// <param name="left">The left automaton</param> /// <param name="right">The right automaton</param> /// <param name="useClones">True to completely clone the sub-automata</param> /// <returns>The new automaton</returns> // TODO: should get rid of static methods public static NFA NewUnion(NFA left, NFA right, bool useClones) { NFA final = NewMinimal(); if (useClones) { left = left.Clone(true); right = right.Clone(true); } final.states.AddRange(left.states); final.states.AddRange(right.states); final.StateEntry.AddTransition(NFA.EPSILON, left.StateEntry); final.StateEntry.AddTransition(NFA.EPSILON, right.StateEntry); left.StateExit.AddTransition(NFA.EPSILON, final.StateExit); right.StateExit.AddTransition(NFA.EPSILON, final.StateExit); return(final); }
/// <summary> /// Creates an automaton that is the difference between the left and right sub-automata /// </summary> /// <param name="left">The left automaton</param> /// <param name="right">The right automaton</param> /// <param name="useClones">True to completely clone the sub-automata</param> /// <returns>The new automaton</returns> // TODO: should get rid of static methods public static NFA NewDifference(NFA left, NFA right, bool useClones) { NFA final = NewMinimal(); NFAState statePositive = final.AddNewState(); NFAState stateNegative = final.AddNewState(); statePositive.Mark = 1; stateNegative.Mark = -1; if (useClones) { left = left.Clone(true); right = right.Clone(true); } final.states.AddRange(left.states); final.states.AddRange(right.states); final.StateEntry.AddTransition(NFA.EPSILON, left.StateEntry); final.StateEntry.AddTransition(NFA.EPSILON, right.StateEntry); left.StateExit.AddTransition(NFA.EPSILON, statePositive); right.StateExit.AddTransition(NFA.EPSILON, stateNegative); statePositive.AddTransition(NFA.EPSILON, final.StateExit); final.StateExit.AddItem(DummyItem.Instance); DFA equivalent = new DFA(final); equivalent.Prune(); final = new NFA(equivalent); final.StateExit = final.AddNewState(); foreach (NFAState state in final.states) { if (state.Items.Contains(DummyItem.Instance)) { state.ClearItems(); state.AddTransition(NFA.EPSILON, final.StateExit); } } return(final); }
/// <summary> /// Inserts all the states of the given automaton into this one /// This does not make a copy of the states, this directly includes them /// </summary> /// <param name="sub">Sub-automaton to include in this one</param> public void InsertSubNFA(NFA sub) { states.AddRange(sub.states); }