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

Sim*_*cia 2 c struct parameter-passing bison flex-lexer

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

{pattern_to_match}           {
                                 yylval.type_val.str=strdup(yytext);
                                 yylval.type_val.int=1;
                                 return TOKEN;
                             }
Run Code Online (Sandbox Code Playgroud)

这是词法分析器的一部分

%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);
            }
Run Code Online (Sandbox Code Playgroud)

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

tor*_*rek 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); }
        ;
Run Code Online (Sandbox Code Playgroud)

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


扩展讨论

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

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

当野牛(或byacc)发射码时,它使用所分配的或假定的类型,从%token,%type或尖括号提供的名称,根据需要添加一个联合元素名称.例如,假设yacc值栈被命名S(它不仅仅是假设),并且假设$1实际上是S[1],$2正在S[2]等等.没有%union指令而没有显式类型,$n只需直接转换为S[n].当你介绍%union,但是,将其转换为S[n].field,其中field名字来自于暗示或提供的类型.

因此,在上面,当处理INTEGER只生产a single_ival,bison/byacc的产生你需要的东西而你不需要额外的工作.但是,当处理a TOKEN产生a时pair,S[1].pair不足以选择一个元素struct.添加.pair_sval选择的char *元素struct.

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