{-# LANGUAGE ScopedTypeVariables #-} -- | Defines a main() and print statements to easily execute generated Copilot specs. module Language.Copilot.AtomToC(getPrePostCode) where import Language.Copilot.AdHocC import Language.Copilot.Core import Data.Maybe (fromMaybe) import Data.List -- allExts represents all the variabbles to monitor (used for declaring them) -- inputExts represents the monitored variables which are to be fed to the -- standard input of the C program. only used for the testing with random -- streams and values. getPrePostCode :: Bool -> (Maybe String, Maybe String) -> Name -> StreamableMaps Spec -> [Exs] -> [(Ext,Int)] -> Vars -> Period -> (String, String) getPrePostCode simulatation (pre, post) cName streams allExts arrDecs inputExts p = ( (if simulatation then preCode (extDecls allExts arrDecs) else "") ++ fromMaybe "" pre , fromMaybe "" post ++ periodLoop cName p ++ if simulatation then (postCode cName streams inputExts) else "" ) -- Make the declarations for external vars extDecls :: [Exs] -> [(Ext,Int)] -> [String] extDecls allExtVars arrDecs = let uniqueExtVars = nubBy (\ (x, y, _) (x', y', _) -> x == x' && y == y') allExtVars getDec :: Exs -> String getDec (t, (ExtV v), ExtRetV) = varDecl t [v] getDec (_, (Fun _ _), ExtRetV) = "" getDec (t, arr, ExtRetA _) = case getIdx arr of Nothing -> error $ "Please use the setArrs option to provide a list of " ++ "pairs (a,idx) where a is the name of an external array and idx " ++ "is its static size to declare. There is no size for array " ++ show arr ++ "." Just idx -> arrDecl t [(show arr, idx)] getIdx arr = lookup arr arrDecs in map getDec uniqueExtVars preCode :: [String] -> String preCode extDeclarations = unlines $ [ includeBracket "stdio.h" , includeBracket "stdlib.h" , includeBracket "string.h" -- , includeBracket "inttypes.h" , "" , "unsigned long long rnd;" ] ++ extDeclarations -- | Generate a temporary C file name. tmpCFileName :: String -> String tmpCFileName name = "__" ++ name periodLoop :: Name -> Period -> String periodLoop cName p = unlines [ "\n" , "void " ++ tmpCFileName cName ++ "(void) {" , " int i;" , " for(i = 0; i < " ++ show p ++ "; i++) {" , " " ++ cName ++ "();" , " }" , "}" ] postCode :: Name -> StreamableMaps Spec -> Vars -> String postCode cName streams inputExts = unlines $ [""] ++ (if isEmptySM inputExts then [] else cleanString) ++ -- make a loop to complete a period of computation. [ "int main(int argc, char *argv[]) {" , " if (argc != 2) {" , " " ++ printfNewline "Please pass a single argument to the simulator containing the number of rounds to execute it." [] , " return 1;" , " }" , " rnd = atoi(argv[1]);" , " int i;" , " for(i = 0; i < rnd ; i++) {" , " " ++ printf "period: %i " ["i"] ] ++ inputExtVars inputExts " " ++ [" " ++ tmpCFileName cName ++ "();"] ++ outputVars cName streams ++ [ " " ++ printfNewline "" [] , " fflush(stdout);" , " }" , " return EXIT_SUCCESS;" , "}" ] where cleanString = [ "void clean(const char *buffer, FILE *fp) {" , " char *p = strchr(buffer,'\\n');" , " if (p != NULL)" , " *p = 0;" , " else {" , " int c;" , " while ((c = fgetc(fp)) != '\\n' && c != EOF);" , " }" , "}" , "" ] inputExtVars :: Vars -> String -> [String] inputExtVars exts indent = foldStreamableMaps decl exts [] where decl :: Streamable a => Var -> [a] -> [String] -> [String] decl v l ls = let string = "string_" ++ v in (indent ++ "char " ++ string ++ " [50] = \"\";") : (indent ++ "fgets (" ++ string ++ ", sizeof(" ++ string ++ "), stdin);") : (indent ++ "sscanf (" ++ string ++ ", \"" ++ typeId (head l) ++ "\", &" ++ v ++ ");") : (indent ++ "clean (" ++ string ++ ", stdin);") : ls outputVars :: Name -> StreamableMaps Spec -> [String] outputVars cName streams = foldStreamableMaps decl streams [] where decl :: forall a. Streamable a => Var -> Spec a -> [String] -> [String] decl v _ ls = (" " ++ printf (v ++ ": " ++ typeIdPrec (unit::a) ++ " ") [vPre cName ++ v]) : ls