I have developed a complex grammar using Antlr 3 using AST tree. ANTLR generates the Lexer and Parser. The problem is that when the user enters a syntax that is not valid for example, the grammar is expecting ';'. The user does not enter this, then in my Eclipse IDE I get the following Exception:
line 1:24 mismatched input '<EOF>' expecting ';'
How can this Exception be handled because I try to catch this Exception, but the Exception is not catched. Is this an Exception at all? I don't seem to understand why this Exception is not caught. I tried to find out, however the Antlr website seems to be down for some time now.
I looked at the following: ANTLR exception handling with "$", Java and followed that example, but when the Lexer generates the code by adding the RuntimeException(), I get unreachable code.
I am not sure what to do.
When I try to get the number of syntax errors from the parser it displays 0.
EDIT:
I have found a solution that works by looking at: ANTLR not throwing errors on invalid input
However, when I try to get the Exception message back, it is null. Have I set everything up correctly? Please see sample grammar:
grammar i;
options {
output=AST;
}
@header {
package com.data;
}
@rulecatch {
catch(RecognitionException e) {
throw e;
}
}
// by having these below it makes no difference
/**@parser::members {
@Override
public void reportError(RecognitionException e) {
throw new RuntimeException("Exception : " + " " + e.getMessage());
}
}
@lexer::members {
@Override
public void reportError(RecognitionException e) {
throw new RuntimeException("Exception : " + " " + e.getMessage());
}
}*/
EDIT:
Please see what I have so far:
grammar i;
options {
output=AST;
}
@header {
package com.data;
}
@rulecatch {
// ANTLR does not generate its normal rule try/catch
catch(RecognitionException e) {
throw e;
}
}
@parser::members {
@Override
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
String hdr = getErrorHeader(e);
String msg = getErrorMessage(e, tokenNames);
throw new RuntimeException(hdr + ":" + msg);
}
}
@lexer::members {
@Override
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
String hdr = getErrorHeader(e);
String msg = getErrorMessage(e, tokenNames);
throw new RuntimeException(hdr + ":" + msg);
}
}
operatorLogic : 'AND' | 'OR';
value : STRING;
query : (select)*;
select : 'SELECT'^ functions 'FROM table' filters?';';
operator : '=' | '!=' | '<' | '>' | '<=' | '>=';
filters : 'WHERE'^ conditions;
members : STRING operator value;
conditions : (members (operatorLogic members)*);
functions : '*';
STRING : ('a'..'z'|'A'..'Z')+;
WS : (' '|'\t'|'\f'|'\n'|'\r')+ {skip();}; // handle white space between keywords
public class Processor {
public Processor() {
}
/**
* This method builds the MQL Parser.
* @param args the args.
* @return the built IParser.
*/
private IParser buildMQLParser(String query) {
CharStream cs = new ANTLRStringStream(query);
// the input needs to be lexed
ILexer lexer = new ILexer(cs);
CommonTokenStream tokens = new CommonTokenStream();
IParser parser = new IParser(tokens);
tokens.setTokenSource(lexer);
// use the ASTTreeAdaptor so that the grammar is aware to build tree in AST format
parser.setTreeAdaptor((TreeAdaptor) new ASTTreeAdaptor().getASTTreeAdaptor());
return parser;
}
/**
* This method parses the MQL query.
* @param query the query.
*/
public void parseMQL(String query) {
IParser parser = buildMQLParser(query);
CommonTree commonTree = null;
try {
commonTree = (CommonTree) parser.query().getTree();
}
catch(Exception e) {
System.out.println("Exception :" + " " + e.getMessage());
}
}
}
public class ASTTreeAdaptor {
public ASTTreeAdaptor() {
}
/**
* This method is used to create a TreeAdaptor.
* @return a treeAdaptor.
*/
public Object getASTTreeAdaptor() {
TreeAdaptor treeAdaptor = new CommonTreeAdaptor() {
public Object create(Token payload) {
return new CommonTree(payload);
}
};
return treeAdaptor;
}
}
So when I enter the following: SELECT * FROM table
without a ';' I get the a MismatchedTokenException:
catch(Exception e) {
System.out.println("Exception : " + " " e);
}
When I try:
e.getMessage();
it returns null.
Try overriding
displayRecognitionError
instead:If you want to track errors rather than abort, you could create a handler interface to track them:
The error tracker could then decide whether to throw an exception or continue.
The code above allows you to track "recoverable" errors, errors that ANTLR can skip over. There are still scenarios that produce unrecoverable errors, such as
SELECT * FROM table
(without the ending;
). In that case, you'll have to catch the exceptions inparseMQL
or somewhere around there. (You could try writing your own recovery code, but I wouldn't recommend that you do.)Here is a modified
parseMQL
that shows the two different types of parsing errors. Note that I removed the call togetMessage
because not all exceptions derived off ofRecognitionException
fill it in.Input
SELECT * FROM table
produces message "Fatal mismatched token exception: expected ';' but was <EOF>". This exception was produced directly by ANTLR.Input
SELECT FROM table;
produces message "Other exception : line 1:7:missing '*' at 'FROM table'". This exception was produced by the code above.If I understand correctly you want to handle your language syntax errors. This is how I have this setup on my project.
Here is the Error Node
And this is how this is all glued together.
We simply created our lexer and parser then we setup our parser with custom Tree adapter (PhantomTreeAdaptor). From there we can check if we have errors in our custom code.