Compare commits

...

19 Commits

Author SHA1 Message Date
Arnaud DABY-SEESARAM
8c3e3d1eac [C] malloc->calloc + conditions merged in free_state_* 2022-12-20 16:52:59 +01:00
Arnaud DABY-SEESARAM
a673c447e3 [messages] better comment and errors 2022-12-20 16:41:21 +01:00
Arnaud DABY-SEESARAM
03def2ce1a [C] new lines in then output after each step 2022-12-20 16:38:29 +01:00
Arnaud DABY-SEESARAM
ffa8918330 [C] a few fixes 2022-12-20 16:34:31 +01:00
Arnaud DABY-SEESARAM
24108925fd [cprint] free the allocated memory (states). 2022-12-20 16:29:35 +01:00
fd95446636 Modify C main to initialize correctly the state with is_reset = false 2022-12-20 15:46:31 +01:00
19524ea99c Merge branch 'ast2C_proposition' of https://gitea.lemnoslife.com/Benjamin_Loison/Synchronous_reactive_systems into ast2C_proposition 2022-12-20 15:42:59 +01:00
88c145a527 Disable mallocs when reseting 2022-12-20 15:39:33 +01:00
Arnaud DABY-SEESARAM
52092b1480 [cprint] code reduction 2022-12-20 15:24:55 +01:00
Arnaud DABY-SEESARAM
f121f55432 [cprint] add a main function 2022-12-20 15:11:12 +01:00
Arnaud DABY-SEESARAM
42536df81c [parser] update of some error messages 2022-12-20 14:10:34 +01:00
Arnaud DABY-SEESARAM
c7edb27fb0 [lustre_pp] fix a typing error 2022-12-20 14:04:50 +01:00
Arnaud DABY-SEESARAM
3ad133344a [lustre_pp] precise error messages 2022-12-20 14:02:00 +01:00
4303dcd0e4 Correct a typo in src/main.ml disabling the compilation 2022-12-20 13:09:09 +01:00
Arnaud DABY-SEESARAM
f5daae824c [merge] 2022-12-20 09:51:59 +01:00
9fbdb7000f Merge branch 'ast2C_proposition' of https://gitea.lemnoslife.com/Benjamin_Loison/Synchronous_reactive_systems into ast2C_proposition 2022-12-20 03:51:31 +01:00
e1de3e6829 Add support for resets 2022-12-20 03:51:28 +01:00
Arnaud DABY-SEESARAM
91ff654fc9 [passes] ensure that apps don't mix with operators 2022-12-19 23:21:11 +01:00
025d25a146 Replace nunmbers to numbers in two comments of src/parser.mly 2022-12-19 19:48:21 +01:00
6 changed files with 271 additions and 33 deletions

View File

@@ -236,11 +236,15 @@ let cp_init_aux_nodes fmt (node, h) =
| None -> () (** All auxiliary nodes have been initialized *) | None -> () (** All auxiliary nodes have been initialized *)
| Some n -> | Some n ->
begin begin
Format.fprintf fmt "%a\t\tstate->aux_states[%d] = malloc (sizeof (%s));\n\ Format.fprintf fmt "%a\t\tif(!state->is_reset) {\n\
\t\t((%s*)(state->aux_states[%d]))->is_init = true;\n" \t\t\tstate->aux_states[%d] = calloc (1, sizeof (%s));\n\
\t\t}\n\
\t\t((%s*)(state->aux_states[%d]))->is_init = true;\n\
\t\t((%s*)(state->aux_states[%d]))->is_reset = state->is_reset;\n"
aux (node, nst, i-1) aux (node, nst, i-1)
(i-1) (Format.asprintf "t_state_%s" n.n_name) (i-1) (Format.asprintf "t_state_%s" n.n_name)
(Format.asprintf "t_state_%s" n.n_name) (i-1) (Format.asprintf "t_state_%s" n.n_name) (i-1)
(Format.asprintf "t_state_%s" n.n_name) (i-1)
end end
in in
let nst = Hashtbl.find h node.in_name in let nst = Hashtbl.find h node.in_name in
@@ -310,9 +314,11 @@ let ast_to_c verbose debug prog =
verbose "Computation of the node_states"; verbose "Computation of the node_states";
let prog_st_types = make_state_types prog in let prog_st_types = make_state_types prog in
debug (Format.asprintf "%a" dump_var_locations prog_st_types); debug (Format.asprintf "%a" dump_var_locations prog_st_types);
let prog: i_nodelist = ast_to_intermediate_ast prog prog_st_types in let iprog: i_nodelist = ast_to_intermediate_ast prog prog_st_types in
Format.printf "%a\n\n%a\n\n/* Nodes: */\n%a" Format.printf "%a\n\n%a\n\n%a\n\n/* Nodes: */\n%a%a\n"
cp_includes (Config.c_includes) cp_includes (Config.c_includes)
cp_state_types prog_st_types cp_state_types prog_st_types
cp_nodes (prog, prog_st_types) cp_state_frees (iprog, prog_st_types)
cp_nodes (iprog, prog_st_types)
cp_main_fn (prog, prog_st_types)

View File

@@ -3,4 +3,4 @@
* variables. *) * variables. *)
let maxvar = 100 let maxvar = 100
let c_includes = ["stdbool"; "stdlib"] let c_includes = ["stdbool"; "stdlib"; "stdio"; "string"]

