我已经为ANTLR v4编写了一个语法,c#目标使用一些左递归解析规则,每次我试图解析一些应该使用这些规则的示例代码时,解析引擎都会选择错误的规则。
解析规则:expr
: expr COR term
| expr CAND term
| term
;
我要解析的代码:
...
print("Testing Program p00csxn");
...
使用来自解析引擎的信息的访问者:
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,也许问题是我忽略的一些简单的东西。任何帮助将非常感激;我一直在阅读文档并运行调试器几天,现在断断续续地试图找出这个问题。
谢谢!
您应该避免使用ParserRuleContext.altNum
字段,原因如下:
- 对于左递归规则永远不会初始化,所以不可靠。
- 这是一个巨大的内存浪费,我希望删除它。
- 我还没有执行任何测试来验证其准确性或在任何其他情况下的可用性。
请尝试以下任意一种:
-
通过首先检查
context.expr()
是否返回null来测试备选项。如果是这样,那么你有一个term
。如果expr()
返回非空,那么您可以检查context.COR()
或context.CAND()
中哪个返回非空,以确定实际使用的操作符 -
标记你最外层的替代品,像这样
expr : expr COR term # orExpr | expr CAND term # andExpr | term # termExpr ;
我建议你完全取消左递归:
expr
scope
{
LogicOperator op;
}
: expr ((COR {expr.op = LogicOperator.Or;} | CAND {expr.op = LogicOperator.And;}) exp)*
| term
;
注。我的ANTLR3语法与逻辑运算符和优先级