3

当我将规则与我的词法分析器(用 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);
            }

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

4

1 回答 1

6

您的%union指令看起来……嗯,就您所展示的内容而言,“几乎可以”,但是缺少一个右括号。我不能说你省略的部分,但这int int是一个语法错误,所以我必须假设这也不是那里的内容。

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

这是一些正确的语法(我添加了更多名称以供讨论,并添加了一些其他项以使输出可编译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_svalpair_ival,当标记是 时,但当标记是 时TOKEN,这$1只是一个简单的single_ivalINTEGER。访问值时必须选择结构成员 ( .pair_svaland ) ,但必须省略单词。访问时,您也省略了该词;并且由于没有子名称,因此 . 之后没有其他内容。.pair_ivalpairpairsingle_ivalsingle_ival.field$1


扩展讨论

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

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

当 bison(或 byacc)发出代码时,它使用分配的或假定的类型 from %token%type或尖括号提供的名称,根据需要添加联合元素名称。例如,假设 yacc 值堆栈被命名S(不是只是假设),并且假设$1实际上是S[1]$2beingS[2]等。没有%union指令也没有显式类型,$n直接转换为S[n]. 但是,当您引入%union时,它会转换为S[n].field,其中field名称来自隐含或提供的类型。

因此,在上面,当处理INTEGER只产生 a的 an 时single_ival,bison/byacc 会生成您需要的内容,而无需您进行额外的工作。但是,在处理TOKEN产生 a 的 a时pairS[1].pair选择 的一个元素是不够的struct。添加.pair_sval选择 的char *元素struct

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

于 2013-08-31T20:05:14.703 回答