使用語義謂詞時,我在錯誤恢復中遇到了一些奇怪的行爲。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