-
Notifications
You must be signed in to change notification settings - Fork 4
/
brainfuck.hs
110 lines (95 loc) · 2.88 KB
/
brainfuck.hs
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
module Main where
import Control.Monad
import Control.Monad.State
import qualified Data.Map as M
import Data.Char
import Text.ParserCombinators.Parsec
import System.IO
data Stmt
= IncPtr | DecPtr | IncVal | DecVal
| PutChar | GetChar | While [Stmt]
| Nop
deriving (Show,Eq)
data St = MkSt
{ ptr :: Int
, mem :: M.Map Int Int
}
deriving (Show,Eq)
type EvalM = StateT St IO
initialSt :: St
initialSt = MkSt
{ ptr = 0
, mem = M.empty
}
eval :: Stmt -> EvalM ()
eval IncPtr = modify $ \st -> st { ptr = ptr st + 1 }
eval DecPtr = modify $ \st -> st { ptr = ptr st - 1 }
eval IncVal = modify $ \st -> st { mem = M.insert (ptr st) (look 0 (ptr st) (mem st) + 1) (mem st) }
eval DecVal = modify $ \st -> st { mem = M.insert (ptr st) (look 0 (ptr st) (mem st) - 1) (mem st) }
eval PutChar = do
st <- get
lift $ putChar $ chr $ look 0 (ptr st) (mem st)
eval GetChar = do
x <- lift getChar
modify $ \st -> st { mem = M.insert (ptr st) (ord x) (mem st) }
eval (While ss) = do
st <- get
if look 0 (ptr st) (mem st) /= 0
then mapM_ eval ss >> eval (While ss)
else return ()
eval Nop = return ()
look :: (Ord a) => b -> a -> M.Map a b -> b
look def x v
| Just y <- M.lookup x v = y
| otherwise = def
parseBrainfuck :: String -> Either ParseError [Stmt]
parseBrainfuck input = parse (many parseStmt) "(unknown)" input
run :: String -> IO ()
run input = do
case parseBrainfuck input of
Right ss -> evalStateT (mapM_ eval ss) initialSt
Left e -> putStrLn . show $ e
main :: IO ()
main = hSetBuffering stdout NoBuffering >> getContents >>= run
parseStmt :: GenParser Char st Stmt
parseStmt = choice [parseSimpleStmt, parseWhileStmt, parseDummy]
parseSimpleStmt :: GenParser Char st Stmt
parseSimpleStmt = do
symbol <- oneOf "><+-.,"
case symbol of
'>' -> return IncPtr
'<' -> return DecPtr
'+' -> return IncVal
'-' -> return DecVal
'.' -> return PutChar
',' -> return GetChar
parseWhileStmt :: GenParser Char st Stmt
parseWhileStmt = do
char '['
body <- many parseStmt
char ']'
return $ While body
parseDummy :: GenParser Char st Stmt
parseDummy = do
noneOf "><+-.,[]"
return Nop
helloWorldBF :: String
helloWorldBF =
"++++++++++\
\[\
\ >+++++++>++++++++++>+++>+<<<<-\
\] Schleife zur Vorbereitung der Textausgabe\
\>++. Ausgabe von 'H'\
\>+. Ausgabe von 'e'\
\+++++++. 'l'\
\. 'l'\
\+++. 'o'\
\>++. Leerzeichen\
\<<+++++++++++++++. 'W'\
\>. 'o'\
\+++. 'r'\
\------. 'l'\
\--------. 'd'\
\>+. '!'\
\>. Zeilenvorschub\
\+++. Wagenrücklauf"