question: public void visitErrorNode ( ErrorNode node ) { ProgressIndicatorProvider . checkCanceled ( ) ; Token badToken = node . getSymbol ( ) ; boolean isConjuredToken = badToken . getTokenIndex ( ) < 0 ; int nodeStartIndex = badToken . getStartIndex ( ) ; SyntaxError error = tokenToErrorMap . get ( nodeStartIndex ) ; if ( error != null ) { PsiBuilder . Marker errorMarker = builder . mark ( ) ; if ( badToken . getStartIndex ( ) >= 0 && badToken . getType ( ) != Token . EOF && ! isConjuredToken ) { builder . advanceLexer ( ) ; } String message = String . format ( "%s%n" , error . getMessage ( ) ) ; errorMarker . error ( message ) ; } else { if ( isConjuredToken ) { PsiBuilder . Marker errorMarker = builder . mark ( ) ; errorMarker . error ( badToken . getText ( ) ) ; } else { builder . advanceLexer ( ) ; } } }
target:  Summary. For any syntax error thrown by the parser, there will be an ErrorNode in the parse tree and this method will process it. All errors correspond to actual tokens in the input except for missing token errors. There are there are multiple error situations to consider: 1. Extraneous token. The parse tree will have an ErrorNode for token. 2. Token mismatch. The parse tree will have an ErrorNode for token. 3. Missing token. The parse tree will have an ErrorNode but it does not correspond to any bit of the input. We underline the current token. 4. NoViableAlt (input inconsistent with any rule alt). The parse tree will have an ErrorNode for token. 5. Tokens consumed to resync the parser during recovery. The parse tree will have an ErrorNode for each token. This is complicated by errors that occur at EOF but I have modified error strategy to add error nodes for EOF if needed. Another complication. During prediction, we might match n tokens and then fail on the n+1 token, leading to NoViableAltException. But, it's offending token is at n+1 not current token where prediction started (which we use to find syntax errors). So, SyntaxError objects return start not offending token in this case.