-
Notifications
You must be signed in to change notification settings - Fork 259
Expand file tree
/
Copy pathbf.hs
More file actions
85 lines (73 loc) · 2.51 KB
/
bf.hs
File metadata and controls
85 lines (73 loc) · 2.51 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
module Main where
import qualified Data.Array.Base as ArrayBase
import qualified Data.Array.Unboxed as UArray
import qualified Data.ByteString.Char8 as C
import Data.Char (chr)
import System.Environment (getArgs)
import System.IO (hFlush, stdout)
import Network.Simple.TCP
import System.Posix (getProcessID)
data Op = Inc Int | Move Int | Print | Loop [Op] deriving Show
data Tape = Tape { tapeData :: UArray.UArray Int Int
, tapePos :: Int
} deriving Show
current :: Tape -> Int
current tape = ArrayBase.unsafeAt (tapeData tape) (tapePos tape)
inc :: Int -> Tape -> Tape
inc delta tape =
tape { tapeData = newData }
where
newData = ArrayBase.unsafeReplace (tapeData tape)
[(tapePos tape, (current tape) + delta)]
move :: Int -> Tape -> Tape
move m tape =
tape { tapeData = newData, tapePos = newPos }
where
curData = tapeData tape
len = ArrayBase.numElements curData
newPos = (tapePos tape) + m
asc = ArrayBase.assocs curData
newData = if newPos < len
then curData
else ArrayBase.unsafeArray (0, newPos)
(asc ++ [(i, 0) | i <- [len..newPos]])
parse :: ([Char], [Op]) -> ([Char], [Op])
parse ([], acc) = ([], reverse acc)
parse (c:cs, acc) =
case c of
'+' -> parse (cs, Inc 1:acc)
'-' -> parse (cs, Inc (-1):acc)
'>' -> parse (cs, Move 1:acc)
'<' -> parse (cs, Move (-1):acc)
'.' -> parse (cs, Print:acc)
'[' -> parse (newCs, Loop loop:acc)
where (newCs, loop) = parse (cs, [])
']' -> (cs, reverse acc)
otherwise -> parse (cs, acc)
run :: [Op] -> Tape -> IO Tape
run [] tape = return tape
run (op:ops) tape = do
case op of
Inc d -> run ops $ inc d tape
Move m -> run ops $ move m tape
Print -> do
putStr $ [chr $ current tape]
hFlush stdout
run ops tape
Loop loop -> do
if current tape == 0
then run ops tape
else do
newTape <- run loop tape
run (op:ops) newTape
notify msg = do
connect "localhost" "9001" $ \(socket, _) -> do
send socket $ C.pack msg
main = do
[filename] <- getArgs
source <- readFile filename
pid <- getProcessID
notify $ "Haskell\t" ++ show pid
let (_, ops) = parse (source, [])
run ops (Tape (ArrayBase.unsafeArray (0, 0) [(0, 0)]) 0)
notify "stop"