/// <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);
        }
Example #2
0
        /// <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);
                }
            }
        }