Bison 野牛:如何在不使用全局变量的情况下访问以前的非终端的值?

Bison 野牛:如何在不使用全局变量的情况下访问以前的非终端的值?,bison,yacc,Bison,Yacc,我的大语法有两条规则: indexed_component : name '(' val_list ')' ; val_list : val | val_list ',' val ; 如何在val_列表中访问“name”的值 我知道我可以使用全局变量,但这是高度递归的,因此我必须使用堆栈,我希望避免麻烦。在您的情况下,您可以在bison文档中使用所谓的中间规则操作。下面是它可能的样子: {% std::string compone

我的大语法有两条规则:

indexed_component
    : name '(' val_list ')' 
    ;

val_list
    : val          
    | val_list ',' val
    ;
如何在val_列表中访问“name”的值


我知道我可以使用全局变量,但这是高度递归的,因此我必须使用堆栈,我希望避免麻烦。

在您的情况下,您可以在bison文档中使用所谓的中间规则操作。下面是它可能的样子:

{%
std::string componentName:
%}
%union {
    char* id;
}
%type <id> name
%%
indexed_component : name { componentName = $1; } '(' val_list ')' ;

val_list : val
| val_list ',' val ;
{%
std::字符串组件名称:
%}
%联合{
字符*id;
}
%类型名
%%
索引的_组件:名称{componentName=$1;}'('val_list');
val_列表:val
|val_列表“,”val;
只要从lexer中提取
),mid-rule操作就会在这里执行。然后
componentName
的值将在rule
val\u list
的任何语义操作中可用,因为mid-rule操作是在之前执行的

中期规则行动的文件:

编辑:


但是该解决方案需要一个全局变量,这是您不希望看到的。那么我能看到的唯一其他解决方案是构建一个语法树,并将名称的值作为继承属性传播到
val_list
子树中。

您想要的是所谓的继承属性,不幸的是,yacc和bison不是真的你可以通过访问带有负索引的属性来“破解”它,但这很容易出错

如果你想尝试使用,它有一些语法糖来帮助你(至少允许他们被打字检查)

indexed_component : name '(' val_list($1) ')' ;
val_list($name) : val
         | val_list($name) ',' val ;
然后在
val_列表上的操作中
您可以访问
$name
。使用
%union
您需要使用
%type
正确声明:

%union {
    char *str;
    struct list *list;
}

%type <str> name                // name gives a string
%type <list> val_list(<str>)    // val_list takes a string and gives a list
%union{
char*str;
结构列表*列表;
}
%type name//name给出一个字符串
%键入val_list()//val_list接受一个字符串并给出一个列表
正如我所提到的,这只是btyacc中的语法糖——它最终被转换为具有$0访问权限的内联操作。因此它将被转换为:

indexed_component : name '(' { $<str>$ = $1; } val_list ')' ;
val_list : val
         | val_list ',' val ;
index_组件:名称“({$$=$1;}val_列表”);
val_列表:val
|val_列表“,”val;
在val_列表操作中使用
$name
,将变成
$0

其工作方式是当
val_list
规则减少且规则的RHS值(名义上)为弹出--它是右上角的
val_list
之前的最后一个值,无论规则
val_list
出现在的右上角。

如果这是您使用val_list的唯一位置,您可以在val_list的操作中访问
$-1
,以访问名称(如果使用
%union
,则此处需要显式类型标记--
$-1