在不使用 %prec 或 %left 的情况下,如何在 Bison 中设置优先级和关联性?有没有办法在不需要的地方编写语法?
2 回答
如果您不想使用%prec
,%left
和%right
,则必须使用多个非终结符来建立优先级。
例如,考虑以下语法:
%token NUMBER
%left '+'
%left '*'
%right '^'
%%
expression
: NUMBER
| expression '+' expression
| expression '*' expression
| expression '^' expression
| '(' expression ')'
;
%%
让我们看看它是如何匹配表达式的1 + 2 * 3
。如果我们从上面的文法中删除优先级指令,那么文法可以通过两种方式匹配这个表达式。这是一种方法:
expression(+)
|
+-- expression(NUMBER 1)
|
+-- expression(*)
|
+-- expression(NUMBER 2)
|
+-- expression(NUMBER 3)
这是另一种方式:
expression(*)
|
+-- expression(+)
| |
| +-- expression(NUMBER 1)
| |
| +-- expression(NUMBER 2)
|
+-- expression(NUMBER 3)
我们想编写一个只能像第一种方式那样匹配的语法,其中的*
绑定比+
. 我们必须创建新的非终结符并将expression
非终结符的产生式拆分到新的非终结符中,如下所示:
%token NUMBER
%%
primaryExpression
: NUMBER
| '(' expression ')'
;
exponentiationExpression
: primaryExpression
// Right-recursion makes this right-associative.
| primaryExpression '^' exponentiationExpression
;
multiplicationExpression
: exponentiationExpression
// Left recursion makes this left-associative.
| multiplicationExpression '*' exponentiationExpression
;
additionExpression
: multiplicationExpression
| additionExpression '+' multiplicationExpression
;
expression
: additionExpression
;
让我们看看这个语法如何匹配表达式1 + 2 * 3
。它只能这样匹配:
expression
|
+-- additionExpression
|
+-- additionExpression
| |
| +-- multiplicationExpression
| |
| +-- exponentiationExpression
| |
| +-- primaryExpression(NUMBER 1)
|
+-- multiplicationExpression
|
+-- multiplicationExpression
| |
| +-- exponentiationExpression
| |
| +-- primaryExpression(NUMBER 2)
|
+-- exponentiationExpression
|
+-- primaryExpression(NUMBER 3)
虽然现在解析树中有更多级别,但它匹配所需的绑定优先级。
如果您想以这种方式编写语法,请记住,LALR 解析器在处理右递归时通常比处理左递归时使用更多的内存。所以通常将右递归(在 中使用exponentiationExpression
)重写为左递归,并修复代码中的关联性。
是的——您可以对不同级别的优先级使用单独的规则,并通过左递归与右递归控制关联性。例如,要获得+
and-
的优先级低于*
and /
,一个左关联,另一个右关联1,您可以执行以下操作:
number: literal | variable;
mul_expr: number
| mul_expr MUL_OP number
;
add_expr: mul_expr
| mul_expr ADD_OP add_expr
;
是的,这确实是类似 yacc 的伪代码;我确信 yacc、byacc、Bison 等会按原样拒绝它。
1是的,这些通常都是左关联的,但我这样做只是为了演示如何根据需要制作右关联的东西。