open Intermediate_utils open Intermediate_ast open Ast open Cast (** This file contains extremely simple functions printing C code. *) let rec cp_includes fmt = function | [] -> () | h :: t -> Format.fprintf fmt "#include <%s.h>\n%a" h cp_includes t let cp_node_state fmt (st: node_state) = let print_if_any fmt (ty, nb, name): unit = if nb = 0 then () else Format.fprintf fmt "\n\t%s %s[%d];" ty name nb in if st.nt_count_app = 0 then Format.fprintf fmt "typedef struct {%a%a%a\n\ \tbool is_init, is_reset;\n\ } %s;\n\n" print_if_any ("int", st.nt_nb_int, "ivars") print_if_any ("bool", st.nt_nb_bool, "bvars") print_if_any ("double", st.nt_nb_real, "rvars") st.nt_name else Format.fprintf fmt "typedef struct {%a%a%a\n\ \tbool is_init, is_reset;\n\ \tvoid* aux_states[%d]; /* stores the states of auxiliary nodes */\n\ } %s;\n\n" print_if_any ("int", st.nt_nb_int, "ivars") print_if_any ("bool", st.nt_nb_bool, "bvars") print_if_any ("double", st.nt_nb_real, "rvars") st.nt_count_app st.nt_name let cp_state_types fmt (h: (ident, node_state) Hashtbl.t): unit = Hashtbl.iter (fun n nst -> Format.fprintf fmt "/* Struct holding states of the node %s: */\n%a" n cp_node_state nst) h let cp_var' fmt = function | CVStored (arr, idx) -> Format.fprintf fmt "state->%s[%d]" arr idx | CVInput s -> Format.fprintf fmt "%s" s let cp_var fmt = function | IVar s -> Format.fprintf fmt "int %s" s | BVar s -> Format.fprintf fmt "bool %s" s | RVar s -> Format.fprintf fmt "double %s" s let rec cp_varlist' fmt vl = let print_if_any fmt = function | [] -> () | _ :: _ -> Format.fprintf fmt ", " in match vl with | [] -> () | v :: vl -> Format.fprintf fmt "%a%a%a" cp_var' v print_if_any vl cp_varlist' vl let rec cp_varlist fmt vl = let print_if_any fmt = function | [] -> () | _ :: _ -> Format.fprintf fmt ", " in match vl with | [] -> () | v :: vl -> Format.fprintf fmt "%a%a%a" cp_var v print_if_any vl cp_varlist vl let cp_prototype fmt (node, h): unit = match Hashtbl.find_opt h node.in_name with | None -> failwith "This should not happened!" | Some nst -> begin Format.fprintf fmt "void fn_%s (%s *state, %a)" node.in_name nst.nt_name cp_varlist node.in_inputs end let rec cp_prototypes fmt ((nodes, h): i_nodelist * node_states) = match nodes with | [] -> () | node :: nodes -> Format.fprintf fmt "%a;\n%a" cp_prototype (node, h) cp_prototypes (nodes, h) let rec cp_value fmt (value, (hloc: (ident * bool, string * int) Hashtbl.t)) = let string_of_binop = function | BOp_add -> "+" | BOp_sub -> "-" | BOp_mul -> "*" | BOp_div -> "/" | BOp_mod -> "%" | BOp_and -> "&&" | BOp_or -> "||" | BOp_arrow -> failwith "string_of_binop undefined on (->)" in let string_of_compop = function | COp_eq -> "==" | COp_neq -> "!=" | COp_le -> "<=" | COp_lt -> "<" | COp_ge -> ">=" | COp_gt -> ">" in match value with | CVariable (CVInput s) -> Format.fprintf fmt "%s" s | CVariable (CVStored (arr, idx)) -> Format.fprintf fmt "state->%s[%d]" arr idx | CConst (CInt i) -> Format.fprintf fmt "%d" i | CConst (CBool b) -> Format.fprintf fmt "%s" (Bool.to_string b) | CConst (CReal r) -> Format.fprintf fmt "%f" r | CMonOp (MOp_not, v) -> Format.fprintf fmt "! (%a)" cp_value (v, hloc) | CMonOp (MOp_minus, v) -> Format.fprintf fmt "- (%a)" cp_value (v, hloc) | CMonOp (MOp_pre, (CVariable v)) -> let varname = (match v with | CVStored (arr, idx) -> begin match find_varname hloc (arr, idx) with | None -> failwith "This varname should be defined." | Some (n, _) -> n end | CVInput n -> n) in let (arr, idx) = Hashtbl.find hloc (varname, true) in Format.fprintf fmt "state->%s[%d]" arr idx | CBinOp (BOp_arrow, v, v') -> Format.fprintf fmt "(state->is_init ? (%a) : (%a))" cp_value (v, hloc) cp_value (v', hloc) | CBinOp (op, v, v') -> Format.fprintf fmt "(%a) %s (%a)" cp_value (v, hloc) (string_of_binop op) cp_value (v', hloc) | CComp (op, v, v') -> Format.fprintf fmt "(%a) %s (%a)" cp_value (v, hloc) (string_of_compop op) cp_value (v', hloc) | CMonOp (MOp_pre, _) -> failwith "The linearization should have removed this case." let prefix_ = ref "\t" (** The following function prints one transformed equation of the program into a * set of instruction ending in assignments. *) let rec cp_block fmt (b, hloc) = match b with | [] -> () | e :: b -> Format.fprintf fmt "%a%a" cp_expression (e, hloc) cp_block (b, hloc) and cp_expression fmt (expr, hloc) = let prefix = !prefix_ in match expr with | CAssign (CVStored (arr, idx), value) -> begin Format.fprintf fmt "%sstate->%s[%d] = %a;\n" prefix arr idx cp_value (value, hloc) end | CAssign (CVInput _, _) -> failwith "never assign an input." | CSeq (e, e') -> Format.fprintf fmt "%a%a" cp_expression (e, hloc) cp_expression (e', hloc) | CApplication (fn, nb, argl, destl, h) -> begin let aux_node_st = Hashtbl.find h fn in let h_out = aux_node_st.nt_output_map in Format.fprintf fmt "%sfn_%s(%s, %a);\n" prefix fn (Format.asprintf "state->aux_states[%d]" (nb-1)) cp_varlist' argl; let _ = List.fold_left (fun i var -> match var with | CVStored (arr, idx) -> let (arr', idx') = Hashtbl.find h_out i in Format.fprintf fmt "%sstate->%s[%d] = ((%s*)(state->aux_states[%d]))->%s[%d];\n" prefix arr idx aux_node_st.nt_name (nb-1) arr' idx'; i+1 | CVInput _ -> failwith "Impossible!") 0 destl in () end | CReset (node_name, i, v, b) -> begin Format.fprintf fmt "\tif (%a) {\n\ \t\t((t_state_%s*)(state->aux_states[%d]))->is_init = true;\n\ \t\t((t_state_%s*)(state->aux_states[%d]))->is_reset = true;\n\ \t}\n\ %a\n" cp_value (v, hloc) node_name (i - 1) node_name (i - 1) cp_block (b, hloc) end | CIf (v, b1, []) -> let p = prefix in prefix_ := prefix^"\t"; Format.fprintf fmt "%sif (%a) {\n%a%s}\n" p cp_value (v, hloc) cp_block (b1, hloc) p; prefix_ := p | CIf (v, b1, b2) -> let p = prefix in prefix_ := prefix^"\t"; Format.fprintf fmt "%sif (%a) {\n%a%s} else {\n%a%s}\n" p cp_value (v, hloc) cp_block (b1, hloc) p cp_block (b2, hloc) p; prefix_ := p (** [cp_main] tries to print a main function to the C code. * If there is a function [main] in the lustre program, it will generate a main * function in the C code, otherwise it does not do anything. *) let cp_main_fn fmt (prog, sts) = let rec cp_array fmt (vl: t_var list): unit = match vl with | [] -> () | v :: vl -> let typ, name = match v with | IVar s -> ("int", s) | RVar s -> ("double", s) | BVar s -> Format.fprintf fmt "\tchar _char_of_%s;\n" s; ("bool", s) in Format.fprintf fmt "\t%s %s;\n%a" typ name cp_array vl in let rec cp_inputs fmt (f, l) = match l with | [] -> () | h :: t -> (if f then Format.fprintf fmt ", %s%a" else Format.fprintf fmt "%s%a") (Utils.name_of_var h) cp_inputs (true, t) in let cp_scanf fmt vl = let rec cp_scanf_str fmt (b, vl) = match vl with | [] -> () | h :: t -> (if b then Format.fprintf fmt " %s%a" else Format.fprintf fmt "%s%a") (match h with | IVar _ -> "%d" | BVar _ -> "%c" | RVar _ -> "%lf") cp_scanf_str (true, t) in let rec cp_scanf_args fmt vl = match vl with | [] -> () | RVar s :: vl | IVar s :: vl -> Format.fprintf fmt ", &%s%a" s cp_scanf_args vl | BVar s :: vl -> Format.fprintf fmt ", &%s%a" (Format.sprintf "_char_of_%s" s) cp_scanf_args vl in Format.fprintf fmt "\"%a\"%a" cp_scanf_str (false, vl) cp_scanf_args vl in let cp_printf fmt vl = let rec cp_printf_str fmt (b, vl) = match vl with | [] -> () | h :: t -> (if b then Format.fprintf fmt " %s%a" else Format.fprintf fmt "%s%a") (match h with | IVar _ -> "%d" | BVar _ -> "%c" | RVar _ -> "%f") cp_printf_str (true, t) in let rec cp_printf_arg fmt (h, i) = match Hashtbl.find_opt h i with | None -> () | Some (s, i) -> Format.fprintf fmt ", state.%s[%d]%a" s i cp_printf_arg (h, i+1) in Format.fprintf fmt "\"%a\"%a" cp_printf_str (false, vl) cp_printf_arg ((Hashtbl.find sts "main").nt_output_map, 0) in let rec cp_char_to_bool fmt vl = match vl with | [] -> () | RVar _ :: vl | IVar _ :: vl -> Format.fprintf fmt "%a" cp_char_to_bool vl | BVar s :: vl -> Format.fprintf fmt "\t\t%s = (%s == 't') ? true : false;\n%a" s (Format.sprintf "_char_of_%s" s) cp_char_to_bool vl in match List.find_opt (fun n -> n.n_name = "main") prog with | None -> () | Some node -> Format.fprintf fmt "int main (int argc, char **argv)\n\ {\n%a\n\ \tchar _buffer[1024];\n\ \tt_state_main state;\n\ \tstate.is_init = true;\n\ \tstate.is_reset = false;\n\ \twhile(true) {\n\ \t\tscanf(\"%%s\", _buffer);\n\ \t\tif(!strcmp(_buffer, \"exit\")) { exit (EXIT_SUCCESS); }\n\ \t\tsscanf(_buffer, %a);\n%a\ \t\tfn_main(&state, %a);\n\ \t\tprintf(%a);\n\ \t}\n\ \treturn EXIT_SUCCESS;\n\ }\n" cp_array (snd node.n_inputs) cp_scanf (snd node.n_inputs) cp_char_to_bool (snd node.n_inputs) cp_inputs (false, snd node.n_inputs) cp_printf (snd node.n_outputs)