有没有人有使用 ANTLR 语法文件和 Java 源代码来分析 Java 源代码的完整实现(可能是 github 或 googlecode)。例如,我希望能够简单地计算变量、方法等的数量。
还使用最新版本的 ANTLR。
我想我会在午休时间解决这个问题。这可能无法完全解决您的问题,但可能会给您一个起点。该示例假定您在同一目录中执行所有操作。
从 GitHub下载ANTLR 源代码。来自 ANTLR 站点的预编译“完整”JAR 包含一个已知错误。GitHub 存储库已修复。
提取 ANTLR 压缩包。
% tar xzf antlr-antlr3-release-3.4-150-g8312471.tar.gz
构建 ANTLR“完整”JAR。
% cd antlr-antlr3-8312471
% mvn -N install
% mvn -Dmaven.test.skip=true
% mvn -Dmaven.test.skip=true package assembly:assembly
% cd -
下载Java 语法。还有其他的,但我知道这个有效。
将语法编译为 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
编译 Java 源代码。
% javac -classpath antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated/*.java
添加以下源文件 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);
}
}
编译。
% javac -classpath .:antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar Main.java
选择您要统计的 Java 源类型;例如,VAR_DECLARATOR
、FUNCTION_METHOD_DECL
或VOID_METHOD_DECL
。
% cat com/habelitz/jsobjectizer/unmarshaller/antlrbridge/generated/Java.tokens
在任何文件上运行,包括最近创建的 Main.java。
% java -classpath .:antlr-antlr3-8312471/target/antlr-master-3.4.1-SNAPSHOT-completejar.jar Main VAR_DECLARATOR Main.java
6
当然,这是不完美的。如果仔细观察,您可能已经注意到增强for
语句的局部变量没有被计算在内。为此,您需要使用 type FOR_EACH
,而不是VAR_DECLARATOR
.
您需要对 Java 源代码的元素有很好的理解,并且能够合理猜测这些元素如何与这个特定语法的定义相匹配。您也无法进行引用计数。声明很容易,但例如计算字段的使用,需要引用解析。是指包内的类p.C.f
的静态字段,还是指由类的静态字段存储的对象的实例字段?基本解析器不会解析像 Java 这样复杂的语言的引用,因为一般情况可能非常困难。如果您想要这种级别的控制,您将需要使用编译器(或更接近它的东西)。Eclipse 编译器是一种流行的选择。f
C
p
f
C
p
我还应该提到,除了 ANTLR 之外,您还有其他选择。JavaCC 是另一个解析器生成器。使用 JavaCC 作为其解析器生成器的静态分析工具 PMD 允许您编写可用于您指定的计数类型的自定义规则。