Beispiel #1
0
        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;
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #6
0
        /// <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);
        }
Beispiel #7
0
        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);
        }