/// <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 CharFA <TAccept> Optional(CharFA <TAccept> expr, TAccept accept = default(TAccept)) { var result = expr.Clone(); var f = result.FirstAcceptingState; f.AcceptSymbol = accept; result.EpsilonTransitions.Add(f); return(result); }
/// <summary> /// Makes the specified expression case insensitive /// </summary> /// <param name="expr">The target expression</param> /// <param name="accept">The accept symbol</param> /// <returns>A new expression that is the case insensitive equivelent of <paramref name="expr"/></returns> public static CharFA <TAccept> CaseInsensitive(CharFA <TAccept> expr, TAccept accept = default(TAccept)) { var fa = expr.Clone(); var closure = fa.FillClosure(); for (int ic = closure.Count, i = 0; i < ic; ++i) { var ffa = closure[i]; if (ffa.IsAccepting) { ffa.AcceptSymbol = accept; } foreach (var trns in ffa.InputTransitions as IDictionary <CharFA <TAccept>, ICollection <char> > ) { foreach (var ch in new List <char>(trns.Value)) { if (char.IsLower(ch)) { var cch = char.ToUpperInvariant(ch); if (!trns.Value.Contains(cch)) { ffa.InputTransitions.Add(cch, trns.Key); } } else if (char.IsUpper(ch)) { var cch = char.ToLowerInvariant(ch); if (!trns.Value.Contains(cch)) { ffa.InputTransitions.Add(cch, trns.Key); } } } } } return(fa); }
/// <summary> /// Creates a new FA that will match a repetition of the specified FA expression /// </summary> /// <param name="expr">The expression to repeat</param> /// <param name="minOccurs">The minimum number of times to repeat or -1 for unspecified (0)</param> /// <param name="maxOccurs">The maximum number of times to repeat or -1 for unspecified (unbounded)</param> /// <param name="accept">The symbol to accept</param> /// <returns>A new FA that matches the specified FA one or more times</returns> public static CharFA <TAccept> Repeat(CharFA <TAccept> expr, int minOccurs = -1, int maxOccurs = -1, TAccept accept = default(TAccept)) { expr = expr.Clone(); if (minOccurs > 0 && maxOccurs > 0 && minOccurs > maxOccurs) { throw new ArgumentOutOfRangeException(nameof(maxOccurs)); } CharFA <TAccept> result; switch (minOccurs) { case -1: case 0: switch (maxOccurs) { case -1: case 0: result = new CharFA <TAccept>(); var final = new CharFA <TAccept>(true, accept); final.EpsilonTransitions.Add(result); foreach (var afa in expr.FillAcceptingStates()) { afa.IsAccepting = false; afa.EpsilonTransitions.Add(final); } result.EpsilonTransitions.Add(expr); result.EpsilonTransitions.Add(final); //Debug.Assert(null != result.FirstAcceptingState); return(result); case 1: result = Optional(expr, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); default: var l = new List <CharFA <TAccept> >(); expr = Optional(expr); l.Add(expr); for (int i = 1; i < maxOccurs; ++i) { l.Add(expr.Clone()); } result = Concat(l, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); } case 1: switch (maxOccurs) { case -1: case 0: result = new CharFA <TAccept>(); var final = new CharFA <TAccept>(true, accept); final.EpsilonTransitions.Add(result); foreach (var afa in expr.FillAcceptingStates()) { afa.IsAccepting = false; afa.EpsilonTransitions.Add(final); } result.EpsilonTransitions.Add(expr); //Debug.Assert(null != result.FirstAcceptingState); return(result); case 1: //Debug.Assert(null != expr.FirstAcceptingState); return(expr); default: result = Concat(new[] { expr, Repeat(expr.Clone(), 0, maxOccurs - 1) }, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); } default: switch (maxOccurs) { case -1: case 0: result = Concat(new[] { Repeat(expr, minOccurs, minOccurs, accept), Repeat(expr, 0, 0, accept) }, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); case 1: throw new ArgumentOutOfRangeException(nameof(maxOccurs)); default: if (minOccurs == maxOccurs) { var l = new List <CharFA <TAccept> >(); l.Add(expr); //Debug.Assert(null != expr.FirstAcceptingState); for (int i = 1; i < minOccurs; ++i) { var e = expr.Clone(); //Debug.Assert(null != e.FirstAcceptingState); l.Add(e); } result = Concat(l, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); } result = Concat(new[] { Repeat(expr.Clone(), minOccurs, minOccurs, accept), Repeat(Optional(expr.Clone()), maxOccurs - minOccurs, maxOccurs - minOccurs, accept) }, accept); //Debug.Assert(null != result.FirstAcceptingState); return(result); } } }