View difference between Paste ID: wcYAfuUm and Mxy75qzN
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