【问题标题】:parsing incomplete Java source code解析不完整的Java源代码
【发布时间】:2013-08-04 20:00:30
【问题描述】:

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

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

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

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

"myMethod(aVarName)"

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

【问题讨论】:

  • 我不确定,但我认为这在 Java 中是不可能的。不过我肯定是错的
  • 应该是自动还是手动过程?在最后一种情况下,我建议使用 Eclipse 及其快速修复来完成源代码。
  • 应该是自动的
  • 为什么解析带有未定义变量名的Java很难?你只需要一个Java语法和解析引擎;即使是现成的,周围也有很多。您想做什么,“未定义的名称”是一个问题?如果代码语法格式错误,那就是另一个问题了。

标签: java parsing


【解决方案1】:

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

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

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

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

【讨论】:

  • 我明白了。您认为我应该能够将 Eclipse JDT 作为独立库用于我的目的吗? (我的意思是,不必为此启动一个完整的 Eclipse 实例?)
  • 简短的回答是肯定的,但同样,这不是一个简单的过程,因为您必须弄清楚您需要提取哪一组 JAR 文件并弄清楚如何使用他们。如果您与 eclipse 工具链结婚,那么使用 Xtend 可能会更好。 Xtend 和 ANTLR 都有更好的通用文档。还有一个叫做勺子的工具可以让你更接近你的目标:spoon.gforge.inria.fr
  • 所以 JDT 似乎不是最好的主意。您认为 JavaCC 可能是一种选择吗?我不明白你为什么建议 Xtend,在它的网页上它看起来像是一种通用语言,它是否提供任何工具来获得不完整的 Java 源代码的方便表示?
【解决方案2】:

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

解释 ASTParser 的教程有很多,here 就是其中之一。

【讨论】:

  • 链接坏了:-(
【解决方案3】:

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

但是有一个现有的解决方案 - 我需要解决一个类似的问题,并发现一个叫 Barthélémy Dagenais 的好人已经在研究它,产生了一个 paper 和 一对open-source tools - 一个基于Soot,另一个(通常更可取)基于 Eclipse。我都用过,它们都有效,尽管它们有自己的局限性——不要指望奇迹。

Here's a direct link to a quick tutorial on how to start with the Eclipse-based tool.

【讨论】:

    【解决方案4】:

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

    • Eclipse JDT ASTParser

    Eclipse JDT ASTParser 是最强大和最广泛使用的工具。这是解析方法调用节点的代码sn-p。

    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 库。这是解析方法调用节点的代码sn-p。

    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 来确定您应该使用哪个功能。

    • 购电协议

    Partial Program Analysis for 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;
        }
    });
    

    【讨论】:

      猜你喜欢
      • 2011-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多