在语法中找不到减少/减少冲突

ado*_*srs 1 parsing yacc bison

我写了以下语法,Bison 警告我有关归约/归约冲突。

\n\n
parser.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]\n
Run Code Online (Sandbox Code Playgroud)\n\n

如何检测语法的哪一部分产生了冲突?Bison 是否生成了日志,可以在其中查看冲突?还有,我该如何解决这个问题?

\n\n

语法:

\n\n
%left TK_OC_OR TK_OC_AND\n%left \'<\' \'>\' TK_OC_LE TK_OC_GE TK_OC_EQ TK_OC_NE\n%left \'+\' \'-\'\n%left \'*\' \'/\'\n\n%nonassoc LOWER_THAN_ELSE\n%nonassoc TK_PR_ELSE\n\n%start s\n\n%type<symbol> decl_var\n%type<symbol> cabecalho\n\n%%\n\ns: decl_global s\n  | def_funcao s\n  |\n  ;\n\ndecl_global: decl_var \';\'\n  | decl_vetor \';\'\n  | decl_var {error("Faltando o \';\' no final do comando.", $1->line); return IKS_SYNTAX_ERRO;}\n  ;\n\ndecl_local: decl_var \';\' decl_local\n   |\n   ;\n\ndecl_var\n  : tipo_var TK_IDENTIFICADOR {$$ = $2;}\n  ;\n\ndecl_vetor\n   : tipo_var TK_IDENTIFICADOR \'[\' TK_LIT_INT \']\'\n   ;\n\n\ntipo_var: TK_PR_INT\n        | TK_PR_FLOAT\n        | TK_PR_BOOL\n        | TK_PR_CHAR\n        | TK_PR_STRING\n        ;\n\ndef_funcao: cabecalho decl_local bloco_comando\n  | cabecalho decl_local bloco_comando \';\' {error("Declara\xc3\xa7\xc3\xa3o de fun\xc3\xa7\xc3\xa3o com \';\' no final do comando.\\n",$1->line); return IKS_SYNTAX_ERRO;} \n  ;\n\nchamada_funcao\n  : TK_IDENTIFICADOR \'(\' lista_expressoes \')\'\n  ;\n\ncabecalho: decl_var \'(\' lista_parametros \')\' {$$ = $1;}\n  ;\n\nlista_parametros: lista_parametros_nao_vazia\n  |\n  ;\n\nlista_parametros_nao_vazia: parametro \',\' lista_parametros_nao_vazia\n  | parametro\n  ;\n\nparametro: decl_var\n  ;\n\ncomando: bloco_comando\n  | controle_fluxo\n  | atribuicao\n  | entrada\n  | saida\n  | retorna\n  | decl_var \';\'\n  | chamada_funcao\n  | \';\'\n  ;\n\nbloco_comando: \'{\' seq_comando \'}\'\n  ;\n\nseq_comando: comando seq_comando\n  | comando\n  |\n  ;\n\natribuicao: TK_IDENTIFICADOR \'=\' expressao\n  | TK_IDENTIFICADOR \'[\' expressao \']\' \'=\' expressao\n  ;\n\nentrada\n  : TK_PR_INPUT TK_IDENTIFICADOR\n  ;\n\nsaida\n  : TK_PR_OUTPUT lista_expressoes_nao_vazia\n  ;\n\nlista_expressoes_nao_vazia: expressao \',\' lista_expressoes_nao_vazia\n  | expressao\n  ;\n\nretorna: TK_PR_RETURN expressao \';\'\n  ;\n\ncontrole_fluxo\n  : TK_PR_IF \'(\' expressao \')\' TK_PR_THEN comando %prec LOWER_THAN_ELSE\n  | TK_PR_IF \'(\' error \')\' TK_PR_THEN comando \n  | TK_PR_IF \'(\' expressao \')\' TK_PR_THEN comando TK_PR_ELSE comando\n  | TK_PR_WHILE \'(\' expressao \')\' TK_PR_DO comando\n  | TK_PR_DO comando TK_PR_WHILE \'(\' expressao \')\'\n  | TK_PR_DO comando TK_PR_WHILE \'(\' error \')\'\n  ;\n\nexpressao: TK_IDENTIFICADOR\n  | TK_IDENTIFICADOR \'[\' expressao \']\'\n  | TK_LIT_INT\n  | TK_LIT_FLOAT\n  | TK_LIT_FALSE\n  | TK_LIT_TRUE\n  | TK_LIT_CHAR\n  | TK_LIT_STRING\n  | expressao \'+\' expressao \n  | expressao \'-\' expressao \n  | expressao \'*\' expressao \n  | expressao \'/\' expressao \n  | expressao \'<\' expressao \n  | expressao \'>\' expressao \n  | \'+\' expressao\n  | \'-\' expressao\n  | \'(\' expressao \')\'\n  | expressao TK_OC_LE expressao\n  | expressao TK_OC_GE expressao\n  | expressao TK_OC_EQ expressao\n  | expressao TK_OC_NE expressao\n  | expressao TK_OC_AND expressao\n  | expressao TK_OC_OR expressao\n  | chamada_funcao\n  ;\n\nlista_expressoes: lista_expressoes_nao_vazia\n  |\n  ;\n
Run Code Online (Sandbox Code Playgroud)\n

ric*_*ici 5

如何检测语法的哪一部分产生了冲突?Bison 是否生成了日志,可以在其中查看冲突?还有,我该如何解决这个问题?

是的。如果您-v在 bison 命令行上使用,它将在名为 的文件中生成所有状态的报告<filename>.output。该报告将包括各种冲突,您可以从指示的状态中看到冲突的模式是什么。在阅读本答案的其余部分之前,您应该尝试一下。

如果你这样做,你就会看到问题:

seq_comando: comando seq_comando
  | comando
  |
  ;
Run Code Online (Sandbox Code Playgroud)

由于seq_comando可以为空,因此单个comando可以匹配:

seq_comando: comando seq_comando
Run Code Online (Sandbox Code Playgroud)

或者

seq_comando: comando
Run Code Online (Sandbox Code Playgroud)

简单的解决办法就是摆脱规则seq_comando: comando。您可能还需要考虑将右递归更改为左递归 ( seq_comando: seq_comando comando | /* empty */;),因为这将需要更少的解析器堆栈。