-- Parsing Examples: -- -- > functionParse "(x+1)^2" -- Just (Exp (Add (Var "x") (Num 1.0)) (Num 2.0)) -- -- > functionParse "e^x*(cos(5*x) - 3*sin x)" -- Just (Mul (Exp (Var "e") (Var "x")) (Sub (Cos (Mul (Num 5.0) (Var "x"))) (Mul (Num 3.0) (Sin (Var "x"))))) module Text.ParserCombinators.Parsec.ParserFunction (functionParse) where import Data.Char (toLower) import Text.ParserCombinators.Parsec import Text.ParserCombinators.Parsec.Expr data Expr = Num Double | Var String | Sub Expr Expr | Div Expr Expr | Exp Expr Expr | Log Expr | Abs Expr | Sqrt Expr | Cbrt Expr | ArcSinh Expr | ArcCosh Expr | ArcTanh Expr | ArcSin Expr | ArcCos Expr | ArcTan Expr | Sinh Expr | Cosh Expr | Tanh Expr | Sin Expr | Cos Expr | Tan Expr | ArcSech Expr | ArcCsch Expr | ArcCoth Expr | ArcSec Expr | ArcCsc Expr | ArcCot Expr | Sech Expr | Csch Expr | Coth Expr | Sec Expr | Csc Expr | Cot Expr | Mul Expr Expr | Add Expr Expr deriving (Show, Eq, Ord) functionParse :: String -> Maybe Expr functionParse xs = either (const Nothing) (Just) (parse getFunction "" handleString) where handleString = "(" ++ (map toLower $ filter (/=' ') xs) ++ ")" getFunction :: Parser Expr getFunction = buildExpressionParser expressionTable factor expressionTable :: [[Operator Char st Expr]] expressionTable = [[pr "arcsinh" ArcSinh, pr "arcsin" ArcSin, pr "sinh" Sinh, pr "sin" Sin], [pr "arccosh" ArcCosh, pr "arccos" ArcCos, pr "cosh" Cosh, pr "cos" Cos], [pr "arctanh" ArcTanh, pr "arctan" ArcTan, pr "tanh" Tanh, pr "tan" Tan], [pr "arcsech" ArcSech, pr "arcsec" ArcSec, pr "sech" Sech, pr "sec" Sec], [pr "arccsch" ArcCsch, pr "arccsc" ArcCsc, pr "csch" Csch, pr "csc" Csc], [pr "arccoth" ArcCoth, pr "arccot" ArcCot, pr "coth" Coth, pr "cot" Cot], [pr "log" Log, pr "abs" Abs], [pr "sqrt" Sqrt, pr "cbrt" Cbrt], [op "^" Exp AssocLeft], [op "*" Mul AssocLeft, op "/" Div AssocLeft], [op "+" Add AssocLeft, op "-" Sub AssocLeft]] where op s f assoc = Infix (do{ string s; return f}) assoc pr s f = Prefix (try (string s) >> return f) factor :: Parser Expr factor = do char '(' e <- getFunction char ')' return e <|> variables variables :: Parser Expr variables = do ds <- many1 letter return $ case ds of ds | (length ds) == 1 -> Var ds ds -> error $ "parser error on `" ++ ds ++ "'" <|> number number :: Parser Expr number = do br <- many digit let d :: Double d = fromInteger (foldl ((. ch2num) . (+) . (*10)) 0 br) option (Num (d)) (try (do char '.' ar <- many1 digit return $ (Num (d + foldr (fd) 0 ar)) )) where fd a b = (fromInteger (ch2num a) + b) / 10 fe = toInteger . fromEnum ch2num = (subtract $ fe '0') . fe