Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module D071PO where
- import Control.Monad.Trans.Reader
- import Control.Monad.State
- import Data.Maybe
- import Data.List
- import Data.List.Split
- import Data.Vector (Vector)
- import qualified Data.Vector as V
- import Data.Map (Map)
- import qualified Data.Map as M
- -- Created by Szegedi Gábor, VSZM
- {- Useful:
- :set +t -- type info always on
- -}
- data Tape = T
- { tVec :: Vector Int
- , tIx :: Int
- } deriving (Show, Eq)
- newTape :: Int -> Tape
- newTape n = T { tVec = V.replicate n 0,tIx = 0}
- class BFMem m where
- incVal :: m -> m
- decVal :: m -> m
- isNull :: m -> Bool
- getVal :: m -> Int
- putVal :: m -> Int -> m
- memLeft :: m -> m
- memRight :: m -> m
- instance BFMem Tape where
- incVal T {tVec = vec, tIx = idx} = T {tVec = vec V.// [(idx, vec V.! idx + 1)], tIx = idx}
- decVal T {tVec = vec, tIx = idx} = T {tVec = vec V.// [(idx, vec V.! idx - 1)], tIx = idx}
- isNull T {tVec = vec, tIx = idx} = vec V.! idx == 0
- getVal T {tVec = vec, tIx = idx} = vec V.! idx
- putVal T {tVec = vec, tIx = idx} val = T {tVec = vec V.// [(idx, val)], tIx = idx}
- memLeft T {tVec = vec, tIx = idx} = T {tVec = vec, tIx = if idx == (V.length vec) - 1
- then 0
- else idx + 1}
- memRight T {tVec = vec, tIx = idx} = T {tVec = vec, tIx = if idx == 0
- then (V.length vec) - 1
- else idx - 1}
- {-
- class YesNo a where
- yesno :: a -> Bool
- instance YesNo Int where
- yesno 0 = False
- yesno _ = True
- -}
- test_BFMem_Tape =
- [ incVal t == t { tVec = V.fromList [ 1, 1, 2, 3] }
- , decVal t == t { tVec = V.fromList [-1, 1, 2, 3] }
- , isNull t == True
- , isNull t { tIx = 1 } == False
- , getVal t == 0
- , getVal t { tIx = 3 } == 3
- , putVal t 451 == t { tVec = V.fromList [451, 1, 2, 3] }
- , putVal t { tIx = 3 } 451 == T { tVec = V.fromList [0, 1, 2, 451], tIx = 3 }
- , memLeft t == t { tIx = 1 }
- , memLeft t { tIx = 3 } == t { tIx = 0 }
- , memRight t { tIx = 3 } == t { tIx = 2 }
- , memRight t == t { tIx = 3 }
- ]
- where t = T { tVec = V.fromList [0, 1, 2, 3], tIx = 0 }
- data BFSymbol
- = Inc | Dec | MemLeft | MemRight | BrktOpen | BrktClose | In | Out
- | StartSeq | EndSeq | SeqId Char
- deriving (Show, Eq)
- type BFSequence = Vector BFSymbol
- type BFEnv = Map Char BFSequence
- sq0 :: Char
- sq0 = '*'
- parseProgram :: String -> BFEnv
- parseProgram str = M.fromList $ map parseSequence $ splitOn ";" str
- parseSequence :: String -> (Char, BFSequence)
- parseSequence str | Just seq <- stripPrefix ":" str = (seq!!0, V.fromList $ map charToBFSymbol $ tail seq)
- parseSequence baseseq = (sq0, V.fromList $ map charToBFSymbol baseseq)
- charToBFSymbol :: Char -> BFSymbol
- charToBFSymbol '+' = Inc
- charToBFSymbol '-' = Dec
- charToBFSymbol '>' = MemRight
- charToBFSymbol '<' = MemLeft
- charToBFSymbol '[' = BrktOpen
- charToBFSymbol ']' = BrktClose
- charToBFSymbol ',' = In
- charToBFSymbol '.' = Out
- charToBFSymbol x = SeqId x
- test_parseProgram =
- [ parseProgram "+-<>[],." == M.fromList [(sq0, V.fromList [Inc, Dec, MemLeft, MemRight, BrktOpen, BrktClose, In, Out])]
- , parseProgram ":A-;A+" == M.fromList [(sq0, V.fromList [SeqId 'A', Inc]), ('A', V.fromList [Dec])]
- , parseProgram ":A-;:B+;AB+" == M.fromList [(sq0, V.fromList [SeqId 'A', SeqId 'B', Inc]), ('A', V.fromList [Dec]), ('B', V.fromList [Inc])]
- ]
- inc :: Int -> Int
- inc i = i + 1
- dec :: Int -> Int
- dec i = i - 1
- matchingBracket :: BFSequence -> Int -> Int
- matchingBracket seq idx | seq V.! idx == BrktOpen = matchBrackets seq (idx+1) [BrktOpen] inc
- matchingBracket seq idx | seq V.! idx == BrktClose = matchBrackets seq (idx-1) [BrktClose] dec
- test_matchingBracket = testBrkt sq1 pairs1 ++ testBrkt sq2 pairs2
- where
- testBrkt sq pairs = map (\(s, e) -> matchingBracket (mkSq sq) s == e) pairs
- mkSq = V.fromList . map (\c -> case c of '(' -> BrktOpen; ')' -> BrktClose; _ -> Inc)
- sq1 = "(a)(b)"
- pairs1 = [(0, 2), (3, 5)]
- sq2 = "((())()())"
- pairs2 = zip [0..9] [9, 4, 3, 2, 1, 6, 5, 8, 7, 0]
- matchBrackets :: BFSequence -> Int -> [BFSymbol] -> (Int -> Int) -> Int
- matchBrackets seq idx brkts f
- | null brkts && isInc f = idx - 1
- | null brkts && isDec f = idx + 1
- | oppositeOfLast brkts (seq V.! idx) = matchBrackets seq (f idx) (init brkts) f-- Remove bracket because of matching pair
- | isBracket (seq V.! idx) = matchBrackets seq (f idx) (brkts ++ [seq V.! idx]) f-- Unmatched bracket, depth increases
- | otherwise = matchBrackets seq (f idx) brkts f-- is not a bracket, ignore
- where
- oppositeOfLast brkts symbol
- | symbol == BrktOpen && (last brkts) == BrktClose = True
- | symbol == BrktClose && (last brkts) == BrktOpen = True
- | otherwise = False
- isBracket brkt
- | brkt == BrktOpen = True
- | brkt == BrktClose = True
- | otherwise = False
- isInc f = (f 0) == 1
- isDec f = (f 0) == -1
- data BFState = S
- { sCallStk :: [(Int, Char)]
- , sMem :: Tape
- , sIn :: [Int]
- , sOut :: [Int]
- } deriving (Show, Eq)
- stret = S {sCallStk = [], sMem = newTape 1, sIn = [42], sOut = []}
- -- Like greeter http://adit.io/posts/2013-06-10-three-useful-monads.html
- step :: ReaderT BFEnv (State BFState) ()
- step = do
- bfstate <- get -- gets BFState from State monad
- bfenv <- ask -- gets BFEnv from Reader monad
- put $ stepImpl bfstate bfenv -- setsBFState to State monad
- return ()
- stepImpl :: BFState -> BFEnv -> BFState
- stepImpl bfstate bfenv
- | (instructionPointer bfstate) == V.length (currentSeq bfstate bfenv) = bfstate{sCallStk = tail $ sCallStk bfstate} -- reached end of the currentSeq
- | (instruction bfstate bfenv) == Inc = moveIP bfstate{sMem = incVal $ sMem bfstate} bfenv
- | (instruction bfstate bfenv) == Dec = moveIP bfstate{sMem = decVal $ sMem bfstate} bfenv
- | (instruction bfstate bfenv) == MemLeft = moveIP bfstate{sMem = memLeft $ sMem bfstate} bfenv
- | (instruction bfstate bfenv) == MemRight = moveIP bfstate{sMem = memRight $ sMem bfstate} bfenv
- | (instruction bfstate bfenv) == (SeqId x) = bfstate{sCallStk = [(0, x)] ++ (sCallStk $ moveIP bfstate bfenv)}
- | otherwise = bfstate
- where
- instruction bfstate bfenv = (currentSeq bfstate bfenv) V.! (instructionPointer bfstate)
- currentSeq bfstate bfenv = bfenv M.! (currentSeqName bfstate)
- currentSeqName bfstate = snd $ sCallStk bfstate !! 0
- instructionPointer bfstate = fst $ sCallStk bfstate !! 0
- moveIP bfstate bfenv
- | null $ sCallStk bfstate = bfstate
- -- | (instructionPointer bfstate) == V.length (currentSeq bfstate bfenv) - 1 = moveIP bfstate{sCallStk = tail $ sCallStk bfstate} bfenv currentSeq ended, move back on the stack
- | otherwise = bfstate{sCallStk = [(1 + instructionPointer bfstate, currentSeqName bfstate)] ++ (tail $ sCallStk bfstate)} -- we move forward in currentSeq
- test_step =
- [ exec env1 st1{sCallStk = [(0, sq0)]} == st1{sCallStk = [(1, sq0)], sMem = incVal $ newTape 32}
- , exec env1 st1{sCallStk = [(1, sq0)]} == st1{sCallStk = [(2, sq0)], sMem = memRight $ newTape 32}
- , exec env1 st1{sCallStk = [(2, sq0)]} == st1{sCallStk = [(5, sq0)]}
- , exec env1 st1{sCallStk = [(2, sq0)], sMem = incVal $ newTape 32} == st1{sCallStk = [(3, sq0)], sMem = incVal $ newTape 32}
- , exec env1 st1{sCallStk = [(4, sq0)]} == st1{sCallStk = [(2, sq0)]}
- , exec env1 st1{sCallStk = [(5, sq0)]} == st1{sCallStk = [(6, sq0)], sMem = putVal (newTape 32) 43, sIn = []}
- , exec env1 st1{sCallStk = [(6, sq0)]} == st1{sCallStk = [(7, sq0)], sOut = [0]}
- , exec env2 st2{sCallStk = [(1, sq0)]} == st2{sCallStk = [(0, 'A'), (2, sq0)]}
- , exec env2 st2{sCallStk = [(0, 'A'), (2, sq0)]} == st2{sCallStk = [(1, 'A'), (2, sq0)], sMem = incVal $ newTape 32}
- , exec env2 st2{sCallStk = [(1, 'A'), (2, sq0)]} == st2{sCallStk = [(2, sq0)]}
- ]
- where
- exec env st = execState (runReaderT step env) st
- env1 = M.fromList [(sq0, V.fromList [Inc, MemRight, BrktOpen, Inc, BrktClose, In, Out])]
- st1 = S {sCallStk = [], sMem = newTape 32, sIn = [43], sOut = []}
- env2 = M.fromList [(sq0, V.fromList [Dec, SeqId 'A']), ('A', V.fromList [Inc])]
- st2 = S {sCallStk = [], sMem = newTape 32, sIn = [], sOut = []}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement