我正在学习yacc,而我从书中得到的这段代码片段似乎没有正确应用优先级规则。
这是yacc文件:
%{
#include <stdio.h>
extern int yylex();
void yyerror (char const *msg);
%}
%token NAME NUMBER
%left '+' '-'
%left '*' '/'
%%
statement: NAME '=' expression
| expression { printf("= %d\n", $1); }
;
expression: expression '+' NUMBER { $$ = $1 + $3; }
| expression '-' NUMBER { $$ = $1 - $3; }
| expression '*' NUMBER { $$ = $1 * $3; }
| expression '/' NUMBER { if ($3) $$ = $1 / $3;
else yyerror("divide by zero"); }
| '-' expression { $$ = -$2; }
| '(' expression ')' { $$ = $2; }
| NUMBER { $$ = $1; }
;
%%
这是lex:
%{
#include "y.tab.h"
#include <stdio.h>
extern int yylval;
%}
%%
[0-9]+ { yylval = atoi(yytext); return NUMBER; }
[ \t] { ; }
\n { return 0; }
. { return yytext[0]; }
%%
我用以下代码编译它:
lex foo.l
yacc -d foo.y
clang -o foo lex.yy.c y.tab.c -ly -ll
运行乘法 - 首先给出正确的答案:
> ./foo
3 * 2 + 1
= 7
但是当乘法发生在第二位时,它给出了错误的答案:
> ./foo
4 + 5 * 2
= 18
在yacc文件中添加行%left '+' '-'
和%left '*' '/'
应该解决这个问题,但他们没有。谁能告诉我为什么?
答案 0 :(得分:2)
但是你对作品的说明是错误的。它应该是expression '+' expression
而不是expression '+' NUMBER
(并且在每个运算符的情况下类似),i。即双方都是表达,你不想禁止添加两个表达,你呢。
答案 1 :(得分:1)
优先规则仅用于解决语法中的歧义。如果你的语法直接编码优先级,那么优先级规则就没有歧义。
将语法定义为expr: expr op NUMBER
将所有运算符的优先级定义为相同,并严格按从左到右的方式对其进行求值。您希望为每个运算符将语法定义为expr: expr op expr
,以便语法不明确,并且优先级规则可以解决歧义。