読者です 読者をやめる 読者になる 読者になる

はわわーっ

はわわわわっ

brainf*ck インタープリタを作ってみた

やってみた。

import Data.Char (chr)
import System.IO


readBF :: FilePath -> IO String
readBF file = do
  com <- readFile file
  return $ filter (`elem` "><+-.,[]") com


brainfuck :: String -> String
brainfuck com = reverse $ interp com (repeat 0, 0, [], [])
  where
    interp []     (_,   _,   _,   out) = out
    interp (c:cs) (mem, ptr, stk, out) =
      case c of
        '>' -> interp cs (mem, ptr+1, c:stk, out)
        '<' -> interp cs (mem, ptr-1, c:stk, out)
        '+' -> interp cs (inc mem ptr, ptr, c:stk, out)
        '-' -> interp cs (dec mem ptr, ptr, c:stk, out)
        '.' -> interp cs (mem, ptr, c:stk, chr (mem !! ptr) : out)
        -- ','
        '[' -> if mem !! ptr == 0
                 then let (cs', stk') = findClose cs (c:stk) 0 in
                      interp cs' (mem, ptr, stk', out)
                 else interp cs (mem, ptr, c:stk, out)
        ']' -> if mem !! ptr /= 0
                 then let (cs', stk') = findOpen cs (c:stk) 0 in
                      interp cs' (mem, ptr, stk', out)
                 else interp cs (mem, ptr, c:stk, out)

    inc mem ptr = take ptr mem ++ [(mem !! ptr) +1] ++ drop (ptr+1) mem
    dec mem ptr = take ptr mem ++ [(mem !! ptr) -1] ++ drop (ptr+1) mem

    findClose (c:cs) stk nst
      | c == ']' && nst == 1 = (cs, c:stk)
      | c == '['             = findClose cs (c:stk) (nst+1)
      | c == ']'             = findClose cs (c:stk) (nst-1)
      | otherwise            = findClose cs (c:stk) nst

    findOpen cs (s:stk) nst
      | s == '[' && nst == 1 = (s:cs, stk)
      | s == ']'             = findOpen (s:cs) stk (nst+1)
      | s == '['             = findOpen (s:cs) stk (nst-1)
      | otherwise            = findOpen (s:cs) stk nst


main :: IO ()
main = do
  bf <- readBF "helloworld.bf"
  putStrLn $ brainfuck bf
# helloworld

+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.
Hello, world!

参考