Created
July 19, 2021 18:28
-
-
Save astynax/2cdeff86cf303305115bde8ddf3192c8 to your computer and use it in GitHub Desktop.
A stupid simple BF interpreter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE LambdaCase #-} | |
{-# LANGUAGE BangPatterns #-} | |
module Main where | |
import Data.Char | |
import Text.Parsec | |
import Text.Parsec.String | |
data Machine = Machine ![Int] !Int ![Int] deriving Show | |
data Op | |
= Inc | |
| Dec | |
| Inp | |
| Out | |
| Lft | |
| Rgt | |
| Loop ![Op] | |
deriving Show | |
helloworld :: String | |
helloworld = | |
"++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++\ | |
\.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.\ | |
\------.--------.>+.>." | |
main :: IO () | |
main = | |
case parse bfP "BF" helloworld of | |
Left e -> print e | |
Right pgm -> () <$ runBF initial pgm | |
bfP :: Parser [Op] | |
bfP = many (loopP <|> opP) <* eof | |
opP :: Parser Op | |
opP = anyChar >>= \case | |
'+' -> pure Inc | |
'-' -> pure Dec | |
',' -> pure Inp | |
'.' -> pure Out | |
'<' -> pure Lft | |
'>' -> pure Rgt | |
c -> fail $ "Bad char: " <> [c] | |
loopP :: Parser Op | |
loopP = | |
between (char '[') (char ']') | |
$ Loop <$> many (try opP <|> loopP) | |
initial :: Machine | |
initial = Machine [] 0 [] | |
runBF :: Machine -> [Op] -> IO Machine | |
runBF !m = \case | |
[] -> pure m | |
(x:xs) -> | |
(`runBF` xs) =<< case x of | |
Inc -> pure $ inc m | |
Dec -> pure $ dec m | |
Inp -> (`put` m) . ord <$> getChar | |
Out -> m <$ putChar (chr $ get m) | |
Lft -> pure $ lft m | |
Rgt -> pure $ rgt m | |
Loop p -> loop m p | |
inc, dec :: Machine -> Machine | |
inc (Machine l x r) = Machine l (x + 1) r | |
dec (Machine l x r) = Machine l (x - 1) r | |
lft, rgt :: Machine -> Machine | |
lft (Machine [] x rs) = Machine [] 0 (x:rs) | |
lft (Machine (l:ls) x rs) = Machine ls l (x:rs) | |
rgt (Machine ls x []) = Machine (x:ls) 0 [] | |
rgt (Machine ls x (r:rs)) = Machine (x:ls) r rs | |
put :: Int -> Machine -> Machine | |
put x (Machine l _ r) = Machine l x r | |
get :: Machine -> Int | |
get (Machine _ x _) = x | |
loop :: Machine -> [Op] -> IO Machine | |
loop !m p | |
| get m == 0 = pure m | |
| otherwise = runBF m p >>= (`loop` p) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment