Пример #1
0
        private static bool Accepts(this INfa <char> nfa, string input, IState state, Dictionary <Tuple <IState, string>, bool> cache)
        {
            if (input == string.Empty && nfa.IsAccepting(state))
            {
                return(true);
            }

            var key = Tuple.Create(state, input);

            if (!cache.ContainsKey(key))
            {
                cache[key] = false; // temporarily mark the (state, string) pair as non-accepting to avoid cycles

                // check epsilon transitions
                var result = nfa.EpsilonTransitions(state).Any(nextState => nfa.Accepts(input, nextState, cache));

                // check transitions using the first letter of input
                if (input.Length > 0)
                {
                    var firstLetter    = input[0];
                    var remainingInput = input.Substring(1);

                    var transitions = nfa.Transitions(state).GetValueOrDefault(firstLetter);
                    if (transitions != null)
                    {
                        result = result || transitions.Any(nextState => nfa.Accepts(remainingInput, nextState, cache));
                    }
                }

                cache[key] = result;
            }

            return(cache.GetValueOrDefault(key));
        }
 private static void VerifyNfaIsNotNullAndHasValidStartAndEndStates(INfa nfa)
 {
     Assert.IsNotNull(nfa);
     Assert.IsNotNull(nfa.Start);
     Assert.IsNotNull(nfa.End);
     Assert.AreEqual(0, nfa.End.Transitions.Count());
 }
Пример #3
0
        private static Util.HashableHashSet <IState> EpsilonClosure(INfa <Symbol> nfa, Util.HashableHashSet <IState> states)
        {
            Util.HashableHashSet <IState> closure = new Util.HashableHashSet <IState>();
            Queue <IState> q = new Queue <IState>();

            foreach (IState state in states)
            {
                closure.Add(state);
                q.Enqueue(state);
            }

            while (q.Count != 0)
            {
                IState state = q.Dequeue();
                foreach (IState neighbour in nfa.EpsilonTransitions(state))
                {
                    if (!closure.Contains(neighbour))
                    {
                        closure.Add(neighbour);
                        q.Enqueue(neighbour);
                    }
                }
            }

            return(closure);
        }
        private static INfa KleenePlus(INfa nfa)
        {
            var end = new NfaState();

            nfa.End.AddTransistion(new NullNfaTransition(end));
            nfa.End.AddTransistion(new NullNfaTransition(nfa.Start));
            return(new Nfa(nfa.Start, end));
        }
Пример #5
0
        public static ConcreteNfa <Symbol> CreateFromNfa(INfa <Symbol> nfa)
        {
            var stateIds = new Dictionary <IState, int>();
            var newNfa   = new ConcreteNfa <Symbol>(new ValueState <int>(0));

            newNfa.ConstructStates(stateIds, nfa, nfa.StartingState());
            return(newNfa);
        }
Пример #6
0
        private static IDfa <bool, TLabel> RegexToDfa(Regex <TLabel> regex)
        {
            INfa <TLabel> nfa = RegexToNfaConverter <TLabel> .Convert(regex);

            IDfa <bool, TLabel> dfa = NfaToDfaConverter <TLabel> .Convert(nfa);

            return(DfaMinimizer <bool, TLabel> .Minimize(dfa));
        }
        public IDfaState Transform(INfa nfa)
        {
            var processOnceQueue = new ProcessOnceQueue<NfaClosure>();

            var set = SharedPools.Default<HashSet<INfaState>>().AllocateAndClear();
            foreach (var state in nfa.Start.Closure())
                set.Add(state);

            var start = new NfaClosure(set, nfa.Start.Equals(nfa.End));

            processOnceQueue.Enqueue(start);

            while (processOnceQueue.Count > 0)
            {
                var nfaClosure = processOnceQueue.Dequeue();
                var transitions = SharedPools
                    .Default<Dictionary<ITerminal, HashSet<INfaState>>>()
                    .AllocateAndClear();

                foreach (var state in nfaClosure.Closure)
                {
                    for (var t = 0; t < state.Transitions.Count; t++)
                    {
                        var transition = state.Transitions[t];
                        switch (transition.TransitionType)
                        {
                            case NfaTransitionType.Terminal:
                                var terminalTransition = transition as TerminalNfaTransition;
                                var terminal = terminalTransition.Terminal;

                                if (!transitions.ContainsKey(terminalTransition.Terminal))
                                    transitions[terminal] = SharedPools.Default<HashSet<INfaState>>().AllocateAndClear();
                                transitions[terminal].Add(transition.Target);
                                break;
                        }
                    }
                }

                foreach (var terminal in transitions.Keys)
                {
                    var targetStates = transitions[terminal];
                    var closure = Closure(targetStates, nfa.End);
                    closure = processOnceQueue.EnqueueOrGetExisting(closure);
                    nfaClosure.State.AddTransition(
                        new DfaTransition(terminal, closure.State));
                    SharedPools.Default<HashSet<INfaState>>().Free(targetStates);
                }
                SharedPools
                    .Default<HashSet<INfaState>>()
                    .Free(nfaClosure.Closure);
                SharedPools
                    .Default<Dictionary<ITerminal, HashSet<INfaState>>>()
                    .ClearAndFree(transitions);
            }

            return start.State;
        }
        private static INfa Optional(INfa nfa)
        {
            var start = new NfaState();
            var end   = new NfaState();

            start.AddTransistion(new NullNfaTransition(nfa.Start));
            start.AddTransistion(new NullNfaTransition(end));
            nfa.End.AddTransistion(new NullNfaTransition(end));
            return(new Nfa(start, end));
        }
