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

Reply via email to