Parse assembly statements

This commit begins the rewrite of the assembly parser to use the new (not yet
written down) syntax.
This commit is contained in:
Joscha 2019-11-20 20:46:34 +00:00
parent 7def23284d
commit f3b39f78f4
6 changed files with 259 additions and 1 deletions

View file

@ -0,0 +1,41 @@
{-# LANGUAGE OverloadedStrings #-}
module Mima.Parse.Assembly.Common
( number
, word
, largeValue
, smallValue
, Address(..)
, address
) where
import Text.Megaparsec
import qualified Text.Megaparsec.Char.Lexer as L
import Mima.Label
import Mima.Parse.Assembly.Lexeme
import Mima.Parse.Common
import Mima.Parse.Weed
import Mima.Word
number :: Parser Integer
number = L.signed (pure ()) $
(symbol' "0b" *> binNumber)
<|> (symbol' "0o" *> octNumber)
<|> (symbol' "0x" *> hexNumber)
<|> decNumber
word :: Parser MimaWord
word = label "word (24 bit)" $ asWord number
largeValue :: Parser LargeValue
largeValue = label "large value (20 bit)" $ asLargeValue number
smallValue :: Parser SmallValue
smallValue = label "large value (16 bit)" $ asSmallValue number
data Address = Direct LargeValue | Indirect (WithOffset LabelName)
deriving (Show)
address :: Parser Address
address = (Direct <$> largeValue) <|> (Indirect <$> withOffset labelName)

View file

@ -0,0 +1,65 @@
{-# LANGUAGE OverloadedStrings #-}
module Mima.Parse.Assembly.Directive
( SetRegister(..)
, Directive(..)
, lDirective
) where
import qualified Data.Set as Set
import Text.Megaparsec
import Mima.Parse.Assembly.Common
import Mima.Parse.Assembly.Lexeme
import Mima.Parse.Common
import Mima.Word
data SetRegister a
= SetIAR a
| SetACC MimaWord
| SetRA a
| SetSP a
| SetFP a
deriving (Show)
data Directive a
= DReg (SetRegister a) -- .reg (iar|acc|ra|sp|fp) <initial value>
| DOrg MimaAddress -- .org <address>
| DLit MimaWord -- .lit <word>
| DArr [MimaWord] -- .arr [<word>, ...]
| DFlag (Set.Set Char) -- .flag <chars>
| DFlagOn (Set.Set Char) -- .flagon <chars>
| DFlagOff (Set.Set Char) -- .flagoff <chars>
deriving (Show)
lSetRegister :: Parser (SetRegister Address)
lSetRegister =
SetIAR <$> sepBySpace "iar" address
<|> SetACC <$> sepBySpace "acc" word
<|> SetRA <$> sepBySpace "ra" address
<|> SetSP <$> sepBySpace "sp" address
<|> SetFP <$> sepBySpace "fp" address
where
sepBySpace name parser = symbol name *> lSpace *> lexeme parser
lWordArray :: Parser [MimaWord]
lWordArray = open *> (word `sepBy` comma) <* close
where
open = lexeme $ symbol "["
comma = lexeme $ symbol ","
close = lexeme $ symbol "]"
lFlags :: Parser (Set.Set Char)
lFlags = Set.unions <$> some (lexeme flag)
lDirective :: Parser (Directive Address)
lDirective = label "assembler directive" $ undefined
DReg <$> directive ".reg" lSetRegister
<|> DOrg <$> directive ".org" (lexeme largeValue)
<|> DLit <$> directive ".lit" (lexeme word)
<|> DArr <$> directive ".arr" lWordArray
<|> DFlag <$> directive ".flag" lFlags
<|> DFlagOn <$> directive ".flagon" lFlags
<|> DFlagOff <$> directive ".flagoff" lFlags
where
directive name parser = symbol name *> lSpace *> parser

View file

@ -0,0 +1,40 @@
{-# LANGUAGE OverloadedStrings #-}
module Mima.Parse.Assembly.Lexeme
( space
, lexeme
, symbol
, symbol'
, lSpace
, lNewline
, lNewlines
) where
import Control.Monad
import qualified Data.Text as T
import Text.Megaparsec
import qualified Text.Megaparsec.Char as C
import qualified Text.Megaparsec.Char.Lexer as L
import Mima.Parse.Common
space :: Parser ()
space = L.space (void whitespace) (L.skipLineComment ";") empty
lexeme :: Parser a -> Parser a
lexeme = L.lexeme space
symbol :: T.Text -> Parser T.Text
symbol = L.symbol space
symbol' :: T.Text -> Parser T.Text
symbol' = L.symbol' space
lSpace :: Parser ()
lSpace = lexeme space
lNewline :: Parser ()
lNewline = void $ lexeme C.newline
lNewlines :: Parser ()
lNewlines = void (some lNewline) <|> eof

View file

@ -0,0 +1,78 @@
{-# LANGUAGE OverloadedStrings #-}
module Mima.Parse.Assembly.RawInstruction
( RawInstruction(..)
, lRawInstruction
, cookInstruction
) where
import qualified Data.Text as T
import Text.Megaparsec
import Mima.Instruction
import Mima.Parse.Assembly.Common
import Mima.Parse.Assembly.Lexeme
import Mima.Parse.Common
import Mima.Word
data RawInstruction a
= RawSmallInstruction SmallOpcode a
| RawLargeInstruction LargeOpcode SmallValue
deriving (Show)
parseByName :: [(T.Text, a)] -> Parser a
parseByName = foldl (<|>) empty . map (\(name, a) -> a <$ symbol' name)
smallOpcode :: Parser SmallOpcode
smallOpcode = parseByName
[ ("ldc", LDC)
, ("ldv", LDV)
, ("stv", STV)
, ("add", ADD)
, ("and", AND)
, ("or", OR)
, ("xor", XOR)
, ("eql", EQL)
, ("jmp", JMP)
, ("jmn", JMN)
, ("ldiv", LDIV)
, ("stiv", STIV)
, ("call", CALL)
, ("adc", ADC)
]
largeOpcode :: Parser LargeOpcode
largeOpcode = parseByName
[ ("halt", HALT)
, ("not", NOT)
, ("rar", RAR)
, ("ret", RET)
, ("ldra", LDRA)
, ("stra", STRA)
, ("ldsp", LDSP)
, ("stsp", STSP)
, ("ldfp", LDFP)
, ("stfp", STFP)
]
largeOpcodeWithArgument :: Parser LargeOpcode
largeOpcodeWithArgument = parseByName
[ ("ldrs", LDRS)
, ("strs", STRS)
, ("ldrf", LDRF)
, ("strf", STRF)
]
lRawInstruction :: Parser (RawInstruction Address)
lRawInstruction = label "instruction" $
(RawSmallInstruction <$> smallOpcode <*> addr)
<|> (RawLargeInstruction <$> largeOpcode <*> optionalSv)
<|> (RawLargeInstruction <$> largeOpcodeWithArgument <*> sv)
where
addr = lexeme space *> lexeme address
sv = lexeme space *> lexeme smallValue
optionalSv = lexeme (lexeme space *> smallValue <|> pure 0)
cookInstruction :: RawInstruction MimaAddress -> Instruction
cookInstruction (RawSmallInstruction so lv) = SmallInstruction so lv
cookInstruction (RawLargeInstruction lo sv) = LargeInstruction lo sv

View file

@ -0,0 +1,35 @@
{-# LANGUAGE OverloadedStrings #-}
module Mima.Parse.Assembly.Statement
( Statement(..)
, lStatement
, lStatements
) where
import Text.Megaparsec
import Mima.Label
import Mima.Parse.Assembly.Common
import Mima.Parse.Assembly.Directive
import Mima.Parse.Assembly.Lexeme
import Mima.Parse.Assembly.RawInstruction
import Mima.Parse.Common
import Mima.Parse.Weed
data Statement a
= SDirective (Directive a)
| SRawInstruction (RawInstruction a)
| SLabel LabelName
deriving (Show)
lLabel :: Parser LabelName
lLabel = lexeme $ try $ labelName <* symbol ":"
lStatement :: Parser (Statement Address)
lStatement =
SDirective <$> lDirective <* lNewlines
<|> SRawInstruction <$> lRawInstruction <* lNewlines
<|> SLabel <$> lLabel <* many lNewline
lStatements :: Parser [WithOffset (Statement Address)]
lStatements = many (withOffset lStatement)

View file

@ -6,7 +6,6 @@ module Mima.Parse.FlagFile
) where ) where
import Control.Monad import Control.Monad
import Data.Char
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.Text as T import qualified Data.Text as T