예제 #1
0
        public static NFA AnyOf(NFA left, NFA right)
        {
            var result = new NFA();

            result.AddState(0, false);
            result.AddTransition(0, result.Add(left), Epsilon);
            result.AddTransition(0, result.Add(right), Epsilon);
            return(result);
        }
예제 #2
0
        private int Add(NFA left)
        {
            int stateOffset = NewState();

            foreach (var s in left.states)
            {
                AddState(s + stateOffset, left.final.Contains(s));
            }
            foreach (var t in left.transitions)
            {
                AddTransition(t.Item1 + stateOffset, t.Item2 + stateOffset, t.Item3);
            }
            return(stateOffset);
        }
예제 #3
0
        public static NFA Concat(NFA left, NFA right)
        {
            var result = new NFA();

            result.Add(left);

            var leftFinals = result.final.ToArray();

            result.final.Clear();

            int rightInitial = result.Add(right);

            foreach (var final in leftFinals)
            {
                result.AddTransition(final, rightInitial, Epsilon);
            }
            return(result);
        }
예제 #4
0
        public static NFA Star(NFA input)
        {
            var result = new NFA();

            var newFinal = result.NewState();

            result.AddState(newFinal, true);

            var start  = result.Add(input);
            var finals = result.final.Where(h => h != newFinal).ToArray();

            foreach (var final in finals)
            {
                result.AddTransition(final, start, Epsilon);
            }
            result.AddTransition(newFinal, start, Epsilon);

            return(result);
        }
예제 #5
0
        public NFA Determinize()
        {
            NFA target = new NFA();

            Stack <Tuple <int, HashSet <int> > > frontier = new Stack <Tuple <int, HashSet <int> > >();
            Dictionary <HashSet <int>, int>      seen     = new Dictionary <HashSet <int>, int>(new SetStateComparer());
            int set_key = 0;

            HashSet <int> set_initial = new HashSet <int>();

            set_initial.Add(0);
            EpsilonClosure(set_initial);

            target.AddState(set_key, ContainsFinalState(set_initial));

            frontier.Push(new Tuple <int, HashSet <int> >(set_key, set_initial));
            seen[set_initial] = set_key;

            while (frontier.Count > 0)
            {
                var current     = frontier.Pop();
                var current_key = current.Item1;
                var current_set = current.Item2;

                bool hasA = false, hasB = false;
                foreach (var st in current_set)
                {
                    foreach (var t in FindTransitions(st))
                    {
                        if (t.Item3 == Epsilon)
                        {
                            continue;
                        }
                        else if (t.Item3 == 'a')
                        {
                            hasA = true;
                        }
                        else if (t.Item3 == 'b')
                        {
                            hasB = true;
                        }
                        if (hasA && hasB)
                        {
                            break;
                        }
                    }
                    if (hasA && hasB)
                    {
                        break;
                    }
                }

                var inputs = "ab";
                if (!(hasA & hasB))
                {
                    inputs = hasA ? "a" : "b";
                }

                foreach (var i in inputs)
                {
                    HashSet <int>  new_state       = new HashSet <int>();
                    HashSet <char> new_transitions = new HashSet <char>();

                    foreach (var st in current_set)
                    {
                        foreach (var t in FindTransitions(st).Where(j => j.Item3 == i))
                        {
                            new_transitions.Add(t.Item3);
                            new_state.Add(t.Item2);
                        }
                    }

                    EpsilonClosure(new_state);

                    int seen_state_key;
                    if (!seen.TryGetValue(new_state, out seen_state_key))
                    {
                        set_key++;

                        target.AddState(set_key, ContainsFinalState(new_state));

                        foreach (var t in new_transitions)
                        {
                            target.AddTransition(current_key, set_key, t);
                        }

                        frontier.Push(new Tuple <int, HashSet <int> >(set_key, new_state));
                        seen[new_state] = set_key;
                    }
                    else
                    {
                        foreach (var t in new_transitions)
                        {
                            target.AddTransition(current_key, seen_state_key, t);
                        }
                    }
                }
            }

            return(target);
        }
예제 #6
0
        public NFA Parse(string input)
        {
            //Shunting-Yard algorithm
            Stack <char> s = new Stack <char>();
            List <char>  q = new List <char>();

            var  c    = input.GetEnumerator();
            char prev = '\0';

            while (c.MoveNext())
            {
                switch (c.Current)
                {
                case 'a':
                case 'b':
                    q.Add(c.Current);
                    if (prev == 'a' || prev == 'b' || prev == ')')
                    {
                        s.Push('-');
                    }
                    break;

                case '(':
                    if (prev == 'a' || prev == 'b' || prev == ')')
                    {
                        s.Push('-');
                    }
                    s.Push(c.Current);
                    break;

                case '*':
                case '|':
                    s.Push(c.Current);
                    break;

                case ')':
                    while (s.Count > 0 && s.Peek() != '(')
                    {
                        q.Add(s.Pop());
                    }
                    s.Pop();
                    break;
                }
                prev = c.Current;
            }

            Stack <NFA> calc = new Stack <NFA>();

            foreach (var i in q)
            {
                if (i == '*')
                {
                    calc.Push(NFA.Star(calc.Pop()));
                }
                else if (i == '-')
                {
                    var right = calc.Pop();
                    var left  = calc.Pop();
                    calc.Push(NFA.Concat(left, right));
                }
                else if (i == '|')
                {
                    var right = calc.Pop();
                    var left  = calc.Pop();
                    calc.Push(NFA.AnyOf(left, right));
                }
                else
                {
                    NFA nfa = new NFA();
                    nfa.AddState(0, false);
                    nfa.AddState(1, true);
                    nfa.AddTransition(0, 1, i);
                    calc.Push(nfa);
                }
            }

            return(calc.Pop());
        }