X-Git-Url: https://git.martlubbers.net/?a=blobdiff_plain;f=gen.icl;h=d139804acf681111aa45a4279e72d4fc7bc3de00;hb=f081c2c5e248331eb6e2f090f4afe818fd8259eb;hp=eb96982bcb0caf638cf0b63441510ded9bc707c6;hpb=4039c774404fffec583dc64a3c95c1c08e9c7deb;p=cc1516.git diff --git a/gen.icl b/gen.icl index eb96982..d139804 100644 --- a/gen.icl +++ b/gen.icl @@ -1,41 +1,224 @@ implementation module gen - import StdMisc import StdList import StdOverloaded import StdString - -from Data.Func import $ -from Text import class Text(join), instance Text String -from Data.List import intersperse +from StdFunc import id, const +import StdTuple +import StdEnum + +import Data.Func +import qualified Data.Map as Map +import Data.List +import Data.Either +import Data.Tuple +import Data.Functor +import Data.Monoid +import Data.Maybe +import Control.Applicative +import Control.Monad +import Control.Monad.Trans +from Text import class Text(concat), instance Text String import AST +import RWST -//Instruction is an instruction, with possible arguments and a possible comment -//Or is a label +TRUE :== -1 +FALSE :== 0 :: Instr = Instr String [Arg] String - | Label String -:: Arg = L String | Lit Int + | Lab Label +:: Label :== String +:: Arg = L Label | Lit Int | Raw String :: SSMProgram :== [Instr] - -gen :: AST -> String -gen _ = toString [Label "Test" - ,Instr "ldc" [Lit 1] "Eerste instructie" - ,Instr "ldc" [Lit 2] "Tweede instructie"] - - -class g a :: a -> SSMProgram +:: GenError = Error String +:: Addressbook :== 'Map'.Map String Address +:: Address = LAB String | ADDR Int +:: Gen a :== RWST () SSMProgram (Addressbook, [Label]) (Either GenError) a + +labelStream :: [Label] +labelStream = ["lbl_" +++ toString i\\i<-[1..]] + +defaultAddressBook :: Addressbook +defaultAddressBook = extend "print" (LAB "print") + $ extend "read" (LAB "read") + $ extend "isEmpty" (LAB "isEmpty") + 'Map'.newMap + +gen :: AST -> Either String String +gen (AST fds) = case evalRWST prog () (defaultAddressBook, labelStream) of + Left (Error e) = Left e + Right (_, p) = Right $ toString p + where + prog = tell [ + Instr "bsr" [L "main"] "", + Instr "halt" [] "" + ] >>| tell programContext + >>| mapM_ g fds + +programContext :: SSMProgram +programContext = [Lab "print" //there is no actual IO in SSM + ,Instr "link" [Lit 0] "" + ,Instr "unlink" [] "" + ,Instr "ret" [] "" + ,Lab "read" //there is no actual IO in SSM + ,Instr "link" [Lit 0] "" + ,Instr "ldc" [Lit 0] "" + ,Instr "sth" [] "" + ,Instr "str" [Raw "RR"] "" + ,Instr "unlink" [] "" + ,Instr "ret" [] "" + ,Lab "isEmpty" + ,Instr "link" [Lit 0] "" + ,Instr "ldl" [Lit -2] "load prt to list" + ,Instr "lda" [Lit 0] "derefrence ptr" + ,Instr "ldc" [Lit 0] "" + ,Instr "eq" [] "test for null pointer" + ,Instr "str" [Raw "RR"] "" + ,Instr "unlink" [] "" + ,Instr "ret" [] "" + ] + +//helper functions for the gen monad +getAdressbook :: Gen Addressbook +getAdressbook = gets fst + +updateAdressbook :: (Addressbook -> Addressbook) -> Gen Addressbook +updateAdressbook f = modify (appFst f) >>| getAdressbook + +extend :: String Address Addressbook -> Addressbook +extend k pl g = 'Map'.put k pl g + +fresh :: Gen Label +fresh = gets snd >>= \vars-> + modify (appSnd $ const $ tail vars) >>| + pure (head vars) + +class g a :: a -> Gen () + +instance g Op1 where + g UnNegation = tell [Instr "not" [] ""] + g UnMinus = tell [Instr "neg" [] ""] + +instance g Op2 where + g o = tell [Instr s [] ""] + where + s = case o of + BiPlus = "add" + BiMinus = "sub" + BiTimes = "mul" + BiDivide = "div" + BiMod = "mod" + BiEquals = "eq" + BiLesser = "lt" + BiGreater = "gt" + BiLesserEq = "le" + BiGreaterEq = "ge" + BiUnEqual = "ne" + BiAnd = "and" + BiOr = "or" + BiCons = abort "Shit, Cons, how to deal with this?" instance g Expr where - g _ = undef - - + g (IntExpr _ i) = tell [Instr "ldc" [Lit i] ""] + g (CharExpr _ c) = tell [Instr "ldc" [Lit (toInt c)] ""] + g (BoolExpr _ b) = tell [Instr "ldc" [Lit (if b TRUE FALSE)] ""] + g (EmptyListExpr _) = tell [Instr "ldc" [Lit 0] ""] + >>| tell [Instr "sth" [] ""] + g (Op1Expr _ o e) = g e >>| g o + g (Op2Expr _ e1 BiCons e2) = g e2 >>| g e1 + >>| tell [Instr "sth" [] ""] + >>| tell [Instr "ajs" [Lit -1] ""] + >>| tell [Instr "sth" [] ""] + g (Op2Expr _ e1 op e2) = g e1 >>| g e2 >>| g op + g (TupleExpr _ (e1,e2)) = g e1 + >>| tell [Instr "sth" [] ""] + >>| g e2 + >>| tell [Instr "sth" [] ""] + >>| tell [Instr "ajs" [Lit -1] ""] + g (VarExpr _ (VarDef k fs)) = getAdressbook >>= \ab->case 'Map'.get k ab of + Nothing = liftT (Left $ Error "PANIC: undefined variable") + Just (ADDR t) = tell [Instr "ldl" [Lit t] ""] + Just (LAB t) = liftT (Left $ Error "PANIC: variable and function name clash") + //load k >>= \instr-> tell [instr] //note: pure is pure for list, i.e. [] + g (FunExpr _ k es fs) = + mapM_ g es + >>| jump "bsr" k + >>| mapM_ (const $ tell [Instr "ajs" [Lit -1] ""]) es //clean up args + >>| tell [Instr "ldr" [Raw "RR"] ""] + +jump :: String String -> Gen () +jump instr k = getAdressbook >>= \ab->case 'Map'.get k ab of + Nothing = liftT (Left $ Error $ concat ["PANIC: ", k, " not found as function"]) + Just (LAB t) = tell [Instr instr [L t] (k +++"()")] + Just (ADDR t) = liftT (Left $ Error $ "PANIC: jump should go to label") + +instance g Stmt where + g (IfStmt cond th el) = + fresh >>= \elseLabel-> + fresh >>= \endLabel-> + g cond >>| + tell [Instr "brf" [L elseLabel] "branch else"] >>| + mapM_ g th >>| + tell [Instr "bra" [L endLabel] "branch end if"] >>| + tell [Lab elseLabel] >>| + mapM_ g el >>| + tell [Lab endLabel] + g (WhileStmt cond th) = + fresh >>= \startLabel-> + fresh >>= \endLabel -> + tell [Lab startLabel] >>| + g cond >>| + tell [Instr "brf" [L endLabel] "branch end while"] >>| + mapM_ g th >>| + tell [Instr "bra" [L startLabel] "branch start while"] >>| + tell [Lab endLabel] + g (AssStmt (VarDef k fs) e) = + g e >>| getAdressbook >>= \ab->case 'Map'.get k ab of + Nothing = liftT (Left $ Error $ concat ["PANIC: ", k, " not found as var"]) + Just (LAB t) = liftT (Left $ Error $ "PANIC: cannot assign to function") + Just (ADDR t) = tell [Instr "stl" [Lit t] ""] + g (FunStmt k es) = mapM_ g es + >>| jump "bsr" k + >>| mapM_ (const $ tell [Instr "ajs" [Lit -1] ""]) es //clean up args + >>| pure () + g (ReturnStmt Nothing) = tell [Instr "unlink" [] ""] + >>| tell [Instr "ret" [] ""] + g (ReturnStmt (Just e)) = g e + >>| tell [Instr "str" [Raw "RR"] ""] + >>| g (ReturnStmt Nothing) + +foldVarDecl :: Int VarDecl -> Gen Int +foldVarDecl x (VarDecl _ _ k e) = g e + >>| annote x k + >>| updateAdressbook (extend k (ADDR x)) >>| pure (x + 1) + +addVars :: [String] -> (Addressbook -> Addressbook) +addVars [] = id +addVars [x:xs] = \ab->extend x (ADDR (-2 - (length xs))) (addVars xs ab) + +instance g FunDecl where + g (FunDecl _ k args _ vds stms) = + //varDecls can call the enclosing function, so first reserve a label for it + updateAdressbook (extend k (LAB k)) >>| + getAdressbook >>= \oldMap -> + updateAdressbook (addVars args) >>| + tell [Lab k] >>| + tell [Instr "link" [Lit 0] ""] >>| + //add the vars + foldM foldVarDecl 1 vds >>| + //and the statements + mapM_ g stms >>| + updateAdressbook (const oldMap) >>| pure () + +annote :: Int String -> Gen () +annote pos key = + tell [Instr "annote" [Raw "MP", Lit pos, Lit pos, Raw "green", Raw key] ""] class print a :: a -> [String] instance print Instr where - print (Label l) = [l, ":", "\n"] + print (Lab l) = [l, ":", "\n"] print (Instr i args com) = ["\t", i] ++ print args ++ [" ;", com, "\n"] instance print [Arg] where @@ -44,6 +227,7 @@ instance print [Arg] where instance toString Arg where toString (L l) = l toString (Lit int) = toString int + toString (Raw s) = s instance toString SSMProgram where - toString p = join " " $ map (\i-> join " " $ print i) p \ No newline at end of file + toString p = concat $ intersperse " " $ map (\i-> concat $ intersperse " " $ print i) p