当我将规则与我的词法分析器(用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都有)。我做错了什么?
答案 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认为$1
是struct 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
实际为$1
,S[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
时 - 你需要使用结构类型的名称。如果你从不这样做,你可以完全省略名称。