在非终端Bison规则之间传递超过一个值

时间:2013-08-31 18:10:04

标签: c struct parameter-passing bison flex-lexer

当我将规则与我的词法分析器(用Flex编写)匹配时,我试图传递多个值。

{pattern_to_match}           {
                                 yylval.type_val.str=strdup(yytext);
                                 yylval.type_val.int=1;
                                 return TOKEN;
                             }

这是词法分析者

%union {
struct{
        char * str;
            int    int;
   }str_int;

%token <str_int> TOKEN

 TOKEN      {       
                printf("%s\n",$1.str_int.str);
                printf("%s\n",$1.str);
            }

在这里我们可以看到野牛结构。我已经将两个字符串写入了printf中,如教程中所示,但没有一个(字符串和int都有)。我做错了什么?

1 个答案:

答案 0 :(得分:5)

你的%union指令看起来......好吧,就你所展示的内容而言“几乎可以”,但是有一个缺失的紧密支撑。我不能说你省略的部分,但int int是一个语法错误,所以我不得不假设这不是那里的。

大括号中的代码(flex和bison部分)与union中显示的片段不匹配。

这是一些正确的语法(为了讨论的目的,我添加了更多的名称,以及使用gcc -O -Wall -c编译输出的其他一些项目):

%{
#include <stdio.h>
extern int yylex(void);
extern int yyerror(const char *);
%}

%union {
    struct named_for_discussion_below {
        char *pair_sval;
        int pair_ival;
    } pair;
    int single_ival;
}

%token <pair> TOKEN
%token <single_ival> INTEGER

%%

prog: exprlist;

exprlist: exprlist expr
        | /*empty*/
        ;

expr    : TOKEN { printf("got: %s %d\n", $1.pair_sval, $1.pair_ival); }
        | INTEGER { printf("got: %d\n", $1); }
        ;

请注意,由于两个%token指令中提供的类型,bison认为$1struct named_for_discussion_below的实例,包含pair_sval和{{1} },当令牌为pair_ival时,但当令牌为TOKEN时,$1只是一个简单的single_ival值。访问INTEGER值时,您必须选择结构成员(.pair_sval.pair_ival),但必须省略单词pair。访问pair时,您也省略了single_ival这个词;由于没有single_ival子名称,因此.field之后不会出现任何其他内容。


扩展讨论

至少如果你知道生成的解析器如何工作的基础知识,可能会有所帮助,这里要注意解析堆栈的每个元素都是$1类型。 (好吧,它是在使用union之后,否则它只是一个普通的%union。)

int指令提供此类型的内容。它的内部名称是%union,它有一个typedef-alias拼写union YYSTYPE,这是你(或flex)在为每个标记设置辅助值时应该使用的。每次调用YYSTYPE都必须返回一个普通的yylex()值,即标记号(EOF为0,普通int为1到255),标记值从256开始或高于256令牌)。 (Byacc使用char从257开始,而现代野牛使用#define并从258开始。)每个调用也设置enum并推送yylval中的值(转移到它的解析堆栈上,以及令牌。 (bison和byacc都使用两个并行堆栈,一个用于解析器状态,一个用于值,但这是一个你不需要关心的实现细节。除了“Bob Corbett编写了两者的第一个版本”之外我不知道为什么他们俩这里的工作方式相同。)

当bison(或byacc)发出代码时,它使用指定的或假定的类型,从yylval%token或angle-bracket提供的名称,根据需要添加union元素名称。例如,假设yacc值堆栈名为%type(它不仅仅是假设),并假设S实际为$1S[1]$2,等等。如果没有S[2]指令且没有明确的类型,%union只会直接转换为$n。但是,当您引入S[n]时,它会转换为%union,其中S[n].field名称来自隐含或提供的类型。

因此,在上文中,当处理仅生成field的{​​{1}}时,bison / byacc会生成您需要的内容,而无需您进行额外的工作。但是,在处理产生INTEGER的{​​{1}}时,single_ival不足以选择TOKEN的一个元素。添加pair会选择S[1].pair的{​​{1}}元素。

结构类型的名称struct永远不会出现在任何自动生成的代码中。如果要将结构类型的副本或指向其实例的指针传递给某个例程,例如,.pair_sval,当char *扩展为struct时 - 需要使用结构类型的名称。如果你从不这样做,你可以完全省略名称。