fork download
  1. import Text.Parsec
  2. import qualified Text.Parsec.Token as P
  3. import Text.Parsec.Language
  4. import Control.Applicative hiding ((<|>))
  5. import Control.Arrow
  6.  
  7. data T = N Double | T :* T | T :/ T | T :+ T | T :- T
  8. | B Bool | T :> T | T :< T | T :== T
  9. | If T T T
  10. deriving (Show)
  11.  
  12. a --> b = (a, b <$ rOp a)
  13.  
  14. -- Operators: from lowest to highest precedence
  15. ops = [ [">" --> (:>), "<" --> (:<), "==" --> (:==)]
  16. , ["+" --> (:+), "-" --> (:-)]
  17. , ["*" --> (:*), "/" --> (:/)]
  18. ]
  19.  
  20. myL = P.makeTokenParser $ javaStyle {
  21. P.reservedOpNames = map fst $ concat ops
  22. , P.reservedNames = ["if", "else", "true", "false"]
  23. }
  24. rOp = P.reservedOp myL
  25. rW = P.reserved myL
  26. parens = P.parens myL
  27. braces = P.braces myL
  28. bool = B <$> ((True <$ rW "true")
  29. <|> (False <$ rW "false"))
  30. num = N <$> P.float myL
  31. if_ = If <$> (rW "if" *> expr)
  32. <*> (braces expr)
  33. <*> (rW "else" *> braces expr)
  34.  
  35. infix_ x@(l:t) = do
  36. a <- math t
  37. f <- choice $ map snd l
  38. b <- math x
  39. return $ f a b
  40.  
  41. math' = parens $ math ops
  42. math [] = try num <|> try bool <|> parens expr
  43. math l@(_:t) = try math' <|> try (infix_ l) <|> math t
  44.  
  45. test1 = "1.3 + 1.0 * (2.1 + 3.1) + 1.5"
  46.  
  47. test2 = "if (2.0 + 2.0 * 1.5== 4.0) { \
  48. \ if(true == false) { \
  49. \ true \
  50. \ } else { \
  51. \ 2.1 \
  52. \ } \
  53. \} else { \
  54. \ 1.0 \
  55. \} "
  56.  
  57. expr = try if_ <|> try bool <|> math ops
  58.  
  59. main = mapM (print . parse (expr <* eof) "") [test1, test2, "2.1 == 1.1"]
  60.  
Success #stdin #stdout 0s 5972KB
stdin
Standard input is empty
stdout
Right (N 1.3 :+ ((N 1.0 :* (N 2.1 :+ N 3.1)) :+ N 1.5))
Right (If ((N 2.0 :+ (N 2.0 :* N 1.5)) :== N 4.0) (If (B True :== B False) (B True) (N 2.1)) (N 1.0))
Right (N 2.1 :== N 1.1)