Advertisement
Guest User

Untitled

a guest
Mar 29th, 2018
32
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. module Lib
  2.     ( interpret
  3.     ) where
  4.  
  5. import Data.Char
  6. import Data.Maybe
  7. import System.IO
  8.  
  9. data BFInstruction = MemoryRight | MemoryLeft | Increment | Decrement | Output | Input | LoopBegin | LoopEnd deriving (Enum, Eq, Show)
  10. data BFProgram = BFProgram [BFInstruction] BFInstruction [BFInstruction] deriving Show
  11.  
  12. newtype BFMemoryCell = BFMemoryCell Int deriving Show
  13. data BFMemory = BFMemory [BFMemoryCell] BFMemoryCell [BFMemoryCell] deriving Show
  14.  
  15. startProgram :: [BFInstruction] -> BFProgram
  16. startProgram instructions = BFProgram [] (head instructions) (tail instructions)
  17.  
  18. advance :: BFProgram -> BFProgram
  19. advance (BFProgram past current next) = BFProgram (past ++ [current]) (head next) (tail next)
  20.  
  21. decrease :: BFProgram -> BFProgram
  22. decrease (BFProgram past current next) = BFProgram (init past) (last past) (current:next)
  23.  
  24. jumpAfterMatchingLoopEnd :: BFProgram -> BFProgram
  25. jumpAfterMatchingLoopEnd program = jumpAfterMatchingLoopEnd' 0 (advance program)
  26.  
  27. jumpAfterMatchingLoopEnd' :: Int -> BFProgram -> BFProgram
  28. jumpAfterMatchingLoopEnd' 0 program@(BFProgram _ LoopEnd _) = advance program
  29. jumpAfterMatchingLoopEnd' nesting program@(BFProgram _ instruction _) = case instruction of
  30.     LoopEnd     -> jumpAfterMatchingLoopEnd' (nesting - 1) (advance program)
  31.    LoopBegin   -> jumpAfterMatchingLoopEnd' (nesting + 1) (advance program)
  32.     _           -> jumpAfterMatchingLoopEnd' nesting (advance program)
  33.  
  34. jumpToMatchingLoopBegin :: BFProgram -> BFProgram
  35. jumpToMatchingLoopBegin program = jumpToMatchingLoopBegin' 0 (decrease program)
  36.  
  37. jumpToMatchingLoopBegin' :: Int -> BFProgram -> BFProgram
  38. jumpToMatchingLoopBegin' 0 program@(BFProgram _ LoopBegin _) = program
  39. jumpToMatchingLoopBegin' nesting program@(BFProgram _ instruction _) = case instruction of
  40.    LoopBegin   -> jumpToMatchingLoopBegin' (nesting - 1) (decrease program)
  41.     LoopEnd     -> jumpToMatchingLoopBegin' (nesting + 1) (decrease program)
  42.    _           -> jumpToMatchingLoopBegin' nesting (decrease program)
  43.  
  44. makeCell :: Int -> BFMemoryCell
  45. makeCell = BFMemoryCell . wrap
  46.  
  47. incrementCell :: BFMemoryCell -> BFMemoryCell
  48. incrementCell = makeCell . (+1) . getCell
  49.  
  50. decrementCell :: BFMemoryCell -> BFMemoryCell
  51. decrementCell = makeCell . subtract 1 . getCell
  52.  
  53. getCell :: BFMemoryCell -> Int
  54. getCell (BFMemoryCell value) = value
  55.  
  56. wrap :: Int -> Int
  57. wrap input = mod input 256
  58.  
  59. moveMemoryRight :: BFMemory -> BFMemory
  60. moveMemoryRight (BFMemory previous current []) = BFMemory (previous ++ [current]) (makeCell 0) []
  61. moveMemoryRight (BFMemory previous current next) = BFMemory (previous ++ [current]) (head next) (tail next)
  62.  
  63. moveMemoryLeft :: BFMemory -> BFMemory
  64. moveMemoryLeft (BFMemory [] current next) = BFMemory [] (makeCell 0) (current:next)
  65. moveMemoryLeft (BFMemory previous current next) = BFMemory (init previous) (last previous) (current:next)
  66.  
  67. onCurrentCell :: (BFMemoryCell -> BFMemoryCell) -> BFMemory -> BFMemory
  68. onCurrentCell func (BFMemory previous current next) = BFMemory previous (func current) next
  69.  
  70. setCurrentCell :: BFMemoryCell -> BFMemory -> BFMemory
  71. setCurrentCell cell (BFMemory previous _ next) = BFMemory previous cell next
  72.  
  73. toInstructions :: String -> [BFInstruction]
  74. toInstructions = mapMaybe toInstruction
  75.  
  76. toInstruction :: Char -> Maybe BFInstruction
  77. toInstruction instruction = case instruction of
  78.     '>' -> Just MemoryRight
  79.     '<' -> Just MemoryLeft
  80.     '+' -> Just Increment
  81.     '-' -> Just Decrement
  82.     '.' -> Just Output
  83.     ',' -> Just Input
  84.     '[' -> Just LoopBegin
  85.     ']' -> Just LoopEnd
  86.     _   -> Nothing
  87.  
  88. interpret :: String -> IO (Either String BFMemory)
  89. interpret program = step (startProgram $ toInstructions program) (BFMemory [] (makeCell 0) [])
  90.  
  91. step :: BFProgram -> BFMemory -> IO (Either String BFMemory)
  92. step (BFProgram _ _ []) memory = return . Right $ memory
  93. step program@(BFProgram _ instruction _) memory@(BFMemory _ currentMemory _) = case instruction of
  94.     MemoryRight -> step (advance program) (moveMemoryRight memory)
  95.     MemoryLeft  -> step (advance program) (moveMemoryLeft memory)
  96.     Increment   -> step (advance program) (onCurrentCell incrementCell memory)
  97.     Decrement   -> step (advance program) (onCurrentCell decrementCell memory)
  98.     Output      -> do
  99.         putChar . chr . getCell $ currentMemory
  100.         hFlush stdout
  101.         step (advance program) memory
  102.     Input       -> do
  103.         newCurrentChar <- getChar
  104.         let newCurrent = makeCell . ord $ newCurrentChar
  105.         step (advance program) (setCurrentCell newCurrent memory)
  106.     LoopBegin   -> case getCell currentMemory of
  107.         0   -> step (jumpAfterMatchingLoopEnd program) memory
  108.         _   -> step (advance program) memory
  109.     LoopEnd     -> case getCell currentMemory of
  110.         0   -> step (advance program) memory
  111.         _   -> step (jumpToMatchingLoopBegin program) memory
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement