Exceptions for Antlr Handling

I developed complex grammar using Antlr 3 using the AST tree. ANTLR generates Lexer and Parser. The problem is that when the user enters syntax that is invalid, for example, the grammar expects ';'. 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 I handle this exception because I'm trying to catch this exception, but the exception is not caught. Is this an exception? I don't seem to understand why this exception is not caught. I tried to find out, however the Antlr website does not seem to be working for a long time.

I looked at the following: handling ANTLR exceptions with "$", Java, and followed this example, but when Lexer throws code by adding a RuntimeException () exception, I get unreachable code.

I'm not sure what to do.

When I try to get the number of syntax errors from the parser, it displays 0.

EDIT:

I found a solution that works by looking at: ANTLR does not throw errors on invalid input

However, when I try to get an exception message, it is null. Have I set everything up correctly? 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:

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; } } 

Therefore, when I enter the following: SELECT * FROM table

without ';' I get a MismatchedTokenException:

 catch(Exception e) { System.out.println("Exception : " + " " e); } 

When I try:

 e.getMessage(); 

it returns null.

+7
source share
2 answers

Try overriding displayRecognitionError instead:

 @parser::members { ... @Override public void displayRecognitionError(String[] tokenNames, RecognitionException e) { String hdr = getErrorHeader(e); String msg = getErrorMessage(e, tokenNames); throw new RuntimeException(hdr + ":" + msg); } ... } //same code in @lexer::members 

If you want to track errors, not interrupt, you can create a handler interface to track errors:

 @parser::members { ... private YourErrorTrackerInterface errorTracker; //getter/setter for errorTracker here @Override public void displayRecognitionError(String[] tokenNames, RecognitionException e) { String hdr = getErrorHeader(e); String msg = getErrorMessage(e, tokenNames); if (errorTracker != null){ errorTracker.addError(e, tokenNames, hdr, msg); } } ... } //same code in @lexer::members 

Error tracking can then decide whether to exclude or continue.


The above code allows you to track "recoverable" errors, errors that ANTLR may skip. There are also scripts that create fatal errors, such as SELECT * FROM table (without ending ; ). In this case, you will have to catch the exceptions in parseMQL or somewhere else. (You can try writing your own recovery code, but I would not recommend doing it.)

Here is a modified parseMQL that shows two different types of parsing errors. Please note that I deleted the getMessage call because not all exceptions received from RecognitionException filled it.

 public void parseMQL(String query) { iParser parser = buildMQLParser(query); CommonTree commonTree = null; try { commonTree = (CommonTree) parser.query().getTree(); } catch (MismatchedTokenException e){ //not production-quality code, just forming a useful message String expected = e.expecting == -1 ? "<EOF>" : iParser.tokenNames[e.expecting]; String found = e.getUnexpectedType() == -1 ? "<EOF>" : iParser.tokenNames[e.getUnexpectedType()]; System.out.println("Fatal mismatched token exception: expected " + expected + " but was " + found); } catch (RecognitionException e) { System.out.println("Fatal recognition exception " + e.getClass().getName() + " : " + e); } catch (Exception e) { System.out.println("Other exception : " + e.getMessage()); } } 

Entering SELECT * FROM table displays the message "Fatal inappropriate token exception: expected"; but there was <EOF>. "This exception was directly received by ANTLR.

Entering SELECT FROM table; gives the message "Another exception: line 1: 7: missing * * 'in' FROM table '". This exception was thrown using the code above.

+5
source

If I understand correctly, you want to handle language syntax errors. This is how I have this setup in my project.

 /** * Adapter need for ANTL to recognize our custom nodes * * @author Greg */ public class PhantomTreeAdaptor extends CommonTreeAdaptor{ @Override public Object create(Token payload){ return new ASTNode(payload); } @Override public Object dupNode(Object old){ return (old == null) ? null : ((ASTNode) old).dupNode(); } @Override public Object errorNode(TokenStream input, Token start, Token stop, RecognitionException e){ return new ASTErrorNode(input, start, stop, e); } } 

Below is the Node error

 /** * This is our custom Error node used by the adapter. * * @author Greg */ public class ASTErrorNode extends ASTNode { org.antlr.runtime.tree.CommonErrorNode delegate; public ASTErrorNode(TokenStream input, Token start, Token stop, RecognitionException e) { delegate = new CommonErrorNode(input, start, stop, e); } public boolean isNil() { return delegate.isNil(); } public int getType() { return delegate.getType(); } public String getText() { return delegate.getText(); } public String toString() { return delegate.toString(); } } 

And this is how it is all glued together.

  final PhantomSQLLexer lex = new PhantomSQLLexer(input); final CommonTokenStream tokens = new CommonTokenStream(lex); final PhantomSQLParser g = new PhantomSQLParser(tokens); g.setTreeAdaptor(new PhantomTreeAdaptor()); final start_rule_return r = g.start_rule(); if (g.getNumberOfSyntaxErrors() == 0) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("tree=" + ((Tree) r.tree).toStringTree()); LOGGER.debug("-------------------------------------------"); } final ASTNode root = r.tree; exec(root); } else { LOGGER.debug("Error parsing input"); } 

We just created our lexer and parser, then we configure our parser using a custom tree adapter (PhantomTreeAdaptor). From there we can check to see if we have errors in our custom code.

+1
source

All Articles