You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java ANTLR4的visitTerminal重写方法中获取Python注释?

如何在ANTLR4 Python监听器中捕获注释内容

背景

根据相关方案自动生成了以下ANTLR4文件:

  • Python3Lexer.java
  • Python3ParserBase.java
  • Python3ParserListener.java
  • PythonDocstringModifierListener.java
  • Python3Parser.java

随后编写了自定义监听器类:

public class SomePythonListener extends Python3ParserBaseListener {
  public SomePythonListener(Python3Parser parser, String someValue) {
    this.parser = parser;
    this.someValue = someValue;
  }

  @Override
  public void visitTerminal(TerminalNode node) {
    Token token = node.getSymbol();
    System.out.println("token.getType()=" + token.getType());
    System.out.println("getText:" + token.getText() + "XXXX\n\n");
  } 
}

测试用的Python源码:

"""A file docstring.
With a multiline starting docstring.
That spans the first 3 lines."""
# Some Comment.

# Another comment
"""Some string."""
def foo():
    """Some docstring."""
    print('hello world')
    def bar():
        """Another docstring."""
        print('hello world')
def baz():
        """Third docstring."""
        print('hello universe')

运行后发现,文档字符串、换行符都被正常捕获,但# Some Comment.和# Another comment这两个注释完全没出现在输出里。

问题根源

自定义监听器的visitTerminal方法只能处理**默认通道(DEFAULT_TOKEN_CHANNEL)的Token,而ANTLR会把注释这类不需要参与语法解析的内容放到隐藏通道(HIDDEN)**中,这些Token不会被加入到语法树,所以默认方法访问不到。

解决方法

方法1:从Token流中提取隐藏通道的注释

在监听器中通过Token流手动获取隐藏通道的内容,推荐在enterEveryRule方法中处理(确保每个语法规则执行前都检查前置的注释):

public class SomePythonListener extends Python3ParserBaseListener {
  private final CommonTokenStream tokenStream;

  public SomePythonListener(Python3Parser parser, String someValue) {
    this.tokenStream = (CommonTokenStream) parser.getInputStream();
    this.parser = parser;
    this.someValue = someValue;
  }

  @Override
  public void enterEveryRule(ParserRuleContext ctx) {
    // 获取当前规则起始Token左侧的所有隐藏Token
    List<Token> hiddenTokens = tokenStream.getHiddenTokensToLeft(ctx.getStart().getTokenIndex());
    if (hiddenTokens != null) {
      for (Token token : hiddenTokens) {
        // 匹配Python3Lexer中定义的注释类型(需确认实际的注释Token类型值)
        if (token.getType() == Python3Lexer.COMMENT) {
          System.out.println("捕获到注释:" + token.getText());
        }
      }
    }
  }

  // 保留原有的visitTerminal方法
  @Override
  public void visitTerminal(TerminalNode node) {
    Token token = node.getSymbol();
    System.out.println("token.getType()=" + token.getType());
    System.out.println("getText:" + token.getText() + "XXXX\n\n");
  } 
}

方法2:修改词法规则(不推荐)

如果不想处理隐藏通道,可以修改Python3Lexer.g4中的注释规则,将注释从HIDDEN通道移到默认通道:
原规则大概是这样:

COMMENT : '#' ~[\r\n]* -> channel(HIDDEN);

修改为:

COMMENT : '#' ~[\r\n]*;

修改后重新生成词法分析器,注释就会出现在默认通道,visitTerminal就能捕获到。但这种方法会改变语法树结构,可能影响后续解析逻辑,谨慎使用。

原理说明

ANTLR默认将注释、空白符这类辅助性内容放到HIDDEN通道,避免干扰语法解析逻辑。这些Token不会进入语法树,所以必须手动从Token流中提取才能访问到。

内容的提问来源于stack exchange,提问作者a.t.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 02:06:12