Created
January 26, 2014 07:37
-
-
Save CodaFi/8629725 to your computer and use it in GitHub Desktop.
A very simple, very naïve, implementation of a Stack-based calculator language over integers with Haskell.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main where | |
import Control.Monad (forever) | |
import System.Exit (exitSuccess) | |
import Data.String | |
import Data.Char (isDigit) | |
data Stack a = Empty | Elem a (Stack a) | |
data OpCode = INT Int | | |
ADD | | |
SUB | | |
MUL | | |
DIV | | |
LET String Int | | |
CMP | | |
GEQ | | |
LEQ | | |
NOP deriving (Show) | |
instance Show a => Show (Stack a) where | |
show Empty = "EOF" | |
show (Elem a stk) = (show a) ++ " " ++ (show stk) | |
instance IsString OpCode where | |
fromString s | |
| isNum s = INT ((read s) :: Int) | |
| s == "+" = ADD | |
| s == "-" = SUB | |
| s == "*" = MUL | |
| s == "/" = DIV | |
| s == "==" = CMP | |
| s == "<=" = LEQ | |
| s == ">=" = GEQ | |
-- | isLet s = evalLet s | |
| otherwise = NOP | |
main :: IO () | |
main = do | |
putStrLn "CSCI" | |
forever $ do | |
g <- getLine | |
if g == ":quit" | |
then do putStrLn "Bye-bye!" | |
exitSuccess | |
else do putStrLn $ "> " ++ (show . eval . tokenize) g | |
return () | |
isNum :: String -> Bool | |
isNum = all isDigit | |
push :: OpCode -> Stack OpCode -> Stack OpCode | |
push el s = Elem el s | |
pop :: Stack OpCode -> (OpCode, Stack OpCode) | |
pop Empty = (NOP, Empty) | |
pop (Elem a s) = (a, s) | |
tokenize :: String -> Stack OpCode | |
tokenize [] = Empty | |
tokenize s = foldl (\s el -> push el s) Empty (map fromString (words s)) | |
eval :: Stack OpCode -> Int | |
eval Empty = 0 | |
eval (Elem (INT i) Empty) = i | |
eval (Elem op stk) = let op2 = fst $ pop stk in | |
let stk2 = snd $ pop stk in | |
let op3 = fst $ pop stk2 in | |
let stk3 = snd $ pop stk2 in | |
case op of | |
INT i -> eval $ push (INT (evalExpr i op2 op3)) stk3 | |
_ -> 0 | |
{- | |
evalLet :: String -> LET String Int | |
evalLet [] = LET "" 0 | |
evalLet s = LET | |
-} | |
evalExpr :: Int -> OpCode -> OpCode -> Int | |
evalExpr r op (INT l) = case op of | |
ADD -> l + r | |
SUB -> l - r | |
MUL -> l * r | |
DIV -> l `div` r | |
CMP -> if (l == r) then 1 else 0 | |
LEQ -> if (l <= r) then 1 else 0 | |
GEQ -> if (l >= r) then 1 else 0 | |
NOP -> 0 | |
_ -> 0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment