static IList <_LexRule> _ParseRules(TextReader inp)
        {
            var result = new List <_LexRule>();
            var pc     = LexContext.CreateFrom(inp);

            pc.EnsureStarted();
            while (-1 != pc.Current)
            {
                pc.TrySkipCCommentsAndWhiteSpace();
                if (-1 == pc.Current)
                {
                    break;
                }
                pc.ClearCapture();
                var l    = pc.Line;
                var c    = pc.Column;
                var p    = pc.Position;
                var rule = new _LexRule();
                rule.Line     = l;
                rule.Column   = c;
                rule.Position = p;
                if (!pc.TryReadCIdentifier())
                {
                    throw new ExpectingException(string.Format("Identifier expected at line {0}, column {1}, position {2}", l, c, p), l, c, p, "identifier");
                }
                rule.Symbol = pc.GetCapture();
                rule.Id     = int.MinValue;
                pc.ClearCapture();
                pc.TrySkipCCommentsAndWhiteSpace();
                pc.Expecting('<', '=', '{');
                if ('<' == pc.Current)
                {
                    pc.Advance();
                    pc.Expecting();
                    var attrs = new List <KeyValuePair <string, object> >();
                    while (-1 != pc.Current && '>' != pc.Current)
                    {
                        pc.TrySkipCCommentsAndWhiteSpace();
                        pc.ClearCapture();
                        l = pc.Line;
                        c = pc.Column;
                        p = pc.Position;
                        if (!pc.TryReadCIdentifier())
                        {
                            throw new ExpectingException(string.Format("Identifier expected at line {0}, column {1}, position {2}", l, c, p), l, c, p, "identifier");
                        }
                        var aname = pc.GetCapture();
                        pc.TrySkipCCommentsAndWhiteSpace();
                        pc.Expecting('=', '>', ',');
                        if ('=' == pc.Current)
                        {
                            pc.Advance();
                            pc.TrySkipCCommentsAndWhiteSpace();
                            l = pc.Line;
                            c = pc.Column;
                            p = pc.Position;
                            var value = pc.ParseJsonValue();
                            attrs.Add(new KeyValuePair <string, object>(aname, value));
                            if (0 == string.Compare("id", aname) && (value is double))
                            {
                                rule.Id = (int)((double)value);
                                if (0 > rule.Id)
                                {
                                    throw new ExpectingException(string.Format("Expecting a non-negative integer at line {0}, column {1}, position {2}", l, c, p), l, c, p, "nonNegativeInteger");
                                }
                            }
                        }
                        else
                        {                         // boolean true
                            attrs.Add(new KeyValuePair <string, object>(aname, true));
                        }
                        pc.TrySkipCCommentsAndWhiteSpace();
                        pc.Expecting(',', '>');
                        if (',' == pc.Current)
                        {
                            pc.Advance();
                        }
                    }
                    pc.Expecting('>');
                    pc.Advance();
                    rule.Attributes = attrs.ToArray();
                    pc.TrySkipCCommentsAndWhiteSpace();
                }
                pc.Expecting('=', '{');
                var isAsm = '{' == pc.Current;

                pc.Advance();
                if (!isAsm)
                {
                    pc.TrySkipCCommentsAndWhiteSpace();
                    pc.Expecting('\'', '\"');
                    if ('\'' == pc.Current)
                    {
                        pc.Advance();
                        pc.ClearCapture();
                        pc.TryReadUntil('\'', '\\', false);
                        pc.Expecting('\'');
                        var pc2 = LexContext.Create(pc.GetCapture());
                        pc2.EnsureStarted();
                        pc2.SetLocation(pc.Line, pc.Column, pc.Position, pc.FileOrUrl);
                        rule.Part = Lex.CompileRegexPart(pc2);
                        pc.Advance();
                    }
                    else
                    {
                        var str = pc.ParseJsonString();
                        rule.Part = Lex.CompileLiteralPart(str);
                    }
                }
                else
                {
                    rule.Part = Lex.Assemble(pc);
                    pc.Expecting('}');
                    pc.Advance();
                }
                result.Add(rule);
            }
            if (0 == result.Count)
            {
                throw new ExpectingException("Expecting lexer rules, but the document was empty", 0, 0, 0, "rule");
            }
            return(result);
        }