Skip to content

Instantly share code, notes, and snippets.

@CodaFi
Created January 26, 2014 07:37
Show Gist options
  • Save CodaFi/8629725 to your computer and use it in GitHub Desktop.
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.
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