解析不完整的Java源代码

时间:2013-08-04 20:00:31

标签: java parsing

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

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

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

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

"myMethod(aVarName)"

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

4 个答案:

答案 0 :(得分:6)

嗯......这个问题甚至没有任何含糊的喜欢一个简单的答案。任何上述解析器技术都允许你做你想做的事情,如果你编写正确的语法并操纵解析器做回退解析未知令牌逾越节的事情。

让你到达目的地的最少工作是要么使用具有可恢复解析的ANTLR并且附带一个相当完整的java 7语法,要么看看你可以从日食JDT中取出什么(使用的是用于在eclipse IDE中执行错误和意图符号以及语法突出显示。)

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

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

答案 1 :(得分:2)

Eclipse只包含:一个可以处理不完整java代码的编译器(基本上,这是这些人实现自己的java编译器的一个原因。(更多解释见here

有几个教程可以解释ASTParser,here就是一个。

答案 2 :(得分:2)

如果您只想要基本的解析 - 未修饰的AST - 您可以使用现有的Java解析器。但是根据你的问题,我理解你对深入检查部分代码感兴趣。首先,要意识到你试图解决的问题远非简单,特别是因为部分代码引入了很多歧义。

但是有一个现有的解决方案 - 我需要解决一个类似的问题,并发现一个名为Barthélémy Dagenais的好人已经开发了它,产生了paper一对{ {3}} - 一个基于open-source tools,另一个基于Eclipse(通常更可取)。我已经使用了它们并且它们有效,尽管它们有其自身的局限性 - 不要指望奇迹。

Soot

答案 3 :(得分:1)

我需要在最近的工作中解决类似的问题。我尝试了很多工具,包括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

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'例外。您可以阅读source code以确定应该使用哪个功能。

  • PPA

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

PPA是一组Eclipse插件,这意味着它需要与Eclipse一起运行。它提供了headless方式来运行而不显示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;
    }
});