Left Recursive Elimination Algorithm - Oya-Learning-Notes/Compilers GitHub Wiki

Elimination Of Left Recursive

The goal is to eliminate both direct and indirect left recursive.

Direct Recursive

Single RHS

Let’s start with one single left-recursive Production RHS:

$$ A \to Aa $$

We could create a new Production to solve the recursive:

$$ \begin{aligned} A \to & A' \ A' \to & aA' | \epsilon \ \end{aligned} $$

Multiple RHS

When considering Production with more than one RHS:

$$ A \to Aa | b $$

If we analyze the language this Production will generate, it would be like:

b
baa
baaa
baaaaaaa
...

It's actually equivalent to RegExp b(a*). Knowing this, the previous Production could be converted to the pattern below:

$$ \begin{aligned} A \to & b A' \ A' \to & aA' | \epsilon \ \end{aligned} $$

This Production will produce the same language as the one above.

Conclusion

In general, for a Production like:

$$ \begin{aligned} A \to & Ax_1 | Ax_2 | \cdots | Ax_m \ & | y_1 | y_2 | \cdots | y_n \end{aligned} $$

It could be converted to:

$$ \begin{aligned} A \to & y_1A' | y_2A' | \cdots | y_nA' \ A' \to & x_1A' | x_2A' | \cdots | x_mA' | \epsilon \end{aligned} $$

This rules is acutally the enhanced version of the one in Multiple RHS sectoin.

Indirect Recursive

The idea is to first convert indirect left-recursive into direct recursive, then using the method mentioned above to eliminate.

One algorithm is to use loops to iterate through all Productions to eliminate all possible recursive:

for prod_current in prodcutions:

    # get all productions before prod_current
    for prod_prev in productions.slice(from=0, to=prod_current):
        prod_current.replace_nonterminal_using_production(prod_prev)

    # eliminate direct recursive in modified prod
    prod_current.eliminate_direct_left_recursive() 

Let's see an example:

image

Check out Compilers-TSU P83 for original example.