Previous: Mid-Rule Action Translation, Up: Mid-Rule Actions


3.4.8.3 Conflicts due to Mid-Rule Actions

Taking action before a rule is completely recognized often leads to conflicts since the parser must commit to a parse in order to execute the action. For example, the following two rules, without mid-rule actions, can coexist in a working parser because the parser can shift the open-brace token and look at what follows before deciding whether there is a declaration or not:

     compound:
       '{' declarations statements '}'
     | '{' statements '}'
     ;

But when we add a mid-rule action as follows, the rules become nonfunctional:

     compound:
       { prepare_for_local_variables (); }
          '{' declarations statements '}'
     |    '{' statements '}'
     ;

Now the parser is forced to decide whether to run the mid-rule action when it has read no farther than the open-brace. In other words, it must commit to using one rule or the other, without sufficient information to do it correctly. (The open-brace token is what is called the lookahead token at this time, since the parser is still deciding what to do about it. See Lookahead Tokens.)

You might think that you could correct the problem by putting identical actions into the two rules, like this:

     compound:
       { prepare_for_local_variables (); }
         '{' declarations statements '}'
     | { prepare_for_local_variables (); }
         '{' statements '}'
     ;

But this does not help, because Bison does not realize that the two actions are identical. (Bison never tries to understand the C code in an action.)

If the grammar is such that a declaration can be distinguished from a statement by the first token (which is true in C), then one solution which does work is to put the action after the open-brace, like this:

     compound:
       '{' { prepare_for_local_variables (); }
         declarations statements '}'
     | '{' statements '}'
     ;

Now the first token of the following declaration or statement, which would in any case tell Bison which rule to use, can still do so.

Another solution is to bury the action inside a nonterminal symbol which serves as a subroutine:

     subroutine:
       %empty  { prepare_for_local_variables (); }
     ;
     
     compound:
       subroutine '{' declarations statements '}'
     | subroutine '{' statements '}'
     ;

Now Bison can execute the action in the rule for subroutine without deciding which rule for compound it will eventually use.