我使用 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);
}
}
}
结果 = map ,如下所示:
"develop cycle" -> for(...){...}
"atomic" -> int a
"revision required" -> {...}
已关注 official book (1)和 stackoverflow 上的类似主题( (2) 、 (3) 、 (4) 、 (5) 、 (6) )我尝试了几种方法。
起初我希望有特殊的评论 channel ,如 (1) 中所述。和 (2)但错误rule 'LINE_COMMENT' contains a lexer command with an unrecognized constant value; lexer interpreters may produce incorrect output
发生了。
我想以忽略所有单行注释的方式解析源代码会更好,但以 TODO
开头的注释除外。 。我希望可以将待办事项注释直接添加到 AST 中,以便使用监听器/步行器。我只需要为 TODO 注释注册监听器/步行器并提取以下语句,将两者添加到所需的 map 中。
我一直在修改官方Java8 gammar两天但没有任何成功。要么编译器提示,要么 AST 被破坏。
这是我所做的更新:
// ...
COMMENT
: '/*' .*? '*/' -> skip
;
TODO_COMMENT
: '// TODO' ~[\r\n]*
;
LINE_COMMENT
: '//' ~[\r\n]* -> skip
;
有人可以帮我吗?语法不是我的菜。提前致谢
编辑1:
上面发布的语法修改符合要求,没有错误,但生成了以下树(请注意红色标记的节点包括 int
)
编辑2:
假设上面的代码示例,在调用 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, '@'}
很明显语法是不正确的,因为它很难处理简单的例子
最佳答案
原因是您不希望在任何解析器规则中添加特殊注释,即没有解析器会匹配它。
您(至少)可以执行以下操作:
- 添加可选的
TODO_COMMENT
?在每个解析器规则的前面。 - 将
TODO_COMMENT
token 添加到单独的 channel ,例如ToDoCommentChannel
(不要忘记定义此 channel 的常量!)并选择树遍历中注释后面的每个构造。
我会做什么的粗略概述:
- 为
TODO_COMMENT
使用单独的 channel 。 - 照常进行 lex 和解析
- 从 token 流中获取所有 token ,并找到所需 channel 的 token ,并在默认 channel 上获取以下 token 并将它们存储在列表中。
- 遍历解析并检查每个输入的规则,如果起始标记在列表中。如果是,则将规则文本复制到结果列表中,否则递归(如果
TODO_COMMENT
可以嵌套,甚至在起始标记位于列表中时递归)。
更新:
关于规则“LINE_COMMENT”包含具有无法识别的常量值的词法分析器命令;词法分析器解释器可能会产生不正确的输出
错误:
这可以忽略,因为它只影响 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 运行时代码中使用 channel 的常量值)。
关于parsing - 如何使用 ANTLRv4 仅解析一些评论,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24280850/