ANTLR:以编程方式运行解析器时,将忽略语法错误

时间:2011-07-13 11:39:16

标签: java eclipse-plugin antlr antlr3

我目前正在使用ANTLR创建一个或多或少简单的表达式求值程序。

我的语法很简单(至少我希望如此),看起来像这样:

grammar SXLGrammar;

options {
  language = Java;
  output   = AST;
}

tokens {
  OR  = 'OR';
  AND = 'AND';
  NOT = 'NOT';
  GT  = '>'; //greater then
  GE  = '>='; //greater then or equal
  LT  = '<'; //lower then
  LE  = '<='; //lower then or equal
  EQ  = '=';
  NEQ = '!='; //Not equal
  PLUS = '+';
  MINUS = '-';
  MULTIPLY = '*';
  DIVISION = '/';
  CALL;
}

@header {
package somepackage;
}

@members {

}


@lexer::header {
package rise.spics.sxl;
}

rule
  :  ('='|':')! expression 
  ;

expression
    : booleanOrExpression
    ;

booleanOrExpression
    :
    booleanAndExpression ('OR'^ booleanAndExpression)*
    ;

booleanAndExpression
  :
  booleanNotExpression ('AND'^ booleanNotExpression)*
  ;

booleanNotExpression
  :
  ('NOT'^)? booleanAtom
  ;

booleanAtom
  :
  | compareExpression
  ;

compareExpression
    :
    commonExpression (('<' | '>' | '=' | '<=' | '>=' | '!=' )^ commonExpression)?
    ;

commonExpression
  :
  multExpr
  (
    (
      '+'^
      | '-'^
    )
    multExpr
  )*
  | DATE
  ;

multExpr
  :
  atom (('*'|'/')^ atom)*
  | '-'^ atom
  ;

atom
  :
  INTEGER
  | DECIMAL
  | BOOLEAN
  | ID
  | '(' expression ')' -> expression
  | functionCall
  ;

functionCall
  :
  ID '(' arguments ')' -> ^(CALL ID arguments?)
  ;

arguments
  :
  (expression) (','! expression)*
  |  WS
  ;

BOOLEAN
  :
  'true'
  | 'false'
  ;

ID
  :
  (
    'a'..'z'
    | 'A'..'Z'
  )+
  ;

INTEGER
  :
  ('0'..'9')+ 
  ;

DECIMAL
  :
  ('0'..'9')+ ('.' ('0'..'9')*)?
  ;

DATE
  :
  '!' '0'..'9' '0'..'9' '0'..'9' '0'..'9' '-' '0'..'9' '0'..'9' '-' '0'..'9' '0'..'9' (' ' '0'..'9' '0'..'9' ':''0'..'9' '0'..'9' (':''0'..'9' '0'..'9')?)?
  ;

WS
  :  (' '|'\t' | '\n' | '\r' | '\f')+ { $channel = HIDDEN; };

现在,如果我尝试解析像“= true NOT true”这样的无效表达式,则eclipse插件的图形化测试工具会抛出NoViableAltException:第1:6行在输入“NOT”时没有可行的替代方法,这是正确的,假设

现在,如果我尝试在Java程序中解析表达式,则没有任何反应。该计划

    String expression = "=true NOT false";

    CharStream input = new ANTLRStringStream(expression);
    SXLGrammarLexer lexer = new SXLGrammarLexer(input);
    TokenStream tokenStream = new CommonTokenStream(lexer);
    SXLGrammarParser parser = new SXLGrammarParser(tokenStream);
    CommonTree tree = (CommonTree) parser.rule().getTree();
    System.out.println(tree.toStringTree());
    System.out.println(parser.getNumberOfSyntaxErrors());

会输出:

true
0

这意味着,解析器创建的AST存在一个节点而忽略其余节点。我想在我的应用程序中处理语法错误,但如果生成的解析器没有发现任何错误,则无法实现。

我还尝试通过用以下方法覆盖displayRecognitionError()方法来改变解析器:

public void displayRecognitionError(String[] tokenNames,
                                    RecognitionException e) {
    String msg = getErrorMessage(e, tokenNames);
    throw new RuntimeException("Error at position "+e.index+" " + msg);
} 

但是从不调用displayRecognitionError。

如果我尝试“= 1 +”之类的东西,则会显示错误。我猜我的语法有问题,但是为什么eclipse插件会抛出那个错误,而生成的解析器却没有?

1 个答案:

答案 0 :(得分:4)

如果您希望rule使用整个令牌流,则必须指定您希望输入结束的位置。像这样:

rule
  :  ('='|':')! expression EOF
  ;

如果没有EOF,你的解析器会将true读为布尔值而忽略其余的。