Sprache:语法中的左递归

时间:2013-11-11 11:18:52

标签: c# parsing sprache

我正在为类似于SQL的语言开发解析器,我遇到了创建一些语言规则的问题,例如:expression IS NULLexpression IN (expression1, expression2, ...),逻辑和数学运算符之间具有优先级。

我上传了一个GitHub测试项目https://github.com/anpv/SpracheTest/,但这种变体并不好 我试图使用以下规则:

private static readonly Parser<AstNode> InOperator =
    from expr in Parse.Ref(() => Expression)
    from inKeyword in Parse.IgnoreCase("in").Token()
    from values in Parse
        .Ref(() => Expression)
        .DelimitedBy(Comma)
        .Contained(OpenParenthesis, CloseParenthesis)
    select new InOperator(expr, values);

private static readonly Parser<AstNode> IsNullOperator =
    from expr in Parse.Ref(() => Expression)
    from isNullKeyword in Parse
         .IgnoreCase("is")
         .Then(_ => Parse.WhiteSpace.AtLeastOnce())
         .Then(_ => Parse.IgnoreCase("null"))
    select new IsNullOperator(expr);

private static readonly Parser<AstNode> Equality =
    Parse
        .ChainOperator(Eq, IsNullOperator.Or(InOperator).Or(Additive), MakeBinary);

会在ParseExceptionScriptParser.ParseExpression("1 is null")等代码中引发ScriptParser.ParseExpression("1 in (1, 2, 3)"): "Parsing failure: Left recursion in the grammar."

我如何预测Expression,或者是否存在其他变体来解决这个问题?

1 个答案:

答案 0 :(得分:6)

不幸的是,答案是Sprache无法解析左递归语法。我偶然发现源代码中的评论,讨论了在研究这个问题时我是如何删除对左递归语法的错误支持的(这也是我发现你的问题的方式) - 请参阅source code

为了解决这个问题,您需要重新组织解析方式。例如,如果您正在编写一个简单的表达式解析器,那么这是您必须处理的常见问题。在网上搜索有很多关于如何从语法中删除左递归的讨论,特别是对于表达式。

在您的情况下,我希望您需要执行以下操作:

term := everything simple in an expression (like "1", "2", "3", etc.)
expression := term [ IN ( expression*) | IS NULL | "+" expression | "-" expression | etc.]

或类似 - 基本上 - 你必须自己解除递归。通过这样做,我能够解决表达式问题。我怀疑任何基本的编译器书可能都有关于如何“规范化”语法的部分。

它使从解析器返回的任何对象构建更多的痛苦,但是在select语句中而不是“select new Expression(arg1,arg2)”我将其更改为函数调用,并且函数根据参数决定返回的特定对象。