CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-antlr--antlr4-master

ANTLR is a powerful parser generator for reading, processing, executing, or translating structured text or binary files

Overview
Eval results
Files

error-handling.mddocs/

Error Handling

ANTLR4 provides a comprehensive error handling system with customizable recovery strategies, detailed error reporting, and multiple approaches to handling syntax errors during parsing.

Capabilities

Error Listener Interface

Interface for receiving and handling syntax errors.

/**
 * Interface for handling syntax errors during parsing
 */
public interface ANTLRErrorListener {
    /**
     * Called when parser encounters a syntax error
     * @param recognizer the parser or lexer that encountered the error
     * @param offendingSymbol the problematic token or character
     * @param line the line number where error occurred
     * @param charPositionInLine the character position in line
     * @param msg error message
     * @param e recognition exception (may be null)
     */
    void syntaxError(Recognizer<?, ?> recognizer,
                    Object offendingSymbol,
                    int line,
                    int charPositionInLine,
                    String msg,
                    RecognitionException e);
}

/**
 * Base error listener providing empty implementations
 */
public class BaseErrorListener implements ANTLRErrorListener {
    @Override
    public void syntaxError(Recognizer<?, ?> recognizer,
                           Object offendingSymbol,
                           int line,
                           int charPositionInLine,
                           String msg,
                           RecognitionException e) {
        // Empty implementation - override in subclasses
    }
}

/**
 * Console error listener that prints errors to stderr
 */
public class ConsoleErrorListener extends BaseErrorListener {
    /** Singleton instance */
    public static final ConsoleErrorListener INSTANCE = new ConsoleErrorListener();
    
    @Override
    public void syntaxError(Recognizer<?, ?> recognizer,
                           Object offendingSymbol,
                           int line,
                           int charPositionInLine,
                           String msg,
                           RecognitionException e) {
        System.err.println("line " + line + ":" + charPositionInLine + " " + msg);
    }
}

Usage Example:

import org.antlr.v4.runtime.*;

// Custom error listener
class MyErrorListener extends BaseErrorListener {
    @Override
    public void syntaxError(Recognizer<?, ?> recognizer,
                           Object offendingSymbol,
                           int line,
                           int charPositionInLine,
                           String msg,
                           RecognitionException e) {
        System.err.println("Syntax error at " + line + ":" + charPositionInLine);
        System.err.println("Message: " + msg);
        
        if (offendingSymbol instanceof Token) {
            Token token = (Token) offendingSymbol;
            System.err.println("Problematic token: '" + token.getText() + "'");
        }
    }
}

// Add custom error listener to parser
MyParser parser = new MyParser(tokens);
parser.removeErrorListeners(); // Remove default console listener
parser.addErrorListener(new MyErrorListener());

Error Recovery Strategies

Interfaces and implementations for error recovery during parsing.

/**
 * Interface for error recovery strategies
 */
public interface ANTLRErrorStrategy {
    /** Reset strategy state */
    void reset(Parser recognizer);
    
    /** Recover from token mismatch */
    Token recoverInline(Parser recognizer) throws RecognitionException;
    
    /** Recover from recognition exception */
    void recover(Parser recognizer, RecognitionException e) throws RecognitionException;
    
    /** Synchronize parser after error */
    void sync(Parser recognizer) throws RecognitionException;
    
    /** Check if in error recovery mode */
    boolean inErrorRecoveryMode(Parser recognizer);
    
    /** Report error match */
    void reportMatch(Parser recognizer);
    
    /** Report error */
    void reportError(Parser recognizer, RecognitionException e);
}

/**
 * Default error recovery strategy with sync and single token insertion/deletion
 */
public class DefaultErrorStrategy implements ANTLRErrorStrategy {
    /** Whether in error recovery mode */
    protected boolean errorRecoveryMode = false;
    
    /** Last error index to avoid infinite loops */
    protected int lastErrorIndex = -1;
    
    /** IntervalSet of tokens for synchronization */
    protected IntervalSet lastErrorStates;
    
