当前位置: 首页 > 知识库问答 >
问题:

使用ANTLR4计数令牌

敖永丰
2023-03-14

我需要编写一个Java程序,使用ANTLR4,在给定一个源文件和一个方法的情况下,可以计算变量、运算符、标点符号和保留字的数量。

如何使用ANTLR4根据标记的类型对其计数?

共有1个答案

柴辰阳
2023-03-14

在做了一些研究之后,并基于奥詹·杜兹,我意识到我需要两种技术:

  • 运算符、保留字和标点符号可以使用ANTLR4 lexer进行计数,因为它们可以在源代码中识别,而无需将它们放到上下文中。
  • 变量(以及常量、方法、类…)可以使用ANTLR4解析器计算,因为识别它们需要解析和理解这些标识符出现在。
  • 中的上下文

为了所有将来需要做类似事情的人,下面是我的做法:

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、Parser、ParseTree和parsetreewalker:

  • lexer-从头到尾遍历代码,并将其拆分为“令牌”--标识符、文字、运算符等。每个令牌都有一个名称和一个类型。类型列表可以在lexer文件的开头找到(在我们的例子中是javalexer.java)
  • 解析器--使用lexer的输出构建表示代码的AST(抽象语法树)。这样,除了标记源代码外,还可以理解每个标记出现在哪个上下文中。
  • 解析树-您的整个代码的AST或它的子树
  • ParsetreeWalker-允许“遍历”树的对象,这基本上意味着分层扫描代码,而不是从头到尾

然后,最后,实例化您的侦听器并遍历解析树。

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);
}
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();
}
 类似资料:
  • 我正在用ANTLR4/JavaScript编写一个简单的“语言”,它可以将数字与变量关联起来并打印出来。这很好,但是在扩展print语句以获取一个或多个变量之后,我不知道如何获得它们的计数。(我使用的是访问者,而不是倾听者,但我对两者都感兴趣。) 语法:

  • 我是一个Antlr4新手,有一个相对简单的语法问题。语法在末尾的底部给出。(这是一个语法片段,用于分析生物序列变体的描述)。 在下面的单元测试中,我试图解析字符串。 这里出了什么问题?我在哪里可以学习如何解决这个问题?

  • 我试图使用ANTLR4创建一个简单的解析器,但我在识别lexer令牌方面遇到了问题。问题是,即使单词SAYS后面有一个“:”,解析器规则也不能识别它。而且对于提及,@Michael也没有被识别出来。 输入的文本是:john说:hello@Michael这将不起作用 //LEXER规则

  • 我正在为一种语言编写一个编译器,作为大学使用ANTLR4的项目。我使用Java编写了这个编译器,并采用了Visitor模式,当我到达测试阶段时,我注意到ANTLR忽略了我的部分代码,并生成了它不应该生成的错误。 语法: 以下是我的主要观点: 当我运行Main时,它显示: 第1行:0不匹配的输入'import'应为{(',INT,FLOAT,STRING,IDF} 我的语法有什么地方错了吗?如果没有

  • 我们如何才能让他们识别lexer规则?所有、和规则都可能与匹配。那么我在测试它的时候应该使用什么类型。 我的意思是: 一般来说,我想了解如何知道的类型?

  • 将标记移动到公共文件之前的语法 将标记移动到公共文件后的语法 通用lexer由其他3个lexer导入。它具有共享的标识符令牌。 以下lexer导入通用lexer,并具有几种模式 解析器语法: 结果:一个命令,如“删除资源:A先前标识为COMMAND\u START now的将被识别为标识符。 结果屏幕截图 问题:我如何解决这个问题?标识符应保留在CommonLexer中。 如果您需要更多详细信息,