View File

@@ -19,7 +19,7 @@ let cp_node_state fmt (st: node_state) =
if st.nt_count_app = 0 if st.nt_count_app = 0
then then
Format.fprintf fmt "typedef struct {%a%a%a\n\ Format.fprintf fmt "typedef struct {%a%a%a\n\
\tbool is_init;\n\ \tbool is_init, is_reset;\n\
} %s;\n\n" } %s;\n\n"
print_if_any ("int", st.nt_nb_int, "ivars") print_if_any ("int", st.nt_nb_int, "ivars")
print_if_any ("bool", st.nt_nb_bool, "bvars") print_if_any ("bool", st.nt_nb_bool, "bvars")
@@ -27,7 +27,7 @@ let cp_node_state fmt (st: node_state) =
st.nt_name st.nt_name
else else
Format.fprintf fmt "typedef struct {%a%a%a\n\ Format.fprintf fmt "typedef struct {%a%a%a\n\
\tbool is_init;\n\ \tbool is_init, is_reset;\n\
\tvoid* aux_states[%d]; /* stores the states of auxiliary nodes */\n\ \tvoid* aux_states[%d]; /* stores the states of auxiliary nodes */\n\
} %s;\n\n" } %s;\n\n"
print_if_any ("int", st.nt_nb_int, "ivars") print_if_any ("int", st.nt_nb_int, "ivars")
@@ -40,6 +40,89 @@ let cp_state_types fmt (h: (ident, node_state) Hashtbl.t): unit =
Format.fprintf fmt "/* Struct holding states of the node %s: */\n%a" n Format.fprintf fmt "/* Struct holding states of the node %s: */\n%a" n
cp_node_state nst) h cp_node_state nst) h
(** [cp_state_frees] prints the required code to recursively free the node
* states. *)
let cp_state_frees fmt (iprog, sts) =
let rec find_callee (i: int) (f: i_node) =
let rec aux_expr = function
| IETuple [] | IEVar _ | IEConst _ -> None
| IEMonOp (_, e) -> aux_expr e
| IEWhen (e, e')
| IEReset (e, e')
| IEComp (_, e, e')
| IEBinOp (_, e, e') ->
begin
match aux_expr e with
| None -> aux_expr e'
| Some res -> Some res
end
| IETriOp (_, e, e', e'') ->
begin
match aux_expr e with
| None ->
(match aux_expr e' with
| None -> aux_expr e''
| Some res -> Some res)
| Some res -> Some res
end
| IETuple (h :: t) ->
begin
match aux_expr h with
| None -> aux_expr (IETuple t)
| Some res -> Some res
end
| IEApp (j, n, e) ->
if i = j
then Some n.n_name
else aux_expr e
in
List.fold_right
(fun (_, expr) acc ->
match acc with
| Some _ -> acc
| None -> aux_expr expr)
f.in_equations None
in
let rec cp_free_aux fmt (i, caller_name) =
let idx = i - 1 in
match find_callee i (List.find (fun n -> n.in_name = caller_name) iprog)with
| None -> ()
| Some callee_name ->
let callee_st = Hashtbl.find sts callee_name in
if callee_st.nt_count_app > 0
then
Format.fprintf fmt "\tif (st->aux_states[%d]) {\n\
\t\tfree_state_%s((t_state_%s*)(st->aux_states[%d]));\n\
\t\tfree (st->aux_state[%d]);\n\t}\n%a"
idx callee_name callee_name idx
idx cp_free_aux (i+1, caller_name)
else Format.fprintf fmt "\tif (st->aux_states[%d])\n\
\t\tfree(st->aux_states[%d]);\n%a"
idx idx cp_free_aux (i+1, caller_name)
in
Hashtbl.iter
(fun node_name node_st ->
if node_st.nt_count_app = 0
then () (** Nothing to free for the node [node_name]. *)
else
Format.fprintf fmt "void free_state_%s(t_state_%s *);\n"
node_name node_name) sts;
Hashtbl.iter
(fun node_name node_st ->
if node_st.nt_count_app = 0
then () (** Nothing to free for the node [node_name]. *)
else
Format.fprintf fmt "void free_state_%s(t_state_%s *st)\n\
{\n\
%a\
}\n"
node_name node_name
cp_free_aux (1, node_name)) sts
let cp_var' fmt = function let cp_var' fmt = function
| CVStored (arr, idx) -> Format.fprintf fmt "state->%s[%d]" arr idx | CVStored (arr, idx) -> Format.fprintf fmt "state->%s[%d]" arr idx
| CVInput s -> Format.fprintf fmt "%s" s | CVInput s -> Format.fprintf fmt "%s" s
@@ -75,6 +158,13 @@ let rec cp_varlist fmt vl =
print_if_any vl print_if_any vl
cp_varlist vl cp_varlist vl
(** [cp_prototype] prints functions prototypes (without the «;»). It is only
* used to write the beginning of functions right now. If we later allow to
* use auxiliary nodes before their definition, it might be useful to declare
* all the prototypes at the beginning of the file (Cf. [cp_prototypes] below.
*)
let cp_prototype fmt (node, h): unit = let cp_prototype fmt (node, h): unit =
match Hashtbl.find_opt h node.in_name with match Hashtbl.find_opt h node.in_name with
| None -> failwith "This should not happened!" | None -> failwith "This should not happened!"
@@ -96,6 +186,10 @@ let rec cp_prototypes fmt ((nodes, h): i_nodelist * node_states) =
(** [cp_value] prints values, that is unary or binary operations which can be
* inlined in the final code without requiring many manipulations.
* It uses a lot of parenthesis at the moment. An improvement would be to
* remove useless ones at some point. *)
let rec cp_value fmt (value, (hloc: (ident * bool, string * int) Hashtbl.t)) = let rec cp_value fmt (value, (hloc: (ident * bool, string * int) Hashtbl.t)) =
let string_of_binop = function let string_of_binop = function
| BOp_add -> "+" | BOp_add -> "+"
@@ -146,6 +240,8 @@ let rec cp_value fmt (value, (hloc: (ident * bool, string * int) Hashtbl.t)) =
| CMonOp (MOp_pre, _) -> | CMonOp (MOp_pre, _) ->
failwith "The linearization should have removed this case." failwith "The linearization should have removed this case."
let prefix_ = ref "\t" let prefix_ = ref "\t"
(** The following function prints one transformed equation of the program into a (** The following function prints one transformed equation of the program into a
@@ -191,10 +287,16 @@ and cp_expression fmt (expr, hloc) =
end end
| CReset (node_name, i, v, b) -> | CReset (node_name, i, v, b) ->
begin begin
Format.fprintf fmt "\tif (%a) {\n\t\t((t_state_%s*)(state->aux_states[%d]))->is_init = true;\n\t}\n%a\n" 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) cp_value (v, hloc)
node_name node_name
(i - 1) (i - 1)
node_name
(i - 1)
cp_block (b, hloc) cp_block (b, hloc)
end end
| CIf (v, b1, []) -> | CIf (v, b1, []) ->
@@ -218,3 +320,127 @@ and cp_expression fmt (expr, hloc) =
p; p;
prefix_ := p prefix_ := p
(** [cp_main] prints a main function to the C code if necessary:
* 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\\n\"%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
let cp_free fmt () =
let main_st = Hashtbl.find sts "main" in
if main_st.nt_count_app = 0
then ()
else Format.fprintf fmt "\tfree_state_main(&state);\n"
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\")) { break; }\n\
\t\tsscanf(_buffer, %a);\n%a\
\t\tfn_main(&state, %a);\n\
\t\tprintf(%a);\n\
\t}\n\
%a\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)
cp_free ()

View File

@@ -37,7 +37,7 @@ let rec pp_varlist fmt : t_varlist -> unit = function
Format.fprintf fmt "%s: bool, %a" h pp_varlist (tl, h' :: l) Format.fprintf fmt "%s: bool, %a" h pp_varlist (tl, h' :: l)
| (TReal :: tl, RVar h :: h' :: l) -> | (TReal :: tl, RVar h :: h' :: l) ->
Format.fprintf fmt "%s: real, %a" h pp_varlist (tl, h' :: l) Format.fprintf fmt "%s: real, %a" h pp_varlist (tl, h' :: l)
| _ -> raise (MyTypeError "This exception should not have beed be raised.") | _ -> raise (MyTypeError "(1) This exception should not have beed be raised.")
let pp_expression = let pp_expression =
let upd_prefix s = s ^ " | " in let upd_prefix s = s ^ " | " in
@@ -45,11 +45,14 @@ let pp_expression =
let rec pp_expression_list prefix fmt exprs = let rec pp_expression_list prefix fmt exprs =
match exprs with match exprs with
| ETuple([], []) -> () | ETuple([], []) -> ()
| ETuple (_ :: tt, expr :: exprs) -> | ETuple (typs, expr :: exprs) ->
let typ_h, typ_t =
Utils.list_select (List.length (Utils.type_exp expr)) typs in
Format.fprintf fmt "%a%a" Format.fprintf fmt "%a%a"
(pp_expression_aux (prefix^" |> ")) expr (pp_expression_aux (prefix^" |> ")) expr
(pp_expression_list prefix) (ETuple (tt, exprs)) (pp_expression_list prefix) (ETuple (typ_t, exprs))
| _ -> raise (MyTypeError "This exception should not have been raised.") | ETuple (_, []) -> failwith "An empty tuple has a type!"
| _ -> failwith "This exception should never occur."
in in
match expression with match expression with
| EWhen (_, e1, e2) -> | EWhen (_, e1, e2) ->

View File

@@ -63,7 +63,7 @@
let make_binop_nonbool e1 e2 op error_msg = let make_binop_nonbool e1 e2 op error_msg =
let t1 = type_exp e1 in let t2 = type_exp e2 in let t1 = type_exp e1 in let t2 = type_exp e2 in
(** e1 and e2 should be nunmbers here.*) (** e1 and e2 should be numbers here.*)
if list_chk t1 [[TInt]; [TReal]] && list_chk t2 [[TInt]; [TReal]] if list_chk t1 [[TInt]; [TReal]] && list_chk t2 [[TInt]; [TReal]]
then then
begin begin
@@ -88,7 +88,7 @@
let make_comp_nonbool e1 e2 op error_msg = let make_comp_nonbool e1 e2 op error_msg =
let t1 = type_exp e1 in let t2 = type_exp e2 in let t1 = type_exp e1 in let t2 = type_exp e2 in
(** e1 and e2 should be nunmbers here.*) (** e1 and e2 should be numbers here.*)
if list_chk t1 [[TInt]; [TReal]] && list_chk t2 [[TInt]; [TReal]] if list_chk t1 [[TInt]; [TReal]] && list_chk t2 [[TInt]; [TReal]]
then then
begin begin
@@ -216,8 +216,8 @@ node_content:
if vars_distinct e_in e_out (snd $10) if vars_distinct e_in e_out (snd $10)
then (Hashtbl.add defined_nodes node_name n; n) then (Hashtbl.add defined_nodes node_name n; n)
else raise (MyParsingError else raise (MyParsingError
("There is a conflict between the names of local, input \ ("There is a conflict between the names of local,\
or output variables.", input or output variables.",
current_location())) current_location()))
end}; end};
@@ -313,33 +313,33 @@ expr:
| MO_pre expr { EMonOp (type_exp $2, MOp_pre, $2) } | MO_pre expr { EMonOp (type_exp $2, MOp_pre, $2) }
| MINUS expr | MINUS expr
{ monop_neg_condition $2 [TBool] { monop_neg_condition $2 [TBool]
"You cannot take the opposite of a boolean expression." "You cannot take the opposite of an expression that is not a number."
(EMonOp (type_exp $2, MOp_minus, $2)) } (EMonOp (type_exp $2, MOp_minus, $2)) }
| PLUS expr | PLUS expr
{ monop_neg_condition $2 [TBool] { monop_neg_condition $2 [TBool]
"You cannot take the plus of a boolean expression." $2 } "(+) expects its argument to be a number." $2 }
/* Binary operators */ /* Binary operators */
| expr PLUS expr | expr PLUS expr
{ make_binop_nonbool $1 $3 BOp_add { make_binop_nonbool $1 $3 BOp_add
"You should know better; addition hates booleans" } "Addition expects both arguments to be (the same kind of) numbers." }
| expr MINUS expr | expr MINUS expr
{ make_binop_nonbool $1 $3 BOp_sub { make_binop_nonbool $1 $3 BOp_sub
"You should know better; subtraction hates booleans" } "Substraction expects both arguments to be (the same kind of) numbers." }
| expr BO_mul expr | expr BO_mul expr
{ make_binop_nonbool $1 $3 BOp_mul { make_binop_nonbool $1 $3 BOp_mul
"You should know better; multiplication hates booleans" } "Multiplication expects both arguments to be (the same kind of) numbers." }
| expr BO_div expr | expr BO_div expr
{ make_binop_nonbool $1 $3 BOp_div { make_binop_nonbool $1 $3 BOp_div
"You should know better; division hates booleans" } "Division expects both arguments to be (the same kind of) numbers." }
| expr BO_mod expr | expr BO_mod expr
{ make_binop_nonbool $1 $3 BOp_mod { make_binop_nonbool $1 $3 BOp_mod
"You should know better; modulo hates booleans" } "Modulo expects both arguments to be numbers." }
| expr BO_and expr | expr BO_and expr
{ make_binop_bool $1 $3 BOp_and { make_binop_bool $1 $3 BOp_and
"You should know better; conjunction hates numbers" } "Conjunction expects both arguments to be booleans." }
| expr BO_or expr | expr BO_or expr
{ make_binop_bool $1 $3 BOp_or { make_binop_bool $1 $3 BOp_or
"You should know better; disjunction hates numbers" } "Disjunction expects both arguments to be booleans." }
| expr BO_arrow expr | expr BO_arrow expr
{ let e1 = $1 in let t1 = type_exp e1 in { let e1 = $1 in let t1 = type_exp e1 in
let e2 = $3 in let t2 = type_exp e2 in let e2 = $3 in let t2 = type_exp e2 in

View File

@@ -1,15 +1,18 @@
node id (a: bool) returns (o: bool); node id_int (i: int) returns (o: int);
let let
o = a; o = i -> i;
tel tel
node test_merge_tuples (a, b: bool) returns (o: bool); node aux (i, j: int) returns (o: int);
var t: bool;
let let
(o, t) = if a and b then (true, false) else (false, true); o = id_int(i) + id_int(j);
tel tel
node my_and (a, b: bool) returns (o: bool); node main (i: int) returns (a, b: int);
var tmp: int;
let let
o = if a then b else id(false -> a); a = 1;
b = aux (i, a);
tmp = aux (a+b, i);
tel tel