【问题标题】:Pass more than a value between non-terminal Bison rule在非终端 Bison 规则之间传递多个值
【发布时间】:2013-09-04 06:27:54
【问题描述】:

当我用我的词法分析器(用 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 都适用)。我做错了什么?

【问题讨论】:

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


    【解决方案1】:

    您的%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 假定$1struct named_for_discussion_below 的一个实例,包含pair_svalpair_ival,当令牌为TOKEN 时,但是当令牌为INTEGER 时,$1 只是一个简单的single_ival 值。访问pair 值时必须选择结构成员(.pair_sval.pair_ival),但必须省略单词pair。访问single_ival 时,您也省略了single_ival 一词;并且由于没有.field 子名称,因此$1 之后没有其他内容。


    扩展讨论

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

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

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

    因此,在上述情况下,当处理仅生成 single_ivalINTEGER 时,bison/byacc 无需您进行额外工作即可生成您需要的内容。但是,在处理产生pairTOKEN 时,S[1].pair 不足以选择struct 的一个元素。添加.pair_sval 选择structchar * 元素。

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

    【讨论】:

    • 我做了一些复制/粘贴错误,发布时没有注意到它们。顺便说一句,你的回答让我意识到我做错了什么!我是 Bison 的初学者,我觉得我仍然缺少一些东西。非常感谢!!
    猜你喜欢
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-05
    • 2018-06-05
    • 2016-02-26
    • 1970-01-01
    相关资源
    最近更新 更多