Пример #9
0
        public Nfa BuildConcat(INfa concat1, INfa concat2)
        {
            var shiftedConcat2 = new ShiftedNfa(concat2, concat1.Size - 1);
            var nfa            = new Nfa(concat1.Size + concat2.Size - 1);

            nfa.FillStates(concat1);
            nfa.FillStates(shiftedConcat2);

            return(nfa);
        }
Пример #10
0
        public INfa Union(INfa nfa)
        {
            var newStart = new NfaState();
            var newEnd = new NfaState();

            newStart.AddTransistion(new NullNfaTransition(Start));
            newStart.AddTransistion(new NullNfaTransition(nfa.Start));

            End.AddTransistion(new NullNfaTransition(newEnd));
            nfa.End.AddTransistion(new NullNfaTransition(newEnd));

            return new Nfa(newStart, newEnd);
        }
Пример #11
0
        public INfa Union(INfa nfa)
        {
            var newStart = new NfaState();
            var newEnd   = new NfaState();

            newStart.AddTransistion(new NullNfaTransition(Start));
            newStart.AddTransistion(new NullNfaTransition(nfa.Start));

            End.AddTransistion(new NullNfaTransition(newEnd));
            nfa.End.AddTransistion(new NullNfaTransition(newEnd));

            return(new Nfa(newStart, newEnd));
        }
Пример #12
0
        public Nfa BuildStar(INfa inner)
        {
            var shiftedInner = new ShiftedNfa(inner, 1);
            var nfa          = new Nfa(shiftedInner.Size + 2);

            nfa.FillStates(shiftedInner);

            nfa.AddEpsilonTransition(nfa.Initial, shiftedInner.Initial);
            nfa.AddEpsilonTransition(nfa.Initial, nfa.Final);
            nfa.AddEpsilonTransition(shiftedInner.Final, nfa.Final);
            nfa.AddEpsilonTransition(shiftedInner.Final, shiftedInner.Initial);

            return(nfa);
        }
        private static INfa Union(INfa first, INfa second)
        {
            var start = new NfaState();

            start.AddTransistion(new NullNfaTransition(first.Start));
            start.AddTransistion(new NullNfaTransition(second.Start));

            var end           = new NfaState();
            var endTransition = new NullNfaTransition(end);

            first.End.AddTransistion(endTransition);
            second.End.AddTransistion(endTransition);

            return(new Nfa(start, end));
        }
        private static INfa KleeneStar(INfa nfa)
        {
            var start          = new NfaState();
            var nullToNfaStart = new NullNfaTransition(nfa.Start);

            start.AddTransistion(nullToNfaStart);
            nfa.End.AddTransistion(nullToNfaStart);

            var end          = new NfaState();
            var nullToNewEnd = new NullNfaTransition(end);

            start.AddTransistion(nullToNewEnd);
            nfa.End.AddTransistion(nullToNewEnd);

            return(new Nfa(start, end));
        }
