Skip to main content
  1. Posts/

How to silence ANTLR4's error messages

·442 words·3 mins
Author
Christopher Taylor
A collection of interesting things I’ve seen, as I’ve seen them.

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`:

 1public class DSLErrorListener extends BaseErrorListener
 2{
 3    private List<SyntaxErrorItem> items;
 4    
 5    public DSLErrorListener ( )
 6    {
 7        this.items = new ArrayList<SyntaxErrorItem>();
 8    }
 9    
10    @Override
11    public void syntaxError ( Recognizer<?, ?> recognizer, 
12                               Object offendingSymbol, 
13                               int line, 
14                               int charPositionInLine, 
15                               String msg, 
16                               RecognitionException e )
17    {
18        items.add ( new SyntaxErrorItem ( line, 
19                                         charPositionInLine, 
20                                         msg, 
21                                         offendingSymbol, 
22                                         e ) 
23        );
24    }
25
26    public boolean hasErrors ( )
27    {
28        return this.items.size() > 0;
29    }
30    
31    @Override
32    public String toString ( )
33    {
34        if ( !hasErrors() ) return "0 errors";
35        StringBuilder builder = new StringBuilder();
36        for ( SyntaxErrorItem s : items )
37        {
38            builder.append ( String.format ( "%s\n", s ) );
39        }
40        return builder.toString();
41    }
42}
43
44class SyntaxErrorItem
45{
46    private int                  line;
47
48    private Object               offendingSymbol;
49
50    private int                  column;
51
52    private String               msg;
53
54    private RecognitionException oops;
55    
56    SyntaxErrorItem ( int line, 
57                      int column, 
58                      String msg, 
59                      Object symbol, 
60                      RecognitionException oops )
61    {
62        this.line = line;
63        this.column = column;
64        this.msg = msg;
65        this.offendingSymbol = symbol;
66        this.oops = oops;
67    }
68    
69    @Override
70    public String toString()
71    {
72        if ( oops == null ) return String.format ( "[%d:%d] %s", line, column, msg );
73        else {
74            StringWriter sw = new StringWriter();
75            PrintWriter pw = new PrintWriter ( sw );
76            oops.printStackTrace(pw);
77            pw.close();
78            return String.format ( "[%d:%d] %s\n%s", line, column, msg, sw.toString() );
79        }
80    }
81}

You would add it to a Parser using the addErrorListener method.

Here’s a complete example:

 1ANTLRInputStream input = ...;
 2Lexer lexer = ...;
 3CommonTokenStream tokens = new CommonTokenStream ( lexer );
 4DSLErrorListener errorListener = new DSLErrorListener();
 5Parser parser = ...;
 6parser.removeErrorListeners();
 7parser.addErrorListener ( errorListener );
 8ParseTree tree = ...; // Usually the parser subclass top-level rule name
 9if ( errorListener.hasErrors() ) System.err.printf( "%s\n", errorListener ); // Or parse the errors: up to you
10else {
11    ParseTreeWalker walker = new ParseTreeWalker(); 
12    // Walk the tree or visit it
13}

Related