/// <summary>
        ///
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static ABFN_Group Parse(System.IO.StringReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            // group = "(" *c-wsp alternation *c-wsp ")"

            if (reader.Peek() != '(')
            {
                throw new ParseException("Invalid ABNF 'group' value '" + reader.ReadToEnd() + "'.");
            }

            // Eat "(".
            reader.Read();

            // TODO: *c-wsp

            ABFN_Group retVal = new ABFN_Group();

            // We reached end of stream, no closing ")".
            if (reader.Peek() == -1)
            {
                throw new ParseException("Invalid ABNF 'group' value '" + reader.ReadToEnd() + "'.");
            }

            retVal.m_pAlternation = ABNF_Alternation.Parse(reader);

            // We don't have closing ")".
            if (reader.Peek() != ')')
            {
                throw new ParseException("Invalid ABNF 'group' value '" + reader.ReadToEnd() + "'.");
            }
            else
            {
                reader.Read();
            }

            return(retVal);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static ABNF_Repetition Parse(System.IO.StringReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            /*
             *  repetition     =  [repeat] element
             *  repeat         =  1*DIGIT / (*DIGIT "*" *DIGIT)
             *  element        =  rulename / group / option / char-val / num-val / prose-val
             */

            int min = 0;
            int max = int.MaxValue;

            // --- range ------------------------------------
            if (char.IsDigit((char)reader.Peek()))
            {
                StringBuilder minString = new StringBuilder();
                while (char.IsDigit((char)reader.Peek()))
                {
                    minString.Append((char)reader.Read());
                }
                min = Convert.ToInt32(minString.ToString());
            }
            if (reader.Peek() == '*')
            {
                reader.Read();
            }
            if (char.IsDigit((char)reader.Peek()))
            {
                StringBuilder maxString = new StringBuilder();
                while (char.IsDigit((char)reader.Peek()))
                {
                    maxString.Append((char)reader.Read());
                }
                max = Convert.ToInt32(maxString.ToString());
            }
            //-----------------------------------------------

            // End of stream reached.
            if (reader.Peek() == -1)
            {
                return(null);
            }
            // We have rulename.
            else if (char.IsLetter((char)reader.Peek()))
            {
                return(new ABNF_Repetition(min, max, ABNF_RuleName.Parse(reader)));
            }
            // We have group.
            else if (reader.Peek() == '(')
            {
                return(new ABNF_Repetition(min, max, ABFN_Group.Parse(reader)));
            }
            // We have option.
            else if (reader.Peek() == '[')
            {
                return(new ABNF_Repetition(min, max, ABNF_Option.Parse(reader)));
            }
            // We have char-val.
            else if (reader.Peek() == '\"')
            {
                return(new ABNF_Repetition(min, max, ABNF_CharVal.Parse(reader)));
            }
            // We have num-val.
            else if (reader.Peek() == '%')
            {
                // Eat '%'.
                reader.Read();

                if (reader.Peek() == 'd')
                {
                    return(new ABNF_Repetition(min, max, ABNF_DecVal.Parse(reader)));
                }
                else
                {
                    throw new ParseException("Invalid 'num-val' value '" + reader.ReadToEnd() + "'.");
                }
            }
            // We have prose-val.
            else if (reader.Peek() == '<')
            {
                return(new ABNF_Repetition(min, max, ABNF_ProseVal.Parse(reader)));
            }

            return(null);
        }