Antlr4.Runtime.DefaultErrorStrategy.Sync C# (CSharp) Method

Sync() public method

The default implementation of IAntlrErrorStrategy.Sync(Parser) 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.

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

 a : sync ( stuff sync )* ; sync : {consume to what can follow sync} ; 
At the start of a sub rule upon error, Sync(Parser) 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.

If the sub rule is optional ( (...)? , (...)* , or block with an empty alternative), then the expected set includes what follows the subrule.

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.

ORIGINS

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

 classDef : 'class' ID '{' member* '}' 
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.

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 { }.

public Sync ( Parser recognizer ) : void
recognizer Parser
return void
        public virtual void Sync(Parser recognizer)
        {
            ATNState s = recognizer.Interpreter.atn.states[recognizer.State];
            //		System.err.println("sync @ "+s.stateNumber+"="+s.getClass().getSimpleName());
            // If already recovering, don't try to sync
            if (InErrorRecoveryMode(recognizer))
            {
                return;
            }
            ITokenStream tokens = ((ITokenStream)recognizer.InputStream);
            int la = tokens.LA(1);
            // try cheaper subset first; might get lucky. seems to shave a wee bit off
            if (recognizer.Atn.NextTokens(s).Contains(la) || la == TokenConstants.EOF)
            {
                return;
            }
            // Return but don't end recovery. only do that upon valid token match
            if (recognizer.IsExpectedToken(la))
            {
                return;
            }
            switch (s.StateType)
            {
                case StateType.BlockStart:
                case StateType.StarBlockStart:
                case StateType.PlusBlockStart:
                case StateType.StarLoopEntry:
                {
                    // report error and recover if possible
                    if (SingleTokenDeletion(recognizer) != null)
                    {
                        return;
                    }
                    throw new InputMismatchException(recognizer);
                }

                case StateType.PlusLoopBack:
                case StateType.StarLoopBack:
                {
                    //			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;
                }
            }
        }