///////////////////////////////////////////////////////////////// // // NFA building functions // // Using Thompson Construction, build NFAs from basic inputs or // compositions of other NFAs. // /// <summary> /// Builds a basic, single input NFA /// </summary> /// <param name="in"></param> /// <returns></returns> public static NFA BuildNFABasic(input @in) { NFA basic = new NFA(2, 0, 1); basic.AddTrans(0, 1, @in); return(basic); }
public NFA(NFA nfa) { initial = nfa.initial; final = nfa.final; size = nfa.size; inputs = nfa.inputs; transTable = nfa.transTable; }
/// <summary> /// Fills states 0 up to other.size with other's states. /// </summary> /// <param name="other"></param> public void FillStates(NFA other) { for (state i = 0; i < other.size; ++i) { for (state j = 0; j < other.size; ++j) { transTable[i][j] = other.transTable[i][j]; } } SCG.IEnumerator <input> cE = other.inputs.GetEnumerator(); while (cE.MoveNext()) { inputs.Add(cE.Current); } }
public void FillStates(NFA other) { for (state i = 0; i < other.size; ++i) { for (state j = 0; j < other.size; ++j) { transTable[i][j] = other.transTable[i][j]; } } for (int i = 0; i < other.inputs.Count; i++) { if (!inputs.Contains(other.inputs[i])) { inputs.Add(other.inputs[i]); } } }
/// <summary> /// The main entry point of the Console Application /// </summary> /// <param name="args"></param> static void Main(string[] args) { if (args.Length != 3) { Console.WriteLine("Call with the regex as an argument."); Environment.Exit(1); } RegexParser myRegexParser = new RegexParser(); // Passing the regex to be preprocessed. myRegexParser.Init(args[1]); // Creating a parse tree with the preprocessed regex ParseTree parseTree = myRegexParser.Expr(); // Checking for a string termination character after // parsing the regex if (myRegexParser.Peek() != '\0') { Console.WriteLine("Parse error: unexpected char, got {0} at #{1}", myRegexParser.Peek(), myRegexParser.GetPos()); Environment.Exit(1); } PrintTree(parseTree, 1); NFA nfa = NFA.TreeToNFA(parseTree); nfa.Show(); DFA dfa = SubsetMachine.SubsetConstruct(nfa); dfa.Show(); Console.Write("\n\n"); Console.Write("Result: {0}", dfa.Simulate(args[2])); Console.ReadKey(); }
/// <summary> /// Builds a star (kleene closure) of nfa (nfa*) /// How this is done: First will come the new initial state, then NFA, then the /// new final state /// </summary> /// <param name="nfa"></param> /// <returns></returns> public static NFA BuildNFAStar(NFA nfa) { // Makes room for the new initial state nfa.ShiftStates(1); // Makes room for the new final state nfa.AppendEmptyState(); // Adds new transitions nfa.AddTrans(nfa.final, nfa.initial, (char)Constants.Epsilon); nfa.AddTrans(0, nfa.initial, (char)Constants.Epsilon); nfa.AddTrans(nfa.final, nfa.size - 1, (char)Constants.Epsilon); nfa.AddTrans(0, nfa.size - 1, (char)Constants.Epsilon); nfa.initial = 0; nfa.final = nfa.size - 1; return(nfa); }
/// <summary> /// Builds an alternation of nfa1 and nfa2 (nfa1|nfa2) /// </summary> /// <param name="nfa1"></param> /// <param name="nfa2"></param> /// <returns></returns> public static NFA BuildNFAConcat(NFA nfa1, NFA nfa2) { // How this is done: First will come nfa1, then nfa2 (its initial state replaced // with nfa1's final state) nfa2.ShiftStates(nfa1.size - 1); // Creates a new NFA and initialize it with (the shifted) nfa2 NFA newNFA = new NFA(nfa2); // nfa1's states take their places in newNFA // note: nfa1's final state overwrites nfa2's initial state, // thus we get the desired merge automagically (the transition // from nfa2's initial state now transits from nfa1's final state) newNFA.FillStates(nfa1); // Sets the new initial state (the final state stays nfa2's final state, // and was already copied) newNFA.initial = nfa1.initial; return(newNFA); }
/// <summary> /// Builds an alternation of nfa1 and nfa2 (nfa1|nfa2) /// </summary> /// <param name="nfa1"></param> /// <param name="nfa2"></param> /// <returns></returns> public static NFA BuildNFAAlter(NFA nfa1, NFA nfa2) { // How this is done: the new nfa must contain all the states in // nfa1 and nfa2, plus a new initial and final states. // First will come the new initial state, then nfa1's states, then // nfa2's states, then the new final state // make room for the new initial state nfa1.ShiftStates(1); // make room for nfa1 nfa2.ShiftStates(nfa1.size); // create a new nfa and initialize it with (the shifted) nfa2 NFA newNFA = new NFA(nfa2); // nfa1's states take their places in new_nfa newNFA.FillStates(nfa1); // Set new initial state and the transitions from it newNFA.AddTrans(0, nfa1.initial, (char)Constants.Epsilon); newNFA.AddTrans(0, nfa2.initial, (char)Constants.Epsilon); newNFA.initial = 0; // Make up space for the new final state newNFA.AppendEmptyState(); // Set new final state newNFA.final = newNFA.size - 1; newNFA.AddTrans(nfa1.final, newNFA.final, (char)Constants.Epsilon); newNFA.AddTrans(nfa2.final, newNFA.final, (char)Constants.Epsilon); return(newNFA); }
/// <summary> /// Builds the Epsilon closure of states for the given NFA /// </summary> /// <param name="nfa"></param> /// <param name="states"></param> /// <returns></returns> static Set <state> EpsilonClosure(NFA nfa, Set <state> states) { // Push all states onto a stack SCG.Stack <state> uncheckedStack = new SCG.Stack <state>(states); // Initialize EpsilonClosure(states) to states Set <state> epsilonClosure = states; while (uncheckedStack.Count != 0) { // Pop state t, the top element, off the stack state t = uncheckedStack.Pop(); int i = 0; // For each state u with an edge from t to u labeled Epsilon foreach (input input in nfa.transTable[t]) { if (input == (char)NFA.Constants.Epsilon) { state u = Array.IndexOf(nfa.transTable[t], input, i); // If u is not already in epsilonClosure, add it and push it onto stack if (!epsilonClosure.Contains(u)) { epsilonClosure.Add(u); uncheckedStack.Push(u); } } i = i + 1; } } return(epsilonClosure); }
/// <summary> /// Subset machine that employs the powerset construction or subset construction algorithm. /// It creates a DFA that recognizes the same language as the given NFA. /// </summary> public static DFA SubsetConstruct(NFA nfa) { DFA dfa = new DFA(); // Sets of NFA states which is represented by some DFA state Set <Set <state> > markedStates = new Set <Set <state> >(); Set <Set <state> > unmarkedStates = new Set <Set <state> >(); // Gives a number to each state in the DFA HashDictionary <Set <state>, state> dfaStateNum = new HashDictionary <Set <state>, state>(); Set <state> nfaInitial = new Set <state>(); nfaInitial.Add(nfa.initial); // Initially, EpsilonClosure(nfa.initial) is the only state in the DFAs states // and it's unmarked. Set <state> first = EpsilonClosure(nfa, nfaInitial); unmarkedStates.Add(first); // The initial dfa state state dfaInitial = GenNewState(); dfaStateNum[first] = dfaInitial; dfa.start = dfaInitial; while (unmarkedStates.Count != 0) { // Takes out one unmarked state and posteriorly mark it. Set <state> aState = unmarkedStates.Choose(); // Removes from the unmarked set. unmarkedStates.Remove(aState); // Inserts into the marked set. markedStates.Add(aState); // If this state contains the NFA's final state, add it to the DFA's set of // final states. if (aState.Contains(nfa.final)) { dfa.final.Add(dfaStateNum[aState]); } SCG.IEnumerator <input> iE = nfa.inputs.GetEnumerator(); // For each input symbol the NFA knows... while (iE.MoveNext()) { // Next state Set <state> next = EpsilonClosure(nfa, nfa.Move(aState, iE.Current)); // If we haven't examined this state before, add it to the unmarkedStates, // and make up a new number for it. if (!unmarkedStates.Contains(next) && !markedStates.Contains(next)) { unmarkedStates.Add(next); dfaStateNum.Add(next, GenNewState()); } KeyValuePair <state, input> transition = new KeyValuePair <state, input>(); transition.Key = dfaStateNum[aState]; transition.Value = iE.Current; dfa.transTable[transition] = dfaStateNum[next]; } } return(dfa); }