import Text.Parsec import qualified Text.Parsec.Token as P import Text.Parsec.Language import Control.Applicative hiding ((<|>)) import Control.Arrow data T = N Double | T :* T | T :/ T | T :+ T | T :- T | B Bool | T :> T | T :< T | T :== T | If T T T deriving (Show) a --> b = (a, b <$ rOp a) -- Operators: from lowest to highest precedence ops = [ [">" --> (:>), "<" --> (:<), "==" --> (:==)] , ["+" --> (:+), "-" --> (:-)] , ["*" --> (:*), "/" --> (:/)] ] myL = P.makeTokenParser $ javaStyle { P.reservedOpNames = map fst $ concat ops , P.reservedNames = ["if", "else", "true", "false"] } rOp = P.reservedOp myL rW = P.reserved myL parens = P.parens myL braces = P.braces myL bool = B <$> ((True <$ rW "true") <|> (False <$ rW "false")) num = N <$> P.float myL if_ = If <$> (rW "if" *> expr) <*> (braces expr) <*> (rW "else" *> braces expr) infix_ x@(l:t) = do a <- math t f <- choice $ map snd l b <- math x return $ f a b math' = parens $ math ops math [] = try num <|> try bool <|> parens expr math l@(_:t) = try math' <|> try (infix_ l) <|> math t test1 = "1.3 + 1.0 * (2.1 + 3.1) + 1.5" test2 = "if (2.0 + 2.0 * 1.5== 4.0) { \ \ if(true == false) { \ \ true \ \ } else { \ \ 2.1 \ \ } \ \} else { \ \ 1.0 \ \} " expr = try if_ <|> try bool <|> math ops main = mapM (print . parse (expr <* eof) "") [test1, test2, "2.1 == 1.1"]