    @Override
    public void reset(Parser recognizer) {
        endErrorCondition(recognizer);
    }
    
    @Override
    public Token recoverInline(Parser recognizer) throws RecognitionException {
        // Try single token deletion
        Token matchedSymbol = singleTokenDeletion(recognizer);
        if (matchedSymbol != null) {
            recognizer.consume();
            return matchedSymbol;
        }
        
        // Try single token insertion
        if (singleTokenInsertion(recognizer)) {
            return getMissingSymbol(recognizer);
        }
        
        // Fall back to more complex recovery
        throw new InputMismatchException(recognizer);
    }
    
    @Override
    public void recover(Parser recognizer, RecognitionException e) throws RecognitionException {
        if (lastErrorIndex == recognizer.getInputStream().index() &&
            lastErrorStates != null && 
            lastErrorStates.contains(recognizer.getState())) {
            // Consume at least one token to avoid infinite loops
            recognizer.consume();
        }
        
        lastErrorIndex = recognizer.getInputStream().index();
        if (lastErrorStates == null) {
            lastErrorStates = new IntervalSet();
        }
        lastErrorStates.add(recognizer.getState());
        
        IntervalSet followSet = getErrorRecoverySet(recognizer);
        consumeUntil(recognizer, followSet);
    }
    
    @Override
    public void sync(Parser recognizer) throws RecognitionException {
        ATNState s = recognizer.getInterpreter().atn.states.get(recognizer.getState());
        if (inErrorRecoveryMode(recognizer)) {
            return;
        }
        
        TokenStream tokens = recognizer.getInputStream();
        int la = tokens.LA(1);
        
        if (recognizer.getATN().nextTokens(s).contains(la)) {
            return;
        }
        
        switch (s.getStateType()) {
            case ATNState.BLOCK_START:
            case ATNState.STAR_BLOCK_START:
            case ATNState.PLUS_BLOCK_START:
            case ATNState.STAR_LOOP_ENTRY:
                if (singleTokenDeletion(recognizer) != null) {
                    return;
                }
                throw new InputMismatchException(recognizer);
                
            default:
                // Nothing to sync on
                break;
        }
    }
    
    /** End error condition and exit recovery mode */
    protected void endErrorCondition(Parser recognizer) {
        errorRecoveryMode = false;
        lastErrorStates = null;
        lastErrorIndex = -1;
    }
    
    /** Enter error recovery mode */
    protected void beginErrorCondition(Parser recognizer) {
        errorRecoveryMode = true;
    }
    
    /** Get missing symbol for recovery */
    protected Token getMissingSymbol(Parser recognizer) {
        Token currentSymbol = recognizer.getCurrentToken();
        IntervalSet expecting = getExpectedTokens(recognizer);
        int expectedTokenType = expecting.getMinElement();
        
        String tokenText;
        if (expectedTokenType == Token.EOF) {
            tokenText = "<missing EOF>";
        } else {
            tokenText = "<missing " + recognizer.getVocabulary().getDisplayName(expectedTokenType) + ">";
        }
        
        Token current = currentSymbol;
        Token lookback = recognizer.getInputStream().LT(-1);
        if (current.getType() == Token.EOF && lookback != null) {
            current = lookback;
        }
        
        return recognizer.getTokenFactory().create(
            new Pair<>(current.getTokenSource(), current.getInputStream()),
            expectedTokenType, tokenText,
            Token.DEFAULT_CHANNEL,
            -1, -1,
            current.getLine(), current.getCharPositionInLine()
        );
    }
}

/**
 * Error strategy that bails out on first error (fail-fast)
 */
public class BailErrorStrategy extends DefaultErrorStrategy {
    @Override
    public void recover(Parser recognizer, RecognitionException e) throws RecognitionException {
        // Don't recover; rethrow exception
        for (ParserRuleContext context = recognizer.getContext(); 
             context != null; 
             context = context.getParent()) {
            context.exception = e;
        }
        throw new ParseCancellationException(e);
    }
    
