2009/07/31

Make Simple Calculator Using Parsec

Make simple calculator using Parsec in Haskell. The calculator can use +, -, *, / and **(power).


import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language
import System.IO

lexer :: P.TokenParser ()
lexer = P.makeTokenParser (haskellDef { reservedOpNames = ["*","/","+","-","**"] })

naturalOrFloat = P.naturalOrFloat lexer
parens = P.parens lexer
reservedOp = P.reservedOp lexer

expr :: Parser Double
expr = buildExpressionParser table factor <?> "expression"
where
table = [
[unary "-" negate, unary "+" id],
[op "**" (**) AssocRight],
[op "*" (*) AssocLeft, op "/" (/) AssocLeft],
[op "+" (+) AssocLeft, op "-" (-) AssocLeft]
]
op s f assoc = Infix (do{ reservedOp s; return f } <?> "operator") assoc
unary s f = Prefix (do{ reservedOp s; return f })

factor :: Parser Double
factor =
do {
parens expr;
} <|> do {
norf <- naturalOrFloat;
case norf of
Left i -> return $ fromInteger i
Right f -> return $ f
} <?>
"factor"

repl :: String -> (String -> Bool) -> (String -> String) -> IO ()
repl prompt bQuit eval = loop
where
loop = do
putStr prompt
s <- getLine
if bQuit s
then return ()
else putStrLn (eval s) >> loop

calc :: IO ()
calc = repl "> " (== ":q") (tostring . parse stmt "")
where
tostring (Right v) = show v
tostring (Left err) = show err
stmt = do
e <- expr
eof
return e

main = hSetBuffering stdout NoBuffering >> putStrLn "type ':q' to quit." >> calc >> putStrLn "Bye"



No comments: