[Haskell-cafe] Parser left recursion

Martin Drautzburg Martin.Drautzburg at web.de
Wed Feb 20 21:48:16 CET 2013


Thank you very much. 

To clarify: I am not in need of a parser, I just wanted to understand why left 
recursion is an issue (that was easy) and what techniques help to circumvent 
the problem. So your answer was spot-on (though I haven't implemented it yet)

On Wednesday, 20. February 2013 09:59:47 Tillmann Rendel wrote:
> 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.

-- 
Martin



More information about the Haskell-Cafe mailing list