使用ANTLR捕获(并保留)所有注释

T S*_*uds 3 parsing comments antlr

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

有没有办法让ANTLR自动将它找到的任何评论添加到AST?我知道词法分析器可以简单地使用任何一个{skip();}或通过将文本发送到隐藏通道来忽略所有注释.使用这些选项中的任何一个,ANTLR都可以毫无问题地解析文件.

欢迎任何想法.

Bar*_*ers 7

有没有办法让ANTLR自动将它找到的任何评论添加到AST?

不,您必须使用额外的comments规则来填充您的整个语法,以便考虑可能发生的所有有效地点:

...

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

...

comments
 : (SingleLineComment | MultiLineComment)*
 ;

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

MultiLineComment
 : '/*' .* '*/'
 ;
Run Code Online (Sandbox Code Playgroud)


小智 7

"最终Antlr 4参考"中的第12.1节显示了如何访问注释,而无需在整个语法中使用注释规则.简而言之,您将其添加到语法文件中:

grammar Java;

@lexer::members {
    public static final int WHITESPACE = 1;
    public static final int COMMENTS = 2;
}
Run Code Online (Sandbox Code Playgroud)

那么对于你的评论规则,这样做:

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

LINE_COMMENT
    : '//' ~[\r\n]* -> channel(COMMENTS)
    ;
Run Code Online (Sandbox Code Playgroud)

然后在你的代码中通过getHiddenTokensToLeft/getHiddenTokensToRight询问令牌并查看书中的12.1部分,你会看到如何做到这一点.


小智 5

首先:将所有评论定向到某个频道(仅评论)

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

LINE_COMMENT
    : '//' ~[\r\n]* -> channel(2)
    ;
Run Code Online (Sandbox Code Playgroud)

第二:打印出所有评论

      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);
         }
      }
Run Code Online (Sandbox Code Playgroud)