调试 Python ANTLR4 语法

Debugging Python ANTLR4 Grammar

我的 ANTLR4 语法有问题,无法正确解析字符串。我对学习如何解决我的问题比解决我的具体问题更感兴趣。如何生成任何类型的调试信息?我想知道解析器是什么 "thinking",因为它解析字符串。

语法可以在这里找到:https://github.com/Metrink/metrink-fe/blob/master/metrink.g4

我正在使用简单的测试字符串:-1d metric('blah', 'blah', 'blah')

我收到以下错误:1:2 missing TIME_INDICATOR at 'd'

语法将 TIME_INDICATOR 定义为 [shmd] 所以我不确定它是如何在字符 d 处缺少 TIME_INDICATOR 而这是可能的标记之一.我在这里错过了什么?

我正在使用从 ANTLR4 生成的 Python3。

我通常做的是首先转储标记以查看是否创建了解析器期望的实际标记。

你可以用这样的小测试 class 来做到这一点(很容易移植到 Python):

public class Main {

    static void test(String input) {

        metrinkLexer lexer = new metrinkLexer(new ANTLRInputStream(input));
        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
        tokenStream.fill();

        System.out.printf("input: `%s`\n", input);

        for (Token token : tokenStream.getTokens()) {
            if (token.getType() != TLexer.EOF) {
                System.out.printf("  %-20s %s\n", metrinkLexer.VOCABULARY.getSymbolicName(token.getType()), token.getText());
            }
        }

        System.out.println();
    }

    public static void main(String[] args) throws Exception {
        test("-1d metric('blah', 'blah', 'blah')");
    }
}

如果您运行上面的代码,以下内容将打印到您的控制台:

input: `-1d metric('blah', 'blah', 'blah')`
  MINUS                -
  INTEGER_LITERAL      1
  IDENTIFIER           d
  METRIC               metric
  LPAREN               (
  STRING_LITERAL       'blah'
  COMMA                ,
  STRING_LITERAL       'blah'
  COMMA                ,
  STRING_LITERAL       'blah'
  RPAREN               )

如您所见,d 被标记为 IDENTIFIER 而不是 TIME_INDICATOR。这是因为 IDENTIFIER 规则是在 TIME_INDICATOR 规则之前定义的。词法分析器不会 "listen" 到解析器可能需要的内容,它只是匹配尽可能多的字符,如果两个或多个规则匹配相同数量的字符,则第一个定义的规则 "wins".

因此,d 可以标记为 TIME_INDICATORIDENTIFIER。如果这取决于上下文,我建议您将其标记为 IDENTIFIER(并删除 TIME_INDICATOR)并创建如下解析器规则:

relative_time_literal:
    MINUS? INTEGER_LITERAL time_indicator;

time_indicator:
    {_input.LT(1)getText().matches("[shmd]")}? IDENTIFIER;

{ ... }?称为谓词:Semantic predicates in ANTLR4?

此外,FALSETRUE 需要放在 IDENTIFIER 规则之前。