使用语义谓词时,我在错误恢复中遇到了一些奇怪的行为。ANTLR4语义谓词混淆了错误恢复。为什么?
我需要错误恢复(特别是单个标记插入)的文本,我将解析有许多“单遗失令牌”的错误。
我还需要语义谓词,因为像ANTLR4: Matching all input alternatives exaclty once(第二种选择)。
但是,它似乎两个不好混合(我以前见过这个,并要求SO寻求帮助:ANTLR4 DefaultErrorStrategy fails to inject missing token;然后我找到了答案,现在我不知道)。
让语法(那么简单,它任意数量的“A”,用空格隔开,由分号结束相匹配):
grammar AAAGrammar;
WS : ' '+ -> channel(HIDDEN);
A : 'A';
SEMICOLON : ';';
aaaaa :
a* ';'
;
a :
A
;
正在运行,以下输入,所得到的分析树是:
- “AAA;”:
(aaaaa (a A) (a A) (a A) ;)
; - “A A A”:
(aaaaa (a A) (a A) (a A) <missing ';'>)
(这个人在stderr上发出警告:第1行:5''''在'')。
这就是我所期望的,正是我想要的(第二个输入的缺失分号被正确注入)。
现在变的简单语法,引入语义谓词(这一个无关痛痒,但我明白,ANTLR4不 - 不应该 - 评估这一点)在“A”的规则,以使其:
a :
{true}? A
;
通过相同的输入再次运行它: - “AAA;”:(aaaaa (a A) (a A) (a A) ;)
; - “A A A”:(aaaaa (a A) (a A) (a A))
(这个也在stderr:line 1:5上发出警告,在输入''处没有可行的选择'')。
所以语义谓词完全搞砸了丢失的令牌注入。
这是预期吗?
为什么?
是否有任何ANTLR4语法技巧来恢复错误恢复,而不删除sempred?
编辑:(答复@CoronA评论)
这里生成的分析器之间的diff -u
(不与语义谓词):
--- withoutsempred.java 2015-05-04 09:39:22.644069398 -0300
+++ withsempred.java 2015-05-04 09:39:13.400046354 -0300
@@ -56,22 +56,24 @@
public final AaaaaContext aaaaa() throws RecognitionException {
AaaaaContext _localctx = new AaaaaContext(_ctx, getState());
enterRule(_localctx, 0, RULE_aaaaa);
- int _la;
try {
+ int _alt;
enterOuterAlt(_localctx, 1);
{
setState(7);
_errHandler.sync(this);
- _la = _input.LA(1);
- while (_la==A) {
- {
- {
- setState(4); a();
- }
+ _alt = getInterpreter().adaptivePredict(_input,0,_ctx);
+ while (_alt!=2 && _alt!=-1) {
+ if (_alt==1) {
+ {
+ {
+ setState(4); a();
+ }
+ }
}
setState(9);
_errHandler.sync(this);
- _la = _input.LA(1);
+ _alt = getInterpreter().adaptivePredict(_input,0,_ctx);
}
setState(10); match(SEMICOLON);
}
@@ -101,7 +103,9 @@
try {
enterOuterAlt(_localctx, 1);
{
- setState(12); match(A);
+ setState(12);
+ if (!(true)) throw new FailedPredicateException(this, " true ");
+ setState(13); match(A);
}
}
catch (RecognitionException re) {
@@ -115,12 +119,25 @@
return _localctx;
}
+ public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) {
+ switch (ruleIndex) {
+ case 1: return a_sempred((AContext)_localctx, predIndex);
+ }
+ return true;
+ }
+ private boolean a_sempred(AContext _localctx, int predIndex) {
+ switch (predIndex) {
+ case 0: return true ;
+ }
+ return true;
+ }
+
public static final String _serializedATN =
- "\3\uacf5\uee8c\u4f5d\u8b0d\u4a45\u78bd\u1b2f\u3378\3\5\21\4\2\t\2\4\3"+
- "\t\3\3\2\7\2\b\n\2\f\2\16\2\13\13\2\3\2\3\2\3\3\3\3\3\3\2\4\2\4\2\2\17"+
- "\2\t\3\2\2\2\4\16\3\2\2\2\6\b\5\4\3\2\7\6\3\2\2\2\b\13\3\2\2\2\t\7\3\2"+
- "\2\2\t\n\3\2\2\2\n\f\3\2\2\2\13\t\3\2\2\2\f\r\7\5\2\2\r\3\3\2\2\2\16\17"+
- "\7\4\2\2\17\5\3\2\2\2\3\t";
+ "\3\uacf5\uee8c\u4f5d\u8b0d\u4a45\u78bd\u1b2f\u3378\3\5\22\4\2\t\2\4\3"+
+ "\t\3\3\2\7\2\b\n\2\f\2\16\2\13\13\2\3\2\3\2\3\3\3\3\3\3\3\3\2\4\2\4\2"+
+ "\2\20\2\t\3\2\2\2\4\16\3\2\2\2\6\b\5\4\3\2\7\6\3\2\2\2\b\13\3\2\2\2\t"+
+ "\7\3\2\2\2\t\n\3\2\2\2\n\f\3\2\2\2\13\t\3\2\2\2\f\r\7\5\2\2\r\3\3\2\2"+
+ "\2\16\17\6\3\2\2\17\20\7\4\2\2\20\5\3\2\2\2\3\t";
public static final ATN _ATN =
ATNSimulator.deserialize(_serializedATN.toCharArray());
static {
我已经调试这两个代码。
假设输入 “AAA”(不分号),没有语义谓词版本变为
while (_la==A) {
{
{
setState(4); a();
}
}
setState(9);
_errHandler.sync(this);
_la = _input.LA(1);
}
此块3次,然后前进到
setState(10); match(SEMICOLON);
的match(SEMICOLON)
注入一个丢失令牌。
现在请注意,带有语义谓词的版本摆脱_la = _input.LA(1)
(向前看)并切换到更高级的预测,其中_alt = getInterpreter().adaptivePredict(_input,0,_ctx)
。
有了非常相同的输入,具有语义谓词的版本有云:
_alt = getInterpreter().adaptivePredict(_input,0,_ctx);
while (_alt!=2 && _alt!=-1) {
if (_alt==1) {
{
{
setState(4); a();
}
}
}
setState(9);
_errHandler.sync(this);
_alt = getInterpreter().adaptivePredict(_input,0,_ctx);
}
此块3倍,但它不例外地离开块。最后的_alt = getInterpreter().adaptivePredict(_input,0,_ctx)
抛出org.antlr.v4.runtime.NoViableAltException
,完全跳过match(SEMICOLON)
。
我认为恢复被调用,但不考虑令牌注入,因为谓词评估不能被恢复模拟。你有调试过吗?在两种情况下它都进入恢复状态吗?如果是这样,你可以重写你的需求恢复。 – CoronA
@CoronA,我已经编辑了答案,以提供一些有关调试揭示的信息。问题在于'match(SEMICOLON)'没有得到执行的机会,因为'adaptativePredict()'在没有可行的替代方案时抛出异常。我认为口译员正在等待“A”或“;”决定走哪条路;但更简单的前瞻(1)策略不会扼杀失踪的';'并让它的match()正常进行(从而注入缺少的标记)。 – rslemos
我刚刚看到提交[ea4676b18ab40c99b629e078f1addd6605988403](https://github.com/antlr/antlr4/commit/ea4676b18ab40c99b629e078f1addd6605988403),这可能已经解决了这个问题。我会用4.5测试,稍后再回来告诉。 – rslemos