Search code examples
c++parsingbisonvariant

Bison C++ mid-rule value lost with variants


I'm using Bison with lalr1.cc skeleton to generate C++ parser and api.value.type variant. I tried to use mid-rule action to return value that will be used in further semantic actions, but it appears that the value on stack becomes zero. Below is an example.

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];
            }

compiling:

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

Simple input like 2+2 should print value 42 but instead appears 0. When variant type is changed to %union, the printed value is as it should be. For a workaround I've been using marker actions with $<type>-n to get deeper values from stack, but that approach can reduce legibility and maintainability.

I've read in the generated source that when using variant type, the default action { $$ = $1 } is not executed. Is it an example of that behavior or is it a bug?


Solution

  • I vote for "bug". It does not have to do with the absence of the default action.

    I traced execution through to the point where it attempts to push the value of the MRA onto the stack. However, it does not get the correct type for the MRA, with the result that the call to yypush_ does nothing, which is clearly not the desired action.

    If I were you, I'd report the problem.