internal Nfa.Nfa BuildNfa() { // build a chain (not connected here) of the minimal repetitions Nfa.Nfa[] min_coll = Enumerable.Range(0, Math.Max(1, repetition.Min)).Select(it => RegexAtomTraits.BuildNfa(atom)).ToArray(); var nfa = Nfa.Nfa.Concat(min_coll).ClearAccepting(min_coll.Last().Accepting()); if (!repetition.Max.HasValue) { min_coll.Last().StartNode.ConnectFrom(min_coll.Last().Accepting(), NfaEdge.CreateEmpty()); } else { IEnumerable <Nfa.Nfa> max_coll = Enumerable.Range(0, repetition.Max.Value - min_coll.Length).Select(it => RegexAtomTraits.BuildNfa(atom)).ToList(); if (max_coll.Any()) { var max_nfa = Nfa.Nfa.Concat(max_coll); max_nfa.StartNode.ConnectFrom(min_coll.Last().Accepting(), NfaEdge.CreateEmpty()); } } // put it as last step, otherwise we could get connection right from the start node if (repetition.Min == 0) { nfa.Accepting().ForEach(it => nfa.StartNode.ConnectTo(it, NfaEdge.CreateEmpty())); } return(nfa); }
internal Nfa.Nfa BuildNfa() { Nfa.Nfa[] alt_nfa = chains.Select(it => RegexChainTraits.BuildNfa(it)).ToArray(); if (alt_nfa.Length == 1) { return(alt_nfa.Single()); } else { var nfa = new Nfa.Nfa(); alt_nfa.ForEach(it => nfa.StartNode.ConnectTo(it.StartNode, NfaEdge.CreateEmpty())); // accepting nodes have no outgoing edges mergeNodes(alt_nfa.Select(it => it.Accepting()).Flatten().Where(it => !it.ConnectedTo.Any()).ToArray()); return(nfa); } }