Пример #15
0
        SubsetConstruction(INfa nfa)
        {
            var first            = EpsilonClosure(nfa, Group <State> .From(nfa.Initial));
            var groupTransitions = new GroupTransitions();
            var terminalGroups   = new List <Group <State> >();

            // Create work queue of groups to look at
            var unmarkedGroups = new Queue <Group <State> >();

            unmarkedGroups.Enqueue(first);

            var markedGroups = new HashSet <Group <State> >();

            while (unmarkedGroups.Count != 0)
            {
                var group = unmarkedGroups.Dequeue();
                markedGroups.Add(group);

                if (group.Contains(nfa.Final))
                {
                    terminalGroups.Add(group);
                }

                // Find a new epsilon closed group for each possible input
                foreach (var input in nfa.Inputs)
                {
                    var closure = EpsilonClosure(nfa, nfa.Move(group, input));

                    if (!closure.Any())
                    {
                        continue;
                    }

                    // Add new groups to unmarked groups
                    if (!unmarkedGroups.Contains(closure) && !markedGroups.Contains(closure))
                    {
                        unmarkedGroups.Enqueue(closure);
                    }

                    var transitions = new GroupTransition(group, input, closure);
                    groupTransitions.Add(transitions);
                }
            }

            return(first, groupTransitions, terminalGroups);
        }
Пример #16
0
        public Nfa BuildAlter(INfa alter1, INfa alter2)
        {
            var shiftedAlter1 = new ShiftedNfa(alter1, 1);
            var shiftedAlter2 = new ShiftedNfa(alter2, alter1.Size + 1);
            var newNfa        = new Nfa(alter1.Size + alter2.Size + 2);

            newNfa.FillStates(shiftedAlter1);
            newNfa.FillStates(shiftedAlter2);

            newNfa.AddEpsilonTransition(0, shiftedAlter1.Initial);
            newNfa.AddEpsilonTransition(0, shiftedAlter2.Initial);

            newNfa.AddEpsilonTransition(shiftedAlter1.Final, newNfa.Final);
            newNfa.AddEpsilonTransition(shiftedAlter2.Final, newNfa.Final);

            return(newNfa);
        }
Пример #17
0
        private static HashSet <Symbol> GetAlphabet(INfa <Symbol> nfa)
        {
            HashSet <Symbol> alphabet = new HashSet <Symbol>();
            Queue <IState>   q        = new Queue <IState>();
            IState           state    = nfa.StartingState();

            Util.HashableHashSet <IState> visited = new Util.HashableHashSet <IState>();
            q.Enqueue(state);
            visited.Add(state);
            while (q.Count != 0)
            {
                state = q.Dequeue();
                IReadOnlyDictionary <Symbol, IReadOnlyCollection <IState> > edges = nfa.Transitions(state);
                foreach (Symbol key in edges.Keys)
                {
                    alphabet.Add(key);
                    foreach (IState neighbour in edges[key])
                    {
                        if (!visited.Contains(neighbour))
                        {
                            visited.Add(neighbour);
                            q.Enqueue(neighbour);
                        }
                    }
                }

                foreach (IState neighbour in nfa.EpsilonTransitions(state))
                {
                    if (!visited.Contains(neighbour))
                    {
                        visited.Add(neighbour);
                        q.Enqueue(neighbour);
                    }
                }
            }

            return(alphabet);
        }
Пример #18
0
    /// <summary>
    /// Implements <see cref="INfa{TState, TSymbol}.EliminateEpsilonTransitions"/>.
    /// </summary>
    /// <typeparam name="TState">The state type.</typeparam>
    /// <typeparam name="TSymbol">The symbol type.</typeparam>
    /// <param name="nfa">The NFA to eliminate epsilon-transitions from.</param>
    /// <param name="copyTransitions">A method to copy transitions from one state to another.</param>
    /// <returns>True, if there were epsilon-transitions to eliminate.</returns>
    public static bool EliminateEpsilonTransitions <TState, TSymbol>(
        INfa <TState, TSymbol> nfa,
        Action <TState, TState> copyTransitions)
    {
        if (nfa.EpsilonTransitions.Count == 0)
        {
            return(false);
        }

        foreach (var state in nfa.States)
        {
            // For each state we look at its epsilon closure
            // For each element in the closure we copy the non-epsilon transitions from state to the others
            // We can omit the state itself from the copy
            var epsilonClosure = nfa
                                 .EpsilonClosure(state)
                                 .Where(s => !nfa.StateComparer.Equals(s, state))
                                 .ToHashSet(nfa.StateComparer);
            foreach (var toState in epsilonClosure)
            {
                copyTransitions(state, toState);
                // If v1 is a starting state, we need to make v2 one aswell
                if (nfa.InitialStates.Contains(state))
                {
                    nfa.InitialStates.Add(toState);
                }
                // If v2 is a final state, v1 needs to be aswell
                if (nfa.AcceptingStates.Contains(toState))
                {
                    nfa.AcceptingStates.Add(state);
                }
            }
        }

        nfa.EpsilonTransitions.Clear();

        return(true);
    }
