/// <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> /// 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)); } switch (minOccurs) { case -1: case 0: switch (maxOccurs) { case -1: case 0: var result = new CharFA <TAccept>(); var final = new CharFA <TAccept>(true, accept); final.EpsilonTransitions.Add(result); foreach (var afa in expr.FillAccepting()) { afa.IsAccepting = false; afa.EpsilonTransitions.Add(final); } result.EpsilonTransitions.Add(expr); result.EpsilonTransitions.Add(final); return(result); case 1: return(Optional(expr, accept)); default: var l = new List <CharFA <TAccept> >(); expr = Optional(expr); l.Add(expr); for (int i = 1; i < maxOccurs; ++i) { l.Add(expr.Clone()); } return(Concat(l, accept)); } case 1: switch (maxOccurs) { case -1: case 0: var result = new CharFA <TAccept>(); var final = new CharFA <TAccept>(true, accept); final.EpsilonTransitions.Add(result); foreach (var afa in expr.FillAccepting()) { afa.IsAccepting = false; afa.EpsilonTransitions.Add(final); } result.EpsilonTransitions.Add(expr); return(result); case 1: return(expr); default: return(Concat(new CharFA <TAccept>[] { expr, Repeat(expr.Clone(), 0, maxOccurs - 1) }, accept)); } default: switch (maxOccurs) { case -1: case 0: return(Concat(new CharFA <TAccept>[] { Repeat(expr, minOccurs, minOccurs, accept), Repeat(expr, 0, 0, accept) }, accept)); case 1: throw new ArgumentOutOfRangeException(nameof(maxOccurs)); default: if (minOccurs == maxOccurs) { var l = new List <CharFA <TAccept> >(); l.Add(expr); for (int i = 1; i < minOccurs; ++i) { l.Add(expr.Clone()); } return(Concat(l, accept)); } return(Concat(new CharFA <TAccept>[] { Repeat(expr.Clone(), minOccurs, minOccurs, accept), Repeat(Optional(expr.Clone()), maxOccurs - minOccurs, maxOccurs - minOccurs, accept) }, accept)); } } // should never get here throw new NotImplementedException(); }