PageRenderTime 48ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/BrainFuck.hs

http://github.com/jkramer/brainfuck
Haskell | 96 lines | 45 code | 37 blank | 14 comment | 5 complexity | 62f9bc090be57b794cf262e29d93b5a6 MD5 | raw file
  1. import System.Environment
  2. import System.IO
  3. import Data.Char
  4. data RunTime = RunTime Int [Int] deriving (Show)
  5. -- RunTime constructor.
  6. newRunTime = RunTime 0 $ replicate 512 0
  7. -- Main function.
  8. main = getArgs >>= mapM_ (\ p -> readFile p >>= execute newRunTime)
  9. -- Execute the brainfuck code from a string.
  10. execute runTime "" = return runTime
  11. execute runTime (command:rest) = do
  12. case command of
  13. '+' -> execute (increase runTime) rest
  14. '-' -> execute (decrease runTime) rest
  15. '>' -> execute (up runTime) rest
  16. '<' -> execute (down runTime) rest
  17. ',' -> input runTime >>= flip execute rest
  18. '.' -> output runTime >> execute runTime rest
  19. '#' -> print runTime >> execute runTime rest
  20. '[' -> runLoop loop runTime >>= flip execute loopRest
  21. _ -> execute runTime rest
  22. where
  23. loop = init (loopCode rest 1)
  24. loopRest = drop ((length loop) + 1) rest
  25. -- Increase the value under the pointer in memory.
  26. increase = changeMemory (+ 1)
  27. -- Decrease the value under the pointer.
  28. decrease = changeMemory (+ (- 1))
  29. -- Move the pointer to the next register.
  30. up (RunTime offset memory) = RunTime (offset + 1) memory
  31. -- Move the pointer to the previous register.
  32. down (RunTime offset memory) = RunTime (offset - 1) memory
  33. -- Read a character into the register at the current position.
  34. input runTime = safeGetChar >>= return . flip changeMemory runTime . const . ord
  35. -- Read a character and return it (or \0 if EOF is reached).
  36. safeGetChar = hIsEOF stdin >>= \ eof -> if eof then return '\0' else getChar
  37. -- Print the character in the current register.
  38. output = (>> hFlush stdout) . putChar . chr . currentValue
  39. -- Take a callback, apply it on the value of the current register.
  40. changeMemory callback (RunTime offset memory) =
  41. let (left, right) = splitAt offset memory
  42. in RunTime offset (left ++ (callback $ head right) : (tail right))
  43. -- Return the value of the current register.
  44. currentValue (RunTime offset memory) = memory !! offset
  45. -- Run a piece of code until the value of the current register is zero.
  46. runLoop code runTime =
  47. if (currentValue runTime) == 0
  48. then return runTime
  49. else execute runTime code >>= runLoop code
  50. -- Extract code until the end of the current loop.
  51. loopCode _ 0 = []
  52. loopCode "" _ = error "no closing bracket"
  53. loopCode (command:rest) level =
  54. command : (loopCode rest level')
  55. where
  56. level' = case command of
  57. '[' -> level + 1
  58. ']' -> level - 1
  59. _ -> level