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