c-warning:2减少/减少yacc语法中的冲突[-Wconflicts-rr]



我有以下yacc语法:

%{
#include  <stdio.h>
extern FILE* yyin;
extern char* yytext;
%}
%token VAR ID_NAME TYPE_STRING TYPE_BOOL TYPE_NUMBER
%token CONST VALUE_STRING VALUE_BOOL VALUE_NUMBER
%%
program
: declarations
;
declarations
: declaration
| declarations declaration
;
declaration
: var_declaration
| const_declaration
;
value
: VALUE_BOOL
| VALUE_STRING
| VALUE_NUMBER
;
assignment
: ID_NAME '=' value
;
assignments
: assignment
| assignments ',' assignment
;
id_list
: ID_NAME
| id_list ',' ID_NAME
;
declaration_expression
: assignments
| id_list
| assignments ',' declaration_expression
| id_list ',' declaration_expression
;
var_declaration
: VAR ':' type declaration_expression ';' { printf("%s varn", $1);  } 
;
const_declaration: CONST ':' type assignments ';' {printf("constn");}
;
type: TYPE_NUMBER 
| TYPE_STRING
| TYPE_BOOL
;
%%
void yyerror (char const *s) {
fprintf (stderr, "%sn", s);
}
int main(int argc, char** argv[])
{
yyparse();
return 0;
}

它应该描述一种允许形式为var:<type> <variables_names or variables_initializations>const:<type> <constants_initialization>的变量和常量声明的小语言。

我想添加对以下语法的支持:

var:<type> var1, var2=<value>, var3;

类似这样的东西:var:<type> (<variables_names>|<variable_initializations>)+

为了实现这一点,我在语法中添加了以下修改:

assignments
: assignment
| assignments ',' assignment
;
id_list
: ID_NAME
| id_list ',' ID_NAME
;
declaration_expression
: assignments
| id_list
| assignments ',' declaration_expression
| id_list ',' declaration_expression
;

我认为这将启用(<variables_names>|<variable_initializations>)+部分。但我遇到了reduce/reduce冲突,原因是以下几行:

| assignments ',' declaration_expression
| id_list ',' declaration_expression

我做错了什么?

如果我理解正确,您希望在var声明中混合使用裸变量名和变量初始化,并且只允许在const声明中进行初始化。这很直接:

initialization : ID '=' value
init_list      : initialization | init_list ',' initialization
init_or_id     : initialization | ID
init_or_id_list: init_or_id
| init_or_id_list ',' init_or_id
const_declaration: CONST ':' type init_list
var_declaration  : VAR   ':' type init_or_id_list

你做错的是用列表扩展混合列表,而不是用items来扩展混合列表。这是不明确的,所以它会导致减少/减少冲突。

上面的方法(和你原来的方法一样)是有效的,因为init_listinit_or_id_list在派生中永远不会出现在同一点(作为非终端)。其中一个明确地遵循const关键字,另一个明确遵循var关键字。这是幸运的,因为一份纯粹的任务列表将满足两部作品的需求,如果它们共享一个上下文,就会产生减少/减少冲突。这个问题也是可以解决的,由于它偶尔会出现,我会添加解决方案,尽管我强调它与这个特定问题无关。(不过,这可能与后来遇到类似问题的读者有关。)

为了使两种可能的列表语法变得明确,有必要确保潜在的纯赋值列表始终是从混合列表派生出的不同产品。所以我们可以写:

init_list: initialization | init_list initialization
init_or_id_list: ID
| init_list ',' ID
| init_or_id_list ',' init_or_id

现在,init_or_id_list必须包含至少一个ID项,因此不能将其与init_list混淆。但现在我们使用最终结果,我们需要记住,接受混合列表的上下文需要允许两种列表可能性:

pure_list: init_list
mixed_list: init_list | init_or_id_list

最新更新