You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
2.4 KiB
101 lines
2.4 KiB
|
4 years ago
|
{-# LANGUAGE OverloadedStrings #-}
|
||
|
|
|
||
|
|
module Nand2Tetris.VM
|
||
|
|
(
|
||
|
|
VMInstruction(..),
|
||
|
|
ArithmeticCmd(..),
|
||
|
|
AccessType(..),
|
||
|
|
SegmentOffset(..),
|
||
|
|
SegmentId(..),
|
||
|
|
parseInstruction
|
||
|
|
) where
|
||
|
|
|
||
|
|
import Nand2Tetris.Error ( Error )
|
||
|
|
import Text.Megaparsec (Parsec, MonadParsec (try), (<|>), choice)
|
||
|
|
import qualified Data.Text as T
|
||
|
|
import Text.Megaparsec.Char (string, space1)
|
||
|
|
import Data.Functor (($>))
|
||
|
|
import qualified Text.Megaparsec.Char.Lexer as L
|
||
|
|
|
||
|
|
data VMInstruction =
|
||
|
|
VMArithmetic ArithmeticCmd
|
||
|
|
| VMMemAccess AccessType SegmentId SegmentOffset
|
||
|
|
deriving (Show, Eq)
|
||
|
|
|
||
|
|
data ArithmeticCmd =
|
||
|
|
ACAdd
|
||
|
|
| ACSub
|
||
|
|
| ACNeg
|
||
|
|
| ACEq
|
||
|
|
| ACGt
|
||
|
|
| ACLt
|
||
|
|
| ACAnd
|
||
|
|
| ACOr
|
||
|
|
| ACNot
|
||
|
|
deriving (Show, Eq)
|
||
|
|
|
||
|
|
data AccessType =
|
||
|
|
ACPush
|
||
|
|
| ACPop
|
||
|
|
deriving (Show, Eq)
|
||
|
|
|
||
|
|
newtype SegmentOffset = SegmentOffset { unSegmentOffset :: Int }
|
||
|
|
deriving (Show, Eq)
|
||
|
|
|
||
|
|
data SegmentId =
|
||
|
|
SLocal
|
||
|
|
| SArgument
|
||
|
|
| SThis
|
||
|
|
| SThat
|
||
|
|
| SConstant
|
||
|
|
| SStatic
|
||
|
|
| SPointer
|
||
|
|
| STemp
|
||
|
|
deriving (Show, Eq)
|
||
|
|
|
||
|
|
type Parser = Parsec Error T.Text
|
||
|
|
|
||
|
|
parseInstruction :: Parser VMInstruction
|
||
|
|
parseInstruction =
|
||
|
|
try parseMemAccess <|>
|
||
|
|
parseArithmetic
|
||
|
|
|
||
|
|
where
|
||
|
|
parseMemAccess :: Parser VMInstruction
|
||
|
|
parseMemAccess = VMMemAccess <$>
|
||
|
|
parseAccessType <*>
|
||
|
|
parseSegmentId <*>
|
||
|
|
parseSegmentOffset
|
||
|
|
|
||
|
|
parseAccessType :: Parser AccessType
|
||
|
|
parseAccessType = try (string "push" >> space1 $> ACPush) <|>
|
||
|
|
(string "pop" >> space1 $> ACPop)
|
||
|
|
|
||
|
|
parseSegmentId :: Parser SegmentId
|
||
|
|
parseSegmentId =
|
||
|
|
choice [ string "local" $> SLocal,
|
||
|
|
string "argument" $> SArgument,
|
||
|
|
string "this" $> SThis,
|
||
|
|
string "that" $> SThat,
|
||
|
|
string "constant" $> SConstant,
|
||
|
|
string "static" $> SStatic,
|
||
|
|
string "pointer" $> SPointer,
|
||
|
|
string "temp" $> STemp
|
||
|
|
] <* space1
|
||
|
|
|
||
|
|
parseSegmentOffset :: Parser SegmentOffset
|
||
|
|
parseSegmentOffset = SegmentOffset <$> L.decimal
|
||
|
|
|
||
|
|
parseArithmetic :: Parser VMInstruction
|
||
|
|
parseArithmetic = VMArithmetic <$>
|
||
|
|
choice [ string "add" $> ACAdd,
|
||
|
|
string "sub" $> ACSub,
|
||
|
|
string "neg" $> ACNeg,
|
||
|
|
string "eq" $> ACEq,
|
||
|
|
string "gt" $> ACGt,
|
||
|
|
string "lt" $> ACLt,
|
||
|
|
string "and" $> ACAnd,
|
||
|
|
string "or" $> ACOr,
|
||
|
|
string "not" $> ACNot
|
||
|
|
]
|