X-Git-Url: https://git.martlubbers.net/?a=blobdiff_plain;f=gen.icl;h=bf3d7c45d61d2030d982ab3b392bfae857bc5fab;hb=9dcc80e7a580836c10157cd742eb1c805ef7311b;hp=9145ee56d8659d0f7db56cc823db54db93aab99c;hpb=2dfaf554d3b448567e41a140d46a27f6dfb5d901;p=cc1516.git diff --git a/gen.icl b/gen.icl index 9145ee5..bf3d7c4 100644 --- a/gen.icl +++ b/gen.icl @@ -1,14 +1,12 @@ implementation module gen - import StdMisc import StdList import StdOverloaded import StdString -from StdFunc import id +from StdFunc import id, const import StdTuple import StdEnum -from StdEnv import const import Data.Func import qualified Data.Map as Map @@ -26,8 +24,6 @@ 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 @@ -36,44 +32,76 @@ FALSE :== 0 :: Arg = L Label | Lit Int | Raw String :: SSMProgram :== [Instr] :: GenError = Error String -:: GenMap :== 'Map'.Map String LoadPlace -//completely change to either Stack, Heap, Register? -:: LoadPlace = LDA Int | LDC Int | LDH Int | LDL Int - | LDR Int | LDS Int - | FUNC Label -:: Gen a :== RWST Label SSMProgram (GenMap, [Label]) (Either GenError) a +:: Addressbook :== 'Map'.Map String Address +:: Address = LAB String | ADDR Int +:: Gen a :== RWST () SSMProgram (Addressbook, [Label]) (Either GenError) a labelStream :: [Label] -labelStream = map (\i-> concat ["lbl_", toString i]) [1..] - -gen :: AST -> String -gen (AST fds) = case evalRWST prog "" ('Map'.newMap, labelStream) of - Left (Error e) = e - Right (_, p) = toString p +labelStream = ["lbl_" +++ toString i\\i<-[1..]] + +defaultAddressBook :: Addressbook +defaultAddressBook = extend "1printint" (LAB "1printint") + $ extend "1printchar" (LAB "1printchar") + $ extend "1readchar" (LAB "1readchar") + $ extend "1readint" (LAB "1readint") + $ 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 "bra" [L "main"] ""] >>| mapM_ g fds -//gen _ = prog -// where -// expr = (Op2Expr zero (Op1Expr zero UnMinus (IntExpr zero 4)) BiPlus (IntExpr zero 7)) -// expr2 = (FunExpr zero "test" [IntExpr zero 4] []) -// stmt = (IfStmt (BoolExpr zero True) [] []) -// prog = case evalRWST (g stmt) 0 ('Map'.newMap, labelStream) of -// Left (Error e) = abort e -// Right (_, prog) = toString prog -//gen _ = toString [Lab "Test" -// ,Instr "ldc" [Lit 1] "Eerste instructie" -// ,Instr "ldc" [Lit 2] "Tweede instructie"] - -//TODO: -//For now in the generation we assume all vars fit on the stack... + prog = tell [ + Instr "bsr" [L "main"] "", + Instr "halt" [] "" + ] >>| tell programContext + >>| mapM_ g fds + +programContext :: SSMProgram +programContext = [Lab "1printint" + ,Instr "link" [Lit 0] "" + ,Instr "ldl" [Lit -2] "load first argument" + ,Instr "trap" [Lit 0] "print int" + ,Instr "unlink" [] "" + ,Instr "ret" [] "" + ,Lab "1printchar" + ,Instr "link" [Lit 0] "" + ,Instr "ldl" [Lit -2] "load first argument" + ,Instr "trap" [Lit 1] "print char" + ,Instr "unlink" [] "" + ,Instr "ret" [] "" + ,Lab "1readint" + ,Instr "link" [Lit 0] "" + ,Instr "trap" [Lit 10] "read int" + ,Instr "str" [Raw "RR"] "" + ,Instr "unlink" [] "" + ,Instr "ret" [] "" + ,Lab "1readchar" + ,Instr "link" [Lit 0] "" + ,Instr "trap" [Lit 11] "read char" + ,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 -genMap :: Gen GenMap -genMap = gets fst -changeGenMap :: (GenMap -> GenMap) -> Gen GenMap -changeGenMap f = modify (appFst f) >>| genMap +getAdressbook :: Gen Addressbook +getAdressbook = gets fst -extend :: String LoadPlace GenMap -> GenMap +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 @@ -83,22 +111,66 @@ fresh = gets snd >>= \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 FieldSelector where + g FieldFst = tell [Instr "lda" [Lit 0] "fst"] + g FieldSnd = tell [Instr "lda" [Lit 1] "snd"] + g FieldHd = tell [Instr "lda" [Lit -1] "hd"] + g FieldTl = tell [Instr "lda" [Lit 0] "tl"] + instance g Expr where - g (VarExpr _ (VarDef k fs)) = load k >>= \instr-> tell [instr] //note: pure is pure for list, i.e. [] - g (IntExpr _ i) = loadP (LDC i) >>= \instr-> tell [instr] - g (CharExpr _ c) = abort "How to deal with chars?" - g (BoolExpr _ True) = loadP (LDC TRUE) >>= \instr-> tell [instr] - g (BoolExpr _ False) = loadP (LDC FALSE) >>= \instr-> tell [instr] - g (Op2Expr _ e1 op e2) = g e1 >>| g e2 >>| tell [Instr (op2ins op) [] ""] - g (Op1Expr _ UnNegation e) = g e >>| tell [Instr "not" [] ""] - g (Op1Expr _ UnMinus e) = g e >>| tell [Instr "neg" [] ""] - g (EmptyListExpr _) = abort "Shit, empty list expr" - g (TupleExpr p (e1,e2)) = abort "How to deal with tuples?" + 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 + Just (ADDR t) = tell [Instr "ldl" [Lit t] ""] >>| mapM_ g fs >>| pure () + _ = liftT (Left $ Error "PANIC: variable and function name clash") g (FunExpr _ k es fs) = - mapM g es >>| //put all arguments on the stack (todo: fix argument handling!) - jump "bsr" k >>= \instr-> - tell [instr] >>| //actually branch to function - tell [Instr "ldr" [Raw "RR"] ""] //push return value on stack, todo: check for VOID + 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) = @@ -121,81 +193,47 @@ instance g Stmt where tell [Instr "bra" [L startLabel] "branch start while"] >>| tell [Lab endLabel] g (AssStmt (VarDef k fs) e) = - g e >>| - abort "Shit, an assignment, figure out something with storing vars or something" - //vars will be on stack in locals (possible pointers to heap) - g (FunStmt _ _) = abort "CodeGen, FunStmt unused" //not used - g (ReturnStmt Nothing) = tell [Instr "ret" [] ""] //NOTE! Assumes only return address on stack, safe? - g (ReturnStmt (Just e)) = - g e >>| - tell [Instr "str" [Raw "RR"] ""] >>| - g (ReturnStmt Nothing) - -instance g VarDecl where - g (VarDecl _ Nothing _ _) = liftT (Left $ Error "PANIC: untyped vardecl") - g (VarDecl _ (Just t) k e) = - (\l->k+++"_"+++l) <$> fresh >>= \lbl-> - changeGenMap (extend k (FUNC lbl)) >>| - tell [Lab lbl] >>| - g e >>| - tell [Instr "str" [Raw "RR"] ""] >>| - tell [Instr "ret" [] ""] - + 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 fs) = mapM_ g es + >>| jump "bsr" k + >>| mapM_ (const $ tell [Instr "ajs" [Lit -1] ""]) es //clean up args + >>| mapM_ g fs + >>| 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 _ _ vds stms) = + g (FunDecl _ k args _ vds stms) = //varDecls can call the enclosing function, so first reserve a label for it - (\l-> if (k=="main") "main" (l+++"_"+++k)) <$> fresh >>= \lbl-> - changeGenMap (extend k (FUNC lbl)) >>| - //then generate functions for the VarDecls - genMap >>= \oldMap -> - mapM_ g vds >>| - //then the main function - tell [Lab lbl] >>| + 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 >>| - changeGenMap (const oldMap) >>| pure () - -op2ins :: Op2 -> String -op2ins op = case op 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?" - -load :: String -> Gen Instr -load k = genMap >>= \g-> case 'Map'.member k g of - False = liftT (Left $ Error $ concat ["PANIC: ", k, " not found in variable mapping"]) - True = loadP $ 'Map'.find k g - -loadP :: LoadPlace -> Gen Instr -loadP pl = dec pl >>= \(instr, arg)-> pure $ Instr instr [arg] "" -where - dec (LDA i) = pure ("lda", Lit i) - dec (LDC i) = pure ("ldc", Lit i) - dec (LDH i) = pure ("ldh", Lit i) - dec (LDL i) = pure ("ldl", Lit i) - dec (LDR i) = pure ("ldr", Lit i) - dec (LDS i) = pure ("lds", Lit i) - dec _ = liftT (Left $ Error "PANIC: trying to load non adres") - -//Instruction (String), key of function to jump to -jump :: String String -> Gen Instr -jump instr k = genMap >>= \g-> case 'Map'.member k g of - False = liftT (Left $ Error $ concat ["PANIC: ", k, " not found as function"]) - True = dec ('Map'.find k g) >>= \lbl-> pure $ Instr instr [lbl] (k +++"()") -where - dec (FUNC l) = pure (L l) - dec _ = liftT (Left $ Error "PANIC: trying to jump to non label") + 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] @@ -212,4 +250,4 @@ instance toString Arg where toString (Raw s) = s instance toString SSMProgram where - toString p = concat $ intersperse " " $ map (\i-> concat $ intersperse " " $ print i) p \ No newline at end of file + toString p = concat $ intersperse " " $ map (\i-> concat $ intersperse " " $ print i) p