警告:2在yacc语法中减少/减少冲突[-Wconflicts-rr]

时间:2017-01-16 19:26:57

标签: c parsing bison yacc

我有以下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 var\n", $1);  } 
    ;

const_declaration: CONST ':' type assignments ';' {printf("const\n");}
    ;

type: TYPE_NUMBER 
    | TYPE_STRING
    | TYPE_BOOL
    ;

%%
void yyerror (char const *s) {
    fprintf (stderr, "%s\n", 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

我做错了什么?

1 个答案:

答案 0 :(得分:1)

如果我理解正确,您希望在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

你做错了是通过使用列表扩展混合列表来制作混合列表,而不是使用。这是模棱两可的,因此会导致减少/减少冲突。

以上作品(与原作一样),因为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