private Automaton <S> MakeKleeneClosure(Automaton <S> sfa) { if (sfa.IsEmpty || sfa.IsEpsilon) { return(this.epsilon); } if (sfa.IsKleeneClosure()) { return(sfa); } if (sfa.DoesNotContainWordBoundaries && sfa.InitialStateIsSource && sfa.HasSingleFinalSink) { //common case, avoid epsilons in this case //just destructively make the final state to be the initial state sfa.RenameInitialState(sfa.FinalState); return(sfa); } int origInitState = sfa.InitialState; if (!sfa.IsFinalState(sfa.InitialState))//the initial state is not final { if (sfa.InitialStateIsSource) { //make the current initial state final sfa.MakeInitialStateFinal(); } else { //add a new initial state that is also final sfa.AddNewInitialStateThatIsFinal(this.MkStateId()); } } //add epsilon transitions from final states to the original initial state foreach (int state in sfa.GetFinalStates()) { if (state != sfa.InitialState && state != origInitState) { sfa.AddMove(Move <S> .Epsilon(state, origInitState)); } } //epsilon loops might have been created, remove them var sfa1 = sfa.RemoveEpsilonLoops(); if (!sfa.DoesNotContainWordBoundaries) { sfa1.AddWordBoundaries(sfa.EnumerateWordBoundaries()); } return(sfa1); }
/// <summary> /// Builds an automaton equivalent to the regex r{m,n}, or r{m,} when n is int.MaxValue; /// r{0,int.MaxValue} is the same as r*; /// r{1,int.MaxValue} is the same as r+. /// </summary> /// <param name="r">regular expression node</param> /// <param name="m">lower loop bound</param> /// <param name="n">upper loop bound</param> /// <returns></returns> public Automaton <S> MkLoop(T r, int m, int n) { bool start = isBeg; bool end = isEnd; isBeg = false; isEnd = false; Automaton <S> sfa = Callback(r); isBeg = start; isEnd = end; Automaton <S> loop; if (m == 0 && sfa.IsEmpty) { loop = this.epsilon; } else if (m == 0 && n == int.MaxValue) //case: * { loop = MakeKleeneClosure(sfa); } else if (m == 0 && n == 1) //case: ? { ; if (sfa.IsFinalState(sfa.InitialState)) { return(sfa); } else if (sfa.InitialStateIsSource) { sfa.MakeInitialStateFinal(); } else { sfa.AddNewInitialStateThatIsFinal(this.MkStateId()); } loop = sfa; } else if (m == 1 && n == 1) //trivial case: r{1,1} = r { if (sfa.IsEmpty) { return(this.empty); } loop = sfa; } else if (n == int.MaxValue) //case: + or generally {m,} for m >= 1 { if (sfa.IsEmpty) { return(this.empty); } if (sfa.IsFinalState(sfa.InitialState)) { loop = MakeKleeneClosure(sfa); //the repetition is a loop } else { List <Automaton <S> > sfas = new List <Automaton <S> >(); for (int i = 0; i < m; i++) { //make m fresh copies sfas.Add(sfa); sfa = sfa.MakeCopy(this.MkStateId); } //the last one is made into a Kleene closure sfas.Add(MakeKleeneClosure(sfa)); //concatenate them all loop = ConcatenateSFAs(sfas); } } else //general case {m,n} { List <Automaton <S> > sfas = new List <Automaton <S> >(); //List<int> newFinals = new List<int>(); for (int i = 0; i < n; i++) { sfas.Add(sfa); if (i < n - 1) { sfa = sfa.MakeCopy(this.MkStateId); if (i >= m - 1) { if (sfa.DoesNotContainWordBoundaries && sfa.InitialStateIsSource && !sfa.IsFinalState(sfa.InitialState)) { sfa.MakeInitialStateFinal(); } else { sfa.AddNewInitialStateThatIsFinal(this.MkStateId()); } } } } loop = ConcatenateSFAs(sfas); if (m == 0) { loop.MakeInitialStateFinal(); } //loop.SetFinalStates(newFinals); } loop = ExtendLoop(start, end, loop); return(loop); }