    @Override
    public Token recoverInline(Parser recognizer) throws RecognitionException {
        InputMismatchException e = new InputMismatchException(recognizer);
        for (ParserRuleContext context = recognizer.getContext(); 
             context != null; 
             context = context.getParent()) {
            context.exception = e;
        }
        throw new ParseCancellationException(e);
    }
    
    @Override
    public void sync(Parser recognizer) throws RecognitionException {
        // Don't sync; let exceptions bubble up
    }
}

Usage Example:

import org.antlr.v4.runtime.*;

// Use default error recovery
MyParser parser = new MyParser(tokens);
// Default strategy is already set

// Use bail error strategy (fail-fast)
MyParser parser2 = new MyParser(tokens);
parser2.setErrorHandler(new BailErrorStrategy());

try {
    ParseTree tree = parser2.expr();
} catch (ParseCancellationException e) {
    System.err.println("Parse failed: " + e.getCause().getMessage());
}

Recognition Exceptions

Exception hierarchy for different types of parsing errors.

/**
 * Base class for all recognition exceptions
 */
public class RecognitionException extends RuntimeException {
    /** Parser or lexer that threw the exception */
    private final Recognizer<?, ?> recognizer;
    
    /** Rule context where exception occurred */
    private final RuleContext ctx;
    
    /** Input stream where exception occurred */
    private final IntStream input;
    
    /** Offending token or character */
    private final Object offendingToken;
    
    /** Position information */
    private final int offendingState;
    
    public RecognitionException(Recognizer<?, ?> recognizer,
                               IntStream input,
                               ParserRuleContext ctx) {
        this.recognizer = recognizer;
        this.input = input;
        this.ctx = ctx;
        if (recognizer != null) {
            this.offendingState = recognizer.getState();
        } else {
            this.offendingState = -1;
        }
    }
    
    /** Get expected tokens at point of error */
    public IntervalSet getExpectedTokens() {
        if (recognizer != null) {
            return recognizer.getATN().getExpectedTokens(offendingState, ctx);
        }
        return IntervalSet.EMPTY_SET;
    }
    
    /** Get rule context */
    public RuleContext getCtx() {
        return ctx;
    }
    
    /** Get input stream */
    public IntStream getInputStream() {
        return input;
    }
    
    /** Get offending token */
    public Object getOffendingToken() {
        return offendingToken;
    }
    
    /** Get recognizer */
    public Recognizer<?, ?> getRecognizer() {
        return recognizer;
    }
}

/**
 * Exception for token mismatch errors
 */
public class InputMismatchException extends RecognitionException {
    public InputMismatchException(Parser recognizer) {
        super(recognizer, recognizer.getInputStream(), recognizer.getContext());
        setOffendingToken(recognizer.getCurrentToken());
    }
    
    public InputMismatchException(Parser recognizer, int state, ParserRuleContext ctx) {
        super(recognizer, recognizer.getInputStream(), ctx);
        setOffendingState(state);
        setOffendingToken(recognizer.getCurrentToken());
    }
}

/**
 * Exception when lexer cannot match input
 */
public class LexerNoViableAltException extends RecognitionException {
    /** Start index of problematic text */
    private final int startIndex;
    
    /** Dead-end configurations */
    private final ATNConfigSet deadEndConfigs;
    
    public LexerNoViableAltException(Lexer lexer,
                                    CharStream input,
                                    int startIndex,
                                    ATNConfigSet deadEndConfigs) {
        super(lexer, input, null);
        this.startIndex = startIndex;
        this.deadEndConfigs = deadEndConfigs;
    }
    
    public int getStartIndex() {
        return startIndex;
    }
    
    public ATNConfigSet getDeadEndConfigs() {
        return deadEndConfigs;
    }
}

/**
 * Exception when parser cannot choose alternative
 */
public class NoViableAltException extends RecognitionException {
    /** Dead-end configurations */
    private final ATNConfigSet deadEndConfigs;
    
    /** Start token */
    private final Token startToken;
    
    public NoViableAltException(Parser recognizer) {
        this(recognizer, recognizer.getInputStream(), recognizer.getCurrentToken(),
             recognizer.getCurrentToken(), null, recognizer.getContext());
    }
    
