I'm not an expert and had never use error reporting until today, but if you just want a list of errors, you could do the following, inspired by chapter 9 of The Definitive ANTLR 4 Reference.
File Question.g4
:
grammar Question;
/* Detecting invalid input after a return statement. */
question
@init {System.out.println("Question last update 1302");}
: function+ EOF
;
function
: STRING OPEN statement_block CLOSE
;
statement_block
: statement* if_last? return_statement
;
statement
: PRINT expr
| IF expr THEN statement ELSE statement
| statement SEMICOLON statement
;
if_last
: IF expr THEN statement_block ELSE statement*
;
return_statement
: RETURN expr
;
expr
: DIGIT
| expr PLUS expr
| expr MINUS expr
| expr EQUALS expr
;
CLOSE : '}' ;
ELSE : 'else' ;
EQUALS : '==' ;
IF : 'if' ;
MINUS : '-' ;
OPEN : '{' ;
PLUS : '+' ;
PRINT : 'print' ;
RETURN : 'return' ;
THEN : 'then' ;
DIGIT : [0-9] ;
STRING : [a-zA-Z]+ ;
SEMICOLON : ';' ;
WS : [ \r\n\t] -> channel(HIDDEN) ;
File MyListener.java
:
public class MyListener extends QuestionBaseListener {
QuestionParser parser;
public MyListener(QuestionParser parser) { this.parser = parser; }
public void exitFunction(QuestionParser.FunctionContext ctx) {
System.out.println(">>> in MyListener for function");
System.out.println(parser.getTokenStream().getText(ctx));
}
}
File test.java
:
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.*;
public class test {
public static class UnderlineListener extends BaseErrorListener {
public void syntaxError(Recognizer<?, ?> recognizer,
Object offendingSymbol,
int line, int charPositionInLine,
String msg,
RecognitionException e)
{
System.err.println("line " + line + ":" + charPositionInLine + " " + msg);
underlineError(recognizer,(Token)offendingSymbol,
line, charPositionInLine);
}
protected void underlineError(Recognizer recognizer,
Token offendingToken, int line,
int charPositionInLine) {
CommonTokenStream tokens =
(CommonTokenStream)recognizer.getInputStream();
String input = tokens.getTokenSource().getInputStream().toString();
String[] lines = input.split("\n");
String errorLine = lines[line - 1];
System.err.println(errorLine);
for (int i=0; i<charPositionInLine; i++) System.err.print(" ");
int start = offendingToken.getStartIndex();
int stop = offendingToken.getStopIndex();
if ( start>=0 && stop>=0 ) {
for (int i=start; i<=stop; i++) System.err.print("^");
}
System.err.println();
}
}
public static void main(String[] args) throws IOException {
ANTLRInputStream input = new ANTLRFileStream(args[0]);
QuestionLexer lexer = new QuestionLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
QuestionParser parser = new QuestionParser(tokens);
parser.removeErrorListeners(); // remove ConsoleErrorListener
parser.addErrorListener(new UnderlineListener()); // add ours
ParseTree tree = parser.question();
System.out.println("---parsing ended");
ParseTreeWalker walker = new ParseTreeWalker();
MyListener my_listener = new MyListener(parser);
System.out.println(">>>> about to walk");
walker.walk(my_listener, tree);
}
}
File t.text
:
test { return 2+2 }
test { if 2 == 2 then return 2 else return 3 }
test { if 2 == 2 then print 2 else print 3 return 4 }
test {return 2; print 3}
test { if 2 == 2 then return 2; abc else return 3; def }
test { if 2 == 2 then if 6 then print 6 else print 3 else if 5 then
print 1; print 2 else print 3 return 4 }
Execution :
$ java test t.text
Question last update 1302
line 4:14 mismatched input ';' expecting {'}', '==', '-', '+'}
test {return 2; print 3}
^
line 5:30 mismatched input ';' expecting {'else', '==', '-', '+'}
test { if 2 == 2 then return 2; abc else return 3; def }
^
line 5:49 mismatched input ';' expecting {'}', '==', '-', '+'}
test { if 2 == 2 then return 2; abc else return 3; def }
^
---parsing ended
>>>> about to walk
>>> in MyListener for function
test { return 2+2 }
>>> in MyListener for function
test { if 2 == 2 then return 2 else return 3 }
>>> in MyListener for function
test { if 2 == 2 then print 2 else print 3 return 4 }
>>> in MyListener for function
test {return 2; print 3}
>>> in MyListener for function
test { if 2 == 2 then return 2; abc else return 3; def }
>>> in MyListener for function
test { if 2 == 2 then if 6 then print 6 else print 3 else if 5 then print 1; print 2 else print 3 return 4 }