ANTLR4在存在未受影响的规则时不会抛出预期的错误

时间:2014-09-03 17:43:35

标签: antlr antlr4

我创建了一个示例语法TestGrammar.g4来说明我的问题:

grammar TestGrammar;

Member_of : 'MEMBER OF';

Identifier : [a-z]+
           ;

WS: [ \n\t\r]+ -> channel(HIDDEN);

parseSimpleExpression : (Identifier '.')+ Identifier
                      ;

collection_member_expression : parseSimpleExpression Member_of parseSimpleExpression
                            ;

以下代码显示了解析器的调用:

String expression = "x.a MEMBER OF y.a";
TestGrammarLexer l = new  TestGrammarLexer(new ANTLRInputStream(expression));
CommonTokenStream tokens = new CommonTokenStream(l);
TestGrammarParser p = new TestGrammarParser(tokens);
p.setErrorHandler(new BailErrorStrategy());
ParserRuleContext ctx = p.parseSimpleExpression();

我的期望是ANTLR会在输入x.a MEMBER OF y.a上抛出语法错误 它不是。相反,它仅消耗部分输入(x.a MEMBER OF)并成功完成。

现在,当我从语法中删除最后一条规则时,ANTLR会按预期引发语法错误。我不理解这种行为,因为最后一个语法规则甚至不应该参与解析,因为它既不是由启动规则直接引用也不是间接引用。

1 个答案:

答案 0 :(得分:2)

ANTLR不应该抛出异常。使用代码:

String expression = "x.a MEMBER OF y.a";
TestGrammarLexer l = new  TestGrammarLexer(new ANTLRInputStream(expression));
CommonTokenStream tokens = new CommonTokenStream(l);
TestGrammarParser p = new TestGrammarParser(tokens);
p.setErrorHandler(new BailErrorStrategy());
ParserRuleContext ctx = p.parseSimpleExpression();

您只是简单地指示ANTLR解析(Identifier '.')+ Identifier,因为"x.z"是输入的第一部分并匹配parseSimpleExpression制作,所以它很乐意这样做。

令牌流中剩余更多令牌这一事实并不重要。如果您想确保消耗整个输入,则需要使用EOF令牌锚定您的规则:

parseSimpleExpression : (Identifier '.')+ Identifier EOF
                      ;
  

Moritz Becker写道

     

......但事实并非如此。相反,它只消耗部分输入(x.a MEMBER OF)和......

不,这不是真的,它只消耗"x.a",因为您可以通过打印上下文匹配来验证自己:

System.out.println(ctx.getText()); // prints "x.a"

如果我从语法中删除collection_member_expression规则并重新生成解析器类并重新运行上面的代码,它的行为完全相同。