    public NoViableAltException(Parser recognizer,
                               TokenStream input,
                               Token startToken,
                               Token offendingToken,
                               ATNConfigSet deadEndConfigs,
                               ParserRuleContext ctx) {
        super(recognizer, input, ctx);
        this.deadEndConfigs = deadEndConfigs;
        this.startToken = startToken;
        setOffendingToken(offendingToken);
    }
    
    public Token getStartToken() {
        return startToken;
    }
    
    public ATNConfigSet getDeadEndConfigs() {
        return deadEndConfigs;
    }
}

/**
 * Exception when semantic predicate fails
 */
public class FailedPredicateException extends RecognitionException {
    /** Rule index */
    private final int ruleIndex;
    
    /** Predicate index */
    private final int predicateIndex;
    
    /** Predicate text */
    private final String predicate;
    
    public FailedPredicateException(Parser recognizer) {
        this(recognizer, null);
    }
    
    public FailedPredicateException(Parser recognizer, String predicate) {
        this(recognizer, predicate, null);
    }
    
    public FailedPredicateException(Parser recognizer, String predicate, String message) {
        super(formatMessage(predicate, message), recognizer, 
              recognizer.getInputStream(), recognizer.getContext());
        
        ATNState s = recognizer.getInterpreter().atn.states.get(recognizer.getState());
        AbstractPredicateTransition trans = (AbstractPredicateTransition) s.transition(0);
        if (trans instanceof PredicateTransition) {
            this.ruleIndex = ((PredicateTransition) trans).ruleIndex;
            this.predicateIndex = ((PredicateTransition) trans).predIndex;
        } else {
            this.ruleIndex = 0;
            this.predicateIndex = 0;
        }
        
        this.predicate = predicate;
        setOffendingToken(recognizer.getCurrentToken());
    }
    
    public int getRuleIndex() {
        return ruleIndex;
    }
    
    public int getPredicateIndex() {
        return predicateIndex;
    }
    
    public String getPredicate() {
        return predicate;
    }
}

Diagnostic Error Listener

Advanced error listener with detailed diagnostic information.

/**
 * Error listener that provides detailed diagnostic information
 */
public class DiagnosticErrorListener extends BaseErrorListener {
    /** Whether to report ambiguities */
    protected final boolean exactOnly;
    
    public DiagnosticErrorListener() {
        this(true);
    }
    
    public DiagnosticErrorListener(boolean exactOnly) {
        this.exactOnly = exactOnly;
    }
    
    @Override
    public void syntaxError(Recognizer<?, ?> recognizer,
                           Object offendingSymbol,
                           int line,
                           int charPositionInLine,
                           String msg,
                           RecognitionException e) {
        System.err.println("Syntax error at " + line + ":" + charPositionInLine + ": " + msg);
        
        if (e != null) {
            System.err.println("Exception type: " + e.getClass().getSimpleName());
            
            if (e instanceof InputMismatchException) {
                IntervalSet expected = e.getExpectedTokens();
                System.err.println("Expected: " + expected.toString(recognizer.getVocabulary()));
            } else if (e instanceof NoViableAltException) {
                NoViableAltException nvae = (NoViableAltException) e;
                System.err.println("No viable alternative");
                System.err.println("Start token: " + nvae.getStartToken().getText());
            } else if (e instanceof FailedPredicateException) {
                FailedPredicateException fpe = (FailedPredicateException) e;
                System.err.println("Failed predicate: " + fpe.getPredicate());
            }
        }
    }
    
    /** Report ambiguity in parse */
    public void reportAmbiguity(Parser recognizer,
                               DFA dfa,
                               int startIndex,
                               int stopIndex,
                               boolean exact,
                               BitSet ambigAlts,
                               ATNConfigSet configs) {
        if (exactOnly && !exact) {
            return;
        }
        
        System.err.println("Ambiguity from " + startIndex + " to " + stopIndex);
        System.err.println("Alternatives: " + ambigAlts);
    }
    
