0

美好的一天,我有简单的语法来描述选择的列。用户可以为它们指定简单的列名、列名和子列(等等),或者使用'*'来选择所有字段。

一些例子:

    exp = "(Id)" - select only Id column
    exp = "(Id, Name)" - select Id and Name columns
    exp = "(Id, Type(Id, Name)" - select Id, Type.Id, Type.Name columns
    exp = "(Id, Type(*))" - select Id and all columns in Type

所以,我定义了令牌枚举:

    enum FieldExpressionToken
    {
        Undefined,
        
        [Token(Example = "(")]
        LBracket,
        
        [Token(Example = ")")]
        RBracket,
        
        [Token(Example = ",")]
        Comma,
        
        [Token(Example = ":")]
        Colon,
        
        [Token(Example = "*")]
        Star,
        
        Identifier
    }

和他们的标记器:

    static class FieldExpressionTokenizer
    {
        private static TextParser<TextSpan> FieldNameToken { get; } =
            Span.Regex(@"@?[a-zA-Z_]\w*(\.@?[a-zA-Z_]\w*)*");
    
        public static Tokenizer<FieldExpressionToken> Instance { get; } = 
            new TokenizerBuilder<FieldExpressionToken>()
                .Match(Character.EqualTo('*'), FieldExpressionToken.Star)
                .Match(Character.EqualTo('('), FieldExpressionToken.LBracket)
                .Match(Character.EqualTo(')'), FieldExpressionToken.RBracket)
                .Match(Character.EqualTo(','), FieldExpressionToken.Comma)
                .Match(Character.EqualTo(':'), FieldExpressionToken.Colon)
                .Match(FieldNameToken, FieldExpressionToken.Identifier)
                .Build();
    }

现在我尝试创建解析器。单个字段的解析器:

    private static readonly TokenListParser<FieldExpressionToken, Field> Field = 
         from identifier in Token
            .EqualTo(FieldExpressionToken.Identifier)
            .Or(Token.EqualTo(FieldExpressionToken.Star))
            .Named("column name")
        select new Field(identifier.ToStringValue());

复合字段解析器:

    private static readonly TokenListParser<FieldExpressionToken, Field> ComplexField =
        from identifier in Token
            .EqualTo(FieldExpressionToken.Identifier)
            .Or(Token.EqualTo(FieldExpressionToken.Star))
            .Named("column name")
            .Try()
            .Then(x => Token
                 .EqualTo(FieldExpressionToken.Colon)
                 .IgnoreThen(Parse.Ref(() => FieldList))
                 .Named("child fields")
                 .Select(value => new Field(x.ToStringValue(), new[] {value})))
        select identifier;

列表解析器:

    private static readonly TokenListParser<FieldExpressionToken, Field> FieldList =
        from begin in Token.EqualTo(FieldExpressionToken.LBracket)
        from fields in Parse
            .Ref(() => FieldExpression)
            .Named("fields")
            .ManyDelimitedBy(
                Token.EqualTo(FieldExpressionToken.Comma), 
                end: Token.EqualTo(FieldExpressionToken.RBracket))
        select new Field("", fields.Select(x => new Field(x.ToString())));

和总表达式解析器:

    private static TokenListParser<FieldExpressionToken, Field> FieldExpression { get; } =
        Field
            .Or(ComplexField)
            .Or(FieldList);

我可以解析像(Name)or这样的简单表达式(Id,Name),但是在表达式上我(Name:(Id))得到错误Syntax error (line 1, column 6): unexpected :), expected .

谁能帮我纠正我的解析器?

4

1 回答 1

0

好的..可能我找到了解决方案,但我不确定 100%

我将整体表达式解析器中的顺序更改为:


    private static TokenListParser<FieldExpressionToken, Field> FieldExpression { get; } =
                ComplexField
                    .Or(Field)
                    .Or(FieldList);

并更新 ComplexFiled 解析器:


    private static readonly TokenListParser<FieldExpressionToken, Field> ComplexField =
                 from identifier in Token
                     .EqualTo(FieldExpressionToken.Identifier)
                     .Or(Token.EqualTo(FieldExpressionToken.Star))
                     .Named("column name")
                     .Then(x => Token
                         .EqualTo(FieldExpressionToken.Colon)
                         .IgnoreThen(Parse.Ref(() => FieldList))
                         .Named("child fields")
                         .Select(value => new Field(x.ToStringValue(), new[] {value})))
                     .Try()
                 select identifier;

而不是它的工作!

于 2021-08-11T13:02:37.463 回答