Merge Interpreter and Parser to VirtualMachine module

This commit is contained in:
2021-11-03 09:16:15 +01:00
parent 85a27b7fb1
commit a5db26d307
4 changed files with 57 additions and 71 deletions

View File

@@ -26,8 +26,6 @@ executable MVM
-- Modules included in this executable, other than Main. -- Modules included in this executable, other than Main.
other-modules: other-modules:
VirtualMachine VirtualMachine
Interpreter
Parser
Util Util
-- LANGUAGE extensions used by modules in this package. -- LANGUAGE extensions used by modules in this package.

View File

@@ -1,39 +0,0 @@
module Interpreter (
interpret,
) where
import Data.Word
import Control.Monad
import Data.Foldable
import qualified Data.Sequence as S
import qualified VirtualMachine as VM
interpret :: [VM.Command] -> VM.VM -> Either String VM.VM
interpret _ vm@(VM.VM _ _ _ True) = Right $ vm
interpret cmds vm = do
vm' <- interpretCommand cmds vm
interpret cmds vm'
interpretCommand :: [VM.Command] -> VM.VM -> Either String VM.VM
interpretCommand [] _ = Left $ "Empty code"
interpretCommand cmds vm@(VM.VM pc _ _ _)
| pc >= length cmds = Right $ vm { VM.halt = True }
| otherwise = case instr of
(VM.Simple _ _ _ _) -> interpretSimple vm cmd
(VM.Complex _ _ _) -> interpretComplex vm cmd
where cmd@(VM.Command instr _) = cmds !! pc
interpretSimple :: VM.VM -> VM.Command -> Either String VM.VM
interpretSimple vm (VM.Command (VM.Simple op _ noPops operation) args) = vm'
where
pops = toList . S.take noPops . VM.stack $ vm
stack' = Right $ operation args pops
vm' = stack' >>= (\s -> Right $ vm { VM.pc = VM.pc vm + 1
, VM.stack = s <> (S.drop noPops . VM.stack) vm
})
interpretSimple _ _ = Left "Unknown operation"
interpretComplex :: VM.VM -> VM.Command -> Either String VM.VM
interpretComplex vm (VM.Command (VM.Complex _ _ operation) args) = operation vm args
interpretComplex _ _ = Left "Unknown operation"

View File

@@ -1,28 +0,0 @@
module Parser (
parse
) where
import Data.Word
import qualified Data.ByteString as B
import qualified Data.Map as Map
import qualified VirtualMachine as VM
import qualified Util as U
parse :: B.ByteString -> Either String [VM.Command]
parse = parseCommands . B.unpack
parseCommands :: [Word8] -> Either String [VM.Command]
parseCommands [] = Right []
parseCommands code@(x:_) = case parseCommand code of
Just (cmd, rest) -> parseCommands rest >>= (\r -> return $ cmd : r)
Nothing -> Left $ "Unparseable byte: " ++ U.byteStr x ++ "\nIn following sequence:\n" ++ U.bytesStr 16 code
parseCommand :: [Word8] -> Maybe (VM.Command, [Word8])
parseCommand [] = Nothing
parseCommand (opByte:xs) = do
let op = toEnum . fromIntegral $ opByte :: VM.Op
instruction <- Map.lookup op VM.instructionByOp
let noParams = VM.noParams instruction
let params = map fromIntegral $ take noParams xs :: [Int]
return (VM.Command instruction params, drop noParams xs)

View File

@@ -6,13 +6,18 @@ module VirtualMachine (
empty, empty,
instructions, instructions,
instructionByOp, instructionByOp,
toOp toOp,
run
) where ) where
import Data.Word
import Data.Foldable import Data.Foldable
import qualified Data.Char as Char import qualified Data.Char as Char
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Sequence as S import qualified Data.Sequence as S
import qualified Data.ByteString as B
import qualified Util as U
data VM = VM { pc :: Int data VM = VM { pc :: Int
, fp :: Int , fp :: Int
@@ -105,3 +110,53 @@ toOp = read . capitalize
where capitalize :: String -> String where capitalize :: String -> String
capitalize [] = [] capitalize [] = []
capitalize (x:xs) = Char.toUpper x : map Char.toLower xs capitalize (x:xs) = Char.toUpper x : map Char.toLower xs
parse :: B.ByteString -> Either String [Command]
parse = parseCommands . B.unpack
parseCommands :: [Word8] -> Either String [Command]
parseCommands [] = Right []
parseCommands code@(x:_) = case parseCommand code of
Just (cmd, rest) -> parseCommands rest >>= (\r -> return $ cmd : r)
Nothing -> Left $ "Unparseable byte: " ++ U.byteStr x ++ "\nIn following sequence:\n" ++ U.bytesStr 16 code
parseCommand :: [Word8] -> Maybe (Command, [Word8])
parseCommand [] = Nothing
parseCommand (opByte:xs) = do
let op = toEnum . fromIntegral $ opByte :: Op
instruction <- Map.lookup op instructionByOp
let paramsNumber = noParams instruction
let params = map fromIntegral $ take paramsNumber xs :: [Int]
return (Command instruction params, drop paramsNumber xs)
interpret :: [Command] -> VM -> Either String VM
interpret _ vm@(VM _ _ _ True) = Right $ vm
interpret cmds vm = do
vm' <- interpretCommand cmds vm
interpret cmds vm'
interpretCommand :: [Command] -> VM -> Either String VM
interpretCommand [] _ = Left $ "Empty code"
interpretCommand cmds vm@(VM pc _ _ _)
| pc >= length cmds = Right $ vm { halt = True }
| otherwise = case instr of
(Simple _ _ _ _) -> interpretSimple vm cmd
(Complex _ _ _) -> interpretComplex vm cmd
where cmd@(Command instr _) = cmds !! pc
interpretSimple :: VM -> Command -> Either String VM
interpretSimple vm (Command (Simple op _ noPops operation) args) = vm'
where
pops = toList . S.take noPops . stack $ vm
stack' = Right $ operation args pops
vm' = stack' >>= (\s -> Right $ vm { pc = pc vm + 1
, stack = s <> (S.drop noPops . stack) vm
})
interpretSimple _ _ = Left "Unknown operation"
interpretComplex :: VM -> Command -> Either String VM
interpretComplex vm (Command (Complex _ _ operation) args) = operation vm args
interpretComplex _ _ = Left "Unknown operation"
run :: VM -> B.ByteString -> Either String VM
run vm code = parse code >>= flip interpret vm