    /** Report attempt to use full context */
    public void reportAttemptingFullContext(Parser recognizer,
                                          DFA dfa,
                                          int startIndex,
                                          int stopIndex,
                                          BitSet conflictingAlts,
                                          ATNConfigSet configs) {
        System.err.println("Attempting full context from " + startIndex + " to " + stopIndex);
    }
    
    /** Report context sensitivity */
    public void reportContextSensitivity(Parser recognizer,
                                       DFA dfa,
                                       int startIndex,
                                       int stopIndex,
                                       int prediction,
                                       ATNConfigSet configs) {
        System.err.println("Context sensitivity from " + startIndex + " to " + stopIndex);
    }
}

Usage Patterns

Basic Error Handling

import org.antlr.v4.runtime.*;

// Simple error collection
List<String> errors = new ArrayList<>();

MyParser parser = new MyParser(tokens);
parser.removeErrorListeners();
parser.addErrorListener(new BaseErrorListener() {
    @Override
    public void syntaxError(Recognizer<?, ?> recognizer,
                           Object offendingSymbol,
                           int line,
                           int charPositionInLine,
                           String msg,
                           RecognitionException e) {
        errors.add("Line " + line + ":" + charPositionInLine + " - " + msg);
    }
});

ParseTree tree = parser.expr();

if (!errors.isEmpty()) {
    System.err.println("Parse errors:");
    for (String error : errors) {
        System.err.println("  " + error);
    }
}

Advanced Error Recovery

import org.antlr.v4.runtime.*;

// Custom error strategy with specific recovery
class MyErrorStrategy extends DefaultErrorStrategy {
    @Override
    protected void reportNoViableAlternative(Parser recognizer, NoViableAltException e) {
        TokenStream tokens = recognizer.getInputStream();
        String input;
        if (tokens != null) {
            if (e.getStartToken().getType() == Token.EOF) {
                input = "<EOF>";
            } else {
                input = tokens.getText(e.getStartToken(), e.getOffendingToken());
            }
        } else {
            input = "<unknown input>";
        }
        
        String msg = "no viable alternative at input " + escapeWSAndQuote(input);
        recognizer.notifyErrorListeners(e.getOffendingToken(), msg, e);
    }
    
    @Override
    protected void reportInputMismatch(Parser recognizer, InputMismatchException e) {
        String msg = "mismatched input " + getTokenErrorDisplay(e.getOffendingToken()) +
                    " expecting " + e.getExpectedTokens().toString(recognizer.getVocabulary());
        recognizer.notifyErrorListeners(e.getOffendingToken(), msg, e);
    }
}

// Use custom strategy
MyParser parser = new MyParser(tokens);
parser.setErrorHandler(new MyErrorStrategy());

Comprehensive Error Reporting

import org.antlr.v4.runtime.*;

// Comprehensive error information
class DetailedErrorListener extends BaseErrorListener {
    @Override
    public void syntaxError(Recognizer<?, ?> recognizer,
                           Object offendingSymbol,
                           int line,
                           int charPositionInLine,
                           String msg,
                           RecognitionException e) {
        
        System.err.println("=== Syntax Error ===");
        System.err.println("Location: " + line + ":" + charPositionInLine);
        System.err.println("Message: " + msg);
        
        if (offendingSymbol instanceof Token) {
            Token token = (Token) offendingSymbol;
            System.err.println("Offending token: '" + token.getText() + 
                              "' (type: " + token.getType() + ")");
        }
        
        if (e != null) {
            System.err.println("Exception: " + e.getClass().getSimpleName());
            
            if (recognizer instanceof Parser) {
                Parser parser = (Parser) recognizer;
                System.err.println("Rule stack: " + parser.getRuleInvocationStack());
                
                if (e.getExpectedTokens() != null) {
                    System.err.println("Expected tokens: " + 
                        e.getExpectedTokens().toString(parser.getVocabulary()));
                }
            }
        }
        System.err.println("==================");
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-antlr--antlr4-master

docs

error-handling.md

index.md

parse-tree-api.md

runtime-api.md

tool-api.md

utilities.md

tile.json