Unify simple instruction actions

This commit is contained in:
2021-11-02 22:25:45 +01:00
parent e263617a2c
commit 2a8e9ca5cf
5 changed files with 38 additions and 46 deletions

View File

@@ -27,7 +27,6 @@ executable MVM
other-modules: other-modules:
VirtualMachine VirtualMachine
Instruction Instruction
Command
Parser Parser
Interpreter Interpreter
Util Util

View File

@@ -1,9 +0,0 @@
module Command (
Command(..)
) where
import qualified Instruction as I
data Command = Command { instr :: I.Instruction
, args :: [Int]
} deriving (Eq, Show)

View File

@@ -1,6 +1,7 @@
module Instruction ( module Instruction (
Op(..), Op(..),
Instruction(..), Instruction(..),
Command(..),
instructions, instructions,
instructionByOp, instructionByOp,
toOp toOp
@@ -8,6 +9,9 @@ module Instruction (
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 VirtualMachine as VM
data Op = Nop -- 0x00 data Op = Nop -- 0x00
| Halt -- 0x01 | Halt -- 0x01
@@ -33,24 +37,33 @@ data Op = Nop -- 0x00
| Ld -- 0x15 | Ld -- 0x15
deriving (Eq, Ord, Enum, Show, Read, Bounded) deriving (Eq, Ord, Enum, Show, Read, Bounded)
type Args = [Int]
type Pops = [Int]
type Pushes = S.Seq Int
data Instruction = Simple { op :: Op data Instruction = Simple { op :: Op
, noParams :: Int , noParams :: Int
, noPops :: Int } , noPops :: Int
| Complex { op :: Op , sAction :: Args -> Pops -> Pushes
}
| Complex { op :: Op
, cAction :: VM.VM -> Command -> Either String VM.VM
}
data Command = Command { instr :: Instruction
, args :: [Int]
} }
deriving (Eq, Show)
instructions :: [Instruction] instructions :: [Instruction]
instructions = [ Simple { op = Nop, noParams = 0, noPops = 0 } instructions = [ Simple { op = Nop, noParams = 0, noPops = 0, sAction = (\_ _ -> S.empty) }
, Simple { op = Halt, noParams = 0, noPops = 0 } , Simple { op = Halt, noParams = 0, noPops = 0, sAction = (\_ _ -> S.empty) }
, Simple { op = Push, noParams = 1, noPops = 0 } , Simple { op = Push, noParams = 1, noPops = 0, sAction = (\args _ -> S.fromList args) }
, Simple { op = Pop, noParams = 0, noPops = 1 } , Simple { op = Pop, noParams = 0, noPops = 1, sAction = (\_ _ -> S.empty) }
] ]
instructionByOp :: Map.Map Op Instruction instructionByOp :: Map.Map Op Instruction
instructionByOp = Map.fromList $ map (\i -> (op i, i)) instructions instructionByOp = Map.fromList $ map (\i -> (op i, i)) instructions
toOp :: String -> Op toOp :: String -> Op
toOp = read . capitalize toOp = read . capitalize
where capitalize :: String -> String where capitalize :: String -> String

View File

@@ -4,46 +4,36 @@ module Interpreter (
import Data.Word import Data.Word
import Control.Monad import Control.Monad
import Data.Foldable
import qualified Data.Sequence as S import qualified Data.Sequence as S
import qualified Command as C
import qualified Instruction as I import qualified Instruction as I
import qualified VirtualMachine as VM import qualified VirtualMachine as VM
interpret :: [C.Command] -> VM.VM -> Either String VM.VM interpret :: [I.Command] -> VM.VM -> Either String VM.VM
interpret _ vm@(VM.VM _ _ _ True) = Right $ vm interpret _ vm@(VM.VM _ _ _ True) = Right $ vm
interpret cmds vm = do interpret cmds vm = do
vm' <- interpretCommand cmds vm vm' <- interpretCommand cmds vm
interpret cmds vm' interpret cmds vm'
interpretCommand :: [C.Command] -> VM.VM -> Either String VM.VM interpretCommand :: [I.Command] -> VM.VM -> Either String VM.VM
interpretCommand [] _ = Left $ "Empty code" interpretCommand [] _ = Left $ "Empty code"
interpretCommand cmds vm@(VM.VM pc _ _ _) interpretCommand cmds vm@(VM.VM pc _ _ _)
| pc >= length cmds = Right $ vm { VM.halt = True } | pc >= length cmds = Right $ vm { VM.halt = True }
| otherwise = case instr of | otherwise = case instr of
(I.Simple _ _ _) -> interpretSimple vm cmd (I.Simple _ _ _ _) -> interpretSimple vm cmd
(I.Complex _) -> interpretComplex vm cmd (I.Complex _ _) -> interpretComplex vm cmd
where cmd@(C.Command instr _) = cmds !! pc where cmd@(I.Command instr _) = cmds !! pc
interpretSimple :: VM.VM -> C.Command -> Either String VM.VM interpretSimple :: VM.VM -> I.Command -> Either String VM.VM
interpretSimple vm (C.Command (I.Simple op _ noPops) args) = vm' interpretSimple vm (I.Command (I.Simple op _ noPops operation) args) = vm'
where where
pops = [1, 2, 3] pops = toList . S.take noPops . VM.stack $ vm
stack' = case op of stack' = Right $ operation args pops
I.Nop -> Right $ nop vm args pops
I.Halt -> Right $ nop vm args pops
I.Push -> Right $ push vm args pops
_ -> Left $ "Unknown operator"
vm' = stack' >>= (\s -> Right $ vm { VM.pc = VM.pc vm + 1 vm' = stack' >>= (\s -> Right $ vm { VM.pc = VM.pc vm + 1
, VM.stack = VM.stack vm <> s , VM.stack = (S.drop noPops . VM.stack) vm <> s
}) })
interpretSimple _ _ = Left $ "Unknown operation" interpretSimple _ _ = Left $ "Unknown operation"
interpretComplex :: VM.VM -> C.Command -> Either String VM.VM interpretComplex :: VM.VM -> I.Command -> Either String VM.VM
interpretComplex _ _ = Left "Not implemented yet" interpretComplex _ _ = Left "Not implemented yet"
nop :: VM.VM -> [Int] -> [Int] -> S.Seq Int
nop vm _ _ = S.empty
push :: VM.VM -> [Int] -> [Int] -> S.Seq Int
push vm args _ = S.fromList args

View File

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