使用ANTLR进行Java源文件的静态分析

Ber*_*own 9 java antlr

有没有人有一个完整的实现(可能是github或googlecode)来使用ANTLR语法文件和Java源代码来分析Java源代码.例如,我想简单地计算变量,方法等的数量.

还使用了最新版本的ANTLR.

Nat*_*yan 12

我以为我会在午休时间对这个问题采取行动.这可能无法完全解决您的问题,但它可能会为您提供一个起点.该示例假设您在同一目录中执行所有操作.

  1. 从GitHub 下载ANTLR源代码.来自ANTLR站点的预编译"完整"JAR包含已知错误.GitHub仓库有修复.

  2. 解压缩ANTLR tarball.

    % tar xzf antlr-antlr3-release-3.4-150-g8312471.tar.gz
    Run Code Online (Sandbox Code Playgroud)
  3. 构建ANTLR"完整"JAR.

    % cd antlr-antlr3-8312471
    % mvn -N install
    % mvn -Dmaven.test.skip=true
    % mvn -Dmaven.test.skip=true package assembly:assembly
    % cd -
    Run Code Online (Sandbox Code Playgroud)
  4. 下载Java语法.还有其他人,但我知道这个有效.

  5. 将语法编译为Java源代码.

    % mkdir com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated
    % mv *.g com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated
    % java -classpath antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar org.antlr.Tool -o com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated Java.g
    Run Code Online (Sandbox Code Playgroud)
  6. 编译Java源代码.

    % javac -classpath antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated/*.java
    Run Code Online (Sandbox Code Playgroud)
  7. 添加以下源文件Main.java.

    import java.io.IOException;
    import java.util.List;
    import org.antlr.runtime.*; import org.antlr.runtime.tree.*;
    import com.habelitz.jsobjectizer.unmarshaller.antlrbridge.generated.*;
    public class Main { public static void main(String... args) throws NoSuchFieldException, IllegalAccessException, IOException, RecognitionException { JavaLexer lexer = new JavaLexer(new ANTLRFileStream(args[1], "UTF-8")); JavaParser parser = new JavaParser(new CommonTokenStream(lexer)); CommonTree tree = (CommonTree)(parser.javaSource().getTree()); int type = ((Integer)(JavaParser.class.getDeclaredField(args[0]).get(null))).intValue(); System.out.println(count(tree, type)); } private static int count(CommonTree tree, int type) { int count = 0; List children = tree.getChildren(); if (children != null) { for (Object child : children) { count += count((CommonTree)(child), type); } } return ((tree.getType() != type) ? count : count + 1); } }
    Run Code Online (Sandbox Code Playgroud)
  8. 编译.

    % javac -classpath .:antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar Main.java
    Run Code Online (Sandbox Code Playgroud)
  9. 选择要计算的Java源类型; 例如,VAR_DECLARATOR,FUNCTION_METHOD_DECL,或VOID_METHOD_DECL.

    % cat com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated/Java.tokens
    Run Code Online (Sandbox Code Playgroud)
  10. 在任何文件上运行,包括最近创建的Main.java.

    % java -classpath .:antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar Main VAR_DECLARATOR Main.java
    6
    Run Code Online (Sandbox Code Playgroud)

当然,这是不完美的.如果仔细观察,您可能已经注意到增强for语句的局部变量没有计算在内.为此,您需要使用类型FOR_EACH,而不是VAR_DECLARATOR.

您需要很好地理解Java源代码的元素,并能够对这些特定语法的定义如何匹配进行合理的猜测.您也无法进行参考计数.声明很简单,但计算字段的使用,例如,需要参考解析.是否p.C.f指的是静电场f一类的C一个包内p,或者它是指一个实例字段f由静态字段存储对象的C一类p?基本解析器不解析像Java这样复杂的语言的引用,因为一般情况可能非常困难.如果你想要这种级别的控制,你需要使用编译器(或更接近它的东西).Eclipse编译器是一种流行的选择.

我还要提到除了ANTLR之外还有其他选择.JavaCC是另一个解析器生成器.静态分析工具PMD使用JavaCC作为其解析器生成器,允许您编写可用于您指示的各种计数的自定义规则.