【问题标题】:Bison C++ mid-rule value lost with variantsBison C++ 中间规则值因变体而丢失
【发布时间】:2017-06-28 20:00:02
【问题描述】:

我正在使用 Bison 和 lalr1.cc 骨架来生成 C++ 解析器和 api.value.type variant。我尝试使用中间规则操作来返回将用于进一步语义操作的值,但堆栈上的值似乎变为零。下面是一个例子。

parser.y:

%require "3.0"
%skeleton "lalr1.cc"
%defines
%define api.value.type variant

%code {
#include <iostream>
#include "parser.yy.hpp"
extern int yylex(yy::parser::semantic_type * yylval);
}

%token <int> NUM

%%
expr: NUM | expr { $<int>$ = 42; } '+' NUM { std::cout << $<int>2 << std::endl; };

%%

void yy::parser::error(const std::string & message){
    std::cerr << message << std::endl;
}

int main(){
    yy::parser p;
    return p.parse();
}

lexer.flex:

%option noyywrap
%option nounput
%option noinput

%{
#include "parser.yy.hpp"
typedef yy::parser::token token;
#define YY_DECL int yylex(yy::parser::semantic_type * yylval)
%}

%%
[ \n\t]+
[0-9]+      {
                yylval->build(atoi(yytext));
                return token::NUM;
            }
.           {
                return yytext[0];
            }

编译:

bison -o parser.yy.cpp parser.y
flex -o lexer.c lexer.flex
g++ parser.yy.cpp lexer.c -O2 -Wall -o parser

2+2 这样的简单输入应该打印值42,但出现0。当变体类型更改为%union 时,打印的值应为应有的值。对于一种解决方法,我一直在使用带有 $&lt;type&gt;-n 的标记操作来从堆栈中获取更深层次的值,但这种方法会降低易读性和可维护性。

我在生成的源代码中读到,当使用变体类型时,默认操作{ $$ = $1 } 不会执行。这是这种行为的一个例子还是一个错误?

【问题讨论】:

    标签: c++ parsing bison variant


    【解决方案1】:

    我投票给“错误”。它与缺少默认操作无关。

    我一直跟踪执行,直到它尝试将 MRA 的值压入堆栈。但是,它没有为 MRA 获取正确的类型,结果是对 yypush_ 的调用什么都不做,这显然不是所需的操作。

    如果我是你,我会报告问题。

    【讨论】:

    • 感谢您的信息。我向 Bison 开发人员报告了这个问题。
    • 该行为明显违反了文档。在中间规则操作中,$$ 表示仅该子操作的结果,并且必须使用$&lt;type&gt;$ 进行归因,因为该类型不是从任何地方声明的。稍后可以使用$&lt;type&gt;n 引用此对象,其中n 是规则在产生式中的位置。显然$&lt;int&gt;2 指的是正确的位置,但值不存在。 初步发现错误。
    【解决方案2】:

    这确实是 Bison 3.0.5 中的一个错误,但使用 $&lt;foo&gt;1 本质上也是错误的(但别无选择!)。

    考虑:

    // 1.y
    %nterm <int> exp
    %%
    exp: { $<int>$ = 42; }    { $$ = $<int>1; }
    

    翻译成这样的:

    // 2.y
    %nterm <int> exp
    %%
    @1: %empty { $<int>$ = 42; }
    exp: @1    { $$ = $<int>1; }
    

    这里的问题是我们没有告诉 Bison @1 的语义值是什么类型,所以它不能正确处理这个语义值(通常是没有%printer 和没有@987654329 @ 将被应用)。更糟糕的是:这里,因为它不知道这里实际存储了什么值,所以无法正确操作它:它不知道如何将其从局部变量$$ 复制到堆栈中,这就是该值丢失的原因. (在 C 中,语义值的位是盲目复制的,所以它可以工作。在带有 Bison 变体的 C++ 中,我们使用与当前类型对应的精确赋值/复制运算符,这需要知道类型是什么。)

    显然更好的翻译是给@1一个类型:

    // 3.y
    %nterm <int> exp @1
    %%
    @1: %empty { $$ = 42; }
    exp: @1    { $$ = $1; }
    

    这实际上是任何人都会写的。

    感谢您的提问,Bison 3.1 现在具有 typed midrule actions

    // 4.y
    %nterm <int> exp
    %%
    exp: <int>{ $$ = 42; }    { $$ = $1; }
    

    脱糖,4.y 生成与 3.y 完全相同。

    请参阅http://lists.gnu.org/archive/html/bug-bison/2017-06/msg00000.htmlhttp://lists.gnu.org/archive/html/bug-bison/2018-06/msg00001.html 了解更多详情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-05
      • 1970-01-01
      • 2015-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-05
      • 1970-01-01
      相关资源
      最近更新 更多