Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Minimal Lisp Compiler inspired by Joe Gibbs Politz (@joepolitz) and http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf
import Text.ParserCombinators.Parsec
import Text.Printf
import System.Environment
data Sexp = Atom String
| List [Sexp]
parseSexp :: Parser Sexp
parseSexp = parseAtom <|> parseList
parseAtom :: Parser Sexp
parseAtom = ((many1 letter) <|> (many1 digit)) >>= return . Atom
parseList :: Parser Sexp
parseList = between (char '(') (char ')') $ sepBy parseSexp (many1 space) >>= return . List
stringToSexp :: String -> Sexp
stringToSexp s = case parse parseSexp "compiler" s of
Left err -> error $ "Parse failed at String->Sexp conversion: " ++ show err
Right sexp -> sexp
data Op = Inc
| Dec
data Expr = ENum Integer
| EOp Op Expr
sexpToExpr :: Sexp -> Expr
sexpToExpr (Atom s) = ENum (read s :: Integer)
sexpToExpr (List [Atom "inc", arg]) = EOp Inc (sexpToExpr arg)
sexpToExpr (List [Atom "dec", arg]) = EOp Dec (sexpToExpr arg)
sexpToExpr _ = error "Parse failed at Sexp->Expr conversion"
exprToInstrs :: Expr -> [String]
exprToInstrs (ENum n) = ["move eax, " ++ show n]
exprToInstrs (EOp Inc e) = exprToInstrs e ++ ["add eax, 1"]
exprToInstrs (EOp Dec e) = exprToInstrs e ++ ["sub eax, 1"]
compile :: String -> String
compile s = body `seq` header ++ body ++ footer
where header = "section . text\nglobal our_code_starts_here\nour_code_starts_here:\n"
body = concat $ map (printf " %s\n") $ exprToInstrs $ sexpToExpr $ stringToSexp s
footer = " ret\n"
main :: IO ()
main = do args <- getArgs
source <- readFile $ head args
putStrLn $ compile source
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.