这可能是一个简单的问题,已经有人提出过,但是我在理解Bison尤其是运算符优先级方面遇到困难。如果我有此代码,而+
有left association
。
%left '+'
%%
S:
S E ’\n’ { printf("%d\n", $2); }
|
;
E:
num { $$ = $1; }
| E '+' E {$$ = $1 + $3;}
| E '*' E {$$ = $1 * $3;}
;
%%
输入为2+3+4*5
,输出为25。我的回答是45。
有人可以一步一步告诉我野牛做什么吗?我的意思是如何将元素推入堆栈以及如何以及何时减少它们。甚至可能是解析树。
答案 0 :(得分:3)
查看语法的最简单方法是启用野牛的跟踪工具,如bison manual section on debugging parsers中所述。在读取跟踪时,将状态机放在手边很有用,因为跟踪提供了通过状态机的路径。要查看状态机,请使用bison的-v
选项,该选项将创建扩展名为.output
的文件。
$ cat minimal.y
%{
#include <stdio.h>
#include <ctype.h>
int yylex(void);
void yyerror(const char* msg) {
fprintf(stderr, "%s\n", msg);
}
%}
%token num
%left '+'
%%
S: S E '\n' { printf("%d\n", $2); }
|
E: num { $$ = $1; }
| E '+' E {$$ = $1 + $3;}
| E '*' E {$$ = $1 * $3;}
%%
int yylex(void) {
int c;
do c = getchar(); while (c == ' ');
if (isdigit(c)) {
yylval = c - '0';
return num;
}
return c == EOF ? 0 : c;
}
int main(int argc, char* argv[]) {
#if YYDEBUG
yydebug = 1;
#endif
return yyparse();
}
编译并运行:
$ bison -t -v -o minimal.c minimal.y
minimal.y: warning: 3 shift/reduce conflicts [-Wconflicts-sr]
$ gcc -Wall -o minimal minimal.c
$ ./minimal <<<'2+3+4*5'
Starting parse
Entering state 0
Reducing stack by rule 2 (line 14):
-> $$ = nterm S ()
Stack now 0
我删除了踪迹(尽管您可以在答案的底部看到它)。在跟踪中查找表示正在读取令牌*
的行:
Entering state 8
Reading a token: Next token is token '*' ()
Shifting token '*' ()
Entering state 7
这是minimal.output
中状态8的定义,并带有平移-减少冲突(由将不采取操作的方括号表示)和默认分辨率:
State 8
4 E: E . '+' E
4 | E '+' E .
5 | E . '*' E
'*' shift, and go to state 7
'*' [reduce using rule 4 (E)]
$default reduce using rule 4 (E)
这是完整的跟踪记录(尽管我强烈建议您在自己的计算机上进行实验):
Starting parse
Entering state 0
Reducing stack by rule 2 (line 14):
-> $$ = nterm S ()
Stack now 0
Entering state 1
Reading a token: Next token is token num ()
Shifting token num ()
Entering state 3
Reducing stack by rule 3 (line 16):
$1 = token num ()
-> $$ = nterm E ()
Stack now 0 1
Entering state 4
Reading a token: Next token is token '+' ()
Shifting token '+' ()
Entering state 5
Reading a token: Next token is token num ()
Shifting token num ()
Entering state 3
Reducing stack by rule 3 (line 16):
$1 = token num ()
-> $$ = nterm E ()
Stack now 0 1 4 5
Entering state 8
Reading a token: Next token is token '+' ()
Reducing stack by rule 4 (line 17):
$1 = nterm E ()
$2 = token '+' ()
$3 = nterm E ()
-> $$ = nterm E ()
Stack now 0 1
Entering state 4
Next token is token '+' ()
Shifting token '+' ()
Entering state 5
Reading a token: Next token is token num ()
Shifting token num ()
Entering state 3
Reducing stack by rule 3 (line 16):
$1 = token num ()
-> $$ = nterm E ()
Stack now 0 1 4 5
Entering state 8
Reading a token: Next token is token '*' ()
Shifting token '*' ()
Entering state 7
Reading a token: Next token is token num ()
Shifting token num ()
Entering state 3
Reducing stack by rule 3 (line 16):
$1 = token num ()
-> $$ = nterm E ()
Stack now 0 1 4 5 8 7
Entering state 9
Reading a token: Next token is token '\n' ()
Reducing stack by rule 5 (line 18):
$1 = nterm E ()
$2 = token '*' ()
$3 = nterm E ()
-> $$ = nterm E ()
Stack now 0 1 4 5
Entering state 8
Next token is token '\n' ()
Reducing stack by rule 4 (line 17):
$1 = nterm E ()
$2 = token '+' ()
$3 = nterm E ()
-> $$ = nterm E ()
Stack now 0 1
Entering state 4
Next token is token '\n' ()
Shifting token '\n' ()
Entering state 6
Reducing stack by rule 1 (line 13):
$1 = nterm S ()
$2 = nterm E ()
$3 = token '\n' ()
25
-> $$ = nterm S ()
Stack now 0
Entering state 1
Reading a token: Now at end of input.
Shifting token $end ()
Entering state 2
Stack now 0 1 2
Cleanup: popping token $end ()
Cleanup: popping nterm S ()