我通常做的是首先转储令牌,看看是否创建了解析器期望的实际令牌。
您可以使用这样的小型测试类来做到这一点(很容易移植到 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 规则之前定义的。词法分析器不会“监听”解析器可能需要的内容,它只是匹配尽可能多的字符,如果两个或多个规则匹配相同数量的字符,则首先定义的规则“获胜”。
因此,d 可以标记为 TIME_INDICATOR 或 IDENTIFIER。如果这取决于上下文,我建议您将其标记为 IDENTIFIER(并删除 TIME_INDICATOR)并创建如下解析器规则:
relative_time_literal:
MINUS? INTEGER_LITERAL time_indicator;
time_indicator:
{_input.LT(1)getText().matches("[shmd]")}? IDENTIFIER;
{ ... }? 称为谓词:Semantic predicates in ANTLR4?
另外,FALSE 和 TRUE 需要放在 IDENTIFIER 规则之前。