antlr4 - 错误还是功能?在标记规则上输入监听器的方法

标签 antlr4

在使用解析监听器玩了一下之后,我发现了一个我没有预料到的行为。 我问你的问题是,我的期望是否错误?这种行为是想要的还是一个错误?如果需要这种行为,请解释一下。

这里是示例语法:

grammar Labeled;

file: stmt;

stmt: stmt '+' stmt # Add
    | stmt '*' stmt # Mult
    | FLOAT         # Value
    | INTEGER       # Value
    ;

FLOAT: '-'? DIGIT* '.' DIGIT+;
INTEGER: '-'? DIGIT+;
COMMENT: (COMMENT_LINE | COMMENT_BLOCK) -> skip;
WS: [ \t\r\n] -> skip;

fragment
DIGIT: [0-9];
COMMENT_LINE: '//' ~'\n'*;
COMMENT_BLOCK: '/*' .*? '*/';`

这里是示例监听器:

import org.antlr.v4.runtime.misc.NotNull;

import java.util.HashMap;
import java.util.Map;

public class TestListener extends LabeledBaseListener {

    public static final String ALL_KEY = "All";
    public static final String MULT_KEY = "Mult";
    public static final String ADD_KEY = "Add";
    public static final String VALUE_KEY = "Value";
    public static final String FILE_KEY = "File";


    public Map<String, Integer> enterValues = new HashMap<>();
    public Map<String, Integer> exitValues = new HashMap<>();

    @Override
    public void enterMult(@NotNull LabeledParser.MultContext ctx) {
        addEnter(ALL_KEY);
        addEnter(MULT_KEY);
    }

    @Override
    public void exitMult(@NotNull LabeledParser.MultContext ctx) {
        addExit(ALL_KEY);
        addExit(MULT_KEY);
    }

    @Override
    public void enterValue(@NotNull LabeledParser.ValueContext ctx) {
        addEnter(ALL_KEY);
        addEnter(VALUE_KEY);
    }

    @Override
    public void exitValue(@NotNull LabeledParser.ValueContext ctx) {
        addExit(ALL_KEY);
        addExit(VALUE_KEY);
    }

    @Override
    public void enterFile(@NotNull LabeledParser.FileContext ctx) {
        addEnter(ALL_KEY);
        addEnter(FILE_KEY);
    }

    @Override
    public void exitFile(@NotNull LabeledParser.FileContext ctx) {
        addExit(ALL_KEY);
        addExit(FILE_KEY);
    }

    @Override
    public void enterAdd(@NotNull LabeledParser.AddContext ctx) {
        addEnter(ALL_KEY);
        addEnter(ADD_KEY);
    }

    @Override
    public void exitAdd(@NotNull LabeledParser.AddContext ctx) {
        addExit(ALL_KEY);
        addExit(ADD_KEY);
    }

    // region map helper
    private static void addValue(Map<String, Integer> valueMap, String name) {
        if(valueMap.containsKey(name)) {
            valueMap.put(name, valueMap.get(name) + 1);
        } else {
            valueMap.put(name, 1);
        }
    }

    private void addEnter(String name) {
        addValue(enterValues, name);
    }

    private void addExit(String name) {
        addValue(exitValues, name);
    }
    // endregion
}

主类:

import org.antlr.v4.runtime.ANTLRFileStream;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;

import java.io.File;
import java.io.IOException;
import java.util.Map;

public class Main {


    public static void main(String[] args) throws IOException {
        String filePath = args[0];
        ANTLRInputStream input = new ANTLRFileStream(filePath);
        LabeledLexer lexer = new LabeledLexer(input);
        CommonTokenStream token = new CommonTokenStream(lexer);
        LabeledParser parser = new LabeledParser(token);

        TestListener testListener = new TestListener();
        parser.addParseListener(testListener);

        parser.file();

        System.out.println("Enter Values:");
        System.out.println(getMapString(testListener.enterValues));

        System.out.println("Exit Values:");
        System.out.println(getMapString(testListener.exitValues));

        System.out.println("End");
    }

    private static String getMapString(Map<?, ?> map) {
        StringBuffer buffer = new StringBuffer();
        for(Map.Entry<?, ?> curEntry: map.entrySet()) {

            buffer.append("Key: " + curEntry.getKey() + "\tValue: " + curEntry.getValue() + "\n");
        }

        String result = buffer.toString();
        return result;
    }
}

现在,当我执行包含以下内容的文件时:

-4 + 8

输出将是:

Enter Values:
Key: File   Value: 1
Key: Add    Value: 1
Key: All    Value: 2

Exit Values:
Key: Value  Value: 2
Key: File   Value: 1
Key: Add    Value: 1
Key: All    Value: 4

End

但我期望这个输出:

Enter Values:
Key: Value  Value: 2
Key: File   Value: 1
Key: Add    Value: 1
Key: All    Value: 4

Exit Values:
Key: Value  Value: 2
Key: File   Value: 1
Key: Add    Value: 1
Key: All    Value: 4

End

正如您所见,enterValue() 方法从未被调用。经过更多测试后,如果规则的替代方案中只有一个 token /规则,则不会调用 enterXXX() 方法。

提前致谢!

最佳答案

是的,这种行为是预期的(或者至少是允许的)。该行为本身及其基本原理包含在您使用的 addParseListener 方法的文档中:

Parser.addParseListener(ParseTreeListener)

关于antlr4 - 错误还是功能?在标记规则上输入监听器的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20120795/

相关文章:

c# - Antlr 生成的类对内部的访问修饰符

java - ANTLR4 访问者模式上的简单算术示例

java - 什么是 ANTLR4 的最小示例 Gradle 项目(带有 antlr 插件)?

ANTLR 4 - 不匹配的输入

antlrworks - 如何在ANTLR 4字符串匹配中排除“和\?

java - 如何获取antlr解析的错误信息?

java - Antlr4 - 子句的排序

java - ANTLR:有一个简单的例子吗?

antlr4 - ANTLR4 中的相互左递归规则

antlr - 动态创建词法分析器规则