为什么yacc或bison将$ 1翻译为yyvsp [(1) - (1)]。s?

时间:2015-11-27 07:53:25

标签: c bison yacc

Yacc来源如下:

element:    IDENTIFIER                { $$ = gst_element_factory_make ($1, NULL);
                        if ($$ == NULL) {
                          ADD_MISSING_ELEMENT (graph, $1);
                          SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, _("no element \"%s\""), $1);
                          /* if FATAL_ERRORS flag is set, we don't have to worry about backwards
                           * compatibility and can continue parsing and check for other missing
                           * elements */
                          if ((graph->flags & GST_PARSE_FLAG_FATAL_ERRORS) == 0) {
                            gst_parse_strfree ($1);
                            YYERROR;
                          }
                        }
                        gst_parse_strfree ($1);
                                              }
    |   element ASSIGNMENT        { gst_parse_element_set ($2, $1, graph);
                        $$ = $1;

它被翻译成这样的代码:

 { (yyval.e) = gst_element_factory_make ((yyvsp[(1) - (1)].s), NULL);
                    if ((yyval.e) == NULL) {
                      ADD_MISSING_ELEMENT (graph, (yyvsp[(1) - (1)].s));
                      SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, _("no element \"%s\""), (yyvsp[(1) - (1)].s));
                      /* if FATAL_ERRORS flag is set, we don't have to worry about backwards
                       * compatibility and can continue parsing and check for other missing
                       * elements */
                      if ((graph->flags & GST_PARSE_FLAG_FATAL_ERRORS) == 0) {
                        gst_parse_strfree ((yyvsp[(1) - (1)].s));
                        YYERROR;
                      }
                    }
                    gst_parse_strfree ((yyvsp[(1) - (1)].s));
                                          }
break;

其中一个译文转换为:

gst_element_factory_make ($1, NULL)

为:

gst_element_factory_make ((yyvsp[(1) - (1)].s), NULL)

[(1) - (1)]令我困惑。 为什么[(1) - (1)]句代表$1值?

1 个答案:

答案 0 :(得分:0)

正如Jonathan Leffler在评论中所说,野牛和yacc以便于代码生成的方式生成正确的代码,而非人类读者。

然而,各种堆栈的处理相当简单。 Bison维持两到三个堆栈:状态堆栈;价值堆栈;以及可选的位置堆栈。这三个堆栈是独立的,否则有必要创建一个包含状态,值和(如果需要)位置的堆栈槽结构。

堆栈总是大小相同,这意味着值堆栈的开头(以及位置堆栈)有一个未使用的槽。如果您参考LR解析算法的经典描述,请参阅Dragon Book的“LR解析算法”部分 - 我的版本中的§4.7 - 您将清楚地看到这一点;堆栈有一个多于语法符号的状态,因此没有X0

s0 X1 s1 X2 s2 … Xm sm

(Bison实际上并没有将语法符号保留在堆栈上,因为符号本身可以很容易地计算出来。相反,它保持与符号关联的语义值。)

在代码中,yyvspyyssp分别是指向值和状态堆栈顶部的指针。 (yylsp是指向位置堆栈顶部的指针(如果有的话)。)

它们实际指向各自堆栈的顶部元素,而不是指向顶部元素的顶部元素。一般过去的元素指针在一般的堆栈实现中更常见,因为如果堆栈为空,通常可能没有要指向的顶部元素。但是,在这种特殊情况下,堆栈永远不会为空,因此始终存在顶部元素。 (在算法开始时,顶部状态为0,顶部值和位置是上面提到的未使用的插槽。)与往常一样,堆栈的其余部分从顶部向下,因此倒数第二个元素(如果有的话)位于yyvsp - 1,而第三个元素位于yyvsp - 2

请记住,在C中,*yyvsp表示与yyvsp[0]完全相同。或者,通常,yyvsp[k]*(yyvsp + k)相同。即使k为负数也是如此,因此我们可以编写yyvsp[-1]来引用堆栈中倒数第二个元素。

您引用的代码实现了制作的缩减操作;减少动作通常计算得到的非终端的语义值。假设减产的是:

A → X1 X2 … Xm

在这种情况下,值堆栈的顶部将精确

V1 V2 … Vm

(其中Vi是符号Xi)的语义值。或者,在野牛术语中:

$1 $2 … $m

这意味着$1yyvsp[1-m]$2yyvsp[2-m],依此类推,最高为$m yyvsp[m-m]。而这恰恰是野牛生成的代码所做的事情;它将$i表示为yyvsp[(i)-(m)],其中m是缩小右侧的长度(在语法符号中)。