0

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

解析规则:

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。然而,尽管程序文本中没有 COR ('||'),但解析器却选择了案例 1。

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

谢谢!

4

2 回答 2

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
        ;
    
于 2013-06-18T13:56:33.830 回答
-1

我建议你完全删除左递归:

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

ps 我的ANTLR3 语法与逻辑运算符和优先级

于 2013-06-18T13:54:21.460 回答