Antlr:如何在访客实现中打开令牌类型

Antlr: how to switch on token type in Visitor implementation

我正在玩 Antlr,设计一种玩具语言,我认为这是大多数人的起点! - 我有一个关于如何最好地考虑开启令牌类型的问题。

考虑语言中的 'function call',其中函数可以使用字符串、数字或变量 - 例如如下(project() 是函数调用)

project("ABC") 对比 project(123) 对比 project($SOME_VARIABLE)

我的语法中有更改运算符,所以语法解析正确的东西,但在访问者代码中,最好能说出上述三个版本之间的区别。


   @Override
    public ASTRoot visitCreateproj(projectmgmtParser.CreateprojContext ctx) {


        try {
             s1 = ctx.STRING_LITERAL().getText();
        }catch(Exception e){}
        try{
             s2 = ctx.NUM().getText();
        }catch(Exception e){}
        System.out.println("Created Project via => "  + ctx.getChild(1).toString());
    }

上面的代码有效,取决于 s1s2 是否为空,我可以推断我是如何被调用的(用文字或数字,我没有显示变量大小写上面),但我很感兴趣是否有更好或更优雅的方式 - 例如在访问者代码中打开令牌类型以实际处理语言。

上面的语法是

createproj: 'project('WS?(STRING_LITERAL|NUM)')';

并且当我使用 intellij antlr 插件时,它似乎知道 project() 函数参数的标记类型——但我似乎无法从我的代码中获取它。

你可以这样做:

createproj
 : 'project' '(' WS? param ')'
 ;

param
 : STRING_LITERAL 
 | NUM
 ;

并在您的访客代码中:

@Override
public ASTRoot visitCreateproj(projectmgmtParser.CreateprojContext ctx) {
  switch(ctx.param().start.getType()) {
    case YourLexerName.STRING_LITERAL:
      ...
    case YourLexerName.NUM:
      ...
    ...
  }
}

so by inlining the token in the grammar I had originally, I've lost the opportunity to inspect it in the visitor code?

不,你也可以这样做:

createproj
 : 'project' '(' WS? param_token=(STRING_LITERAL | NUM) ')'
 ;

然后可以这样做:

@Override
public ASTRoot visitCreateproj(projectmgmtParser.CreateprojContext ctx) {
  switch(ctx.param_token.getType()) {
    case YourLexerName.STRING_LITERAL:
      ...
    case YourLexerName.NUM:
      ...
    ...
  }
}

只要确保您没有在您的集合中混用词法分析器规则(标记)和解析器规则 param_token=( ... )。当它是解析器规则时,ctx.param_token.getType() 将失败(它必须是 ctx.param_token.start.getType())。这就是为什么我建议添加一个额外的解析器规则,因为这样仍然有效:

param
 : STRING_LITERAL 
 | NUM
 | some_parser_rule
 ;