]> gitweb.ps.run Git - toc/blob - antlr4-cpp-runtime-4.9.2-source/runtime/src/DefaultErrorStrategy.cpp
add antlr source code and ReadMe
[toc] / antlr4-cpp-runtime-4.9.2-source / runtime / src / DefaultErrorStrategy.cpp
1 /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2  * Use of this file is governed by the BSD 3-clause license that
3  * can be found in the LICENSE.txt file in the project root.
4  */
5
6 #include "NoViableAltException.h"
7 #include "misc/IntervalSet.h"
8 #include "atn/ParserATNSimulator.h"
9 #include "InputMismatchException.h"
10 #include "FailedPredicateException.h"
11 #include "ParserRuleContext.h"
12 #include "atn/RuleTransition.h"
13 #include "atn/ATN.h"
14 #include "atn/ATNState.h"
15 #include "Parser.h"
16 #include "CommonToken.h"
17 #include "Vocabulary.h"
18 #include "support/StringUtils.h"
19
20 #include "DefaultErrorStrategy.h"
21
22 using namespace antlr4;
23 using namespace antlr4::atn;
24
25 using namespace antlrcpp;
26
27 DefaultErrorStrategy::DefaultErrorStrategy() {
28   InitializeInstanceFields();
29 }
30
31 DefaultErrorStrategy::~DefaultErrorStrategy() {
32 }
33
34 void DefaultErrorStrategy::reset(Parser *recognizer) {
35   _errorSymbols.clear();
36   endErrorCondition(recognizer);
37 }
38
39 void DefaultErrorStrategy::beginErrorCondition(Parser * /*recognizer*/) {
40   errorRecoveryMode = true;
41 }
42
43 bool DefaultErrorStrategy::inErrorRecoveryMode(Parser * /*recognizer*/) {
44   return errorRecoveryMode;
45 }
46
47 void DefaultErrorStrategy::endErrorCondition(Parser * /*recognizer*/) {
48   errorRecoveryMode = false;
49   lastErrorIndex = -1;
50 }
51
52 void DefaultErrorStrategy::reportMatch(Parser *recognizer) {
53   endErrorCondition(recognizer);
54 }
55
56 void DefaultErrorStrategy::reportError(Parser *recognizer, const RecognitionException &e) {
57   // If we've already reported an error and have not matched a token
58   // yet successfully, don't report any errors.
59   if (inErrorRecoveryMode(recognizer)) {
60     return; // don't report spurious errors
61   }
62
63   beginErrorCondition(recognizer);
64   if (is<const NoViableAltException *>(&e)) {
65     reportNoViableAlternative(recognizer, static_cast<const NoViableAltException &>(e));
66   } else if (is<const InputMismatchException *>(&e)) {
67     reportInputMismatch(recognizer, static_cast<const InputMismatchException &>(e));
68   } else if (is<const FailedPredicateException *>(&e)) {
69     reportFailedPredicate(recognizer, static_cast<const FailedPredicateException &>(e));
70   } else if (is<const RecognitionException *>(&e)) {
71     recognizer->notifyErrorListeners(e.getOffendingToken(), e.what(), std::current_exception());
72   }
73 }
74
75 void DefaultErrorStrategy::recover(Parser *recognizer, std::exception_ptr /*e*/) {
76   if (lastErrorIndex == static_cast<int>(recognizer->getInputStream()->index()) &&
77       lastErrorStates.contains(recognizer->getState())) {
78
79     // uh oh, another error at same token index and previously-visited
80     // state in ATN; must be a case where LT(1) is in the recovery
81     // token set so nothing got consumed. Consume a single token
82     // at least to prevent an infinite loop; this is a failsafe.
83     recognizer->consume();
84   }
85   lastErrorIndex = static_cast<int>(recognizer->getInputStream()->index());
86   lastErrorStates.add(recognizer->getState());
87   misc::IntervalSet followSet = getErrorRecoverySet(recognizer);
88   consumeUntil(recognizer, followSet);
89 }
90
91 void DefaultErrorStrategy::sync(Parser *recognizer) {
92   atn::ATNState *s = recognizer->getInterpreter<atn::ATNSimulator>()->atn.states[recognizer->getState()];
93
94   // If already recovering, don't try to sync
95   if (inErrorRecoveryMode(recognizer)) {
96     return;
97   }
98
99   TokenStream *tokens = recognizer->getTokenStream();
100   size_t la = tokens->LA(1);
101
102   // try cheaper subset first; might get lucky. seems to shave a wee bit off
103   auto nextTokens = recognizer->getATN().nextTokens(s);
104   if (nextTokens.contains(Token::EPSILON) || nextTokens.contains(la)) {
105     return;
106   }
107
108   switch (s->getStateType()) {
109     case atn::ATNState::BLOCK_START:
110     case atn::ATNState::STAR_BLOCK_START:
111     case atn::ATNState::PLUS_BLOCK_START:
112     case atn::ATNState::STAR_LOOP_ENTRY:
113       // report error and recover if possible
114       if (singleTokenDeletion(recognizer) != nullptr) {
115         return;
116       }
117
118       throw InputMismatchException(recognizer);
119
120     case atn::ATNState::PLUS_LOOP_BACK:
121     case atn::ATNState::STAR_LOOP_BACK: {
122       reportUnwantedToken(recognizer);
123       misc::IntervalSet expecting = recognizer->getExpectedTokens();
124       misc::IntervalSet whatFollowsLoopIterationOrRule = expecting.Or(getErrorRecoverySet(recognizer));
125       consumeUntil(recognizer, whatFollowsLoopIterationOrRule);
126     }
127       break;
128
129     default:
130       // do nothing if we can't identify the exact kind of ATN state
131       break;
132   }
133 }
134
135 void DefaultErrorStrategy::reportNoViableAlternative(Parser *recognizer, const NoViableAltException &e) {
136   TokenStream *tokens = recognizer->getTokenStream();
137   std::string input;
138   if (tokens != nullptr) {
139     if (e.getStartToken()->getType() == Token::EOF) {
140       input = "<EOF>";
141     } else {
142       input = tokens->getText(e.getStartToken(), e.getOffendingToken());
143     }
144   } else {
145     input = "<unknown input>";
146   }
147   std::string msg = "no viable alternative at input " + escapeWSAndQuote(input);
148   recognizer->notifyErrorListeners(e.getOffendingToken(), msg, std::make_exception_ptr(e));
149 }
150
151 void DefaultErrorStrategy::reportInputMismatch(Parser *recognizer, const InputMismatchException &e) {
152   std::string msg = "mismatched input " + getTokenErrorDisplay(e.getOffendingToken()) +
153   " expecting " + e.getExpectedTokens().toString(recognizer->getVocabulary());
154   recognizer->notifyErrorListeners(e.getOffendingToken(), msg, std::make_exception_ptr(e));
155 }
156
157 void DefaultErrorStrategy::reportFailedPredicate(Parser *recognizer, const FailedPredicateException &e) {
158   const std::string& ruleName = recognizer->getRuleNames()[recognizer->getContext()->getRuleIndex()];
159   std::string msg = "rule " + ruleName + " " + e.what();
160   recognizer->notifyErrorListeners(e.getOffendingToken(), msg, std::make_exception_ptr(e));
161 }
162
163 void DefaultErrorStrategy::reportUnwantedToken(Parser *recognizer) {
164   if (inErrorRecoveryMode(recognizer)) {
165     return;
166   }
167
168   beginErrorCondition(recognizer);
169
170   Token *t = recognizer->getCurrentToken();
171   std::string tokenName = getTokenErrorDisplay(t);
172   misc::IntervalSet expecting = getExpectedTokens(recognizer);
173
174   std::string msg = "extraneous input " + tokenName + " expecting " + expecting.toString(recognizer->getVocabulary());
175   recognizer->notifyErrorListeners(t, msg, nullptr);
176 }
177
178 void DefaultErrorStrategy::reportMissingToken(Parser *recognizer) {
179   if (inErrorRecoveryMode(recognizer)) {
180     return;
181   }
182
183   beginErrorCondition(recognizer);
184
185   Token *t = recognizer->getCurrentToken();
186   misc::IntervalSet expecting = getExpectedTokens(recognizer);
187   std::string expectedText = expecting.toString(recognizer->getVocabulary());
188   std::string msg = "missing " + expectedText + " at " + getTokenErrorDisplay(t);
189
190   recognizer->notifyErrorListeners(t, msg, nullptr);
191 }
192
193 Token* DefaultErrorStrategy::recoverInline(Parser *recognizer) {
194   // Single token deletion.
195   Token *matchedSymbol = singleTokenDeletion(recognizer);
196   if (matchedSymbol) {
197     // We have deleted the extra token.
198     // Now, move past ttype token as if all were ok.
199     recognizer->consume();
200     return matchedSymbol;
201   }
202
203   // Single token insertion.
204   if (singleTokenInsertion(recognizer)) {
205     return getMissingSymbol(recognizer);
206   }
207
208   // Even that didn't work; must throw the exception.
209   throw InputMismatchException(recognizer);
210 }
211
212 bool DefaultErrorStrategy::singleTokenInsertion(Parser *recognizer) {
213   ssize_t currentSymbolType = recognizer->getInputStream()->LA(1);
214
215   // if current token is consistent with what could come after current
216   // ATN state, then we know we're missing a token; error recovery
217   // is free to conjure up and insert the missing token
218   atn::ATNState *currentState = recognizer->getInterpreter<atn::ATNSimulator>()->atn.states[recognizer->getState()];
219   atn::ATNState *next = currentState->transitions[0]->target;
220   const atn::ATN &atn = recognizer->getInterpreter<atn::ATNSimulator>()->atn;
221   misc::IntervalSet expectingAtLL2 = atn.nextTokens(next, recognizer->getContext());
222   if (expectingAtLL2.contains(currentSymbolType)) {
223     reportMissingToken(recognizer);
224     return true;
225   }
226   return false;
227 }
228
229 Token* DefaultErrorStrategy::singleTokenDeletion(Parser *recognizer) {
230   size_t nextTokenType = recognizer->getInputStream()->LA(2);
231   misc::IntervalSet expecting = getExpectedTokens(recognizer);
232   if (expecting.contains(nextTokenType)) {
233     reportUnwantedToken(recognizer);
234     recognizer->consume(); // simply delete extra token
235                            // we want to return the token we're actually matching
236     Token *matchedSymbol = recognizer->getCurrentToken();
237     reportMatch(recognizer); // we know current token is correct
238     return matchedSymbol;
239   }
240   return nullptr;
241 }
242
243 Token* DefaultErrorStrategy::getMissingSymbol(Parser *recognizer) {
244   Token *currentSymbol = recognizer->getCurrentToken();
245   misc::IntervalSet expecting = getExpectedTokens(recognizer);
246   size_t expectedTokenType = expecting.getMinElement(); // get any element
247   std::string tokenText;
248   if (expectedTokenType == Token::EOF) {
249     tokenText = "<missing EOF>";
250   } else {
251     tokenText = "<missing " + recognizer->getVocabulary().getDisplayName(expectedTokenType) + ">";
252   }
253   Token *current = currentSymbol;
254   Token *lookback = recognizer->getTokenStream()->LT(-1);
255   if (current->getType() == Token::EOF && lookback != nullptr) {
256     current = lookback;
257   }
258
259   _errorSymbols.push_back(recognizer->getTokenFactory()->create(
260     { current->getTokenSource(), current->getTokenSource()->getInputStream() },
261     expectedTokenType, tokenText, Token::DEFAULT_CHANNEL, INVALID_INDEX, INVALID_INDEX,
262     current->getLine(), current->getCharPositionInLine()));
263
264   return _errorSymbols.back().get();
265 }
266
267 misc::IntervalSet DefaultErrorStrategy::getExpectedTokens(Parser *recognizer) {
268   return recognizer->getExpectedTokens();
269 }
270
271 std::string DefaultErrorStrategy::getTokenErrorDisplay(Token *t) {
272   if (t == nullptr) {
273     return "<no Token>";
274   }
275   std::string s = getSymbolText(t);
276   if (s == "") {
277     if (getSymbolType(t) == Token::EOF) {
278       s = "<EOF>";
279     } else {
280       s = "<" + std::to_string(getSymbolType(t)) + ">";
281     }
282   }
283   return escapeWSAndQuote(s);
284 }
285
286 std::string DefaultErrorStrategy::getSymbolText(Token *symbol) {
287   return symbol->getText();
288 }
289
290 size_t DefaultErrorStrategy::getSymbolType(Token *symbol) {
291   return symbol->getType();
292 }
293
294 std::string DefaultErrorStrategy::escapeWSAndQuote(const std::string &s) const {
295   std::string result = s;
296   antlrcpp::replaceAll(result, "\n", "\\n");
297   antlrcpp::replaceAll(result, "\r","\\r");
298   antlrcpp::replaceAll(result, "\t","\\t");
299   return "'" + result + "'";
300 }
301
302 misc::IntervalSet DefaultErrorStrategy::getErrorRecoverySet(Parser *recognizer) {
303   const atn::ATN &atn = recognizer->getInterpreter<atn::ATNSimulator>()->atn;
304   RuleContext *ctx = recognizer->getContext();
305   misc::IntervalSet recoverSet;
306   while (ctx->invokingState != ATNState::INVALID_STATE_NUMBER) {
307     // compute what follows who invoked us
308     atn::ATNState *invokingState = atn.states[ctx->invokingState];
309     atn::RuleTransition *rt = dynamic_cast<atn::RuleTransition*>(invokingState->transitions[0]);
310     misc::IntervalSet follow = atn.nextTokens(rt->followState);
311     recoverSet.addAll(follow);
312
313     if (ctx->parent == nullptr)
314       break;
315     ctx = static_cast<RuleContext *>(ctx->parent);
316   }
317   recoverSet.remove(Token::EPSILON);
318
319   return recoverSet;
320 }
321
322 void DefaultErrorStrategy::consumeUntil(Parser *recognizer, const misc::IntervalSet &set) {
323   size_t ttype = recognizer->getInputStream()->LA(1);
324   while (ttype != Token::EOF && !set.contains(ttype)) {
325     recognizer->consume();
326     ttype = recognizer->getInputStream()->LA(1);
327   }
328 }
329
330 void DefaultErrorStrategy::InitializeInstanceFields() {
331   errorRecoveryMode = false;
332   lastErrorIndex = -1;
333 }