我创建了一个示例语法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会按预期引发语法错误。我不理解这种行为,因为最后一个语法规则甚至不应该参与解析,因为它既不是由启动规则直接引用也不是间接引用。
答案 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
规则并重新生成解析器类并重新运行上面的代码,它的行为完全相同。