Antlr处理异常

use*_*481 7 java error-handling antlr

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

 line 1:24 mismatched input '<EOF>' expecting ';'
Run Code Online (Sandbox Code Playgroud)

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

我查看了以下内容:使用"$"和Java进行ANTLR异常处理并遵循该示例,但是当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());
    }
}*/
Run Code Online (Sandbox Code Playgroud)

编辑:

请看看我到目前为止:

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; 
}
}
Run Code Online (Sandbox Code Playgroud)

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

没有 ';' 我得到一个MismatchedTokenException:

catch(Exception e) {
     System.out.println("Exception : " + " " e);
}
Run Code Online (Sandbox Code Playgroud)

当我尝试:

e.getMessage();
Run Code Online (Sandbox Code Playgroud)

它返回null.

use*_*210 5

尝试重写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
Run Code Online (Sandbox Code Playgroud)

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

@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
Run Code Online (Sandbox Code Playgroud)

然后,错误跟踪器可以决定是抛出异常还是继续.


上面的代码允许您跟踪"可恢复"错误,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());
    }
}
Run Code Online (Sandbox Code Playgroud)

输入SELECT * FROM table产生消息"致命的不匹配的令牌异常:预期的';' 但是<EOF>".此异常由ANTLR直接生成.

输入SELECT FROM table;产生消息"其他异常:第1行:7:在'FROM table''缺少'*'." 此异常由上面的代码生成.