Java runtime library for ANTLR v3 - a framework for constructing recognizers, interpreters, compilers, and translators from grammatical descriptions.
—
Comprehensive exception hierarchy and error recovery mechanisms for robust parsing. ANTLR provides detailed error reporting with position information and flexible recovery strategies.
Base exception class for all parsing and lexical analysis errors.
/**
* Base class for all recognition exceptions
*/
public class RecognitionException extends Exception {
/** What input stream were we parsing that triggered this exception?
* This includes the current Token in a TokenStream or the current char
* in a CharStream.
*/
public IntStream input;
/** The current Token when an error occurred. Since not all streams
* can retrieve the ith Token, we have to track the Token object.
* For parsers. Even when it's a tree parser, token might be null.
*/
public Token token;
/** If this is a tree parser exception, node is set to the node with
* the problem.
*/
public Object node;
/** The current char when an error occurred. For lexers. */
public int c;
/** Track the line at which the error occurred in case this is
* generated from a lexer. We need to track this since the
* unexpected char doesn't carry the line info.
*/
public int line;
public int charPositionInLine;
/** If you are parsing a tree node stream, you will encounter som
* imaginary nodes but not others. We distinguish.
*/
public boolean approximateLineInfo;
/** Used for remote debugger deserialization */
public RecognitionException();
public RecognitionException(IntStream input);
/** Extract the unexpectedTokenType from the token */
protected int getUnexpectedType();
}Exceptions for various token matching failures.
/**
* Exception for token mismatch errors
*/
public class MismatchedTokenException extends RecognitionException {
public int expecting;
public MismatchedTokenException();
public MismatchedTokenException(int expecting, IntStream input);
public String toString();
}
/**
* Exception for missing expected token
*/
public class MissingTokenException extends MismatchedTokenException {
/** Used for remote debugger deserialization */
public MissingTokenException();
public MissingTokenException(int expecting, IntStream input, Object inserted);
public int getMissingType();
public String toString();
}
/**
* Exception for unwanted extra token
*/
public class UnwantedTokenException extends MismatchedTokenException {
public UnwantedTokenException();
public UnwantedTokenException(int expecting, IntStream input);
public Token getUnexpectedToken();
public String toString();
}Usage Examples:
import org.antlr.runtime.*;
// Catching specific token exceptions
try {
MyParser parser = new MyParser(tokens);
parser.program();
} catch (MismatchedTokenException e) {
System.err.println("Expected token: " + e.expecting +
" but found: " + e.getUnexpectedType());
System.err.println("At line: " + e.line +
" position: " + e.charPositionInLine);
} catch (MissingTokenException e) {
System.err.println("Missing token of type: " + e.getMissingType());
} catch (UnwantedTokenException e) {
System.err.println("Unwanted token: " + e.getUnexpectedToken().getText());
}Exceptions for token set matching failures.
/**
* Exception for set mismatch errors
*/
public class MismatchedSetException extends MismatchedTokenException {
public BitSet expecting;
public MismatchedSetException();
public MismatchedSetException(BitSet expecting, IntStream input);
public String toString();
}
/**
* Exception for negated set mismatch errors
*/
public class MismatchedNotSetException extends MismatchedSetException {
public MismatchedNotSetException();
public MismatchedNotSetException(BitSet expecting, IntStream input);
public String toString();
}Usage Examples:
// Handling set-based matching errors
try {
parser.statement();
} catch (MismatchedSetException e) {
System.err.println("Expected one of: " + e.expecting.toString(tokenNames));
System.err.println("But found: " + e.token.getText());
} catch (MismatchedNotSetException e) {
System.err.println("Did not expect: " + e.token.getText());
System.err.println("Forbidden tokens: " + e.expecting.toString(tokenNames));
}Exceptions for alternative selection and character range failures.
/**
* Exception when no alternative matches
*/
public class NoViableAltException extends RecognitionException {
public int decisionNumber;
public int stateNumber;
public NoViableAltException();
public NoViableAltException(String grammarDecisionDescription,
int decisionNumber,
int stateNumber,
IntStream input);
public String toString();
}
/**
* Exception for character range mismatch
*/
public class MismatchedRangeException extends RecognitionException {
public int a;
public int b;
public MismatchedRangeException();
public MismatchedRangeException(int a, int b, IntStream input);
public String toString();
}
/**
* Exception for early exit from loops
*/
public class EarlyExitException extends RecognitionException {
public int decisionNumber;
public EarlyExitException();
public EarlyExitException(int decisionNumber, IntStream input);
public String toString();
}Usage Examples:
// Handling decision-making exceptions
try {
parser.expression();
} catch (NoViableAltException e) {
System.err.println("No viable alternative at decision " + e.decisionNumber);
System.err.println("State: " + e.stateNumber);
System.err.println("Input: " + e.token.getText());
} catch (EarlyExitException e) {
System.err.println("Early exit from decision " + e.decisionNumber);
System.err.println("At least one iteration required");
}Exceptions for semantic predicates and tree parsing failures.
/**
* Exception for failed predicate evaluation
*/
public class FailedPredicateException extends RecognitionException {
public String ruleName;
public String predicateText;
public FailedPredicateException();
public FailedPredicateException(IntStream input, String ruleName, String predicateText);
public String toString();
}
/**
* Exception for tree node mismatch
*/
public class MismatchedTreeNodeException extends RecognitionException {
public int expecting;
public MismatchedTreeNodeException();
public MismatchedTreeNodeException(int expecting, TreeNodeStream input);
public String toString();
}Usage Examples:
// Handling semantic and tree parsing exceptions
try {
parser.constrainedRule();
} catch (FailedPredicateException e) {
System.err.println("Predicate failed in rule: " + e.ruleName);
System.err.println("Predicate: " + e.predicateText);
System.err.println("At line: " + e.line);
} catch (MismatchedTreeNodeException e) {
System.err.println("Expected tree node type: " + e.expecting);
System.err.println("But found: " + e.getUnexpectedType());
}Attempt to recover by inserting or deleting a single token.
// In BaseRecognizer
protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow)
throws RecognitionException {
// Try single token deletion
if (mismatchIsUnwantedToken(input, ttype)) {
UnwantedTokenException e = new UnwantedTokenException(ttype, input);
beginResync();
input.consume(); // Delete current token
endResync();
reportError(e);
Object matchedSymbol = getCurrentInputSymbol(input);
input.consume(); // Move past the token we are recovering from
return matchedSymbol;
}
// Try single token insertion
if (mismatchIsMissingToken(input, follow)) {
Object inserted = getMissingSymbol(input, null, ttype, follow);
MissingTokenException e = new MissingTokenException(ttype, input, inserted);
reportError(e);
return inserted;
}
// Could not recover
throw new MismatchedTokenException(ttype, input);
}Usage Examples:
// Custom single token recovery
public class MyParser extends Parser {
@Override
protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow)
throws RecognitionException {
// Log recovery attempt
System.err.println("Attempting single token recovery for type: " + ttype);
// Try standard recovery
try {
return super.recoverFromMismatchedToken(input, ttype, follow);
} catch (RecognitionException e) {
// Custom recovery logic
System.err.println("Standard recovery failed, using custom strategy");
throw e;
}
}
}Skip tokens until a safe recovery point is found.
// In BaseRecognizer
public void recover(IntStream input, RecognitionException re) {
if (state.lastErrorIndex == input.index()) {
// Ensure we consume at least one token to avoid infinite loops
input.consume();
}
state.lastErrorIndex = input.index();
BitSet followSet = computeErrorRecoverySet();
beginResync();
consumeUntil(input, followSet);
endResync();
}
protected void consumeUntil(IntStream input, BitSet set) {
int ttype = input.LA(1);
while (ttype != Token.EOF && !set.member(ttype)) {
input.consume();
ttype = input.LA(1);
}
}Usage Examples:
// Custom panic mode recovery
public class MyParser extends Parser {
@Override
public void recover(IntStream input, RecognitionException re) {
System.err.println("Entering panic mode recovery");
// Create custom recovery set
BitSet recoverySet = new BitSet();
recoverySet.add(SEMICOLON);
recoverySet.add(RBRACE);
recoverySet.add(EOF);
// Skip until recovery token
beginResync();
while (input.LA(1) != Token.EOF && !recoverySet.member(input.LA(1))) {
System.err.println("Skipping: " + input.LT(1).getText());
input.consume();
}
endResync();
System.err.println("Recovery complete at: " + input.LT(1).getText());
}
}Calculate recovery points based on grammar structure.
// In BaseRecognizer
protected BitSet computeErrorRecoverySet() {
return combineFollows(false);
}
protected BitSet computeContextSensitiveRuleFOLLOW() {
return combineFollows(true);
}
protected BitSet combineFollows(boolean exact) {
int top = state._fsp;
BitSet followSet = new BitSet();
for (int i = top; i >= 0; i--) {
BitSet localFollowSet = state.following[i];
followSet.or(localFollowSet);
if (exact && !localFollowSet.member(Token.EOR_TOKEN_TYPE)) {
break;
}
}
followSet.remove(Token.EOR_TOKEN_TYPE);
return followSet;
}Override error message formatting for better user experience.
// In BaseRecognizer
public String getErrorMessage(RecognitionException e, String[] tokenNames) {
String msg;
if (e instanceof MismatchedTokenException) {
MismatchedTokenException mte = (MismatchedTokenException)e;
msg = "mismatched input " + getTokenErrorDisplay(e.token) +
" expecting " + getTokenErrorDisplay(mte.expecting, tokenNames);
} else if (e instanceof MismatchedTreeNodeException) {
MismatchedTreeNodeException mtne = (MismatchedTreeNodeException)e;
msg = "mismatched tree node: " + mtne.node +
" expecting " + getTokenErrorDisplay(mtne.expecting, tokenNames);
} else if (e instanceof NoViableAltException) {
msg = "no viable alternative at input " + getTokenErrorDisplay(e.token);
} else if (e instanceof EarlyExitException) {
msg = "required (...)+ loop did not match anything at input " + getTokenErrorDisplay(e.token);
} else if (e instanceof MismatchedSetException) {
MismatchedSetException mse = (MismatchedSetException)e;
msg = "mismatched input " + getTokenErrorDisplay(e.token) +
" expecting set " + mse.expecting;
} else if (e instanceof MismatchedNotSetException) {
MismatchedNotSetException mse = (MismatchedNotSetException)e;
msg = "mismatched input " + getTokenErrorDisplay(e.token) +
" expecting set " + mse.expecting;
} else if (e instanceof FailedPredicateException) {
FailedPredicateException fpe = (FailedPredicateException)e;
msg = "rule " + fpe.ruleName + " " + fpe.predicateText;
} else {
msg = super.getErrorMessage(e, tokenNames);
}
return msg;
}Usage Examples:
// Custom error message formatting
public class MyParser extends Parser {
@Override
public String getErrorMessage(RecognitionException e, String[] tokenNames) {
StringBuilder buf = new StringBuilder();
// Add context information
buf.append("Parse error at line ").append(e.line);
buf.append(", column ").append(e.charPositionInLine).append(": ");
// Add specific error details
if (e instanceof MismatchedTokenException) {
MismatchedTokenException mte = (MismatchedTokenException)e;
buf.append("Expected '").append(tokenNames[mte.expecting]);
buf.append("' but found '").append(e.token.getText()).append("'");
} else {
buf.append(super.getErrorMessage(e, tokenNames));
}
// Add suggestions
buf.append("\nSuggestion: Check for missing semicolon or bracket");
return buf.toString();
}
@Override
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
String hdr = getErrorHeader(e);
String msg = getErrorMessage(e, tokenNames);
// Custom error display with colors/formatting
System.err.println("\u001B[31m" + hdr + " " + msg + "\u001B[0m");
// Show error context
if (e.token != null) {
showErrorContext(e.token);
}
}
private void showErrorContext(Token errorToken) {
// Display source line with error position highlighted
System.err.println("Source: " + getSourceLine(errorToken.getLine()));
System.err.print(" ");
for (int i = 0; i < errorToken.getCharPositionInLine(); i++) {
System.err.print(" ");
}
System.err.println("^");
}
}Implement custom error handling strategies.
public interface ErrorListener {
void syntaxError(Recognizer recognizer, Object offendingSymbol,
int line, int charPositionInLine, String msg, RecognitionException e);
}
// Custom error collector
public class ErrorCollector implements ErrorListener {
private List<SyntaxError> errors = new ArrayList<>();
@Override
public void syntaxError(Recognizer recognizer, Object offendingSymbol,
int line, int charPositionInLine, String msg, RecognitionException e) {
errors.add(new SyntaxError(line, charPositionInLine, msg, e));
}
public List<SyntaxError> getErrors() {
return errors;
}
public boolean hasErrors() {
return !errors.isEmpty();
}
}public class RobustParser extends MyParser {
private List<String> errors = new ArrayList<>();
@Override
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
String msg = getErrorHeader(e) + " " + getErrorMessage(e, tokenNames);
errors.add(msg);
// Continue parsing after error
try {
recover(input, e);
} catch (Exception recovery) {
// Recovery failed, give up
throw new RuntimeException("Cannot recover from parse error", e);
}
}
public List<String> getErrors() {
return errors;
}
public boolean hasErrors() {
return !errors.isEmpty();
}
}// Parse with maximum error tolerance
public ParseResult parseWithErrors(String input) {
ANTLRStringStream stream = new ANTLRStringStream(input);
MyLexer lexer = new MyLexer(stream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
RobustParser parser = new RobustParser(tokens);
Object tree = null;
try {
tree = parser.program().getTree();
} catch (RecognitionException e) {
// Even if parsing fails, collect partial results
System.err.println("Parsing failed but collected " +
parser.getErrors().size() + " errors");
}
return new ParseResult(tree, parser.getErrors());
}// Recovery that attempts multiple strategies
@Override
public void recover(IntStream input, RecognitionException re) {
// Try different recovery strategies in order
if (tryStatementRecovery(input, re)) return;
if (tryExpressionRecovery(input, re)) return;
if (tryBlockRecovery(input, re)) return;
// Fall back to standard recovery
super.recover(input, re);
}
private boolean tryStatementRecovery(IntStream input, RecognitionException re) {
BitSet stmtSet = new BitSet();
stmtSet.add(IF); stmtSet.add(WHILE); stmtSet.add(FOR);
stmtSet.add(SEMICOLON); stmtSet.add(RBRACE);
return consumeUntilSet(input, stmtSet);
}Install with Tessl CLI
npx tessl i tessl/maven-org-antlr--antlr-runtime