如何使用ANTLRv4仅解析一些注释

时间:2014-06-18 08:36:48

标签: parsing comments antlr antlr4

我使用ANTLRv4开发应用程序分析Java源代码。我声称将所有单行注释与第一个令牌TODO(例如// TODO <some-comment>)以及直接跟随声明匹配。

示例代码:

class Simple {
    public static void main(String[] args) {
        // TODO develop cycle
        for (int i = 0; i < 5; i++) {
            // unmatched comment
            System.out.println("hello");
        }
        // TODO atomic
        int a;

        // TODO revision required
        {
            int b = a+4;
            System.out.println(b);
        }
    }
}

结果 = 地图,如下所示:

"develop cycle" -> for(...){...}
"atomic" -> int a
"revision required" -> {...}

关于stackoverflow上的official book (1)和类似主题((2)(3)(4)(5)(6))我尝试了几种方法。

首先,我希望(1)(2)中描述的特殊评论频道,但发生错误rule 'LINE_COMMENT' contains a lexer command with an unrecognized constant value; lexer interpreters may produce incorrect output

我想以一种忽略所有单行注释但以TODO开头的方式解析源代码会更好。我希望可以将todo-comments直接添加到AST中以便使用侦听器/ walker。我只需要注册监听器/ walker进行TODO评论并提取以下声明,并将其添加到所需的地图

我已经修改了官方Java8 gammar两天但没有取得任何成功。编译器抱怨或AST被错误处理。

这是我做的更新:

// ...
COMMENT
    :   '/*' .*? '*/' -> skip
    ;

TODO_COMMENT
    :   '// TODO' ~[\r\n]*
    ;

LINE_COMMENT
    :   '//' ~[\r\n]* -> skip
    ;

有人能帮帮我吗?语法不是我的一杯茶。提前致谢

EDIT1:

上面发布的语法修改符合条件且没有错误,但会生成以下树(请注意红色标记的节点,包括int

error AST

EDIT2:

假设上面的代码示例,在生成跟随错误的parser.compilationUnit();时生成

line 3:2 extraneous input '// TODO develop cycle;' expecting {'abstract', 'assert', 'boolean', 'break', 'byte', 'char', 'class', 'continue', 'do', 'double', 'enum', 'final', 'float', 'for', 'if', 'int', 'interface', 'long', 'new', 'private', 'protected', 'public', 'return', 'short', 'static', 'strictfp', 'super', 'switch', 'synchronized', 'this', 'throw', 'try', 'void', 'while', IntegerLiteral, FloatingPointLiteral, BooleanLiteral, CharacterLiteral, StringLiteral, 'null', '(', '{', '}', ';', '<', '!', '~', '++', '--', '+', '-', Identifier, '@'}
line 8:2 extraneous input '// TODO atomic;' expecting {'abstract', 'assert', 'boolean', 'break', 'byte', 'char', 'class', 'continue', 'do', 'double', 'enum', 'final', 'float', 'for', 'if', 'int', 'interface', 'long', 'new', 'private', 'protected', 'public', 'return', 'short', 'static', 'strictfp', 'super', 'switch', 'synchronized', 'this', 'throw', 'try', 'void', 'while', IntegerLiteral, FloatingPointLiteral, BooleanLiteral, CharacterLiteral, StringLiteral, 'null', '(', '{', '}', ';', '<', '!', '~', '++', '--', '+', '-', Identifier, '@'}
line 11:2 extraneous input '// TODO revision required;' expecting {'abstract', 'assert', 'boolean', 'break', 'byte', 'char', 'class', 'continue', 'do', 'double', 'enum', 'final', 'float', 'for', 'if', 'int', 'interface', 'long', 'new', 'private', 'protected', 'public', 'return', 'short', 'static', 'strictfp', 'super', 'switch', 'synchronized', 'this', 'throw', 'try', 'void', 'while', IntegerLiteral, FloatingPointLiteral, BooleanLiteral, CharacterLiteral, StringLiteral, 'null', '(', '{', '}', ';', '<', '!', '~', '++', '--', '+', '-', Identifier, '@'}

因此,语法很明显,因为它与简单的例子挣扎

1 个答案:

答案 0 :(得分:2)

原因是您不希望在任何解析器规则中发表您的特殊评论,即没有解析器会匹配它。

您可以(至少)执行以下操作:

  1. 添加可选的TODO_COMMENT?在每个解析器规则面前。
  2. TODO_COMMENT令牌添加到单独的频道,例如ToDoCommentChannel(不要忘记为此频道定义常量!)并选择在树行走中跟随注释的每个构造。
  3. 我会做什么的粗略轮廓:

    • TODO_COMMENT s。
    • 使用单独的频道
    • lex并像往常一样解析
    • 从令牌流中获取所有令牌并找到所需频道的令牌并在默认频道上获取以下令牌并将其存储在列表中。
    • 如果起始令牌在列表中,则执行解析并检查每个输入的规则。如果是,请将规则文本复制到结果列表中,否则递归(如果TODO_COMMENT可以嵌套,甚至可以在起始令牌位于列表中时递归)。

    更新:

    关于rule 'LINE_COMMENT' contains a lexer command with an unrecognized constant value; lexer interpreters may produce incorrect output错误:

    这可以忽略,因为它只影响Antlrworks2或插件使用的解释器。你也可以这样做:

    //Instead of
    TODO_COMMENT
        :   '// TODO' ~[\r\n]*  -> channel(ToDoCommentChannel)
        ;    
    
    // do this (assuming the channel value is indeed 42):
    TODO_COMMENT
        :   '// TODO' ~[\r\n]*  -> channel(42 /*ToDoCommentChannel*/)
        ;    
    

    这将在Antlrworks2和代码中工作(您仍然可以在java运行时代码中使用通道的常量值)。