From 7eba112bf0c2ab24653d3ae51d695383870c909c Mon Sep 17 00:00:00 2001 From: "Collin J. Doering" Date: Mon, 15 Jun 2015 03:57:37 -0400 Subject: [PATCH] Working basic assembler Need to implement a fancier main function that accepts a few other arguments and can take input from stdin and output to stdout instead of a file. asmblr [-o[--output=] out] file Where: - out is the name of the file to write to, or '-' for stdout - file is the name of the input hack asm file or '-' for stdin Signed-off-by: Collin J. Doering --- .gitignore | 1 + Asmblr.hs | 68 +++++++++++++++++++++++++----------------------------- 2 files changed, 32 insertions(+), 37 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/Asmblr.hs b/Asmblr.hs index 1744d7b..ec2a92e 100644 --- a/Asmblr.hs +++ b/Asmblr.hs @@ -22,12 +22,11 @@ import Text.ParserCombinators.Parsec import Text.Parsec.Prim (modifyState) import Text.Parsec.Char (endOfLine) -import Data.Functor ((<$>)) import Control.Monad (liftM) import System.Environment (getArgs) import System.IO -import Numeric (showHex, showIntAtBase) +import Numeric (showIntAtBase) import Data.Char (intToDigit) type SymbolTable = Map.Map String Int @@ -43,7 +42,7 @@ aInstrAddr = AInstr . read <$> many1 digit aInstrSym :: GenParser Char (Int, SymbolTable) Instruction aInstrSym = do - var <- many1 (alphaNum <|> oneOf "-_") + var <- symbol (curMem, symTbl) <- getState case Map.lookup var symTbl of @@ -206,38 +205,33 @@ firstPass = do (_, symTbl) <- getState return (str, symTbl) - -- str <- liftM (unlines . filter (not . null)) $ many $ do - -- aLabel <|> comment <|> do - -- i <- manyTill anyChar (lookAhead endOfLine) - -- endOfLine - - -- (lineNum, symTbl) <- getState - -- setState (lineNum + 1, symTbl) - -- return i - -- (_, symTbl) <- getState - -- return (str, symTbl) - - -- optional comment - -- spaces - - -- i <- aInstr <|> cInstr - - -- optional comment - -- endOfLine - - -- return i - - secondPass :: GenParser Char (Int, SymbolTable) [Instruction] secondPass = sepEndBy instr endOfLine -parseHackAsm str = case runParser firstPass (0, Map.empty) "" str of - Left err -> return $ show err +parseHackAsm :: Monad m => String -> m String +parseHackAsm str = case runParser firstPass (0, varSymbols) "" str of + Left err -> return $ show err Right (str', symTbl) -> case runParser secondPass (16, symTbl) "" str' of Left err -> return $ show err Right out -> return $ genHackML out - - + where varSymbols = Map.fromList [ ("R0", 0), ("SP", 0) + , ("R1", 1), ("LCL", 1) + , ("R2", 2), ("ARG", 2) + , ("R3", 3), ("THIS", 3) + , ("R4", 4), ("THAT", 4) + , ("R5", 5) + , ("R6", 6) + , ("R7", 7) + , ("R8", 8) + , ("R9", 9) + , ("R10", 10) + , ("R11", 11) + , ("R12", 12) + , ("R13", 13) + , ("R14", 14) + , ("R15", 15) + , ("SCREEN", 16384) + , ("KBD", 24576) ] genHackML :: [Instruction] -> String genHackML xs = unlines $ map instrToML xs @@ -245,13 +239,13 @@ genHackML xs = unlines $ map instrToML xs instrToML (CInstr op dest jump) = "111" ++ op ++ dest ++ jump leftPad n a xs = replicate (n - (length xs)) a ++ xs +parseHackAsmFile :: FilePath -> IO String parseHackAsmFile f = withFile f ReadMode $ \h -> do - hGetContents h >>= parseHackAsm >>= putStr + hGetContents h >>= parseHackAsm --- main :: IO () --- main = do --- -- parse cli arguments --- filename <- liftM fst $ getArgs --- let outFilename = drop 4 filename - --- writeFile outFilename $ parseHackAsm filename >>= uncurry genHackML +main :: IO () +main = do + args <- getArgs + let filename = head args + outFilename = (reverse $ drop 4 (reverse filename)) ++ ".hack" + parseHackAsmFile filename >>= writeFile outFilename