0

I'm currently writing a parser for a simple programming language. It's getting there however I'm unable to parse a boolean logic statement such as "i == 0 AND j == 0". All I get back is "non exhaustive patterns in case"

When I parse a boolean expression on its own it works fine e.g. "i == 0". Note "i == 0 a" will also return a boolean statement but "i == 0 AND" does not return anything.

Can anyone help please?

Whilst the above works correctly for input such as run parseBoolean "i == 0"

C. A. McCann
  • 76,893
  • 19
  • 209
  • 302
user1424720
  • 61
  • 1
  • 10
  • 9
    Please don't link to external code. Please also don't just dump all that code here. Narrow down the problem and then write a specific question along with the relevant code, expected output and actual output. – Niklas B. May 30 '12 at 13:26
  • 1
    Well... did you examine the associated case statement? – Daniel Wagner May 30 '12 at 13:41
  • Have you tried adding a default case? – phipsgabler May 30 '12 at 13:46
  • Which line of your program gives you that error message? – dave4420 May 30 '12 at 14:20
  • It all compiles fine. It's just when I do run parse boolean "i == 0" It works ok. But when I do run parse booleanLogic "i == 0 AND j == 0" It returns non-exhaustive patterns in case. So it's failing at this function. – user1424720 May 30 '12 at 14:22
  • 2
    Consider using [Text.Parsec.Expr](http://hackage.haskell.org/packages/archive/parsec/latest/doc/html/Text-Parsec-Expr.html). It's much less error-prone than writing expression parsers from scratch. – hammar May 30 '12 at 15:06
  • Paste the *exact* error in your question. Make sure the lines indicated by the error are clearly marked in the code you pasted. (I bet if you do this you'll find your error without our help!) – Daniel Wagner May 30 '12 at 15:37
  • If you're getting a "non exhaustive patterns" error, and you don't think you should be, the first step should almost be to add a default case which gives you an indication of what the case statement is trying to match that fails. The Debug.Trace module is very handy here. Often the problem becomes obvious once you see the input to the pattern match. – Ben May 31 '12 at 03:27

1 Answers1

2

As @hammar points out, you should use Text.Parsec.Expr for this kind of thing. However, since this is homework, maybe you have to do it the hard way!

The problem is in parseArithmetic, you allow anyChar to be an operator, but then in the case statement, you only allow for +, -, *, /, %, and ^. When parseArithmetic tries to parse i == 0, it uses the first = as the operator, but can't parse an intExp2 from the second =, and fails in the monad, and backtracks, before getting to the case statement. However, when you try to parse i == 0 AND j == 0, it gets the i == part, but then it thinks that there's an arithmetic expression of 0 A ND, where A is an operator, and ND is the name of some variable, so it gets to the case, and boom.

Incidentally, instead of using the parser to match a string, and then using a case statement to match it a second time, you can have your parser return a function instead of a string, and then apply the function directly:

 parseOp :: String -> a -> Parser a
 parseOp op a = string op >> spaces >> return a

 parseLogic :: Parser BoolExp 
 parseLogic = do 
    boolExp1 <- parseBoolExp 
    spaces 
    operator <- choice [ try $ parseOp "AND" And
                       , parseOp "OR" Or
                       , parseOp "XOR" XOr
                       ]
    boolExp2 <- parseBoolExp
    return $ operator boolExp1 boolExp2


parseBoolean :: Parser BoolExp 
parseBoolean = do       
   intExp1 <- parseIntExp 
   spaces 
   operator <- choice [ try $ parseOp "==" Main.EQ
                      , parseOp "=>" GTorEQ
                      , parseOp "<=" LTorEQ 
                      ]
   intExp2 <- parseIntExp
   return $ operator intExp1 intExp2
pat
  • 12,587
  • 1
  • 23
  • 52
  • Thanks pat. I was thinking about that the error in parseArithmetic. Do you think it should work if I make it like above using choice? Or would there be a better way to do it? Now that I've started doing it this way I will use Text.Parsec.Expr next time. I did it this way as this is how we were shown to do the parsing in classes. – user1424720 May 30 '12 at 16:59
  • I haven't debugged your whole parser, but only allowing for what you want instead of using `anyChar` is a good thing. – pat May 30 '12 at 17:03
  • Also, you may want all of your terminal parsers to end with `spaces` so that you don't need to sprinkle `spaces` all over your non-terminals. This is what the `lexeme` combinator is for. – pat May 30 '12 at 17:07
  • Thank you. I've changed my code for parse arithmetic using the method you used and everything is working correctly. This is my first big program in Haskell so please excuse any mistakes. Once I've done this I will try using Text.Parsec.Expr – user1424720 May 30 '12 at 17:23