-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbrainfuck.hs
More file actions
113 lines (95 loc) · 2.97 KB
/
brainfuck.hs
File metadata and controls
113 lines (95 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import Control.Monad.State
import Data.Char (ord, chr)
import Data.Maybe (catMaybes)
import Text.ParserCombinators.Parsec
import Prelude hiding (read)
import System.Environment
data Operation = Increment Int
| Decrement Int
| Next Int
| Back Int
| Print
| Read
| Loop [Operation]
deriving (Show,Eq)
type Program = [Operation]
data Symbols = Symbols {
incr :: String, -- +
decr :: String, -- -
right :: String, -- >
left :: String, -- <
read :: String, -- ,
prt :: String, -- .
openl :: String, -- [
closel :: String, -- ]
reserved :: String -- []+-<>.,
}
type BFParser = Parser [Operation]
parser :: Symbols -> BFParser
parser s = fmap catMaybes $ many $ try instr <|> try loop <|> r
where
r = noneOf (reserved s) >> return Nothing
instr = choice [
parseInstr incr (Increment 1),
parseInstr decr (Decrement 1),
parseInstr right (Next 1),
parseInstr left (Back 1),
parseInstr read Read,
parseInstr prt Print
]
loop = between
(string $ openl s)
(string $ closel s)
(Just . Loop <$> parser s)
parseInstr f inst = try $ do
_ <- string $ f s
return $ Just inst
program :: BFParser
program = parser Symbols {
incr = "+",
decr = "-",
right = ">",
left = "<",
read = ",",
prt = ".",
openl = "[",
closel = "]",
reserved = "[]+-<>.,"
}
data Tape = Tape [Int] Int [Int]
empty :: Tape
empty = Tape (repeat 0) 0 (repeat 0)
increment :: Int -> Tape -> Tape
increment i (Tape xs x ys) = Tape xs (x+i) ys
decrement :: Int -> Tape -> Tape
decrement i (Tape xs x ys) = Tape xs (x-i) ys
moveLeft :: Tape -> Tape
moveLeft t@(Tape [] _ _) = t
moveLeft (Tape (x:xs) p ys) = Tape xs x (p:ys)
moveRight :: Tape -> Tape
moveRight t@(Tape _ _ []) = t
moveRight (Tape xs p (y:ys)) = Tape (p:xs) y ys
setV :: Int -> Tape -> Tape
setV x (Tape xs _ ys) = Tape xs x ys
getV :: Tape -> Int
getV (Tape _ x _) = x
execute :: Operation -> StateT Tape IO()
execute (Increment i) = modify (increment i)
execute (Decrement i) = modify (decrement i)
execute (Next i) = modify ((!! i) . iterate moveRight)
execute (Back i) = modify ((!! i) . iterate moveLeft)
execute Read = liftIO getChar >>= modify . setV . ord
execute Print = gets getV >>= liftIO . putStr . return . chr
execute l@(Loop xs) = do
x <- gets getV
unless (x == 0) $ mapM_ execute xs >> execute l
eval :: Program -> IO ()
eval [] = return ()
eval xs = evalStateT (mapM_ execute xs) empty
main :: IO ()
main = do
(fileName:_) <- getArgs
result <- parseFromFile program fileName
case result of
Left err -> putStr "error: " >> Prelude.print err
Right x -> eval x