SHOW:
|
|
- or go back to the newest paste.
| 1 | import qualified Control.Exception as E | |
| 2 | import Control.Monad | |
| 3 | import Data.Array.IO | |
| 4 | import Data.Char | |
| 5 | import Data.IORef | |
| 6 | import qualified Data.Map as M | |
| 7 | import Data.Word | |
| 8 | import System.Environment | |
| 9 | import Data.Maybe (fromJust) | |
| 10 | import qualified Text.ParserCombinators.Parsec as P | |
| 11 | ||
| 12 | data Exp = Back | Forward | Minus | Plus | In | Out | Loop [Exp] | |
| 13 | data State = State (IORef Int) (IOArray Int Word8) | |
| 14 | ||
| 15 | modifyArray :: (Ix i) => IOArray i e -> i -> (e -> e) -> IO () | |
| 16 | modifyArray array index f = do | |
| 17 | old <- readArray array index | |
| 18 | writeArray array index (f old) | |
| 19 | ||
| 20 | eval :: Exp -> State -> IO () | |
| 21 | ||
| 22 | eval Back (State ptr _) = modifyIORef ptr (subtract 1) | |
| 23 | eval Forward (State ptr _) = modifyIORef ptr (+1) | |
| 24 | ||
| 25 | eval Minus (State ptr tape) = do | |
| 26 | curptr <- readIORef ptr | |
| 27 | modifyArray tape curptr (subtract 1) | |
| 28 | ||
| 29 | eval Plus (State ptr tape) = do | |
| 30 | curptr <- readIORef ptr | |
| 31 | modifyArray tape curptr (+1) | |
| 32 | ||
| 33 | eval In (State ptr tape) = do | |
| 34 | curptr <- readIORef ptr | |
| 35 | char <- getChar `E.catch` ((\_ -> return '\xFF') :: E.IOException -> IO Char) | |
| 36 | writeArray tape curptr $ fromIntegral $ ord char | |
| 37 | ||
| 38 | eval Out (State ptr tape) = do | |
| 39 | curptr <- readIORef ptr | |
| 40 | char <- readArray tape curptr | |
| 41 | putChar $ chr $ fromIntegral char | |
| 42 | ||
| 43 | eval exp@(Loop body) st@(State ptr tape) = do | |
| 44 | curptr <- readIORef ptr | |
| 45 | val <- readArray tape curptr | |
| 46 | when (val /= 0) $ do | |
| 47 | sequence $ map (flip eval st) body | |
| 48 | eval exp st | |
| 49 | ||
| 50 | simpleOps = M.fromList [ | |
| 51 | ('<', Back),
| |
| 52 | ('>', Forward),
| |
| 53 | ('-', Minus),
| |
| 54 | ('+', Plus),
| |
| 55 | (',', In),
| |
| 56 | - | parse :: String -> ([Exp], String) |
| 56 | + | |
| 57 | ||
| 58 | - | parse "" = ([], "") |
| 58 | + | parse :: String -> [Exp] |
| 59 | - | parse (x:xs) = case M.lookup x simpleOps of |
| 59 | + | parse str = case P.parse (P.many statement) "" str of |
| 60 | - | Just exp -> let (restExp, restCode) = parse xs in (exp:restExp, restCode) |
| 60 | + | Right x -> x |
| 61 | - | Nothing -> case x of |
| 61 | + | Left x -> error $ "b0rk: " ++ (show x) |
| 62 | - | '[' -> |
| 62 | + | |
| 63 | - | let |
| 63 | + | statement :: P.Parser Exp |
| 64 | - | (body, next) = parse xs |
| 64 | + | statement = P.try (do op <- P.oneOf "<>.,+-" |
| 65 | - | (restExp, restCode) = parse next |
| 65 | + | return (fromJust $ M.lookup op simpleOps)) |
| 66 | - | in ((Loop body):restExp, restCode) |
| 66 | + | P.<|> |
| 67 | - | ']' -> ([], xs) |
| 67 | + | do P.char '[' |
| 68 | - | _ -> parse xs |
| 68 | + | res <- P.many statement |
| 69 | P.char ']' | |
| 70 | return $ Loop res | |
| 71 | ||
| 72 | main :: IO () | |
| 73 | ||
| 74 | main = do | |
| 75 | - | let (exps, _) = parse code |
| 75 | + | |
| 76 | code <- readFile pfile | |
| 77 | let exps = parse code | |
| 78 | ptr <- newIORef 0 | |
| 79 | tape <- newArray (0, 4096) 0 | |
| 80 | sequence_ $ map (flip eval (State ptr tape)) exps |