By default a org.antlr.v4.runtime.Parser
instance, as a subclass of org.antlr.v4.runtime.Recognizer
, will have a org.antlr.v4.runtime.ConsoleErrorListener
attached to it. Error messages will be piped through this listener and out to System.err
, where they will be lost forever.
You can silence this output by calling removeErrorListeners()
before parsing, and if you want to capture the error messages for parsing and display, you can add a custom BaseErrorListener
implementation.
Here’s a simple one that keeps every error in a List
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
public class DSLErrorListener extends BaseErrorListener { private List<SyntaxErrorItem> items; public DSLErrorListener ( ) { this.items = new ArrayList<SyntaxErrorItem>(); } @Override public void syntaxError ( Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e ) { items.add ( new SyntaxErrorItem ( line, charPositionInLine, msg, offendingSymbol, e ) ); } public boolean hasErrors ( ) { return this.items.size() > 0; } @Override public String toString ( ) { if ( !hasErrors() ) return "0 errors"; StringBuilder builder = new StringBuilder(); for ( SyntaxErrorItem s : items ) { builder.append ( String.format ( "%s\n", s ) ); } return builder.toString(); } } class SyntaxErrorItem { private int line; private Object offendingSymbol; private int column; private String msg; private RecognitionException oops; SyntaxErrorItem ( int line, int column, String msg, Object symbol, RecognitionException oops ) { this.line = line; this.column = column; this.msg = msg; this.offendingSymbol = symbol; this.oops = oops; } @Override public String toString() { if ( oops == null ) return String.format ( "[%d:%d] %s", line, column, msg ); else { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter ( sw ); oops.printStackTrace(pw); pw.close(); return String.format ( "[%d:%d] %s\n%s", line, column, msg, sw.toString() ); } } } |
You would add it to a Parser
using the addErrorListener
method.
Here’s a complete example:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
ANTLRInputStream input = ...; Lexer lexer = ...; CommonTokenStream tokens = new CommonTokenStream ( lexer ); DSLErrorListener errorListener = new DSLErrorListener(); Parser parser = ...; parser.removeErrorListeners(); parser.addErrorListener ( errorListener ); ParseTree tree = ...; // Usually the parser subclass top-level rule name if ( errorListener.hasErrors() ) System.err.printf( "%s\n", errorListener ); // Or parse the errors: up to you else { ParseTreeWalker walker = new ParseTreeWalker(); // Walk the tree or visit it } |