Advertisement
Guest User

Untitled

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