@Override
	public void sync(Parser recognizer) throws RecognitionException {
		ATNState s = recognizer.getInterpreter().atn.states.get(recognizer.getState());
//		System.err.println("sync @ "+s.stateNumber+"="+s.getClass().getSimpleName());
		// If already recovering, don't try to sync
		if (inErrorRecoveryMode(recognizer)) {
			return;
		}

        TokenStream tokens = recognizer.getInputStream();
        int la = tokens.LA(1);

        // try cheaper subset first; might get lucky. seems to shave a wee bit off
		IntervalSet nextTokens = recognizer.getATN().nextTokens(s);
		if (nextTokens.contains(la)) {
			// We are sure the token matches
			nextTokensContext = null;
			nextTokensState = ATNState.INVALID_STATE_NUMBER;
			return;
		}

		if (nextTokens.contains(Token.EPSILON)) {
			if (nextTokensContext == null) {
				// It's possible the next token won't match; information tracked
				// by sync is restricted for performance.
				nextTokensContext = recognizer.getContext();
				nextTokensState = recognizer.getState();
			}
			return;
		}

		switch (s.getStateType()) {
		case ATNState.BLOCK_START:
		case ATNState.STAR_BLOCK_START:
		case ATNState.PLUS_BLOCK_START:
		case ATNState.STAR_LOOP_ENTRY:
			// report error and recover if possible
			if ( singleTokenDeletion(recognizer)!=null ) {
				return;
			}

			throw new InputMismatchException(recognizer);

		case ATNState.PLUS_LOOP_BACK:
		case ATNState.STAR_LOOP_BACK:
//			System.err.println("at loop back: "+s.getClass().getSimpleName());
			reportUnwantedToken(recognizer);
			IntervalSet expecting = recognizer.getExpectedTokens();
			IntervalSet whatFollowsLoopIterationOrRule =
				expecting.or(getErrorRecoverySet(recognizer));
			consumeUntil(recognizer, whatFollowsLoopIterationOrRule);
			break;

		default:
			// do nothing if we can't identify the exact kind of ATN state
			break;
		}
	}
The default implementation of {@link ANTLRErrorStrategy#sync} makes sure
that the current lookahead symbol is consistent with what were expecting
at this point in the ATN. You can call this anytime but ANTLR only
generates code to check before subrules/loops and each iteration.

<p>Implements Jim Idle's magic sync mechanism in closures and optional
subrules. E.g.,</p>

<pre>
a : sync ( stuff sync )* ;
sync : {consume to what can follow sync} ;
</pre>

At the start of a sub rule upon error, {@link #sync} performs single
token deletion, if possible. If it can't do that, it bails on the current
rule and uses the default error recovery, which consumes until the
resynchronization set of the current rule.

<p>If the sub rule is optional ({@code (...)?}, {@code (...)*}, or block
with an empty alternative), then the expected set includes what follows
the subrule.</p>

<p>During loop iteration, it consumes until it sees a token that can start a
sub rule or what follows loop. Yes, that is pretty aggressive. We opt to
stay in the loop as long as possible.</p>

<p><strong>ORIGINS</strong></p>

<p>Previous versions of ANTLR did a poor job of their recovery within loops.
A single mismatch token or missing token would force the parser to bail
out of the entire rules surrounding the loop. So, for rule</p>

<pre>
classDef : 'class' ID '{' member* '}'
</pre>

input with an extra token between members would force the parser to
consume until it found the next class definition rather than the next
member definition of the current class.

<p>This functionality cost a little bit of effort because the parser has to
compare token set at the start of the loop and at each iteration. If for
some reason speed is suffering for you, you can turn off this
functionality by simply overriding this method as a blank { }.</p>
runtime/Java/src/org/antlr/v4/runtime/DefaultErrorStrategy.java