All pastes #389491 Raw Edit

0x29A in haskell, nearly

public text v1 · immutable
·published 2007-03-10 19:23 UTC
rendered paste body
module Main where

-- there are bugs yet with missing loop marks at beginning or end.

import Control.Monad.State

data X29AState = X29AState {register::Int,
                            stack :: [X29AFunction]} deriving Show

data X29AFunction = PrimS | PrimK | PrimOut | PrimIn | PrimInc | PrimDec | 
                    Apply X29AFunction X29AFunction deriving Show

type X29AMonad a = StateT X29AState IO a

data X29AInsn = SingleInsn (X29AMonad ()) |
                Loop [X29AInsn]

evaluate :: X29AFunction -> Maybe (X29AMonad ())
evaluate (Apply (Apply (Apply PrimS x) y) z) = Just $ push (Apply (Apply x z) (Apply y z))
evaluate (Apply (Apply PrimK x) y) = Just $ push x
evaluate (Apply (Apply PrimOut x) y) = Just $ do push x
                                                 r <- gets register
                                                 liftIO $ print r
--                                                 liftIO $ putChar (toEnum $ fromIntegral r)
evaluate (Apply (Apply PrimIn x) y) = Just $ do push x
                                                c <- liftIO getChar
                                                modify (\x -> x {register = (fromIntegral $ fromEnum c)})
evaluate (Apply (Apply PrimInc x) y) = Just $ do push x
                                                 r <- gets register
                                                 modify (\x -> x {register = r+1})
evaluate (Apply (Apply PrimDec x) y) = Just $ do push x
                                                 r <- gets register
                                                 modify (\x -> x {register = r-1})
evaluate f = Nothing

push :: X29AFunction -> X29AMonad ()
push i = do s <- gets stack
            modify (\x -> x {stack = i:s})

pop :: X29AMonad X29AFunction
pop = do s <- gets stack
         if null s
           then return $ Apply (Apply PrimS PrimK) PrimS
           else modify (\x -> x {stack = tail s}) >> (return $ head s)

swap :: X29AMonad ()
swap = do a <- pop
          b <- pop
          push a
          push b

apply :: X29AMonad ()
apply = do a <- pop
           b <- pop
           push $ Apply b a

parse0x29A :: String -> Maybe (X29AInsn, String)
parse0x29A ('s':rest) = Just (SingleInsn $ push PrimS, rest)
parse0x29A ('k':rest) = Just (SingleInsn $ push PrimK, rest)
parse0x29A ('.':rest) = Just (SingleInsn $ push PrimOut, rest)
parse0x29A (',':rest) = Just (SingleInsn $ push PrimIn, rest)
parse0x29A ('+':rest) = Just (SingleInsn $ push PrimInc, rest)
parse0x29A ('-':rest) = Just (SingleInsn $ push PrimDec, rest)
parse0x29A ('[':rest) = Just (Loop insns, afterloop) where
     (insns,afterloop) = parse0x29Ablock rest
parse0x29A (']':rest) = Nothing
parse0x29A ('%':rest) = Just (SingleInsn $ swap, rest)
parse0x29A ('~':rest) = Just (SingleInsn $ apply, rest)
paese0x29A (_:rest) = Just (return (),rest) -- FIXME: performance!

parse0x29Ablock :: String -> ([X29AInsn],String)
parse0x29Ablock "" = ([],"")
parse0x29Ablock s = case parse0x29A s of
                       Nothing -> ([],"")
                       Just (i,s') ->
                           case parse0x29Ablock s' of
                             (is,s'') -> (i:is,s'')

parse0x29Aprog :: String -> [X29AInsn]
parse0x29Aprog str =
  case parse0x29Ablock str of
    (prg,"") -> prg
    (prg,rest) -> Loop prg : parse0x29Aprog rest

loop0x29A :: [X29AInsn] -> X29AMonad ()
loop0x29A is = do
                 r <- gets register
                 when (r /= 0) $ exec0x29A is >> loop0x29A is
                             
exec0x29A :: [X29AInsn] -> X29AMonad ()
exec0x29A [] = return ()
exec0x29A (SingleInsn i: is) = i >> execTOS >> exec0x29A is
exec0x29A (Loop l : is) = do
         loop0x29A l
         exec0x29A is

execTOS :: X29AMonad ()
execTOS = do
  s <- gets stack
  when (not $ null s) (case evaluate (head s) of
                             Nothing -> return ()
                             Just f -> pop >> f >> execTOS)

run :: String -> IO ()
run = (\i -> execStateT (exec0x29A i) (X29AState 0 []) >>= print ). parse0x29Aprog