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:预期’;’ 但是
输入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)设置解析器。 从那里我们可以检查我们的自定义代码是否有错误。