I think I have found a bug when using glr2.cc This does not occur when I switch to glr.cc
I am using: bison (GNU Bison) 3.8.2 I have included my parser.y which causes a crash in the generated parser code when I use certain input data. The program crashes in yyremoveDeletes() on this line: yylookaheadNeeds[j] = yylookaheadNeeds[i]; The vector 'yylookaheadNeeds' has size zero and the variable "i" is zero as well, thus a subscript out of range error occurs. The relevant stack trace shows: genCompileTest.exe!std::vector<bool,std::allocator<bool>>::operator[](unsigned __int64 _Off) Line 2779 C++ genCompileTest.exe!`anonymous namespace'::glr_state_set::yyremoveDeletes() Line 959 C++ genCompileTest.exe!`anonymous namespace'::state_stack::reduceToOneStack() Line 1513 C++ genCompileTest.exe!gen::Parser::glr_stack::yyrecoverSyntaxError(gen::location * yylocp) Line 2158 C++ genCompileTest.exe!gen::Parser::glr_stack::parse() Line 2034 C++ genCompileTest.exe!gen::Parser::parse() Line 3113 C++ . . [External Code] I have spent a couple of hours slowly reducing my grammar to the point where it is about as small as I can make it. With the attached grammar, bison reports: 1>parser.y : warning : 2 shift/reduce conflicts [-Wconflicts-sr] 1>parser.y : warning : 2 reduce/reduce conflicts [-Wconflicts-rr] It crashes with the input: foo (*(*bar)())[] [0:12-13] Error: syntax error, unexpected '(', expecting ')' (Note: Yes, I know if 'foo' is a valid type, then the line should have been valid grammar - that's why I was debugging it.) If I comment out line 100 in the grammar file, I get: 1>parser.y : warning : 1 shift/reduce conflict [-Wconflicts-sr] 1>parser.y : warning : 2 reduce/reduce conflicts [-Wconflicts-rr] The app doesn't crash anymore: foo (*(*bar)())[] [0:12-13] Error: syntax error, unexpected '(', expecting ')' If we leave line 100 uncommented but comment out line 135 instead, we still have 2 S/R and 2 R/R but the program runs as above without crashing. (I have placed comments at the end of those two lines for easy locating.) I think this is as far as I can go. Oh, btw: Seasons Greetings? Happy Holidays? Merry Christmas? (pick one or add one) Sorry to find it today (Dec 24) as this is a busy time for many people. Thanks jotdot PS: Ignore the mess in my yylex code - if you recall (Akim) I modified it to pass information to my %merge routines instead of passing data with global variables. Right now, in this sample code, I do not use the %merge feature (but was planning on reintroducing it after). I could remove this mess if we were able to make the %merge routines as members of the Parser class. hint hint - just a gentle nudge :)
%glr-parser %language "c++" %require "3.2" %skeleton "glr2.cc" %locations %header %define api.namespace { gen } %define api.parser.class { Parser } %define parse.error verbose %verbose %define parse.trace %define api.location.type { class gen::location } %code requires { #define NOMINMAX // glr2.cc collision with max() #pragma warning(push) #pragma warning(disable : 4065) // switch statement contains 'default' but no 'case' labels #include <location.hh> #include <genParser.h> struct parse_param_t { // The first portion must be the same or larger than the largest used in the 'union' gen::index_t index; // Largest type used // The rest of this struct holds the semantic info passed into yylex // These values can be accessed in any %merge routine // We need this until bison let's us have merge routines as members of the parser class. // Otherwise we are forced to use static variables in order to pass context // information to the merge routines. void * pval; class gen::location * ploc; class GenParser * pResult; // NOTE: This is stored at an offset greater than the max used in the 'union' of all others }; } %code top { #include <tokens.h> #include "driver.h" #define R (*pDriver->getResult()) #define D (*pDriver) #define P (*D.getParser()) #define S (*D.getScanner()) } %code { int yylex(union gen::Parser::value_type *plval, gen::location *plloc, Driver * pDriver) { plval->parse_param.pval = plval; plval->parse_param.ploc = plloc; plval->parse_param.pResult = pDriver->getResult(); return pDriver->getScanner()->get_next_token(*plval, *plloc, pDriver); } } %param { Driver * pDriver } %union { gen::index_t index; parse_param_t parse_param; } %token <index> IDENTIFIER CONSTANT %token <index> COMPLEX FLOAT %type <index> program %type <index> statements statement %type <index> expr %type <index> ident decl storage decl_single storage_type %type <index> decl_single_vec decl_target pointer_to %start program %% program: decl ; statements: statement | statements ';' statement ; statement: decl | expr ; decl: storage | storage decl_single '(' ')' '{' statements '}' ; storage: storage_type | storage_type '(' expr ')' // If this line commented out, 1 S/R, 2 R/R, app doesn't crash ; storage_type: FLOAT | COMPLEX | ident ; decl_single: decl_single_vec | decl_target | decl_target decl_single_vec | pointer_to | pointer_to decl_single_vec | pointer_to decl_target | pointer_to decl_target decl_single_vec ; decl_single_vec: '[' ']' ; pointer_to: '*' | pointer_to '*' ; decl_target: '(' decl_single ')' | ident ; expr: expr_factor | '*' expr_factor // If this line commented out, 2 S/R, 2 R/R, app doesn't crash ; expr_factor: '(' expr ')' | ident ; ident: IDENTIFIER ; %% /* Epilogue */ #pragma warning(pop) void gen::Parser::error(const location& loc , const std::string& message) { R.error(loc, message.c_str()); }