经过一些研究,基于ÖzhanDüz,我意识到我需要的是两种技术:
为了所有需要在将来做类似事情的人,以下是我的确切方式:
1)使用ANTLR命令行工具为您的语言生成Lexer,Parser和BaseListener.有关如何操作的说明,请访问ANTLR官方网站.在这个例子中,我创建了这些用于分析Java语言的类.
2)创建一个新的Java项目.添加JavaLexer.java,JavaListener.java,JavaParser.java和JavaBaseListener.java你的项目,以及ANTLR库添加到项目的构建路径.
3)创建一个扩展JavaBaseListener基类的新类.查看JavaBaseListener.java您可以覆盖的所有方法的文件.扫描源代码的AST时,将在相应事件发生时调用每个方法(例如 - enterMethodDeclaration()每次解析器到达新方法声明时都会调用).
例如,每次找到新方法时,此侦听器都会将计数器加1:
public static final AtomicInteger count = new AtomicInteger();
/**
* Implementation of the abstract base listener
*/
public static class MyListener extends JavaBaseListener {
/**
* Overrides the default callback called whenever the walker has entered a method declaration.
* This raises the count every time a new method is found
*/
@Override
public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
count.incrementAndGet();
}
}
Run Code Online (Sandbox Code Playgroud)
4)创建一个Lexer,一个Parser,一个ParseTree和一个ParseTreeWalker:
JavaLexer.java)然后,最后,实例化您的侦听器并走ParseTree.
例如:
public static void main(String... args) throws IOException {
JavaLexer lexer = new JavaLexer(new ANTLRFileStream(sourceFile, "UTF-8"));
JavaParser parser = new JavaParser(new CommonTokenStream(lexer));
ParseTree tree = parser.compilationUnit();
ParseTreeWalker walker = new ParseTreeWalker();
MyListener listener = new MyListener();
walker.walk(listener, tree);
}
Run Code Online (Sandbox Code Playgroud)
这是基础.接下来的步骤取决于您想要实现的目标,这让我回到使用Lexer和Parser之间的区别:
对于代码的基本词法分析,例如识别运算符和保留字,使用词法分析器迭代您的标记并通过检查Token.type字段确定其类型.使用此代码计算方法内保留字的数量:
private List<Token> tokenizeMethod(String method) {
JavaLexer lex = new JavaLexer(new ANTLRInputStream(method));
CommonTokenStream tokStream = new CommonTokenStream(lex);
tokStream.fill();
return tokStream.getTokens();
}
/**
* Returns the number of reserved words inside the given method, using lexical analysis
* @param method The method text
*/
private int countReservedWords(String method) {
int count = 0;
for(Token t : tokenizeMethod(method)) {
if(t.getType() <= JavaLexer.WHILE) {
count++;
}
}
return count;
}
Run Code Online (Sandbox Code Playgroud)
对于需要解析AST的任务,比如标识变量,方法,注释等,请使用Parser.使用此代码计算方法内的变量声明的数量:
/**
* Returns the number of variable declarations inside the given method, by parsing the method's AST
* @param method The method text
*/
private int countVariableDeclarations(String method) {
JavaLexer lex = new JavaLexer(new ANTLRInputStream(method));
JavaParser parse = new JavaParser(new CommonTokenStream(lex));
ParseTree tree = parse.methodDeclaration();
ParseTreeWalker walker = new ParseTreeWalker();
final AtomicInteger count = new AtomicInteger();
walker.walk(new JavaBaseListener() {
@Override public void enterLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx) {
count.incrementAndGet();
}
}, tree);
return count.get();
}
Run Code Online (Sandbox Code Playgroud)