Nand2Tetris course artifacts: assembler, VM compiler and more
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

{-# 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
]