Skip to content

Instantly share code, notes, and snippets.

@ujihisa
Created December 26, 2011 05:44
Show Gist options
  • Save ujihisa/1520583 to your computer and use it in GitHub Desktop.
Save ujihisa/1520583 to your computer and use it in GitHub Desktop.
(begin
(def 0 98)
(f 90 7)
(putc (ref 0))
(end)
(defn f (x y)
(putc (g x y)))
(defn g (x y)
(+ x y)))
import qualified VM as V
import qualified Text.Parsec as P
import Control.Applicative ((<|>), (<$>))
import qualified Control.Monad.State as S
import qualified Data.Map as M
import Data.Maybe (fromJust)
data Intermediate = Comment String
| Inst V.Instruction
| Paramdef String
| Paramref String
deriving Show
type LispParser = P.ParsecT String () (S.State String)
type ParamMap = M.Map String Integer
main :: IO ()
main = do
code <- readFile "hworld.lisp"
--mapM_ print $ parse code
let runtime = compile (parse code)
mapM_ print runtime
putStrLn "--"
V.vm (V.VM runtime (V.Stack []) (V.Stack []) M.empty 0)
parse :: String -> [Intermediate]
parse str = either (error . show) id $
S.evalState (P.runPT parseExpr () "lisp" str) "toplevel"
parseExpr :: LispParser [Intermediate]
parseExpr = P.try parseInt
<|> parseDefn
<|> parseBuiltin
<|> parseApply
<|> parseVar
parseInt :: LispParser [Intermediate]
parseInt = do
x <- P.many1 P.digit
return [Inst $ V.Push $ read x]
parseAtom :: LispParser String
parseAtom = P.many1 $ P.noneOf " \t\n()"
parseDefn :: LispParser [Intermediate]
parseDefn = do
P.try $ do
ignoringSpaces $ P.char '('
ignoringSpaces $ P.string "defn"
fname <- requireSpaces parseAtom
S.lift $ S.put fname
ignoringSpaces $ P.char '('
names <- ignoringSpaces $ parseAtom `P.sepBy` P.skipMany1 P.space
ignoringSpaces $ P.char ')'
body <- ignoringSpaces parseExpr
ignoringSpaces $ P.char ')'
S.lift $ S.put "toplevel"
return $
Comment "(defn" :
Inst (V.Label fname) :
map (Paramdef . ((fname ++ "/") ++)) names ++
body ++ [Inst V.Return] ++ [Comment ")"]
parseBuiltin :: LispParser [Intermediate]
parseBuiltin = P.try $ do
(fname, xs) <- atomAndArgs
x <- case (fname, length xs) of
("+", 2) -> return [Inst $ V.Infix V.Plus]
("putc", 1) -> return [Inst V.OutputChar]
("def", 2) -> return [Inst V.Store]
("ref", 1) -> return [Inst V.Retrieve]
("end", 0) -> return [Inst V.End]
("begin", _) -> return []
_ -> fail "omg"
return $ Comment ('(' : fname) : concat xs ++ x ++ [Comment ")"]
parseApply :: LispParser [Intermediate]
parseApply = do
(fname, xs) <- atomAndArgs
return $ concat xs ++ [Inst $ V.Call fname]
atomAndArgs :: LispParser (String, [[Intermediate]])
atomAndArgs = do
ignoringSpaces $ P.char '('
fname <- ignoringSpaces parseAtom
xs <- ignoringSpaces $ parseExpr `P.sepBy` P.many1 P.space
P.char ')'
return (fname, xs)
parseVar :: LispParser [Intermediate]
parseVar = do
name <- ignoringSpaces $ P.many1 $ P.noneOf " \t\n()"
fname <- S.lift S.get
return [Paramref $ fname ++ '/' : name]
ignoringSpaces :: LispParser a -> LispParser a
ignoringSpaces f = P.skipMany P.space >> f
requireSpaces :: LispParser a -> LispParser a
requireSpaces f = P.skipMany1 P.space >> f
compile :: [Intermediate] -> [V.Instruction]
compile inters = concat $ S.evalState (mapM compile' inters) M.empty
compile' :: Intermediate -> S.State ParamMap [V.Instruction]
compile' (Comment _) = return []
compile' (Inst x) = return [x]
compile' (Paramdef name) = do
idx <- pred . negate . fromIntegral . M.size <$> S.get
S.modify $ M.insert name idx
return [V.Push idx, V.Swap, V.Store]
compile' (Paramref name) = do
idx <- fromJust . M.lookup name <$> S.get
return [V.Push idx, V.Retrieve]
diff --git VM.hs VM.hs
index c9e96ab..bb74374 100644
--- VM.hs
+++ VM.hs
@@ -1,6 +1,8 @@
module VM where
import IO
+import qualified Data.Map as M
+import Data.Maybe (fromJust)
{- Stack machine for running whitespace programs -}
@@ -35,7 +37,7 @@ type Loc = Integer
type Program = [Instruction]
newtype Stack = Stack [Integer]
-type Heap = [Integer]
+type Heap = M.Map Integer Integer
data VMState = VM {
program :: Program,
@@ -130,13 +132,7 @@ findLabel' m (_:xs) i = findLabel' m xs (i+1)
-- Heap management
retrieve :: Integer -> Heap -> IO Integer
-retrieve x heap = return (heap!!(fromInteger x))
+retrieve x heap = return $ fromJust $ M.lookup x heap
store :: Integer -> Integer -> Heap -> IO Heap
-store x 0 (h:hs) = return (x:hs)
-store x n (h:hs) = do hp <- store x (n-1) hs
- return (h:hp)
-store x 0 [] = return (x:[])
-store x n [] = do hp <- store x (n-1) []
- return (0:hp)
-
+store x n h = return $ M.insert n x h
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment