使用 ANTLR 捕获(并保留)所有评论

问题描述 投票:0回答:7

我正在 ANTLR 中编写一个语法,将 Java 源文件解析为 AST 以便以后分析。与其他解析器(如 JavaDoc)不同,我试图保留所有注释。这是很难的注释,可以在代码中的任何地方使用。如果源代码中的注释与语法不匹配,ANTLR 将无法完成文件解析。

有没有办法让 ANTLR 自动将它找到的任何注释添加到 AST 中?我知道词法分析器可以使用

{skip();}
或将文本发送到隐藏通道来忽略所有注释。设置这两个选项中的任何一个后,ANTLR 都会毫无问题地解析文件。

欢迎任何想法。

parsing comments antlr
7个回答
13
投票

“The Definitive Antlr 4 Reference”中的第 12.1 节展示了如何访问注释,而不必在整个语法中散布注释规则。简而言之,您将其添加到语法文件中:

grammar Java;

@lexer::members {
    public static final int WHITESPACE = 1;
    public static final int COMMENTS = 2;
}

然后对于您的评论规则,请执行以下操作:

COMMENT
    : '/*' .*? '*/' -> channel(COMMENTS)
    ;

LINE_COMMENT
    : '//' ~[\r\n]* -> channel(COMMENTS)
    ;

然后在代码中通过 getHiddenTokensToLeft/getHiddenTokensToRight 请求令牌,并查看书中的 12.1 部分,您将了解如何执行此操作。


11
投票

第一:将所有评论定向到某个频道(仅限评论)

COMMENT
    : '/*' .*? '*/' -> channel(2)
    ;

LINE_COMMENT
    : '//' ~[\r\n]* -> channel(2)
    ;

第二:打印出所有评论

      CommonTokenStream tokens = new CommonTokenStream(lexer);
      tokens.fill();
      for (int index = 0; index < tokens.size(); index++)
      {
         Token token = tokens.get(index);
         // substitute whatever parser you have
         if (token.getType() != Parser.WS) 
         {
            String out = "";
            // Comments will be printed as channel 2 (configured in .g4 grammar file)
            out += "Channel: " + token.getChannel();
            out += " Type: " + token.getType();
            out += " Hidden: ";
            List<Token> hiddenTokensToLeft = tokens.getHiddenTokensToLeft(index);
            for (int i = 0; hiddenTokensToLeft != null && i < hiddenTokensToLeft.size(); i++)
            {
               if (hiddenTokensToLeft.get(i).getType() != IDLParser.WS)
               {
                  out += "\n\t" + i + ":";
                  out += "\n\tChannel: " + hiddenTokensToLeft.get(i).getChannel() + "  Type: " + hiddenTokensToLeft.get(i).getType();
                  out += hiddenTokensToLeft.get(i).getText().replaceAll("\\s", "");
               }
            }
            out += token.getText().replaceAll("\\s", "");
            System.out.println(out);
         }
      }

8
投票

有没有办法让 ANTLR 自动将它找到的任何注释添加到 AST 中?

不,您必须在整个语法中添加额外的

comments
规则,以考虑注释可能出现的所有有效位置:

...

if_stat
 : 'if' comments '(' comments expr comments ')' comments ...
 ;

...

comments
 : (SingleLineComment | MultiLineComment)*
 ;

SingleLineComment
 : '//' ~('\r' | '\n')*
 ;

MultiLineComment
 : '/*' .* '*/'
 ;

1
投票

还可以使用“岛屿语法”功能。请参阅 ANTLR4 书中的以下部分:

Island Grammars:处理同一文件中的不同格式


0
投票

我在词法分析器部分这样做了:

WS  :   ( [ \t\r\n] | COMMENT) -> skip
;

fragment
COMMENT
: '/*'.*'*/' /*single comment*/
| '//'~('\r' | '\n')* /* multiple comment*/
;

这样它会自动删除它们!


0
投票

对于 ANTLR v3:

空白标记通常不会被解析器处理,但它们仍然在 HIDDEN 通道上被捕获。

如果您使用

BufferedTokenStream
,您可以通过它获取所有令牌的列表并进行后处理,根据需要添加它们。


0
投票

我有一个项目,其中有 Kolasu 作为依赖项。为了保留评论,我合并了 2 个答案(@baron.wang 和 @Bart Kiers),现在有了一个有效的答案。 我将评论发送到频道(2)(@baron.wang答案)并创建了一个地图,没有更改其余的语法(@Bart Kiers答案,不想撒评论),它解析正确。

Kolasu 为每个评论给出了一个点,该点保存在地图上。当我需要某个类的评论时,我会在其 Point 之前进行搜索。

© www.soinside.com 2019 - 2024. All rights reserved.