use*_*288 3 compiler-construction yacc lex bison flex-lexer
如何在不使用%prec或%left的情况下在Bison中设置优先级和关联性?有没有办法在不需要的地方编写语法?
如果您不想使用%prec,%left和%right,则必须使用多个非终结符来建立优先级.
例如,考虑这个语法:
%token NUMBER
%left '+'
%left '*'
%right '^'
%%
expression
: NUMBER
| expression '+' expression
| expression '*' expression
| expression '^' expression
| '(' expression ')'
;
%%
Run Code Online (Sandbox Code Playgroud)
让我们看看它与表达式的匹配程度1 + 2 * 3.如果我们从上面的语法中删除优先级指令,那么语法可以通过两种方式匹配此表达式.这是一种方式:
expression(+)
|
+-- expression(NUMBER 1)
|
+-- expression(*)
|
+-- expression(NUMBER 2)
|
+-- expression(NUMBER 3)
Run Code Online (Sandbox Code Playgroud)
这是另一种方式:
expression(*)
|
+-- expression(+)
| |
| +-- expression(NUMBER 1)
| |
| +-- expression(NUMBER 2)
|
+-- expression(NUMBER 3)
Run Code Online (Sandbox Code Playgroud)
我们想写一个只能像第一种方式匹配的语法,其中*绑定比第一种方式更紧密+.我们必须创建新的非终结符并将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
;
Run Code Online (Sandbox Code Playgroud)
让我们看看这个语法如何匹配表达式1 + 2 * 3.它只能以这种方式匹配:
expression
|
+-- additionExpression
|
+-- additionExpression
| |
| +-- multiplicationExpression
| |
| +-- exponentiationExpression
| |
| +-- primaryExpression(NUMBER 1)
|
+-- multiplicationExpression
|
+-- multiplicationExpression
| |
| +-- exponentiationExpression
| |
| +-- primaryExpression(NUMBER 2)
|
+-- exponentiationExpression
|
+-- primaryExpression(NUMBER 3)
Run Code Online (Sandbox Code Playgroud)
虽然现在解析树中有更多级别,但它匹配所需的绑定优先级.
如果你想用这种方式编写你的语法,请记住,LALR解析器在处理正确的递归时通常比处理左递归时使用更多的内存.因此,通常将右递归(用于exponentiationExpression)重写为左递归,并修复代码中的关联性.