Yacc / Bison语义值在规则中途发生变化

时间:2014-12-06 16:13:50

标签: bison yacc

iteration_stmt : WHILE              {$$ = LabelSeed; LabelSeed++;
                                     fprintf(fp, "While%i:\n", $$);
                                    }
                 '(' expression ')' {fprintf(fp, "cmp %s, 1\n", regToString($<n>3));
                                     fprintf(fp, "jne EndWhile%i\n", $$);
                                     NextReg--;
                                    }
                 statement          {fprintf(fp, "jmp While%i\n", $$);
                                     fprintf(fp, "EndWhile%i:\n", $$);
                                    }
                ;

我尝试使用 iteration_stmt 的语义值来跟踪 LabelSeed 值,但它的值并不是&# 39;在其他2个动作中保持不变。例如,在一种情况下,我的输出是:

While0:
...
jne EndWhile1
...
jmp While0
EndWhile0:

在另一个中:

While2:
...
jne EndWhile2
...
jmp While0
EndWhile0:

整数应该保持不变。我无法想到语义价值会发生变化的任何原因。有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:0)

整个规则减少之前,不会设置 iteration_stmt 的语义值,此时可以使用$$在动作代码中引用它。您在动作代码段中使用$$实际上是指隐式的部分完成的规则​​部分;仅在结束语句的操作中,非终端将$$引用 iteration_stmt

这是因为内部yacc / bison将rules with mid-rule actions实现为常规形式的级联规则,仅在最后执行操作。

所以,试试这个:

iteration_stmt : WHILE              {$$ = LabelSeed; LabelSeed++;
                                     fprintf(fp, "While%i:\n", $$);
                                    }
                 '(' expression ')' {fprintf(fp, "cmp %s, 1\n", regToString($<n>3));
                                     fprintf(fp, "jne EndWhile%i\n", $1);
                                     NextReg--;
                                    }
                 statement          {fprintf(fp, "jmp While%i\n", $1);
                                     fprintf(fp, "EndWhile%i:\n", $1);
                                    }
                ; 

第一个$$加载 WHILE 标记的语义值,其他操作可以引用该标记。