C++ 野牛C++;中间规则值随变量丢失

C++ 野牛C++;中间规则值随变量丢失,c++,parsing,bison,variant,C++,Parsing,Bison,Variant,我使用BISEN和代码> LALR1.cc[骨架]生成C++解析器和 Ap.Value.Type变体< /代码>。我尝试使用mid-rule操作返回将在进一步语义操作中使用的值,但堆栈上的值似乎变为零。下面是一个例子 parser.y: %require "3.0" %skeleton "lalr1.cc" %defines %define api.value.type variant %code { #include <iostream> #include "parser.yy.

我使用BISEN和代码> LALR1.cc[骨架]生成C++解析器和<代码> Ap.Value.Type变体< /代码>。我尝试使用mid-rule操作返回将在进一步语义操作中使用的值,但堆栈上的值似乎变为零。下面是一个例子

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();
}
汇编:

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
时,打印的值与它应该的一样。为了解决这个问题,我一直在使用带有
$-n
的标记操作从堆栈中获取更深的值,但这种方法会降低可读性和可维护性

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

我赞成“bug”。这与没有默认操作无关

我一直跟踪执行,直到它试图将MRA的值推送到堆栈上。但是,它没有为MRA获取正确的类型,结果是对
yypush
的调用没有执行任何操作,这显然不是所需的操作


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

这确实是Bison 3.0.5中的一个bug,但使用
$1
本身也是错误的(但没有其他选择!)

考虑:

// 1.y
%nterm <int> exp
%%
exp: { $<int>$ = 42; }    { $$ = $<int>1; }
这实际上是任何人都会写的

感谢您的提问,Bison 3.1现在具有以下功能:

/4.y
%进出口
%%
exp:{$$=42;}{$$=1;}
Desugared,4.y的生成与3.y完全相同


有关详细信息,请参阅和。

谢谢您提供的信息。我向Bison开发者报告了这个问题。这种行为显然违反了文档。在中间规则操作中,
$
仅表示该子操作的结果,并且必须使用
$$
对其进行属性化,因为该类型不是从任何位置声明的。稍后可以使用
$n
引用此对象,其中
n
规则在产品中的位置。显然,
$2
指的是正确的位置,但值不在那里。表面缺陷。
// 1.y
%nterm <int> exp
%%
exp: { $<int>$ = 42; }    { $$ = $<int>1; }
// 2.y
%nterm <int> exp
%%
@1: %empty { $<int>$ = 42; }
exp: @1    { $$ = $<int>1; }
// 3.y
%nterm <int> exp @1
%%
@1: %empty { $$ = 42; }
exp: @1    { $$ = $1; }
// 4.y
%nterm <int> exp
%%
exp: <int>{ $$ = 42; }    { $$ = $1; }