Пример #19
0
        private Group <State> EpsilonClosure(INfa nfa, Group <State> group)
        {
            var queue   = new Queue <State>(group);
            var closure = new Group <State>();

            while (queue.Count != 0)
            {
                var state = queue.Dequeue();
                closure.Add(state);

                var epsilonTargets = nfa.Transitions
                                     .Where(t => t.Source == state && t.Input == (char)Nfa.Constants.Epsilon)
                                     .Where(t => !closure.Contains(t.Target))
                                     .Select(t => t.Target);

                foreach (var target in epsilonTargets)
                {
                    queue.Enqueue(target);
                }
            }

            return(closure);
        }
Пример #20
0
        public Dfa DfaFromNfa(INfa nfa)
        {
            var(startGroup, groupTransitions, terminalGroups) = SubsetConstruction(nfa);

            var groups = groupTransitions
                         .Select(t => t.Target)
                         .Union(new[] { startGroup }).Distinct();

            var id             = 0;
            var stateFromGroup = groups
                                 .OrderBy(g => g.Min())
                                 .Select(g => (Group: g, Id: id++))
                                 .ToDictionary(kvp => kvp.Group, kvp => kvp.Id);

            var start       = stateFromGroup[startGroup];
            var transitions = groupTransitions.ToDictionary(
                t => (stateFromGroup[t.Source], t.Input),
                t => stateFromGroup[t.Target]
                );
            var terminals = terminalGroups.Select(g => stateFromGroup[g]);

            return(new Dfa(start, transitions, terminals));
        }
Пример #21
0
        // tokenCategories - List of pair (Token, Regex for thie Token)
        public Lexer(
            IEnumerable <KeyValuePair <TLabel, string> > tokenCategories,
            TLabel eof,
            TLabel noneValue,
            Func <IEnumerable <TLabel>, TLabel> conflictSolver)
        {
            this.eof       = eof;
            this.noneValue = noneValue;
            var converter = new StringToRegexConverterFactory().CreateConverter();
            Dictionary <TLabel, IDfa <bool, char> > multipleDfa = tokenCategories.ToDictionary(
                x => x.Key,
                x =>
            {
                Regex <char> regex    = converter.Convert(x.Value);
                INfa <char> nfaPre    = RegexToNfaConverter <char> .Convert(regex);
                INfa <char> nfa       = ConcreteNfa <char> .CreateFromNfa(nfaPre);
                IDfa <bool, char> dfa = NfaToDfaConverter <char> .Convert(nfa);
                return(DfaMinimizer <bool, char> .Minimize(dfa));
            });
            var mergedDfa = DfaMerger <TLabel, char> .Merge(multipleDfa, conflictSolver);

            this.minimalizedDfa = DfaMinimizer <TLabel, char> .Minimize(mergedDfa);
        }
Пример #22
0
        private int ConstructStates(Dictionary <IState, int> stateIds, INfa <Symbol> nfa, IState state)
        {
            if (stateIds.ContainsKey(state))
            {
                return(stateIds[state]);
            }

            int stateId = stateIds.Count;

            stateIds[state] = stateId;

            this.epsilonTransitions.Add(null);
            this.transitions.Add(null);
            this.isAccepting.Add(nfa.IsAccepting(state));

            this.epsilonTransitions[stateId] = nfa.EpsilonTransitions(state).Select(target => new ValueState <int>(this.ConstructStates(stateIds, nfa, target)) as IState).ToList();
            this.transitions[stateId]        = nfa.Transitions(state)
                                               .ToDictionary(
                keySelector: kv => kv.Key,
                elementSelector: kv => kv.Value.Select(target => new ValueState <int>(this.ConstructStates(stateIds, nfa, target))).ToList() as IReadOnlyCollection <IState>);

            return(stateId);
        }
