【问题标题】:warning: rule useless in parser due to conflicts: $@1: /* empty */警告:由于冲突,解析器中的规则无用:$@1: /* empty */
【发布时间】:2017-10-22 07:16:55
【问题描述】:

当我将代码 {printf("something");} 放在规则的中间时,我有这个警告,如果我把代码放在规则的末尾,我没有错误并且一切正常。

这会在标题中抛出警告并抛出 1 shift/reduce 冲突

sent_asig: ID {printf("something");} ASIG exp  {printf("sent_asig: ID ASIG exp \n");}
| ID ASIG CTE_STRING {printf("sent_asig: ID ASIG CTE_STRING \n");}
| ID ASIG CTE_STRING CONCAT ID {printf("sent_asig: ID ASIG CTE_STRING CONCAT ID \n");}
| ID ASIG ID CONCAT CTE_STRING {printf("sent_asig: ID ASIG ID CONCAT CTE_STRING \n");};

而且这不会抛出警告和 0 冲突,工作正常

sent_asig: ID ASIG exp  {printf("sent_asig: ID ASIG exp \n");}
| ID ASIG CTE_STRING {printf("sent_asig: ID ASIG CTE_STRING \n");}
| ID ASIG CTE_STRING CONCAT ID {printf("sent_asig: ID ASIG CTE_STRING CONCAT ID \n");}
| ID ASIG ID CONCAT CTE_STRING {printf("sent_asig: ID ASIG ID CONCAT CTE_STRING \n");};

如果有人想查看完整的规则,因为可能在其他部分是这个错误的根源,这里是

%token ID
%token CTE
%token ABREPAR
%token FINPAREN
%token AND
%token OR
%token COMA
%token ASIG
%token COMP
%token RESTASIG
%token CONCAT
%token SUMASIG
%token MULTASIG
%token DIVASIG
%token MENOR_IGU
%token MENOR
%token MAYOR_IGU
%token MAYOR
%token NOT
%token DIST
%token CTE_REAL
%token CTE_STRING

%token DO
%token IF
%token ENDIF
%token ELSE
%token PUT
%token GET
%token DECLARE
%token ENDDECLARE
%token BEGIN
%token ENDPROGRAM
%token INT
%token REAL
%token STRING
%token REPEAT
%token CONST

%left AND OR
%left OP_SUM OP_RESTA
%left OP_MULT
%left OP_DIV 
%right ASIG
%right SUMASIG 
%right RESTASIG 
%right MULTASIG 
%right DIVASIG 

%% 

programa: BEGIN declar sentencias ENDPROGRAM {printf("programa: BEGIN declar sentencias ENDPROGRAM \n");}
| BEGIN sentencias ENDPROGRAM {printf("programa: BEGIN sentencias ENDPROGRAM \n");};

sentencias: sentencia {printf("sentencia: sentencia \n");}
    |  sentencias sentencia {printf("sentencias: sentencia \n");};
sentencia:  sent_asig {printf("sentencia: sent_asig\n");}
    | sent_mult_asig {printf("sentencia: sent_mult_asig\n");}
    | sent_sum_asig {printf("sentencia: sent_sum_asig");}
    | sent_rest_asig {printf("sentencia: sent_rest_asig \n");}
    | sent_div_asig {printf("sentencia: sent_div_asig \n");}
    | asig_const {printf("sentencia: asig_const \n");}
    | entrada {printf("sentencia: entrada \n");}
    | salida {printf("sentencia: salida \n");}
    | sent_if {printf("sentencia: sent_if \n");}
    | sent_repeat {printf("sentencia: sent_repeat \n");};
sent_asig: ID {printf("something");} ASIG exp  {printf("sent_asig: ID ASIG exp \n");}
    | ID ASIG CTE_STRING {printf("sent_asig: ID ASIG CTE_STRING \n");}
    | ID ASIG CTE_STRING CONCAT ID {printf("sent_asig: ID ASIG CTE_STRING CONCAT ID \n");}
    | ID ASIG ID CONCAT CTE_STRING {printf("sent_asig: ID ASIG ID CONCAT CTE_STRING \n");};
