Antlr处理exception

我使用AST树使用Antlr 3开发了一个复杂的语法。 ANTLR生成Lexer和Parser。 问题是当用户输入例如无效的语法时,语法期望’;’。 用户没有输入,然后在我的Eclipse IDE中我得到以下exception:

line 1:24 mismatched input '' expecting ';' 

如何处理此exception,因为我试图捕获此exception,但是没有捕获exception。 这是一个例外吗? 我似乎不明白为什么没有抓到这个exception。 我试图找出答案,但Antlr网站现在似乎已经停止了一段时间。

我查看了以下内容: 使用“$”和Java进行ANTLRexception处理并遵循该示例,但是当Lexer通过添加RuntimeException()生成代码时,我得到了无法访问的代码。

我不知道该怎么做。

当我尝试从解析器中获取语法错误的数量时,它显示0。

编辑:

我找到了一个解决方案,通过查看: ANTLR不会在无效输入上抛出错误

但是,当我尝试获取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, 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; } } 

所以当我输入以下内容时:SELECT * FROM table

没有 ‘;’ 我得到一个MismatchedTokenException:

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

当我尝试:

 e.getMessage(); 

它返回null。

请尝试覆盖displayRecognitionError

 @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 

如果要跟踪错误而不是中止,可以创建一个处理程序接口来跟踪它们:

 @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 

然后,错误跟踪器可以决定是抛出exception还是继续。


上面的代码允许您跟踪“可恢复”错误,ANTLR可以跳过的错误。 仍然存在产生不可恢复错误的情况,例如SELECT * FROM table (没有结尾; )。 在这种情况下,您必须在parseMQL或其周围的某处捕获exception。 (您可以尝试编写自己的恢复代码,但我不建议您这样做。)

这是一个修改过的parseMQL ,它显示了两种不同类型的解析错误。 请注意,我删除了对getMessage的调用,因为并非所有从RecognitionException派生的exception都会填充它。

 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 ? "" : iParser.tokenNames[e.expecting]; String found = e.getUnexpectedType() == -1 ? "" : 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 table产生消息“致命不匹配令牌exception:预期’;’ 但是“。 此exception由ANTLR直接生成。

输入SELECT FROM table; 产生消息“其他例外:第1:7行:””””””””””””” 此exception由上面的代码生成。

如果我理解正确,您希望处理语言语法错误。 这就是我在项目中进行此设置的方法。

 /** * 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); } } 

这是错误节点

 /** * 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(); } } 

这就是这一切都粘在一起的方式。

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

我们只是创建了词法分析器和解析器,然后使用自定义树适配器(PhantomTreeAdaptor)设置解析器。 从那里我们可以检查我们的自定义代码是否有错误。