【问题标题】:warning: 2 reduce/reduce conflicts [-Wconflicts-rr] in yacc grammar警告:yacc 语法中的 2 个减少/减少冲突 [-Wconflicts-rr]
【发布时间】:2017-01-16 19:26:56
【问题描述】:

我有以下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:&lt;type&gt; &lt;variables_names or variables_initializations&gt;const:&lt;type&gt; &lt;constants_initialization&gt;

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

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

类似这样的:var:&lt;type&gt; (&lt;variables_names&gt;|&lt;variable_initializations&gt;)+

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

assignments
    : assignment
    | assignments ',' assignment
    ;

id_list
    : ID_NAME
    | id_list ',' ID_NAME
    ;

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

我认为这将启用 (&lt;variables_names&gt;|&lt;variable_initializations&gt;)+ 部分。但是由于以下几行,我遇到了reduce/reduce 冲突:

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

我做错了什么?

【问题讨论】:

  • 我认为你的第一个 sn-p 是在非工作修改之后。如果您仍然有工作版本,那将很有帮助。
  • @rici 这是最后一个工作的版本pastebin.com/xb9V3N8G。但是,它只支持以下形式的变量声明:var:&lt;type&gt; &lt;variables_names&gt; | &lt;initializations&gt;。它不允许将variables_namesinitializations 混合使用。
  • 我认为这就是它的样子,但我不确定。谢谢。不过,为了清楚起见,最好编辑您的问题。 “我使用了 declaration_expression 的定义:”(来自 pastebin),但我想更改它,以便 var 声明可以是混合项的列表,可以是 ID 或分配。所以我将其更改为:“(来自当前问题),这给了我减少/减少冲突..

标签: c parsing bison yacc


【解决方案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

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

上面的工作(和你原来的一样)因为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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多