exp:     exp OP_SUM ter {printf("exp: exp OP_SUM ter\n");escribirPolaca("+");}
    | exp OP_RESTA ter {printf("exp: exp OP_RESTA ter\n");escribirPolaca("-");}
    | ter {printf("exp: ter\n");};

ter: ter OP_MULT factor {printf("ter: ter OP_MULT factor\n");escribirPolaca("*");}
    | ter OP_DIV factor {printf("ter: ter OP_DIV factor\n");escribirPolaca("/");}
    | factor {printf("ter: factor\n");};
factor: ID {printf("factor: ID\n"); escribirPolaca(Simbolos[nosalemal][0]);}
    | CTE {printf("factor: CTE\n");escribirPolaca(Simbolos[nosalemal][1]);}
    | CTE_REAL {printf("factor: CTE_REAL \n");escribirPolaca("CTE_REAL");};
    | ABREPAR exp FINPAREN {printf("factor: ABREPAR exp FINPAREN\n");}
sent_sum_asig : ID SUMASIG ID {printf("factor: sent_sum_asig \n");}
    | ID SUMASIG CTE {printf("factor: ID SUMASIG CTE  \n");}
    | ID SUMASIG CTE_REAL {printf("factor: ID SUMASIG CTE_REAL \n");} ;
sent_rest_asig : ID RESTASIG ID {printf("sent_rest_asig: ID RESTASIG ID \n");}
    | ID RESTASIG CTE {printf("sent_rest_asig: ID RESTASIG CTE \n");}
    | ID RESTASIG CTE_REAL {printf("sent_rest_asig: ID RESTASIG CTE_REAL \n");};
sent_mult_asig : ID MULTASIG ID {printf("sent_mult_asig: ID MULTASIG ID \n");}
    | ID MULTASIG CTE {printf("sent_mult_asig: ID MULTASIG CTE \n");}
    | ID MULTASIG CTE_REAL {printf("sent_mult_asig: ID MULTASIG CTE_REAL \n");};
sent_div_asig : ID DIVASIG ID {printf("sent_div_asig: ID DIVASIG ID \n");}
    | ID DIVASIG CTE {printf("sent_div_asig : ID DIVASIG ID \n");}
    | ID DIVASIG CTE_REAL {printf("sent_div_asig: ID DIVASIG ID \n");};
declar: DECLARE declaraciones  ENDDECLARE {printf("declar: DECLARE declaraciones  ENDDECLARE \n");};
declaraciones: dec {printf("declaraciones: dec \n");}
    | dec declaraciones {printf("declaraciones: dec declaraciones \n");};
dec: REAL var {printf("dec: REAL var \n");} 
    | INT var {printf("dec: INT var \n");} 
    | STRING var {printf("dec: STRING var \n");} ; 
var: ID {printf("var: ID \n");}
    | ID COMA var {printf("var: ID COMA var \n");};
asig_const: CONST ID ASIG CTE {printf("asig_const: CONST ID ASIG CTE \n");}
    | CONST ID ASIG CTE_REAL {printf("asig_const: CONST ID ASIG CTE_REAL \n");} 
    | CONST ID ASIG CTE_STRING {printf("asig_const: CONST ID ASIG CTE_STRING \n");};
entrada: PUT CTE_STRING {printf("entrada: PUT CTE_STRING \n");}
    | PUT ID {printf("entrada: PUT ID \n");};
salida: GET ID {printf("salida: GET ID \n");};
sent_if: IF ABREPAR condicion FINPAREN sentencias ENDIF {printf("sent_if: IF ABREPAR condicion FINPAREN sentencias ENDIF \n");}
    | IF ABREPAR condicion FINPAREN sentencias ELSE sentencias ENDIF {printf("sent_if: IF ABREPAR condicion FINPAREN sentencias ELSE sentencias ENDIF \n");}
