\chapter{Command Interpreter} \begin{verbatim} $Log: Main.lhs,v $ Revision 1.1 2004/08/05 11:12:53 malcolm Add a regression testsuite for the nhc98 compiler. It isn't very good, but it is better than nothing. I've been using it for about four years on nightly builds, so it's about time it entered the repository! It includes a slightly altered version of the nofib suite. Instructions are in the README. Revision 1.3 1999/11/02 16:10:42 simonpj Haskell 98 changes Revision 1.2 1996/07/25 21:30:47 partain Bulk of final changes for 2.01 Revision 1.1 1996/01/08 20:05:20 partain Initial revision \end{verbatim} Eventually we will build a command interpreter here, for a desk calculator type language. > module Main where > import RealReals > import Char For the moment on the other hand it just prints a given number. > main = getContents >>= (foldr output (return ()) . map doLine . lines) Printing out @String@'s is easy: > output :: String -> IO () -> IO () > output string dialogue = putStr (string++"\n") >> dialogue The @doLine@ function parses the line, if it is syntactically correct it then evaluates the expression returning the answer string. > doLine :: String -> String > doLine = eval [] . tokenize > tokenize "" = [] > tokenize (c:cs) | isSpace c = tokenize (dropWhile isSpace cs) > tokenize (c:cs) | isSymb c = [c]: tokenize cs > tokenize (c:cs) | isAlpha c = case (span isAlphaNum cs) of > (nam,t) -> (c:nam): tokenize t > tokenize (c:cs) | isDigit c = case (span isDigit cs) of > (num,t) -> (c:num): tokenize t > tokenize _ = ["Error"] > isSymb c = c `elem` "*+-/" > eval :: [RealReal] -> [String] -> String > eval [n] [] = show n > eval ns (t:ts) | isSymb (head t) > = case head t of > '+' -> check2 (+) ns ts > '-' -> check2 (-) ns ts > '*' -> check2 (*) ns ts > '/' -> check2 (/) ns ts > _ -> "Error" > eval ns (t:ts) | isDigit (head t) > = eval (fromInteger (parseInteger t): ns) ts > eval ns (t:ts) | isAlpha (head t) > = case t of > "abs" -> check1 abs ns ts > "signum" -> check1 signum ns ts > "pi" -> eval (pi:ns) ts > "exp" -> check1 exp ns ts > "log" -> check1 log ns ts > "sqrt" -> check1 sqrt ns ts > "sin" -> check1 sin ns ts > "cos" -> check1 cos ns ts > "tan" -> check1 tan ns ts > "asin" -> check1 asin ns ts > "acos" -> check1 acos ns ts > "atan" -> check1 atan ns ts > "sinh" -> check1 sinh ns ts > "cosh" -> check1 cosh ns ts > "tanh" -> check1 tanh ns ts > "asinh" -> check1 asinh ns ts > "acosh" -> check1 acosh ns ts > "atanh" -> check1 atanh ns ts > _ -> "Error" > eval _ _ = "Error" > check1 :: (RealReal -> RealReal) -> [RealReal] -> [String] -> String > check1 f (n:ns) ts = eval (f n: ns) ts > check1 f _ ts = "Error" > check2 :: (RealReal -> RealReal -> RealReal) -> > [RealReal] -> [String] -> String > check2 f (n0:n1:ns) ts = eval (f n1 n0 : ns) ts > check2 f _ ts = "Error" > parseInteger :: String -> Integer > parseInteger = makeNumber 10 . map number > where number :: Char -> Integer > number c = toInteger (fromEnum c - fromEnum '0') > makeNumber :: Integer -> [Integer] -> Integer > makeNumber m = foldl f 0 > where f a x = a * m + x