在 yacc 的 if-else 生产主体中嵌入动作?

问题描述 投票:0回答:2

我制作了一个 yacc 文件,试图将 miniC 语言(功能有限)转换为三地址代码。这是我遇到冲突的代码片段

/*initialization and headers*/
body: body line
|
;

line:
 branch
/* other features like declarations etc */
;

branch: if_else
;

if_else:
 IF '(' boolean ')' {// finalize evaluation of the boolean} block {//finalize block}
| IF '(' boolean ')' {// finalize evaluation of the boolean} block {//finalize block} ELSE {//initialization for else block} block {//finalize block}
;

block: '{' body '}'
;

Currently I just trying to implement single

if
and single
if-else
.

这让我轮班减少冲突,并说

if_else
的第二个生产机构中的行动是无用的。

为什么会这样?我应该如何重组这个语法?任何帮助将不胜感激。

yacc
2个回答
1
投票

在那种情况下,转移/减少冲突是正常的,根本不是问题。 Yacc(或野牛)在 shift/reduce 冲突时选择 shift 而不是 reduce,这是 C 语言(以及所有编程语言)中挂起的

else
的预期行为,因为总是期望
else
附加到最里面的 if 语句。这在here.

中有更详细的解释

真正的问题将来自规则中的中间规则操作引入的减少/减少冲突

if_else
(通过“完成布尔值的评估”这对操作)。当您引入中间规则操作时,yacc 将其替换为生成的 epsilon 规则(产生式为空的规则)。所以,您有这 2 个中间规则操作,yacc 必须选择它应该执行哪一个。默认情况下,yacc 将选择第一个。问题在于,通过做出该选择,它肯定会丢弃其他产品(带有
else
的产品)。因此,它告诉你生产是无用的。

但解决方案很简单:删除中间规则操作。您不需要它们,并且应该能够管理语义操作中所需的所有操作(在制作结束时)。


0
投票

正如 P.PICARD 所指出的,真正的问题是来自重复的中间规则操作的减少/减少冲突。您可以通过将它们组合成一个(明确的)epsilon 规则来解决这个问题。

if_else:
  IF '(' boolean ')' _finalize_bool block {//finalize block}
| IF '(' boolean ')' _finalize_bool block {//finalize block} ELSE {//initialization for else block} block {//finalize block}
;

_finalize_bool: {// finalize evaluation of the boolean}

如果有问题的块需要从

boolean
访问值,这会很复杂——它现在需要使用 $-1 而不是 $2。您可以通过拆分整个条件来清理它:

if_else:
  IF condition block {//finalize block}
| IF condition block {//finalize block} ELSE {//initialization for else block} block {//finalize block}
;

condition: '(' boolean ')' {// finalize evaluation of the boolean}

您可能还会发现将大部分

//finalize block
移动到
block
的动作中很有用,这样您就可以摆脱 IF-ELSE 案例中的一个中间动作规则

© www.soinside.com 2019 - 2024. All rights reserved.