Occasionally it is useful to put an action in the middle of a rule. These
actions are written just like usual end-of-rule actions, but they are executed
before the parser recognizes the components that follow them.

A mid-rule action may refer to the components preceding it using tt($n), but
it may not (cannot) refer to subsequent components because it is executed
before they are parsed.

The mid-rule action itself counts as one of the components of the rule. This
makes a difference when there is another action later in the same rule (and
usually there is another at the end): you have to count the actions along with
the symbols when working out which number tt(n) to use in tt($n).

The mid-rule action can also have a semantic value. The action can set its
value with an assignment to tt($$), and actions later in the rule can refer to
the value using tt($n). Since there is no symbol to name the action, there is
no way to declare a data type for the value in advance, so you must use the
`tt($<...>)' construct to specify a data type each time you refer to this
value.

There is no way to set the value of the entire rule with a mid-rule action,
because assignments to tt($$) do not have that effect. The only way to set the
value for the entire rule is with an ordinary action at the end of the rule.

Here is an example from a hypothetical compiler, handling a tt(let) statement
that looks like ``tt(let (variable) statement)' and serves to create a
variable named tt(variable) temporarily for the duration of statement. To
parse this construct, we must put tt(variable) into the symbol table while
statement is parsed, then remove it afterward. Here is how it is done:
        verb(
    stmt:   
        LET '(' var ')'
        {
            $<u_context>$ = pushSymtab();
            temporaryVariable($3); 
        }
        stmt    
        { 
            $$ = $6;
            popSymtab($<u_context>5); 
        }
        )
    As soon as `tt(let (variable))' has been recognized, the first action is
executed. It saves a copy of the current symbol table as its semantic value,
using alternative tt(u_context) in the data-type union. Then it uses
tt(temporaryVariable()) to add the new variable (using, e.g., a name that
cannot normally be used in the parsed language) to the current symbol
table. Once the first action is finished, the embedded statement (tt(stmt))
can be parsed. Note that the mid-rule action is component number 5, so
`tt(stmt)' is component number 6.

Once the embedded statement is parsed, its semantic value becomes the value of
the entire tt(let)-statement. Then the semantic value from the earlier action
is used to restore the former symbol table. This removes the temporary
tt(let)-variable from the list so that it won't appear to exist while the rest
of the program is parsed.

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:
        verb(
    compound: 
        '{' declarations statements '}'
    | 
        '{' statements '}'
    ;
        )
    But when we add a mid-rule action as follows, the rules become
nonfunctional:
        verb(
    compound: 
        { 
            prepareForLocalVariables(); 
        }
        '{' declarations statements '}'
    | 
        '{' statements '}'
    ;
        )
    Now the parser is forced to decide whether to execute 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 look-ahead token at
this time, since the parser is still deciding what to do about it. See section
ref(LOOKAHEAD).

You might think that the problem can be solved by putting identical actions
into the two rules, like this:
        verb(
        { 
            prepareForLocalVariables(); 
        }
        '{' declarations statements '}'
    | 
        { 
            prepareForLocalVariables(); 
        }
        '{' statements '}'
    ;
        )
    But this does not help, because b() em(never) parses the contents of
actions, and so it does em(not) realize that the two actions are identical.

    If the grammar is such that a declaration can be distinguished from a
statement by the first token (which is true in bf(C), but em(not) in bf(C++),
which allows statements and declarations to be mixed)), then one solution
is to put the action after the open-brace, like this:
        verb(
    compound: 
        '{'
        { 
            prepareForLocalVariables(); 
        }
        declarations statements '}'
    | 
        '{' statements '}'
    ;
        )
    Now the next token following a recognized tt('{') token would be either
the first tt(declarations) token or the first tt(statements) token, which
would in any case tell b() which rule to use, thus solving the problem.

Another (much used) solution is to bury the action inside a support
non-terminal symbol which recognizes the first block-open brace and performs
the required preparations:
        verb(
    openblock:
        '{'
        { 
            prepareForLocalVariables(); 
        }
    ;

    compound: 
            openblock declarations statements '}'
    | 
            openblock statements '}'
    ;
        )
    Now b() can execute the action in the rule for subroutine without
deciding which rule for compound it eventually uses. Note that the action
is now at the end of its rule. Any mid-rule action can be converted to an
end-of-rule action in this way, and this is what b() actually does to
implement mid-rule actions.

    By the way, note that in a language like bf(C++) the above construction is
obsolete anyway, since bf(C++) allows mid-block variable- and object
declarations. In bf(C++) a compound statement could be defined, e.g., as
follows:
        verb(
    stmnt_or_decl:
        declarations
    |
        pure_stmnt      // among which: compound_stmnt
    ;

    statements:
        // empty
    |
        statements stmnt_or_decl
    ;

    compound_stmnt:                 
        open_block statements '}'
    ;
        )
    Here, the tt(compound_stmnt) would begin with the necessary preparations
for local declarations, which would then have been completed by the time they
would really be needed by tt(declarations).

