帮助左保理语法分解以删除左递归

时间:2011-07-08 19:22:36

标签: antlr grammar left-recursion

我有一个小的自定义脚本语言,我试图更新它以允许布尔表达式,如a > 2a > 2 and (b < 3 or c > 5)。这是我在这里遇到麻烦的括号表达式。

这是一个(基于@Bart Kiers答案的原始帖子编辑后)完整语法,展示了这个问题。这是我实际语法的一个简化版本,但问题也出现在这里。

grammar test;


options {
    language = 'JavaScript'; 
    output = AST;
} 


statement 
    :   value_assignment_statement  
        EOF
    ;


value_assignment_statement 
    :   IDENT
        '='
        expression                      
    ;

value_expression 
    :   value_list_expression           
    |   IDENT                           
    ;


value_list_expression 
    :   value_enumerated_list       
    ;


value_enumerated_list : '{' unary+ '}'
    ;



term 
    :   LPAREN expression RPAREN        
    |   INTEGER                         
    |   value_expression                
    ;

unary : ( '+' | '-' )* term
    ;

mult :  unary ( ('*' | '/') unary)*
    ;

expression : mult ( ('+' | '-') mult )*
    ;


boolean 
    :   boolean_expression
        EOF
    ;

boolean_expression
    :   boolean_or_expression
    ;

boolean_or_expression 
    :   boolean_and_expression (OR boolean_and_expression)*
    ;

boolean_and_expression 
    :   boolean_rel_expression (AND boolean_rel_expression)*
    ;

boolean_rel_expression
    :   boolean_neg_expression relational_operator boolean_neg_expression
    ;

boolean_neg_expression 
    :   (NOT)? atom
    ;

atom
    :   LPAREN boolean_expression RPAREN
    //| expression
    ;


relational_operator : '=' | '>' | '<';


LPAREN      :   '(';
RPAREN      :   ')';
AND         :   'and';
OR          :   'or';
NOT         :   'not';
IDENT       :   LETTER LETTER+;
INTEGER     :   DIGIT+;
WS          :   (' ' | '\n' | '\r' | '\t')+     { $channel = HIDDEN; };

fragment DIGIT      : '0'..'9';
fragment LETTER     : ('a'..'z' | 'A'..'Z');

我尝试容纳a > 2 or (b < 3)这样的括号布尔表达式是atom规则中的注释掉的行。当我取消注释这一行并将其包含在语法中时,ANTLR会给我这个错误:

  由于可以从alts 1,2到达的递归规则调用,

[致命]规则atom具有非LL(*)决策。通过左因子分解或使用句法谓词或使用backtrack = true选项来解析。

我想通过删除递归来解决这个问题,但我似乎无法从Wikipedia description on how to remove left recursion转换到我自己的东西。

在使用这个语法时,我希望有时使用statement作为根,输入如abc = 2 + 3,它为一个名为abc的变量赋值。其他时候我想使用语法来评估boolean作为根的表达式,例如abc > 3 and (xyz < 5 or xyz > 10)。当我尝试将@Bart的答案用作模型时,它工作正常,直到我尝试将statement使用的语法部分与boolean使用的部分合并。他们都应该能够使用expression,但这就是我遇到这个左递归错误的地方。

那么,我如何处理括号并避免左递归问题?

1 个答案:

答案 0 :(得分:11)

布尔表达式与加法和乘法表达式相同,因此不应与它们分开。以下是如何考虑所有类型的表达式:

grammar test;

parse
  :  expression EOF
  ;

expression 
  :  or
  ;

or
  :  and (OR and)*
  ;

and
  :  rel (AND rel)*
  ;

rel
  :  add (('=' | '>' | '<') add)*
  ;

add
  :  mult (('+' | '-') mult)*
  ;

mult
  :  unary (('*' | '/') unary)*
  ;

unary 
  :  '-' term
  |  '+' term
  |  NOT term
  |  term
  ;

term 
  :  INTEGER  
  |  IDENT       
  |  list
  |  '(' expression ')'
  ;

list 
  :  '{' (expression (',' expression)*)? '}'
  ;

AND     :  'and';
OR      :  'or';
NOT     :  'not';
IDENT   :  LETTER LETTER*;
INTEGER :  DIGIT+;
WS      :  (' ' | '\n' | '\r' | '\t')+  { $channel = HIDDEN; };

fragment DIGIT   : '0'..'9';
fragment LETTER  : ('a'..'z' | 'A'..'Z');

将解析示例输入:

abc > 3 and (xyz < 5 or xyz > {1, 2, 3})

进入以下解析树:

enter image description here