bisonglr

Controlling a Parse with Arbitrary Predicates Not Working in Bison


In section 1.5.4 Controlling a Parse with Arbitrary Predicates: The bison manual specifies that you can make a parse fail up front for an option in a rule by checking the return of the predicate between the brackets in this format:

parent_rule: %?{ test_predicate_flag } child_rule_1 |
             %?{ !test_predicate_flag } child_rule_2;

The problem is that I get this syntax error with the above format in my grammar file:

error: invalid directive: ‘%?{’

I added the %glr-parser flag before the first %% as stated in the manual. Is there something I'm missing?

update: attempted this with bison version 3.0 prior to posting and didn't work. Not much information online about people's experience with this "experimental feature" as the doc says. Can anyone confirm or deny that it works for them?

update #2: After following the solution that rici posted, the resulting .c file has issues. It seems that in attempt to aid compile debug, bison outputs #line directives of the following format:

#line <line_no> <grammar_file_prefix>.tab.c

In the case of the arbitrary predicate generation, the above predicate option for the rule ends up in the parser file's main switch block as this:

if (! (#line <line_no> <grammar_file_prefix>.tab.c

This will of course not compile, and I'm guessing is intended to be output on the line before the start of the case statement like I see in the rest of the rule match options. Perhaps another bit of information to add to the bug report once it's filed? For now, I can search and replace these out to move forward.


Solution

  • The semantic predicates feature was added in bison 3.0, released at the end of July, 2013; at this writing, it's not yet bundled into most OS distributions so you need to install from source to even try it. However, I took a quick glance at the bison source code (as of October 10, 2013, and found what looks like a bug in the scanner specification, at line 269 of scan.gram.l

    The pattern in that line will match %{nonletter}[[::graph:]]+ (where nonletter is anything other than an alnum, % or {), which will certainly match %?{

    However, it will not match %? {. I tried the example from the manual, and indeed:

    widget:
           %?{  new_syntax } "widget" id new_args  { $$ = f($3, $4); }
         | %?{ !new_syntax } "widget" id old_args  { $$ = f($3, $4); }
         ;
    

    produces the error you see, while

    widget:
           %?  {  new_syntax } "widget" id new_args  { $$ = f($3, $4); }
         | %?  { !new_syntax } "widget" id old_args  { $$ = f($3, $4); }
         ;
    

    does not.

    I believe the fix would be to add ? to the characters not matched by {notletter}. At least, I tried that, and afterwards both of the above snippets "worked" (at least to the extent that bison generated a .c file.)