4

在某些问题中,我需要解析可能不完整的 Java 源代码片段。例如,代码可以引用未在此类片段中定义的变量。

在这种情况下,我仍然想解析这些不完整的 Java 代码,将其转换为方便的可检查表示,并能够从这种抽象表示生成源代码。

什么是正确的工具?在这篇文章中,我找到了使用 Antlr、JavaCC 或 Eclipse JDT 的建议。但是,我没有找到任何关于处理不完整的 Java 源代码片段的参考,因此这个问题(此外,链接的问题已有两年多的历史,所以我想知道地图上是否有新的东西)。

例如,代码可能类似于以下表达式:

"myMethod(aVarName)"

在这种情况下,我希望能够以某种方式检测到aVarName代码中引用了该变量。

4

4 回答 4

6

嗯……这个问题连简单的答案都没有。如果您编写正确的语法并操纵解析器进行后备解析未知令牌逾越类的事情,则上述任何解析器技术都将允许您做您想做的事情。

让您到达目的地的最少工作量是使用具有可恢复解析并带有相当完整的 java 7 语法的 ANTLR,或者查看您可以从 eclipse JDT(用于执行Eclipse IDE 中的错误和意图符号以及语法高亮显示。)

请注意,这些东西都不容易——您正在编写 klocs,而不仅仅是导入一个类并告诉它去。

在某个不正确/不完整的点上,所有这些策略都会失败,因为没有计算机(甚至是人)能够辨别你的意思,除非你至少模糊地说正确。

于 2013-08-04T20:20:51.617 回答
2

如果您只想要基本解析 - 未修饰的 AST - 您可以使用现有的 Java 解析器。但是根据您的问题,我了解到您有兴趣对部分代码进行更深入的检查。首先,请注意您要解决的问题远非简单,尤其是因为部分代码会引入很多歧义。

但是有一个现有的解决方案——我需要解决一个类似的问题,并且发现一个名叫Barthélémy Dagenais的好人已经在研究它,产生了一篇论文一对开源工具——一个基于Soot和另一个(通常更可取)在 Eclipse 上。我已经使用了这两种方法并且它们都有效,尽管它们有自己的局限性 - 不要指望奇迹。

这是一个关于如何开始使用基于 Eclipse 的工具的快速教程的直接链接

于 2013-08-05T12:44:35.933 回答
2

Eclipse 仅包含:一个可以处理不完整的 java 代码的编译器(基本上,这是这些人实现自己的 java 编译器的一个原因。(请参阅此处以获得更好的解释)

有几个解释 ASTParser 的教程,这里是一个。

于 2013-08-05T10:54:30.857 回答
2

我需要在我最近的工作中解决类似的问题。我尝试了很多工具,包括Eclipse JDT ASTParser、 python javalangPPA。我想分享我的经验。综上所述,它们都可以在一定程度上解析代码片段,但是当代码片段太模糊时,偶尔都会解析失败。

  • Eclipse JDT ASTParser

Eclipse JDT ASTParser 是最强大且使用最广泛的工具。这是解析方法调用节点的代码片段。

ASTParser parser = ASTParser.newParser(AST.JLS8);
parser.setResolveBindings(true);
parser.setKind(ASTParser.K_STATEMENTS);
parser.setBindingsRecovery(true);
Map options = JavaCore.getOptions();
parser.setCompilerOptions(options);
parser.setUnitName("test");

String src = "System.out.println(\"test\");";
String[] sources = { };
String[] classpath = {"C:/Users/chenzhi/AppData/Local/Programs/Java/jdk1.8.0_131"};

parser.setEnvironment(classpath, sources, new String[] { }, true);
parser.setSource(src.toCharArray());
final Block block = (Block) parser.createAST(null);
block.accept(new ASTVisitor() {
    public boolean visit(MethodInvocation node) {
        System.out.println(node);
        return false;
    }
});

您应该注意parser.setKind(ASTParser.K_STATEMENTS),这是设置要从源解析的构造类型。ASTParser 定义了四种(K_COMPILATION_UNIT、K_CLASS_BODY_DECLARATIONS、K_EXPRESSION、K_STATEMENTS),你可以看这个javadoc来了解它们之间的区别。

  • 爪哇语言

javalang 是一个简单的python 库。这是解析方法调用节点的代码片段。

src = 'System.out.println("test");'
tokens = javalang.tokenizer.tokenize(code2)
parser = javalang.parser.Parser(tokens)
try:
    ast = parser.parse_expression()
    if type(ast) is javalang.tree.MethodInvocation:
        print(ast)
except javalang.parser.JavaSyntaxError as err:
    print("wrong syntax", err)

注意ast = parser.parse_expression(),就像 Eclipse JDT ASTParser 中的 parser.setKind() 函数一样,你应该设置正确的解析函数,否则你会得到 'javalang.parser.JavaSyntaxError' 异常。您可以阅读源代码以确定您应该使用哪个功能。

  • 购电协议

Java 的部分程序分析 (PPA) 是一个静态分析框架,它将不完整的 Java 程序的源代码转换为类型化的抽象语法树。正如@Oak 所说,这个工具来自学院。

PPA 作为一组 Eclipse 插件提供,这意味着它需要与 Eclipse 一起运行。它提供了一种无需显示 Eclipse GUI 或不需要任何用户输入的无头运行方式,但它太重了。

String src = "System.out.println(\"test\");";
ASTNode node = PPAUtil.getSnippet(src, new PPAOptions(), false);

// Walk through the compilation unit.
node.accept(new ASTVisitor() {
    public boolean visit(MethodInvocation node) {
        System.out.println(node);
        return false;
    }
});
于 2018-01-18T07:06:36.713 回答