static void _Concat(FA <TInput, TAccept> lhs, FA <TInput, TAccept> rhs) { var f = lhs.FirstAcceptingState; lhs.FirstAcceptingState.EpsilonTransitions.Add(rhs); f.Accept = default(TAccept); f.IsAccepting = false; }
/// <summary> /// Creates a new FA that matches the specified FA expression or empty /// </summary> /// <param name="expr">The expression to make optional</param> /// <param name="accept">The symbol to accept</param> /// <returns>A new FA that will match the specified expression or empty</returns> public static FA <TInput, TAccept> Optional(FA <TInput, TAccept> expr, TAccept accept = default(TAccept)) { var result = expr.Clone(); var f = result.FirstAcceptingState; f.Accept = accept; f.IsAccepting = true; result.EpsilonTransitions.Add(f); return(result); }
/// <summary> /// Creates a finite state machine that represents the LL(k) parsing rules /// </summary> /// <returns></returns> public FA <string, CfgRule> ToLLkFsm() { var predict = FillPredict(); var follows = FillFollows(); var nts = FillNonTerminals(); var result = new FA <string, CfgRule>(); for (int ic = nts.Count, i = 0; i < ic; i++) { var nt = nts[i]; var fa = new FA <string, CfgRule>(); result.Transitions.Add(nt, fa); foreach (var p in predict[nt]) { if (null != p.Symbol) { var ffa = new FA <string, CfgRule>(); ffa.IsAccepting = true; ffa.Accept = p.Rule; FA <string, CfgRule> fad; if (fa.Transitions.TryGetValue(p.Symbol, out fad)) { System.Diagnostics.Debugger.Break(); fa.Transitions.Remove(p.Symbol); // // FIRST FIRST conflict } else { fa.Transitions.Add(p.Symbol, ffa); } } else { foreach (var f in follows[nt]) { var ffa = new FA <string, CfgRule>(); ffa.IsAccepting = true; ffa.Accept = p.Rule; FA <string, CfgRule> fad; if (fa.Transitions.TryGetValue(f, out fad)) { System.Diagnostics.Debugger.Break(); // FIRST FOLLOW conflict } fa.Transitions.Add(f, ffa); } } } } return(result); }
/// <summary> /// Creates an FA that will match any one of a set of a characters /// </summary> /// <param name="set">The set of characters that will be matched</param> /// <param name="accept">The symbol to accept</param> /// <returns>An FA that will match the specified set</returns> public static FA <TInput, TAccept> Set(IEnumerable <TInput> set, TAccept accept = default(TAccept)) { var result = new FA <TInput, TAccept>(); var final = new FA <TInput, TAccept>(); final.Accept = accept; final.IsAccepting = true; foreach (TInput ch in set) { result.Transitions.Add(ch, final); } return(result); }
/// <summary> /// Creates an FA that matches a literal string /// </summary> /// <param name="string">The string to match</param> /// <param name="accept">The symbol to accept</param> /// <returns>A new FA machine that will match this literal</returns> public static FA <TInput, TAccept> Literal(IEnumerable <TInput> @string, TAccept accept = default(TAccept)) { var result = new FA <TInput, TAccept>(); var current = result; foreach (TInput ch in @string) { current.Accept = default(TAccept); current.IsAccepting = false; var fa = new FA <TInput, TAccept>(); fa.Accept = accept; fa.IsAccepting = true; current.Transitions.Add(ch, fa); current = fa; } return(result); }
/// <summary> /// Creates a new FA that matche any one of the FA expressions passed /// </summary> /// <param name="exprs">The expressions to match</param> /// <param name="accept">The symbol to accept</param> /// <returns>A new FA that will match the union of the FA expressions passed</returns> public static FA <TInput, TAccept> Or(IEnumerable <FA <TInput, TAccept> > exprs, TAccept accept = default(TAccept)) { var result = new FA <TInput, TAccept>(); var final = new FA <TInput, TAccept>(); final.Accept = accept; final.IsAccepting = true; foreach (var fa in exprs) { fa.EpsilonTransitions.Add(fa); var nfa = fa.Clone(); var nffa = fa.FirstAcceptingState; nfa.FirstAcceptingState.EpsilonTransitions.Add(final); nffa.Accept = default(TAccept); nffa.IsAccepting = false; } return(result); }
public FA <TInput, TAccept> ToDfa() { // The DFA states are keyed by the set of NFA states they represent. var dfaMap = new Dictionary <List <FA <TInput, TAccept> >, FA <TInput, TAccept> >(_SetComparer.Default); var unmarked = new HashSet <FA <TInput, TAccept> >(); // compute the epsilon closure of the initial state in the NFA var states = new List <FA <TInput, TAccept> >(); FillEpsilonClosure(states); // create a new state to represent the current set of states. If one // of those states is accepting, set this whole state to be accepting. FA <TInput, TAccept> dfa = new FA <TInput, TAccept>(); var al = new List <TAccept>(); foreach (var fa in states) { if (fa.IsAccepting) { if (!al.Contains(fa.Accept)) { al.Add(fa.Accept); } } } int ac = al.Count; if (1 == ac) { dfa.Accept = al[0]; dfa.IsAccepting = true; } else if (1 < ac) { // TODO: Give a detailed error message of the conflict throw new InvalidOperationException("Ambiguity in the FA."); } FA <TInput, TAccept> result = dfa; // store the initial state for later, so we can return it. // add it to the dfa map dfaMap.Add(states, dfa); // add it to the unmarked states, signalling that we still have work to do. unmarked.Add(dfa); bool done = false; while (!done) { done = true; HashSet <List <FA <TInput, TAccept> > > mapKeys = new HashSet <List <FA <TInput, TAccept> > >(dfaMap.Keys, _SetComparer.Default); foreach (List <FA <TInput, TAccept> > mapKey in mapKeys) { dfa = dfaMap[mapKey]; if (unmarked.Contains(dfa)) { // when we get here, mapKey represents the epsilon closure of our // current dfa state, which is indicated by kvp.Value // build the transition list for the new state by combining the transitions // from each of the old states // retrieve every possible input for these states HashSet <TInput> inputs = new HashSet <TInput>(); foreach (FA <TInput, TAccept> state in mapKey) { foreach (var inp in state.Transitions.Keys) { inputs.Add(inp); } } foreach (var input in inputs) { var acc = new List <TAccept>(); List <FA <TInput, TAccept> > ns = new List <FA <TInput, TAccept> >(); foreach (var state in mapKey) { FA <TInput, TAccept> dst = null; if (state.Transitions.TryGetValue(input, out dst)) { foreach (var d in dst.FillEpsilonClosure()) { if (d.IsAccepting) { if (!acc.Contains(d.Accept)) { acc.Add(d.Accept); } } if (!ns.Contains(d)) { ns.Add(d); } } } } FA <TInput, TAccept> ndfa; if (!dfaMap.TryGetValue(ns, out ndfa)) { ndfa = new FA <TInput, TAccept>(); ac = acc.Count; if (1 == ac) { ndfa.Accept = acc[0]; ndfa.IsAccepting = true; } else if (1 < ac) { // TODO: Give a detailed error message of the conflict throw new InvalidOperationException("Ambiguity in the FA."); } else { ndfa.Accept = default(TAccept); } dfaMap.Add(ns, ndfa); unmarked.Add(ndfa); done = false; } dfa.Transitions.Add(input, ndfa); } unmarked.Remove(dfa); } } } return(result); }