我正在编写一个支持任意布尔表达式的语法。语法用于表示程序,该程序稍后通过静态分析工具传递。静态分析工具有一定的局限性,因此我想应用以下重写规则:
严格的不等式用epsilon近似:
expression_a > expression_b -> expression_a >= expression_b + EPSILON
使用“或”语句近似不等式:
expression_a != expression_b -> expression_a > expression_b || expression_a < expression_b
使用ANTLR有没有简单的方法?目前我的语法是这样的:
comparison : expression ('=='^|'<='^|'>='^|'!='^|'>'^|'<'^) expression;
我不确定如何应用不同的重写规则,具体取决于运算符。我希望树保持不变,如果运算符是(“==”,“&lt; =”或“&gt; =”)并按照上面定义的规则以递归方式转换它。
答案 0 :(得分:3)
[...]并以递归方式转换它,[...]
你可以部分地做到这一点。
您无法告诉ANTLR将a > b
重写为^('>=' a ^('+' b epsilon))
,然后将a != b
定义为^('||' ^('>' a b) ^('<' a b))
,然后让ANTLR自动重写^('>' a b)
和^('<' a b)
分别为^('>=' a ^('+' b epsilon))
和^('<=' a ^('-' b epsilon))
。
这里需要一些手工工作。诀窍在于,如果实际未解析此令牌,则不能仅使用>=
之类的令牌。解决此问题的方法是使用imaginary tokens。
快速演示:
grammar T;
options {
output=AST;
}
tokens {
AND;
OR;
GTEQ;
LTEQ;
SUB;
ADD;
EPSILON;
}
parse
: expr
;
expr
: logical_expr
;
logical_expr
: comp_expr ((And | Or)^ comp_expr)*
;
comp_expr
: (e1=mult_expr -> $e1) ( Eq e2=mult_expr -> ^(AND ^(GTEQ $e1 $e2) ^(LTEQ $e1 $e2))
| LtEq e2=mult_expr -> ^(LTEQ $e1 $e2)
| GtEq e2=mult_expr -> ^(GTEQ $e1 $e2)
| NEq e2=mult_expr -> ^(OR ^(GTEQ $e1 ^(ADD $e2 EPSILON)) ^(LTEQ $e1 ^(SUB $e2 EPSILON)))
| Gt e2=mult_expr -> ^(GTEQ $e1 ^(ADD $e2 EPSILON))
| Lt e2=mult_expr -> ^(LTEQ $e1 ^(SUB $e2 EPSILON))
)?
;
add_expr
: mult_expr ((Add | Sub)^ mult_expr)*
;
mult_expr
: atom ((Mult | Div)^ atom)*
;
atom
: Num
| Id
| '(' expr ')'
;
Eq : '==';
LtEq : '<=';
GtEq : '>=';
NEq : '!=';
Gt : '>';
Lt : '<';
Or : '||';
And : '&&';
Mult : '*';
Div : '/';
Add : '+';
Sub : '-';
Num : '0'..'9'+ ('.' '0'..'9'+)?;
Id : ('a'..'z' | 'A'..'Z')+;
Space : ' ' {skip();};
从上面的语法生成的解析器将产生以下内容:
a == b
a != b
a > b
a < b