当我在规则的中间放置代码{printf(“something”);}时,我有这个警告,如果我放在规则的末尾,我没有错误,一切正常。< / p>
这会在tittle中抛出警告并抛出1次移位/减少冲突
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");};
%%
抱歉我的英语不好(如果你能用西班牙语回答,那就更好了)
答案 0 :(得分:1)
bison manual解释了这种情况。基本上,使用中规则操作(MRA) - 即规则中间的操作 - 会降低解析器将减少决策推迟到规则末尾的能力。实际上,在解析中的那一点,语法必须是可预测的,就像它是LL(1)语法一样。因此,只有在必要时才应使用MRA。
具体而言,请考虑以下两个备选方案(截断):
sent_asig: ID {printf("something");} ASIG exp …
| ID ASIG CTE_STRING …
现在,假设解析器只识别ID
,输入流中的下一个标记为ASIG
。此时,解析器需要决定是否执行MRA { printf("something"); }
。在幕后,执行MRA与减少标记非终端(右侧为空的终端)相同,因此解析器必须决定是否执行缩减。但它还没有足够的信息;在看到 ASIG
之后的令牌是否为CTE_STRING
之前,无法做出决定。所以解决方案需要两个先行令牌。
这是一个转移/减少冲突:解析器无法决定是否转移 ASIG
或减少标记(执行MRA)。由于bison / yacc解析器总是通过移位解决移位/减少冲突,因此减少将永远不会发生; MRA无法执行,包含它的右侧被有效阻止。因此警告。
请注意,您无法通过在两个点插入相同的MRA来解决问题:
sent_asig: ID {printf("something");} ASIG exp …
| ID {printf("something");} ASIG CTE_STRING …
即使MRA相同,bison / yacc也会为这两个规则插入不同的标记,这会产生减少/减少冲突。通过选择输入文件中较早出现的缩减来解决减少/减少冲突,因此分辨率将与文件中的默认分辨率不同,但它仍会阻止一个(或多个)规则,因此您仍会看到相同的警告。
如果您只是想看看解析器正在做什么,我强烈建议您删除所有这些printfs,而是依赖于bison's built-in trace facility,这非常容易启用(和禁用),以及更全面地了解了解析的进展情况。
答案 1 :(得分:0)
解决这种冲突的一种优雅方式,尤其是当两个动作相同时,是使用一个空的产生式和一个称为子例程的动作。
subroutine:
%empty { prepare_for_local_variables (); }
;
compound:
subroutine '{' declarations statements '}'
| subroutine '{' statements '}'
;