【问题标题】:Antlr: how to switch on token type in Visitor implementationAntlr:如何在访问者实现中打开令牌类型
【发布时间】:2020-10-16 17:59:48
【问题描述】:

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

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

project("ABC") vs project(123) vs 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() 函数的参数的令牌类型 - 但我似乎无法从我的代码中得到它。

【问题讨论】:

    标签: antlr antlr4


    【解决方案1】:

    你可以这样做:

    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:
          ...
        ...
      }
    }
    

    所以通过在我原来的语法中内联标记,我失去了在访问者代码中检查它的机会?

    不,你也可以这样:

    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
     ;
    

    【讨论】:

    • 谢谢,这很有帮助 - 所以通过在我最初的语法中内联标记,我失去了在访问者代码中检查它的机会? .. 因此,通过将其分离出来,我可以访问 start.getType() 方法来检查它。
    • 很好 - 感谢编辑的答案 - 现在更有意义了。
    猜你喜欢
    • 1970-01-01
    • 2020-11-09
    • 2013-07-22
    • 1970-01-01
    • 1970-01-01
    • 2015-04-17
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多