我的语法中有以下内容(为简单起见,此处'name''value'只是静态的,实际上它们不是静态的):

test4 : 'name' CMPOP 'value';

CMPOP       :   EQUALS | NOTEQUALS;
EQUALS      :   '=';
NOTEQUALS   :   '!=';


现在,我想做的是以不同方式(可能通过开关)处理不同的CMPOP。当我在FilterListener实现中评估表达式时,是否有办法获取CMPOP(=或!=)基础令牌的int / enum版本?我知道我可以用getText()来获取字符串,但是比较字符串在任何地方都可能很慢。例如如果我有name=value,我可以看到= TerminalNodeImpl并且它有一个Symbol。唯一看起来相似的是type属性,但这似乎给了我CMPOP。

public void exitTest4(@NotNull testParser.Test4Context ctx) {
    System.out.println(ctx.CMPOP().getSymbol().toString());
    int type = ctx.CMPOP().getSymbol().getType();
    System.out.println(type + "," + testParser.tokenNames[type]);
}


给我:

[@1,4:4='=',<6>,1:4]
6,CMPOP


我想做的是这样的:

switch ( ctx.CMPOP().something() ) {
  EQUALS : //evaluate with = ; break
  NOTEQUALS : //evaluate with != ; break
}


还是我走错路了?我应该将其移至解析器规则,而不是词法分析器规则,例如:'name' (EQUALS | NOTEQUALS) 'value'吗?

我正在使用antlr4。

最佳答案

您有两个主要选择。您可以选择最适合您的方法。

选项1:将CMPOP更改为解析器规则,而不是词法分析器规则

cmpOp
  : EQUALS
  | NOTEQUALS
  ;


优点:


易于执行更改
如果需要更改cmpOp规则,则易于维护
EQUALSNOTEQUALS作为比较运算符更好的概念分组


选项2:删除CMPOP规则,然后将其内联到解析器规则中

将所有当前引用CMPOP的代码替换为(EQUALS | NOTEQUALS)

优点:


每个比较运算符减少1个解析树节点(如果您的情况很重要,则可以减少内存开销)

08-05 19:39