Java 使用ANTLR4计算令牌数
我需要编写一个Java程序,使用Java 使用ANTLR4计算令牌数,java,antlr,antlr4,Java,Antlr,Antlr4,我需要编写一个Java程序,使用ANTLR4,给定一个源文件,使用一个方法,可以计算变量、运算符、标点符号和保留字的数量 如何使用ANTLR4根据标记的类型对其进行计数?您可以像这样使用hashmap来跟踪所有的单词类型 @header { import java.util.HashMap; } @members { // Map variable name to Integer object holding value HashMap memory = new HashMap(); }
ANTLR4
,给定一个源文件,使用一个方法,可以计算变量、运算符、标点符号和保留字的数量
如何使用
ANTLR4
根据标记的类型对其进行计数?您可以像这样使用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)*
;
@标题{
导入java.util.HashMap;
}
@成员{
//将变量名映射到整型对象保持值
HashMap内存=新的HashMap();
}
标识符
:IdentifierNondigit(IdentifierNondigit|Digit)*{
if(memory.containsKey(getText())){
memory.put(getText(),(((整数)memory.get(getText())+1));
}
否则{
put(getText(),1);
}
System.out.println(getText()+“:”+memory.get(getText());
}
//{getText().length()在做了一些研究之后,基于Özhan Düz,我意识到我需要两种技术:
- 运算符、保留字和标点符号可以使用ANTLR4 lexer计数,因为它们可以在源代码中识别,而无需将它们放入上下文中
- 变量(以及常量、方法、类……)可以使用ANTLR4解析器进行计数,因为识别它们需要解析和理解这些标识符出现在其中的上下文
为了所有将来需要做类似事情的人,我就是这样做的:
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) 创建一个词法分析器、一个语法分析器、一个语法树和一个语法树浏览器:
- Lexer—从头到尾运行您的代码,并将其拆分为“标记”-标识符、文本、运算符等。每个标记都有一个名称和一个类型。类型列表可以在Lexer文件的开头找到(在我们的示例中,
JavaLexer.java
)
- 解析器-使用lexer的输出构建一个表示代码的AST(抽象语法树)。这将允许,除了标记源代码之外,还可以理解每个标记出现在哪个上下文中
- ParseTree—整个代码的AST或其子树
- ParseTreeWalker-一个允许“遍历”树的对象,这基本上意味着以层次结构而不是从头到尾扫描代码
然后,最后,实例化您的侦听器并遍历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);
}
这是基础。接下来的步骤取决于您想要实现什么,这让我回到使用词法分析器和解析器之间的区别:
对于代码的基本词法分析,如识别运算符和保留字,请使用词法分析器对标记进行迭代,并通过检查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;
}
/**
* 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();
}