[Haskell-cafe] Parser left recursion

Tillmann Rendel rendel at informatik.uni-marburg.de
Wed Feb 20 09:59:47 CET 2013


Hi,

Martin Drautzburg wrote:
> As an exercise I am writing a parser roughly following the expamples in Graham
> Hutton's book. The language contains things like:
>
> data Exp = Lit Int -- literal integer
>           | Plus Exp Exp

So the grammar is:

   Exp ::= Int
        |  Exp "+" Exp

> My naive parser enters an infinite recursion, when I try to parse "1+2". I do
> understand why:
>
> "hmm, this expression could be a plus, but then it must start with an
> expression, lets check".
>
> and it tries to parse expression again and again considers Plus.

Indeed.

> Twan van Laarhoven told me that:
>
>> Left-recursion is always a problem for recursive-descend parsers.

Note that the left recursion is already visible in the grammar above, no 
need to convert to parser combinators. The problem is that the 
nonterminal Exp occurs at the left of a rule for itself.

One way to fix this problem is to refactor the grammar in order to avoid 
left recursion. So let's distinguish "expressions that can start with 
expressions" and "expressions that cannot start with expressions":

   Exp-norec ::= Int
   Exp-rec   ::= Exp-norec
              |  Exp-norec "+" Exp-rec

Note that Exp-rec describes a list of Exp-norec with "+" in-between, so 
you can implement it with the combinator many.

Now if you want to add a rule like

   Exp ::= "(" Exp ")"

you need to figure out whether to add it to Exp-norec or Exp-rec. Since 
the new rule is not left recursive, you can add it to Exp-norec:

   Exp-norec ::= Int
              |  "(" Exp-rec ")"
   Exp-rec   ::= Exp-norec
              |  Exp-norec "+" Exp-rec

If you implement this grammar with parser combinators, you should be 
able to parse "(1+2)+3" just fine.

   Tillmann

PS. Try adding multiplication to your grammar. You will need a similar 
trick to get the priorities right.



More information about the Haskell-Cafe mailing list