我需要使用ANTLR4编写一个Java程序,该程序可以计算变量、操作符、标点符号和保留单词的数量,给出一个具有单一方法的源文件。
如何使用ANTLR4 来根据令牌的类型进行计数?
发布于 2015-08-15 09:39:46
在做了一些研究之后,基于詹杜兹,我意识到我所需要的需要两种技术:
为了所有将来需要做类似事情的人,我就是这样做的:
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();
}
}4)创建一个ParseTreeWalker ,一个解析器,一个ParseTree和一个
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);
}这就是基础。接下来的步骤取决于您想要实现什么,这使我回到使用Lexer和Parser之间的区别。
对于代码的基本词法分析,如识别运算符和保留单词,请使用lexer对标记进行迭代,并通过检查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;
}对于需要解析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();
}发布于 2015-08-15 00:34:34
您可以像这样使用hashmap来跟踪所有单词类型。
@header {
import java.util.HashMap;
}
@members {
// Map variable name to Integer object holding value
HashMap memory = new HashMap();
}
Identifier
: IdentifierNondigit( IdentifierNondigit | Digit )* {
if(memory.containsKey(getText())){
memory.put(getText(),(((Integer)memory.get(getText()))+1));
}
else {
memory.put(getText(),1);
}
System.out.println(getText()+" : "+memory.get(getText()));
}
// { getText().length()<=3}?{ String str=getText(); while(str.length()<=3){ str=str+str;} setText(str);}
| IdentifierNondigit ( IdentifierNondigit | Digit)*
;像这样,您可以直接说“保留”键而不是getToken(),并在每次增量后存储计数
https://stackoverflow.com/questions/31984268
复制相似问题