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.
63 lines
2.5 KiB
63 lines
2.5 KiB
|
4 years ago
|
|
||
|
|
module Main (main) where
|
||
|
|
|
||
|
|
import Control.Monad (forM_)
|
||
|
|
import Data.Bits (testBit)
|
||
|
|
import Data.Foldable (foldl', foldr)
|
||
|
|
import qualified Data.Map.Strict as M
|
||
|
|
import qualified Data.Text as T
|
||
|
|
import qualified Data.Text.IO as TIO
|
||
|
|
import Nand2Tetris.Hack (AsmLine (LineInstruction), addLabels,
|
||
|
|
addVars, compile, defaultVars,
|
||
|
|
hackParser)
|
||
|
|
import Options.Applicative (execParser, fullDesc, header, help,
|
||
|
|
helper, info, long, metavar, progDesc,
|
||
|
|
short, strOption, (<**>))
|
||
|
|
import System.IO (IOMode (WriteMode), hPutStrLn, withFile)
|
||
|
|
import Text.Megaparsec (runParser)
|
||
|
|
import Text.Megaparsec.Error (ParseErrorBundle,
|
||
|
|
ShowErrorComponent (showErrorComponent),
|
||
|
|
errorBundlePretty)
|
||
|
|
|
||
|
|
data Options =
|
||
|
|
Options
|
||
|
|
{
|
||
|
|
inputFile :: FilePath,
|
||
|
|
outputFile :: FilePath
|
||
|
|
}
|
||
|
|
|
||
|
|
main :: IO ()
|
||
|
|
main = do
|
||
|
|
options <- execParser opts
|
||
|
|
programText <- TIO.readFile (inputFile options)
|
||
|
|
let result = runParser hackParser (inputFile options) programText
|
||
|
|
case result of
|
||
|
|
Left err -> putStrLn $ errorBundlePretty err
|
||
|
|
Right parsed -> do
|
||
|
|
let labels = addLabels M.empty parsed
|
||
|
|
let vars = addVars defaultVars labels parsed
|
||
|
|
print vars
|
||
|
|
let compiled = compile labels vars $ foldr addInstr [] parsed
|
||
|
|
case compiled of
|
||
|
|
Left err -> putStrLn $ "Error: " <> T.unpack err
|
||
|
|
Right program -> withFile (outputFile options) WriteMode $ \h -> forM_ program (\x -> hPutStrLn h (printInstruction x))
|
||
|
|
where
|
||
|
|
printInstruction w = concatMap (\x -> if testBit w x then "1" else "0") $ reverse [0..15]
|
||
|
|
regVars = defaultVars
|
||
|
|
addInstr (LineInstruction instr) is = instr : is
|
||
|
|
addInstr _ is = is
|
||
|
|
|
||
|
|
opts = info (hackAsmOptParser <**> helper)
|
||
|
|
( fullDesc
|
||
|
|
<> progDesc "Compiles a file with Hack assembly instructions to Hask binary code"
|
||
|
|
<> header "hackasm - assembler for hack CPU (nand2tetris)" )
|
||
|
|
hackAsmOptParser = Options <$>
|
||
|
|
strOption ( long "input"
|
||
|
|
<> short 'i'
|
||
|
|
<> metavar "FILENAME"
|
||
|
|
<> help "Input file" ) <*>
|
||
|
|
strOption ( long "output"
|
||
|
|
<> short 'o'
|
||
|
|
<> metavar "FILENAME"
|
||
|
|
<> help "Output file" )
|