Пример #23
0
 public Nfa BuildPlus(INfa inner)
 => BuildConcat(inner, BuildStar(inner));
Пример #24
0
 private static void VerifyNfaIsNotNullAndHasValidStartAndEndStates(INfa nfa)
 {
     Assert.IsNotNull(nfa);
     Assert.IsNotNull(nfa.Start);
     Assert.IsNotNull(nfa.End);
     Assert.AreEqual(0, nfa.End.Transitions.Count());
 }
Пример #25
0
 public INfa Concatenation(INfa nfa)
 {
     End.AddTransistion(
         new NullNfaTransition(nfa.Start));
     return(this);
 }
Пример #26
0
 public INfa Concatenation(INfa nfa)
 {
     End.AddTransistion(
         new NullNfaTransition(nfa.Start));
     return this;
 }
        private static INfa Union(INfa first, INfa second)
        {
            var start = new NfaState();
            start.AddTransistion(new NullNfaTransition(first.Start));
            start.AddTransistion(new NullNfaTransition(second.Start));

            var end = new NfaState();
            var endTransition = new NullNfaTransition(end);
            first.End.AddTransistion(endTransition);
            second.End.AddTransistion(endTransition);

            return new Nfa(start, end);
        }
 private IDfaState ConvertNfaToDfa(INfa nfa)
 {
     return new SubsetConstructionAlgorithm().Transform(nfa);
 }
Пример #29
0
        public static IDfa <bool, Symbol> Convert(INfa <Symbol> nfa)
        {
            HashSet <Symbol> alphabet = GetAlphabet(nfa);
            Dictionary <Util.HashableHashSet <IState>, DfaState> map = new Dictionary <Util.HashableHashSet <IState>, DfaState>();
            HashSet <DfaState> accepting = new HashSet <DfaState>();
            Dictionary <DfaState, Dictionary <Symbol, IState> > trans = new Dictionary <DfaState, Dictionary <Symbol, IState> >();
            Queue <Util.HashableHashSet <IState> > q = new Queue <Util.HashableHashSet <IState> >();

            Util.HashableHashSet <IState> start = new Util.HashableHashSet <IState> {
                nfa.StartingState()
            };
            Util.HashableHashSet <IState> startingClosure = EpsilonClosure(nfa, start);
            map.Add(startingClosure, new DfaState());
            q.Enqueue(startingClosure);
            while (q.Count != 0)
            {
                Util.HashableHashSet <IState> currentSet = q.Dequeue();
                foreach (IState state in currentSet)
                {
                    if (nfa.IsAccepting(state))
                    {
                        accepting.Add(map[currentSet]);
                        break;
                    }
                }

                Dictionary <Symbol, Util.HashableHashSet <IState> > dict = new Dictionary <Symbol, Util.HashableHashSet <IState> >();
                foreach (IState state in currentSet)
                {
                    IReadOnlyDictionary <Symbol, IReadOnlyCollection <IState> > edges = nfa.Transitions(state);
                    foreach (Symbol key in edges.Keys)
                    {
                        if (!dict.ContainsKey(key))
                        {
                            dict.Add(key, new Util.HashableHashSet <IState>());
                        }

                        foreach (IState s in edges[key])
                        {
                            dict[key].Add(s);
                        }
                    }
                }

                foreach (Symbol key in alphabet)
                {
                    if (!dict.ContainsKey(key))
                    {
                        dict.Add(key, new Util.HashableHashSet <IState>());
                    }
                }

                trans.Add(map[currentSet], new Dictionary <Symbol, IState>());
                foreach (Symbol key in dict.Keys)
                {
                    Util.HashableHashSet <IState> neighbour = EpsilonClosure(nfa, dict[key]);
                    if (!map.ContainsKey(neighbour))
                    {
                        map.Add(neighbour, new DfaState());

                        q.Enqueue(neighbour);
                    }

                    trans[map[currentSet]].Add(key, map[neighbour]);
                }
            }

            return(new Dfa <Symbol>(map[startingClosure], accepting, trans));
        }