condicion: cond {printf("condicion: cond \n");}
    | cond AND cond {printf("condicion: cond AND cond\n");}
    | cond OR cond {printf("condicion: cond OR cond \n");}
    | NOT cond {printf("condicion: NOT cond \n");};
cond: exp MENOR exp {printf("cond: exp MENOR exp \n");apilarPilaIteracion(posicionVectorPolaca);escribirPolaca("CMP");posicionVectorPolaca++;}
    | exp MAYOR exp {printf("cond: exp MENOR exp \n");}
    | exp MENOR_IGU exp {printf("cond: exp MENOR exp \n");}
    | exp MAYOR_IGU exp {printf("cond: exp MENOR exp \n");}
    | exp COMP exp {printf("cond: exp MENOR exp \n");escribirPolaca("CMP");}
    | exp DIST exp {printf("cond: exp MENOR exp \n");}
sent_repeat: DO sentencias REPEAT ABREPAR condicion FINPAREN {printf("sent_repeat: DO sentencias REPEAT ABREPAR condicion FINPAREN \n");};
%%

对不起,我的英语不好(如果你能用西班牙语回答,那就更好了)

【问题讨论】:

    标签: parsing syntax bison yacc shift-reduce-conflict


    【解决方案1】:

    bison manual 中解释了这种情况。基本上,使用中间规则动作(MRA)——即在规则中间的动作——会降低解析器将归约决策推迟到规则末尾的能力。实际上,在解析的那个点,文法必须是可预测的,就好像它是 LL(1) 文法一样。因此,只有在绝对必要时才应使用 MRA。

    具体来说,只考虑以下两个备选方案(截断):

    sent_asig: ID {printf("something");} ASIG exp …
             | ID ASIG CTE_STRING …
    

    现在,假设解析器刚刚识别出ID,输入流中的下一个标记是ASIG。此时,解析器需要决定是否执行MRA{ printf("something"); }。在幕后,执行 MRA 与缩减标记非终端(右侧为空的终端)相同,因此解析器必须决定是否执行缩减。但它还没有足够的信息;在查看令牌following ASIG 是否为CTE_STRING 之前,无法做出决定。所以解析需要两个前瞻标记。

    这是一个移位/减少冲突:解析器无法决定是 shift ASIG 还是减少标记(以执行 MRA)。由于 bison/yacc 解析器总是通过移位来解决移位/归约冲突,因此归约永远不会发生; MRA 无法执行,包含它的右侧被有效阻止。因此发出警告。

    请注意,您无法通过在两个点插入相同的 MRA 来解决问题:

    sent_asig: ID {printf("something");} ASIG exp …
             | ID {printf("something");} ASIG CTE_STRING …
    

    即使 MRA 相同,bison/yacc 也会为这两个规则插入不同的标记,这会产生 reduce/reduce 冲突。减少/减少冲突通过选择输入文件中较早出现的减少来解决,因此分辨率将与文件中的默认分辨率不同,但它仍会阻止一个(或多个)规则,因此您仍然会看到相同的警告。


    如果您只是想查看解析器在做什么,我强烈建议您删除所有这些 printfs,并改用 bison's built-in trace facility,它非常容易启用(和禁用),并且提供了更完整地了解解析的进展情况。

    【讨论】:

      【解决方案2】:

      解决这种冲突的一种优雅方法,尤其是当两个动作相同时,是使用一个空产生式和一​​个称为子例程的单个动作。

      subroutine:
        %empty  { prepare_for_local_variables (); }
      ;
      
      compound:
        subroutine '{' declarations statements '}'
      | subroutine '{' statements '}'
      ;
      

      这里有更多信息: https://www.gnu.org/software/bison/manual/html_node/Mid_002dRule-Conflicts.html#Mid_002dRule-Conflicts

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-09
        相关资源
        最近更新 更多