Search code examples
parsinghaskellparsec

Parsec parse many question


I need to create a parser for a programming language. So far it is 95% done, I'd say, except for a tiny detail.

The program written in this language has the following structure:

outputs
inputs
expressions

The requirement is that outputs cannot be mixed with inputs. For example:

x := output of int;
y := output of in;
.....
z := input of int;
t := input of in;
.....
expressions

I can parse a single output just fine but if I try to use (many1 output), to allow multiple outputs, it doesn't work because it tries to parse the inputs as outputs.

My main parser looks like this:

prog =
    do outs <- many1 output
       ins <- many1 input
       exs <- expressions
       eof
       return (Prog outs ins exs) 

I know it seems easy but I tried a lot of stuff and just cannot get it to work. Please help.


Solution

  • If your rule for output looks something like this:

    output = do name <- ident
                string ":= output of"
                type <- ident
                char ';'
                return $ Out name type
    

    and your input rule looks the same except with "input of", then the problem is that both rules start with an ident and since parsec doesn't backtrack automatically, it will just try to apply output first, consuming the ident and then fail when it can't match "output of".

    To fix this you can just wrap output and input in try, i.e.

    outs <- many1 (try output)
    ins <- many1 (try input)