Skip to content

Instantly share code, notes, and snippets.

@DLakomy
Last active September 3, 2022 18:09
Show Gist options
  • Save DLakomy/89cfa19ddd990306c79224dac31f71b4 to your computer and use it in GitHub Desktop.
Save DLakomy/89cfa19ddd990306c79224dac31f71b4 to your computer and use it in GitHub Desktop.
Possibly working BF intepreter
import Text.Parsec.String (Parser)
import Control.Applicative hiding ((<|>))
import Text.ParserCombinators.Parsec hiding (many)
import Data.Char(chr, ord)
import System.Environment
data BFCmd
= BFPrev
| BFNext
| BFInc
| BFDec
| BFRead
| BFPrint
| BFLoop [BFCmd]
deriving (Show, Eq)
data Tape a = Tape [a] -- Left of the pivot element
a -- Pivot element
[a] -- Right of the pivot element
type BFProgram = [BFCmd]
simpleCmds :: String
simpleCmds = "<>+-,."
simpleCmdP :: Parser BFCmd
simpleCmdP = oneOf simpleCmds >>= f
where f x = return $ case x of
'<' -> BFPrev
'>' -> BFNext
'+' -> BFInc
'-' -> BFDec
',' -> BFRead
'.' -> BFPrint
commentP :: Parser String
commentP = many $ noneOf $ simpleCmds++"[]"
bfOpP :: Parser BFCmd
bfOpP = (commentP *> simpleCmdP <* commentP) <?> ""
bfLoopP :: Parser BFCmd
bfLoopP = between (char '['<?>"") (char ']'<?>"loop closing bracket")
(commentP *> many (bfOpP <|> bfLoopP)) >>= \src -> return $ BFLoop src
bfProgramP :: Parser BFProgram
bfProgramP = (many (commentP *> (bfLoopP <|> bfOpP) <* commentP)) <* (eof <?> "")
runBf :: BFProgram -> Tape Int -> IO ()
runBf prog@(cmd:cmds) tape@(Tape left@(l:ls) p right@(r:rs)) =
case cmd of
BFPrev -> runBf cmds $ Tape (p:left) r rs
BFNext -> runBf cmds $ Tape ls l (p:right)
BFInc -> runBf cmds $ Tape left (p+1) right
BFDec -> runBf cmds $ Tape left (p-1) right
BFRead -> getChar >>= \c -> runBf cmds $ Tape left (ord c) right
BFPrint -> putChar (chr p) >> runBf cmds tape
BFLoop loopBody -> if p == 0 then runBf cmds tape else runBf (loopBody++prog) tape
runBf [] _ = return ()
main :: IO ()
main = do
args <- getArgs
src <- readFile $ case args of
[] -> error "Filepath expected!!!"
path:_ -> path
let bfProg = parse bfProgramP "" src
case bfProg of
Right prog ->
let zeros = repeat 0
emptyTape = Tape zeros 0 zeros
in runBf prog emptyTape
Left err -> print err
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment