我有一个小的自定义脚本语言,我试图更新它以允许布尔表达式,如a > 2
和a > 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
,但这就是我遇到这个左递归错误的地方。
那么,我如何处理括号并避免左递归问题?
答案 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})
进入以下解析树: