Action 不能在左递归替换中使用任何{}语句

Action 不能在左递归替换中使用任何{}语句,action,antlr4,left-recursion,Action,Antlr4,Left Recursion,我正在使用Java目标。我有以下简单语法: grammmar example; alpha : alpha 'something' | 'otherthing' ; 现在,我想让解析器在输入规则alpha时,为某物打印Hello-World,为另一物打印Hello-World。因此,我想用以下方式修改我的语法: grammmar example; alpha : {System.out.pr

我正在使用Java目标。我有以下简单语法:

    grammmar example;

    alpha :
            alpha 'something'
          | 'otherthing' ;
现在,我想让解析器在输入规则alpha时,为某物打印
Hello-World
,为另一物打印
Hello-World
。因此,我想用以下方式修改我的语法:

    grammmar example;

    alpha :
            {System.out.println("Hello World for something");}
            alpha 'something'
          | {System.out.println("Hello World for otherthing");}
            'otherthing' ;
但这会导致解析器抛出错误,即规则项是相互左递归的。此错误是由于在左递归备选方案中使用任何{…}语句造成的

由于这似乎是一个bug/在ANTLR4中可以改进,我还有什么其他选择呢?

ANTLR4只支持直接左递归。您在这里所做的是在一个操作之后隐藏左递归

最简单的解决方案是为语法实现一个侦听器,并在
enterAlpha
的实现中添加
println
语句

以下是不带操作的语法代码:

alpha
  : alpha 'something'
  | 'otherthing'
  ;
下面是带有操作代码的侦听器方法:

@Override
public void enterAlpha(AlphaContext ctx) {
  if (ctx.alpha() != null) {
    System.out.println("Hello World for something");
  } else {
    System.out.println("Hello World for otherthing");
  }
}
该代码中使用的条件可能看起来很奇怪,但由于语法的编写方式,没有其他方法可以在代码中确定在
alpha
中采用了哪种替代方法。这种情况可以(也可能应该)通过几种方法来解决,以提高代码的清晰度。以下提示可单独使用或组合使用

选项1:为
something
otherthing
关键字添加显式词法规则。 通过引用
alpha
规则中的
Something
Otherthing
,ANTLR将在
AlphaContext
中生成访问器方法,以便您直接访问为解析树中的标记创建的
TerminalNode
实例

@Override
public void enterAlpha(AlphaContext ctx) {
  if (ctx.Something() != null) {
    System.out.println("Hello World for something");
  } else if (ctx.Otherthing() != null) {
    System.out.println("Hello World for otherthing");
  } else {
    assert ctx.exception != null; // only reachable if a parse error occurred
  }
}
选项2:标记
alpha
规则的外部备选方案。 这将导致ANTLR为每个备选方案生成单独的上下文类,这也允许您单独实现侦听器/访问者功能

alpha
  : alpha 'something'  # mySomething
  | 'otherthing'       # myOtherthing
  ;
侦听器现在可能如下所示:

@Override
public void enterMySomething(MySomethingContext ctx) {
  System.out.println("Hello World for something");
}

@Override
public void enterMyOtherthing(MyOtherthingContext ctx) {
  System.out.println("Hello World for otherthing");
}
@Override
public void enterMySomething(MySomethingContext ctx) {
  System.out.println("Hello World for something");
}

@Override
public void enterMyOtherthing(MyOtherthingContext ctx) {
  System.out.println("Hello World for otherthing");
}