终结符说明:
数字 NUMBER
标识符 INDENTIFI
( LP
) RP
{ LC
} RC
功能需求:
args_list 是函数的参数列表,
实际用途中,可能有多个参数, 可能有1个参数,可能没有参数。
为了兼容上述情景,设计 args_list 的语法为下:
1:空,
2:单字符,
3:左边为1与2组合,右边单字符.
BNF 描述如下:
1 2 3 4
| args_list : | INDENTIFI | args_list INDENTIFI ;
|
问题描述:
YACC 解释时 有冲突!
YACC 文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| chunli@ubuntu:~/lab/yacc/$ cat example.y %{ #include <stdio.h>
%}
%token NUMBER INDENTIFI LP RP LC RC
%%
function_args :INDENTIFI LP args_list RP { // 函数的名形式, 形如下: // foo(int a, double b) // foo(const char *str) // foo(float) // foo() } ;
args_list : { // 允许参数匹配空参数 } | INDENTIFI { // 形如 int } | args_list INDENTIFI { // ... char } ;
%% chunli@ubuntu:~/lab/yacc/$
|
YACC 分析结果:
哦嚯?! YACC 有警告 …
1 2 3
| chunli@ubuntu:~/lab/yacc/$ yacc -v example.y example.y: warning: 1 shift/reduce conflict [-Wconflicts-sr] chunli@ubuntu:~/lab/yacc/$
|
YACC 异常分析
y.output 是 yacc 输出的调试信息文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| chunli@ubuntu:~/lab/yacc/$ vim y.output
State 3 conflicts: 1 shift/reduce
Grammar
0 $accept: function_args $end
1 function_args: INDENTIFI LP args_list RP
2 args_list: %empty 3 | INDENTIFI 4 | args_list INDENTIFI
...省略
State 3
1 function_args: INDENTIFI LP . args_list RP
INDENTIFI shift, and go to state 5
INDENTIFI [reduce using rule 2 (args_list)] $default reduce using rule 2 (args_list)
args_list go to state 6
|
分析:
$accept 代表当前输入的标记
$default 代表 向前看时下一个标记
$end 代表结束标记
可以看到 y.output文件头直接报告 状态3 存在 1 个 移进/规约 的 冲突
来看看 是什么地方导致的 shift/reduce conflicts ?
在 State 3 中
当遇到 INDENTIFI 标记,规约为 规则2(args_list)
当遇到 无论什么 标记,规约为 规则2(args_list)
再看看看 rule 2:
2 args_list: %empty
当遇到 INDENTIFI时, 要么向上规约为args_list, 要么向下移进。
那么到底是要 shift 还是 reduce呢 ?
改正之后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| chunli@ubuntu:~/lab/yacc/$ cat example.y %{ #include <stdio.h>
%}
%token NUMBER INDENTIFI LP RP LC RC
%% function_args :INDENTIFI LP args_list RP { // 函数的名形式, 形如下: // foo(int a, double b) // foo(const char *str) // foo(float) // foo() } ;
args_list : { // 允许参数匹配空参数 } | args_list INDENTIFI { // ... char } ; %% chunli@ubuntu:~/lab/yacc/$ yacc -v example.y chunli@ubuntu:~/lab/yacc/$
|
将 args_list中的规则删除一部分, 可以达到 上述功能需求。
改正之后的 args_list
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| args_list : { // 允许参数匹配空参数 // foo 为 function_的名字 // 匹配 foo()
} | args_list INDENTIFI { // foo 为 function_的名字 // 匹配 foo(int) // 匹配 foo(int a) // 匹配 foo(const int a) } ;
1. 支持参数为空,如 foo() 2. 支持参数1个, 如 foo(int) 2. 支持参数2个, 如 foo(int a) 2. 支持参数3个, 如 foo(const int a)
|