我使用AST树使用Antlr 3开发了一个复杂的语法. ANTLR生成Lexer和Parser.问题是当用户输入例如无效的语法时,语法期望’;’.用户没有输入,然后在我的
Eclipse IDE中我得到以下异常:
line 1:24 mismatched input '<EOF>' expecting ';'
如何处理此异常,因为我试图捕获此异常,但是没有捕获异常.这是一个例外吗?我似乎不明白为什么没有抓到这个异常.我试图找出答案,但Antlr网站现在似乎已经停止了一段时间.
我查看了以下内容:ANTLR exception handling with “$”,Java并遵循该示例,但是当Lexer通过添加RuntimeException()生成代码时,我得到了无法访问的代码.
我不知道该怎么做.
编辑:
我找到了一个解决方案,通过查看:ANTLR not throwing errors on invalid input
但是,当我尝试获取Exception消息时,它为null.我是否正确设置了一切?请参阅示例语法:
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()); } }*/
编辑:
请看看我到目前为止:
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,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; } }
所以当我输入以下内容时:
SELECT * FROM表
没有 ‘;’我得到一个MismatchedTokenException:
catch(Exception e) { System.out.println("Exception : " + " " e); }
当我尝试:
e.getMessage();
它返回null.
解决方法
请尝试覆盖displayRecognitionError:
@parser::members { ... @Override public void displayRecognitionError(String[] tokenNames,tokenNames); throw new RuntimeException(hdr + ":" + msg); } ... } //same code in @lexer::members
如果要跟踪错误而不是中止,可以创建一个处理程序接口来跟踪它们:
@parser::members { ... private YourErrorTrackerInterface errorTracker; //getter/setter for errorTracker here @Override public void displayRecognitionError(String[] tokenNames,tokenNames); if (errorTracker != null){ errorTracker.addError(e,tokenNames,hdr,msg); } } ... } //same code in @lexer::members
然后,错误跟踪器可以决定是抛出异常还是继续.
上面的代码允许您跟踪“可恢复”错误,ANTLR可以跳过的错误.仍然存在产生不可恢复错误的情况,例如SELECT * FROM table(没有结尾;).在这种情况下,您必须在parseMQL或其周围的某处捕获异常. (您可以尝试编写自己的恢复代码,但我不建议您这样做.)
这是一个修改过的parseMQL,它显示了两种不同类型的解析错误.请注意,我删除了对getMessage的调用,因为并非所有从RecognitionException派生的异常都会填充它.
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()); } }
输入SELECT * FROM表产生消息“致命不匹配令牌异常:预期’;’但是< EOF>“.此异常由ANTLR直接生成.