harpy-0.4: examples/evaluator/Evaluator.hs
module Main(main) where
import ArithTypes
import ArithParser
import Harpy
import Harpy.X86Disassembler
import Foreign
import Control.Monad
import System.Console.Readline
import Text.ParserCombinators.Parsec
$(callDecl "callAsWord32" [t|Word32|])
main :: IO ()
main = do putStrLn "\n\n\n\nHarpy Interpreter"
putStrLn "(type :help to see a help message)"
allocaArray 26 (\ p -> mapM_ (\ i -> poke (advancePtr p i) 0) [0..25] >> repl p False)
repl :: Ptr Int32 -> Bool -> IO ()
repl env verbose =
do s <- readline "@ "
case s of
Nothing -> return ()
Just s' -> do addHistory s'
interpret env verbose s'
interpret :: Ptr Int32 -> Bool -> String -> IO ()
interpret env verbose s =
do let e = parse statement "<standard input>" s
case e of
Left err -> do putStrLn (show err)
repl env verbose
Right stmt -> run env verbose stmt
run :: Ptr Int32 -> Bool -> Stmt -> IO ()
run env verbose (Cmd Help) =
do putStrLn "Enter an arithmetic expression to evaluate it"
putStrLn " e.g. 5 / 2"
putStrLn "Enter an assignment to set a variable"
putStrLn " e.g. a := 4 * 2 - (6 + 1)"
putStrLn "Enter :help to see this message again"
putStrLn "Enter :quit to exit"
putStrLn "Enter :verbose to toggle disassembly output"
repl env verbose
run env _ (Cmd Quit) = return ()
run env verbose (Cmd Verbose) = repl env (Prelude.not verbose)
run env verbose stmt@(Assign var exp) =
do (i, ins) <- eval' env stmt
when verbose (mapM_ (putStrLn . showIntel) ins)
repl env verbose
run env verbose stmt@(Print exp) =
do (i, ins) <- eval' env stmt
putStrLn (show i)
when verbose (mapM_ (putStrLn . showIntel) ins)
repl env verbose
-- Function for compiling and executing statements.
eval' :: Ptr Int32 -> Stmt -> IO (Int32, [Instruction])
eval' env e = do (_, Right v) <- runCodeGen (compileAndRun e) env ()
return v
compileAndRun :: Stmt -> CodeGen (Ptr Int32) s (Int32, [Instruction])
compileAndRun (Assign c exp) =
do entryCode
compileExp exp
env <- getEnv
mov (variableAddress env c) eax
exitCode
d <- disassemble
callAsVoid
return (0, d)
compileAndRun (Print exp) =
do entryCode
compileExp exp
exitCode
d <- disassemble
r <- callAsWord32
return (fromIntegral r, d)
compileExp :: Exp -> CodeGen (Ptr Int32) s ()
compileExp (Add e1 e2) = compileBinOp e1 e2 (add eax (Ind esp))
compileExp (Sub e1 e2) = compileBinOp e1 e2 (sub eax (Ind esp))
compileExp (Mul e1 e2) = compileBinOp e1 e2 (imul InPlace eax (Ind esp))
compileExp (Div e1 e2) = compileBinOp e1 e2 (cdq >> idiv (Ind esp))
compileExp (Lit i) = mov eax ((fromIntegral i) :: Word32)
compileExp (Var c) = do env <- getEnv
mov eax (variableAddress env c)
compileBinOp :: Exp -> Exp -> CodeGen (Ptr Int32) s a -> CodeGen (Ptr Int32) s ()
compileBinOp e1 e2 op = do compileExp e2
push eax
compileExp e1
op
add esp (4 :: Word32)
entryCode :: CodeGen e s ()
entryCode = do push ebp
mov ebp esp
exitCode :: CodeGen e s ()
exitCode = do mov esp ebp
pop ebp
ret
variableAddress :: Ptr Int32 -> Char -> Addr
variableAddress env c =
let ofs = fromEnum c - fromEnum 'a'
env' = advancePtr env ofs
in Addr (fromIntegral (ptrToWordPtr env'))