Пример #30
0
 private static List <string> GetAllAcceptedStringsUpToLength(int maxLength, List <char> vocabulary, INfa <char> nfa)
 {
     return(GetAllStringsUpToLength(maxLength, vocabulary).Where(nfa.Accepts).ToList());
 }
 private static INfa Concatenation(INfa first, INfa second)
 {
     first.End.AddTransistion(new NullNfaTransition(second.Start));
     return(new Nfa(first.Start, second.End));
 }
Пример #32
0
 public StarNfa(INfa <Symbol> inner)
 {
     this.Inner = inner;
 }
 private static INfa Optional(INfa nfa)
 {
     var start = new NfaState();
     var end = new NfaState();
     start.AddTransistion(new NullNfaTransition(nfa.Start));
     start.AddTransistion(new NullNfaTransition(end));
     nfa.End.AddTransistion(new NullNfaTransition(end));
     return new Nfa(start, end);
 }
        private static INfa KleeneStar(INfa nfa)
        {
            var start = new NfaState();
            var nullToNfaStart = new NullNfaTransition(nfa.Start);

            start.AddTransistion(nullToNfaStart);
            nfa.End.AddTransistion(nullToNfaStart);

            var end = new NfaState();
            var nullToNewEnd = new NullNfaTransition(end);

            start.AddTransistion(nullToNewEnd);
            nfa.End.AddTransistion(nullToNewEnd);

            return new Nfa(start, end);
        }
 private IDfaState ConvertNfaToDfa(INfa nfa)
 {
     return(new SubsetConstructionAlgorithm().Transform(nfa));
 }
 private static INfa Concatenation(INfa first, INfa second)
 {
     first.End.AddTransistion(new NullNfaTransition(second.Start));
     return new Nfa(first.Start, second.End);
 }
Пример #37
0
 public ShiftedNfa(INfa inner, int shift)
 {
     Inner = inner;
     Shift = shift;
 }
        public IDfaState Transform(INfa nfa)
        {
            var processOnceQueue = new ProcessOnceQueue <NfaClosure>();

            var set = SharedPools.Default <SortedSet <INfaState> >().AllocateAndClear();

            foreach (var state in nfa.Start.Closure())
            {
                set.Add(state);
            }

            var start = new NfaClosure(set, nfa.Start.Equals(nfa.End));

            processOnceQueue.Enqueue(start);

            while (processOnceQueue.Count > 0)
            {
                var nfaClosure  = processOnceQueue.Dequeue();
                var transitions = SharedPools
                                  .Default <Dictionary <ITerminal, SortedSet <INfaState> > >()
                                  .AllocateAndClear();

                for (int i = 0; i < nfaClosure.Closure.Length; i++)
                {
                    var state = nfaClosure.Closure[i];
                    for (var t = 0; t < state.Transitions.Count; t++)
                    {
                        var transition = state.Transitions[t];
                        switch (transition.TransitionType)
                        {
                        case NfaTransitionType.Edge:
                            var terminalTransition = transition as TerminalNfaTransition;
                            var terminal           = terminalTransition.Terminal;

                            if (!transitions.ContainsKey(terminalTransition.Terminal))
                            {
                                transitions[terminal] = SharedPools.Default <SortedSet <INfaState> >().AllocateAndClear();
                            }
                            transitions[terminal].Add(transition.Target);
                            break;
                        }
                    }
                }

                foreach (var terminal in transitions.Keys)
                {
                    var targetStates = transitions[terminal];
                    var closure      = Closure(targetStates, nfa.End);
                    closure = processOnceQueue.EnqueueOrGetExisting(closure);
                    nfaClosure.State.AddTransition(
                        new DfaTransition(terminal, closure.State));
                    SharedPools.Default <SortedSet <INfaState> >().ClearAndFree(targetStates);
                }
                SharedPools
                .Default <SortedSet <INfaState> >()
                .ClearAndFree(nfaClosure.Set);
                SharedPools
                .Default <Dictionary <ITerminal, SortedSet <INfaState> > >()
                .ClearAndFree(transitions);
            }

            return(start.State);
        }
Пример #39
0
 public SumNfa(INfa <Symbol> left, INfa <Symbol> right)
 {
     this.Left  = left;
     this.Right = right;
 }
 private static INfa KleenePlus(INfa nfa)
 {
     var end = new NfaState();
     nfa.End.AddTransistion(new NullNfaTransition(end));
     nfa.End.AddTransistion(new NullNfaTransition(nfa.Start));
     return new Nfa(nfa.Start, end);
 }