ANTLR4留下了递归问题

时间:2013-06-18 13:43:29

标签: c# antlr4

我为ANTLR v4编写了一个带有C#目标的语法,该目标使用了一些左递归解析规则,每次我尝试解析一些应该使用这些规则的示例代码时,解析引擎选择了错误的规则。 / p>

解析规则:

expr
    : expr COR term
    | expr CAND term
    | term
    ;

我正在尝试解析的代码:

...
print("Testing Program p00csx\n");
...

访问者使用解析引擎中的信息:

public override Int32 VisitExpr(CSXParser.ExprContext context)
    {
        if (context == null) return 0;
        switch (context.altNum)
        {
            case 1: //expr COR term
                VisitExpr(context.expr());
                Console.Write(context.COR());
                VisitTerm(context.term());
                break;
            case 2: //expr CAND term
                VisitExpr(context.expr());
                Console.Write(context.CAND());
                VisitTerm(context.term());
                break;
            case 3: //term
                VisitTerm(context.term());
                break;
        }
        return 0;
    }

在这个例子中,print()调用中的字符串文字应解析为'expr',它解析为'term'等,直到我们有'stringLit'。这是上例中的情况3。相反,解析器正在挑选案例1,甚至认为程序文本中没有COR('||')。

ANTLR网站说v4可以处理这些左递归表达式,这让我相信我一定做错了。我是ANTLR的新手,也许这个问题很简单,我忽略了。任何帮助将非常感激;我一直在阅读文档并运行调试器几天,然后尝试解决这个问题。

谢谢!

2 个答案:

答案 0 :(得分:2)

出于以下原因,您应该避免使用ParserRuleContext.altNum字段。

  • 它从未针对左递归规则进行初始化,因此它不可靠。
  • 这是对内存的巨大浪费,我希望将其删除。
  • 我没有进行任何测试来验证其在任何其他情况下的准确性或可用性。

相反,请尝试以下任一方法:

  1. 首先检查context.expr()是否返回null,以测试替代方案。如果是这样,那么你有一个term。如果expr()返回非null,则可以检查context.COR()context.CAND()中的哪一个返回非null,以确定使用的实际运算符。

  2. 标记最外层的替代品,例如

    expr
        : expr COR term  # orExpr
        | expr CAND term # andExpr
        | term           # termExpr
        ;
    

答案 1 :(得分:-1)

我建议您删除左递归:

expr
scope
{
    LogicOperator op;
}
        : expr ((COR {expr.op = LogicOperator.Or;} | CAND {expr.op = LogicOperator.And;}) exp)*
        | term
        ;

P.S。 我的ANTLR3 grammar有逻辑运算符和优先级