public IList <EbnfMessage> DeclareImplicitTerminals()
        {
            var result = new List <EbnfMessage>();
            var terms  = new HashSet <EbnfExpression>();
            var done   = new HashSet <EbnfExpression>();

            foreach (var prod in Productions)
            {
                _VisitFetchTerminals(prod.Value.Expression, terms);
                if (prod.Value.Expression.IsTerminal)
                {
                    done.Add(prod.Value.Expression);
                }
            }

            foreach (var term in terms)
            {
                if (!done.Contains(term))
                {
                    var prod = new EbnfProduction();
                    prod.Expression = ((ICloneable)term).Clone() as EbnfExpression;
                    var newId = _GetImplicitTermId();
                    Productions.Add(newId, prod);
                    result.Add(new EbnfMessage(EbnfErrorLevel.Message, -1, "Terminal was implicitly declared.", term.Line, term.Column, term.Position));
                }
            }
            return(result);
        }
        static void _ReadProduction(EbnfDocument doc, EbnfParser parser)
        {
            parser.Read();
            var id   = parser.Value;
            var prod = new EbnfProduction();

            parser.Read();
            if (EbnfParser.lt == parser.SymbolId)
            {
                parser.Read();
                _ReadAttributes(prod.Attributes, parser);
                parser.Read();
            }
            parser.Read();
            prod.Expression = _ReadExpressions(parser);
        }
        static void _ParseAttribute(EbnfDocument doc, string id, EbnfProduction prod, ParseContext pc)
        {
            pc.TrySkipCCommentsAndWhiteSpace();
            var attrid = _ParseIdentifier(pc);

            pc.TrySkipCCommentsAndWhiteSpace();
            pc.Expecting('=', '>', ',');
            object val = true;

            if ('=' == pc.Current)
            {
                pc.Advance();
                val = pc.ParseJsonValue();
            }
            pc.Expecting(',', '>');
            prod.Attributes[attrid] = val;
            pc.TrySkipCCommentsAndWhiteSpace();
        }
 static void _ParseAttributes(EbnfDocument doc, string id, EbnfProduction prod, ParseContext pc)
 {
     pc.TrySkipCCommentsAndWhiteSpace();
     pc.Expecting('<');
     pc.Advance();
     while (-1 != pc.Current && '>' != pc.Current)
     {
         _ParseAttribute(doc, id, prod, pc);
         pc.TrySkipCCommentsAndWhiteSpace();
         pc.Expecting(',', '>');
         if (',' == pc.Current)
         {
             pc.Advance();
         }
     }
     pc.Expecting('>');
     pc.Advance();
     pc.TrySkipCCommentsAndWhiteSpace();
 }
        static void _ParseProduction(EbnfDocument doc, ParseContext pc)
        {
            pc.TrySkipCCommentsAndWhiteSpace();
            var line     = pc.Line;
            var column   = pc.Column;
            var position = pc.Position;
            var id       = _ParseIdentifier(pc);

            pc.TrySkipCCommentsAndWhiteSpace();
            var prod = doc.Productions.TryGetValue(id, null);

            if (null == prod)
            {
                prod = new EbnfProduction();
                doc.Productions.Add(id, prod);
            }
            if ('<' == pc.Current)
            {
                _ParseAttributes(doc, id, prod, pc);
                pc.TrySkipCCommentsAndWhiteSpace();
            }
            pc.Expecting('=');
            pc.Advance();
            pc.Expecting();
            var expr = _ParseExpression(doc, pc);

            pc.TrySkipCCommentsAndWhiteSpace();
            pc.Expecting(';');
            pc.Advance();
            pc.TrySkipCCommentsAndWhiteSpace();
            // transform this into an OrExpression with the previous
            if (null != prod.Expression)
            {
                prod.Expression = new EbnfOrExpression(prod.Expression, expr);
            }
            else
            {
                prod.Expression = expr;
            }
            prod.SetPositionInfo(line, column, position);
        }