有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我目前正在使用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) 个答案

  1. # 1 楼答案

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

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

    如果没有EOF,解析器将true读取为布尔值,而忽略其余部分