diff --git a/C11-BackEnds/Clean/src/Clean.thy b/C11-BackEnds/Clean/src/Clean.thy index 7633fe618c8d4c87a4c64569c9eaac25683f1d5a..988268dbda7ae90ebafd183f7e94766b8ed588f1 100644 --- a/C11-BackEnds/Clean/src/Clean.thy +++ b/C11-BackEnds/Clean/src/Clean.thy @@ -1415,9 +1415,7 @@ fun mk_seq_C C C' = let val t = fastype_of C fun mk_seq_assign_C rhs lhs varname vartyp= let val t1 = fastype_of rhs val t2 = fastype_of lhs - val abstractedTerm = Term.abstract_over ((Free (varname, vartyp)),lhs) - val lambdaExpr = (Abs (varname,vartyp, abstractedTerm)) - in Const(\<^const_name>\<open>bind_SE\<close>, t1 --> (vartyp --> t2) --> t2 ) $ rhs $ lambdaExpr end; + in Const(\<^const_name>\<open>bind_SE\<close>, t1 --> (vartyp --> t2) --> t2 ) $ rhs $ absfree (varname, vartyp) lhs end; fun mk_skip_C sty = Const(\<^const_name>\<open>skip\<^sub>S\<^sub>E\<close>, StateMgt_core.MON_SE_T HOLogic.unitT sty) @@ -1425,34 +1423,26 @@ fun mk_break sty = Const(\<^const_name>\<open>break\<close>, StateMgt_core.MON_SE_T HOLogic.unitT sty ) fun mk_return_C upd rhs = - let val ty = fastype_of rhs - val (sty,rty) = case ty of - Type("fun", [sty,rty]) => (sty,rty) - | _ => error "mk_return_C: illegal type for body" - val upd_ty = (HOLogic.listT rty --> HOLogic.listT rty) --> sty --> sty + let val (rty, sty) = case fastype_of upd of Type("fun",[Type("fun", [Type(_(*list*),[r_ty]),_]),Type ("fun",[s_ty,_])]) => (r_ty, s_ty) + | _=>error "mk_return_C: illegal type for update func" + val rhs_ty = sty --> rty val mty = StateMgt_core.MON_SE_T HOLogic.unitT sty - in Const(\<^const_name>\<open>return\<^sub>C\<close>, upd_ty --> rhs_ty --> mty) $ upd $ rhs end + in Const(\<^const_name>\<open>return\<^sub>C\<close>, fastype_of upd --> rhs_ty --> mty) $ upd $ rhs end fun mk_assign_global_C upd rhs = - let val ty = fastype_of rhs - val (sty,rty) = case ty of - Type("fun", [sty,rty]) => (sty,rty) - | _ => error "mk_assign_global_C: illegal type for body" - val upd_ty = (rty --> rty) --> sty --> sty + let val (rty, sty) = case fastype_of upd of Type("fun",[Type("fun", [r_ty,_]),Type ("fun",[s_ty,_])]) => (r_ty, s_ty) + | _=>error "mk_assign_global_C: illegal type for update func" val rhs_ty = sty --> rty val mty = StateMgt_core.MON_SE_T HOLogic.unitT sty - in Const(\<^const_name>\<open>assign_global\<close>, upd_ty --> rhs_ty --> mty) $ upd $ rhs end + in Const(\<^const_name>\<open>assign_global\<close>, fastype_of upd --> rhs_ty --> mty) $ upd $ rhs end fun mk_assign_local_C upd rhs = - let val ty = fastype_of rhs - val (sty,rty) = case ty of - Type("fun", [sty,rty]) => (sty,rty) - | _ => error "mk_assign_local_C: illegal type for body" - val upd_ty = (HOLogic.listT rty --> HOLogic.listT rty) --> sty --> sty + let val (rty, sty) = case fastype_of upd of Type("fun",[Type("fun", [Type(_(*list*),[r_ty]),_]),Type ("fun",[s_ty,_])]) => (r_ty, s_ty) + | _=>error "mk_assign_local_C: illegal type for update func" val rhs_ty = sty --> rty val mty = StateMgt_core.MON_SE_T HOLogic.unitT sty - in Const(\<^const_name>\<open>assign_local\<close>, upd_ty --> rhs_ty --> mty) $ upd $ rhs end + in Const(\<^const_name>\<open>assign_local\<close>, fastype_of upd --> rhs_ty --> mty) $ upd $ rhs end fun mk_call_C opn args = let val ty = fastype_of opn diff --git a/C11-BackEnds/Clean_wrapper/examples/Coder_Documentation.thy b/C11-BackEnds/Clean_wrapper/examples/Coder_Documentation.thy new file mode 100644 index 0000000000000000000000000000000000000000..dbbc2b58cbfe5c790753feaa9707509fd1be8162 --- /dev/null +++ b/C11-BackEnds/Clean_wrapper/examples/Coder_Documentation.thy @@ -0,0 +1,135 @@ +(*In this file the current limitations of the translation from C to Clean are shown.*) +theory "Coder_Documentation" + imports + "../src/compiler/Clean_Annotation" + "../src/CleanTranslationHook" +begin + + +section\<open>Architecture remarks\<close> +text\<open> +The function \<open>handle_declarations::nodeInfo cTranslationUnit ->Context.generic -> Context.generic\<close> +can be called with the AST of a translation unit to handle all the definitions. Within that, for every +function the \<open>convertStmt\<close> (CleanCoder) is called to create a translation of the function body. + +The \<open>setup C_Module.C_Term.map_expression\<close> command handles the C-Term-Antiquotation, which is used for the annotations. +The parsing of the annotation is delayed, for the reason that they need a contet within which sigma (and vars) +are already defined. For that reason, they are stored in \<open>Data_Clean_Annotations\<close> as functions with the +signature \<open>Context.generic \<rightarrow> term\<close>. This functions are then called when the new context is available. +Additionally the position and function names are saved, which are needed for assigning pre- and postconditions to +the functions and assigning invariants and measures to a loop (via positions). + +Importantly, the parsing of the expressions still needs the "old" env because it contains informations +about local vars and parameters, therefore this is saved in the beginning of the \<open>map_context_annotation_declaration\<close> function. +The environment is then passed by writing it to the \<open>Data_Surrounding_Env\<close> GenericData-store. + +To prevent Isabelle from coercing types of returned terms \<open>Syntax.parse_term\<close> is used instead of \<open>Syntax.read_term\<close>. +Furthermore as parameters are represented as free variables, all constants that would be "selected" through +a parameter name need to be hidden (\<open>remove_params_from_proof\<close>). + +Environment: +The scope of a parameter now is visible in the environment's var table. It is either "Global", "Local" or "Parameter". +Furthermore each identifier has a field \<open>functionArgs\<close> which is an optional list of function parameters. +When an identifier has \<open>functionArgs = NONE\<close>, then it is a variable. \<open>functionArgs=SOME []\<close> corresponds to a parameterless function. + +Nice to know: +- The environment of the last completely parsed C-context can be retrieved using \<open>C_Module.Data_In_Env\<close>. +- Intermediate envs, containing parameters and local vars can be retrieved using \<open>C_Env.Data_Lang.get'\<close>. +See C5.thy in the examples of C11-Frontend. +\<close> + +section\<open>Limitations\<close> +text\<open> +- Only two types are currently mapped to isabelle types, + namely int -> int and unsigned -> nat. + +- Function calls can only occur as statements or on the right hand side of an assignment. + For example \<open>a = b + foo();\<close> is not allowed. This must be rewritten as \<open>tmp = foo(); a=b+tmp;\<close> + +- Recursive functions must have "void" as return value. This is caused by an issue within + Clean and is about to be fixed. The current translation should work for this case then. + +- Scoping: refrain from defining variables more than once. A read/write from a local variable + always affects the most recent definition. Scoping using curly braces does not work as in C! + example: + \<open>int foo(){ + int x = 3; + { + int x = 5; + } + return x; // wrongly returns 5 + }\<close> + Also defining global variables twice within one translation unit will result in only one definition, + thus the second definition does not "reset" the value of the variable + +- Method overloading: Do not use function names multiple times, as this will break the whole + translation process in several ways. +\<close> + +section\<open>Some examples\<close> +text\<open>See \<open>Coder_Test_T_Units\<close> for more examples\<close> + +C\<open> +int sum_of_array(int arr[], int length){ + int i; + int sum; + i = 0; + sum = 0; + while(i < length){ + /*@ inv\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>i\<close> \<le> \<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>length\<close>\<close> */ + /*@ measure\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>nat \<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>length-i\<close>\<close> */ + sum = sum + arr[i]; + i = i+1; + } + return sum; +} +\<close> +(*look at the annotated while loop - it has the inv as first and the measure as snd argument*) +find_theorems sum_of_array_core + +text\<open>The following program would not work in C - Clean admits it however, but produces warnings\<close> +C\<open> +int A[5][4]; +int swap_rows(unsigned idx1, unsigned idx2){ + int tmp[]; + tmp = A[idx1]; + A[idx1] = A[idx2]; + A[idx2] = tmp; +} +\<close> +find_theorems swap_rows_core + +text\<open>A fully annotated multiply\<close> +C\<open> +int multiply(int a, int b){ + /*@ pre\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>a\<close> \<ge> 0\<close> */ + /*@ post\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<lambda>ret::int. ret = \<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>a*b\<close>\<close> */ + int sum; + int counter; + sum = 0; + counter = 0; + + while(counter < a){ + /*@ inv\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>counter*b\<close> = \<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>sum\<close> \<and> \<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>counter\<close> \<le> \<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>a\<close>\<close> */ + sum = sum + b; + counter = counter + 1; + } + return sum; +} +\<close> +find_theorems multiply +find_theorems multiply_pre +find_theorems multiply_post + +text\<open>A recursive function calculating the factorial of n\<close> +C\<open> +int factorial_result; +void factorial(int n){ + if(n > 1){ + factorial(n-1); + factorial_result = multiply(factorial_result, n); + }else{ + factorial_result = 1; + } +}\<close> +find_theorems factorial_core diff --git a/C11-BackEnds/Clean_wrapper/examples/Coder_Test_ExprStmt.thy b/C11-BackEnds/Clean_wrapper/examples/Coder_Test_ExprStmt.thy index 4820cab5c50de84629506ab58ae5bebc05835738..5cdd77a886463f760621b76f700edbc703bf0561 100644 --- a/C11-BackEnds/Clean_wrapper/examples/Coder_Test_ExprStmt.thy +++ b/C11-BackEnds/Clean_wrapper/examples/Coder_Test_ExprStmt.thy @@ -203,7 +203,7 @@ val S'' = conv_Cexpr_lifted_term sigma_i A_env2 @{theory} "" (K NONE) ast_expr ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> \<comment> \<open>type-check of the latter\<close> -ML\<open> Sign.certify_term @{theory} S \<close> +ML\<open> Sign.certify_term @{theory} (Syntax.check_term @{context} S) \<close> (* This local variable space also creates the update function for the return_result. *) local_vars_test (test_return "int") @@ -257,7 +257,7 @@ val S = conv_Cexpr_lifted_term sigma_i A_env1 @{theory} "" (K NONE) ast_expr ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> \<comment> \<open>type-check of the latter\<close> -ML\<open> Sign.certify_term @{theory} S \<close> +ML\<open>Sign.certify_term @{theory} (Syntax.check_term @{context} S)\<close> (*7*****************************************************************************************************) @@ -280,7 +280,7 @@ val S = conv_Cexpr_lifted_term sigma_i A_env0 @{theory} "" (K NONE) ast_expr ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> \<comment> \<open>type-check of the latter\<close> -ML\<open> Sign.certify_term @{theory} S \<close> +ML\<open>Sign.certify_term @{theory} (Syntax.check_term @{context} S)\<close> section \<open>statements\<close> @@ -316,7 +316,7 @@ val [S] = (C11_Ast_Lib.fold_cStatement ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> \<comment> \<open>type-check of the latter\<close> -ML\<open> Sign.certify_term @{theory} S \<close> +ML\<open>Sign.certify_term @{theory} (Syntax.check_term @{context} S)\<close> text\<open>Write to array\<close> @@ -448,7 +448,7 @@ val [S] = (C11_Ast_Lib.fold_cStatement ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> \<comment> \<open>type-check of the latter\<close> -ML\<open> Sign.certify_term @{theory} S \<close> +ML\<open>Sign.certify_term @{theory} (Syntax.check_term @{context} S)\<close> (*3*****************************************************************************************************) @@ -472,7 +472,7 @@ val [S] = (C11_Ast_Lib.fold_cStatement ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> \<comment> \<open>type-check of the latter\<close> -ML\<open> Sign.certify_term @{theory} S \<close> +ML\<open>Sign.certify_term @{theory} (Syntax.check_term @{context} S)\<close> (*4*****************************************************************************************************) @@ -499,7 +499,7 @@ val [S] = (C11_Ast_Lib.fold_cStatement ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> \<comment> \<open>type-check of the latter\<close> -ML\<open> Sign.certify_term @{theory} S \<close> +ML\<open>Sign.certify_term @{theory} (Syntax.check_term @{context} S)\<close> (*5*****************************************************************************************************) @@ -537,7 +537,7 @@ ML\<open> read_N_coerce @{theory} "a" (sigma_i --> intT)\<close> ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> \<comment> \<open>type-check of the latter\<close> -ML\<open> Sign.certify_term @{theory} S \<close> +ML\<open>Sign.certify_term @{theory} (Syntax.check_term @{context} S)\<close> (* a very serious problem : the inheritance on state spaces is not appropriately mirrored. *) @@ -744,7 +744,7 @@ val [S] = (C11_Ast_Lib.fold_cStatement ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> -ML\<open>Sign.certify_term @{theory} S\<close> +ML\<open>Sign.certify_term @{theory} (Syntax.check_term @{context} S)\<close> subsection\<open>Call with no return type\<close> (*Methods call only with sideeffects*) @@ -769,7 +769,7 @@ term assign_to_a ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> -ML\<open>Sign.certify_term @{theory} S\<close> +ML\<open>Sign.certify_term @{theory} (Syntax.check_term @{context} S)\<close> subsection\<open>Call with return type\<close> consts fun_with_ret_value :: "(int) \<Rightarrow> (int,'a local_test_return_state_scheme)MON\<^sub>S\<^sub>E " @@ -806,7 +806,7 @@ term assign_to_a ML\<open>writeln (Syntax.string_of_term_global @{theory} S);\<close> -ML\<open>Sign.certify_term @{theory} S\<close> +ML\<open>Sign.certify_term @{theory} (Syntax.check_term @{context} S)\<close> section \<open>Experiments with Local Scopes\<close> diff --git a/C11-BackEnds/Clean_wrapper/examples/Coder_Test_TUnits b/C11-BackEnds/Clean_wrapper/examples/Coder_Test_TUnits deleted file mode 100644 index 0caf1f6ce14ca21d54c0bb1922d638a6d9455983..0000000000000000000000000000000000000000 --- a/C11-BackEnds/Clean_wrapper/examples/Coder_Test_TUnits +++ /dev/null @@ -1,3 +0,0 @@ -theory "Coder_Test_ExprStmt" - imports "../src/CleanCoder" (* Coder_Test_Env_AEnv *) -begin diff --git a/C11-BackEnds/Clean_wrapper/examples/Coder_Test_TUnits.thy b/C11-BackEnds/Clean_wrapper/examples/Coder_Test_TUnits.thy index 267b5e44111fb7a7cc891f525c7b1dd2a9879d4d..36ff8a10e8e6cb8144c72b7abccb7a516bc53592 100644 --- a/C11-BackEnds/Clean_wrapper/examples/Coder_Test_TUnits.thy +++ b/C11-BackEnds/Clean_wrapper/examples/Coder_Test_TUnits.thy @@ -1,198 +1,98 @@ theory "Coder_Test_TUnits" - imports "../src/CleanCoder" (* Coder_Test_Env_AEnv *) + imports "../src/compiler/Clean_Annotation" + "../src/CleanTranslationHook" begin -ML\<open> -(*This is an override for the update_Root_Ast function that is registered in C_Command.*) - -fun transform_type typ = if typ = HOLogic.intT then "int" - else if typ = HOLogic.natT then "nat" - else if is_listTy typ then (transform_type (dest_listTy typ))^" list" - else if typ = HOLogic.unitT then "unit" - else error "Unknown variable type" - -local open C_AbsEnv HOLogic in -fun get_hol_type (C_Env.Parsed ret) params = let - val base_type =the (C11_TypeSpec_2_CleanTyp.conv_cDeclarationSpecifier_typ (SOME ret)) - fun transform_type ((C_Ast.CArrDeclr0 _)::R) base_type = listT (transform_type R base_type) - | transform_type [] base_type = base_type - in transform_type params base_type end -fun map_env_ident_to_identifier (name,(positions,_,data)) = - let fun get_ident_scope C_Env.Global = Global - |get_ident_scope C_Env.Local = Local "" - |get_ident_scope C_Env.Parameter = Parameter "" - in - case #functionArgs data of C_Ast.None => Identifier(name, if null positions then @{here} else hd positions,get_hol_type (#ret data) (#params data),get_ident_scope (#scope data)) - |_=> Identifier(name, @{here},intT,FunctionCategory (Final, NONE)) (*this line is wrong because of different function types*) - end -end - -fun declare_function idents name ast ret_ty recursive ctxt = - let val param_idents = filter (fn i => case i of C_AbsEnv.Identifier(_,_,_, C_AbsEnv.Parameter f_name) => f_name = name |_=>false) idents - val local_idents = filter (fn i => case i of C_AbsEnv.Identifier(_,_,_, C_AbsEnv.Local f_name) => f_name = name |_=>false) idents - val global_idents = filter (fn i => case i of C_AbsEnv.Identifier(_,_,_, C_AbsEnv.Global) => true - | C_AbsEnv.Identifier(_,_,_,C_AbsEnv.FunctionCategory _)=>true - | _ => false) idents - - (*Obtain the parameters and local variables*) - val params = map (fn C_AbsEnv.Identifier(name,pos,typ, _) => (Binding.make (name, pos), transform_type typ)) (param_idents) - val locals = map (fn C_AbsEnv.Identifier(name,pos,typ, _) => (Binding.make (name, pos), transform_type typ, NoSyn)) (local_idents) - - (*This is necessary, as parameters are represented as free variables. - When the Invariants, post- and preconditions are read through the term antiquotations, - Syntax.parse_term (Syntax.read_term does this too) would substitute them by another const, - which could be a local or global variable*) - fun remove_params_from_proof ctx = let - val param_names = List.map (fn C_AbsEnv.Identifier(n,_,_,_) => n) param_idents - fun filter_by_shortname param_names (n, _) = - List.exists (fn ele => ele = Long_Name.base_name n) param_names - val longnames = List.filter (filter_by_shortname param_names) (#constants (Consts.dest (Sign.consts_of (Proof_Context.theory_of ctx)))) - val thy0 = Proof_Context.theory_of ctx - val thy' = List.foldl (fn (longname, thy')=> thy' |> Sign.hide_const true longname) thy0 (List.map fst longnames) - in Proof_Context.init_global thy' end - - (*Invariants and measuress need to be matched to a loop. This is done by comparing the parse locations of all while loops. - The following are helper methods, to obtain the function get_invariant: positiona \<rightarrow> (context\<rightarrow>term) option*) - val invariants:((string*(Context.generic -> term)*Position.range) list) = List.filter (fn (f_name,_,_) => f_name = name) - (#invariants (Clean_Annotation.Data_Clean_Annotations.get ctxt)) - val measures:((string*(Context.generic -> term)*Position.range) list) = List.filter (fn (f_name,_,_) => f_name = name) - (#measures (Clean_Annotation.Data_Clean_Annotations.get ctxt)) - val loop_pos =Library.distinct (op =) (C11_Ast_Lib.fold_cStatement (fn a => fn b => a@b) C11_Unit_2_Clean.get_loop_positions ast []) - fun compare_pos ((C_Ast.Position0 (pos1,_,_,_)),(C_Ast.Position0 (pos2,_,_,_))) = Int.compare (pos1,pos2) - val loop_pos_sorted = Library.sort compare_pos loop_pos - fun range_less_than_pos (range:Position.range) (C_Ast.Position0 (pos,_,_,_)) = the (Position.offset_of (fst range)) < pos - fun get_for_position (((inv,inv_pos)::R_inv): ((Context.generic -> term)*Position.range)list) - (loop_positions: C_Ast.positiona list) - (pos3: C_Ast.positiona) - (* search the first invariant, which is not declared before pos3 *) - = (if range_less_than_pos inv_pos pos3 then get_for_position R_inv loop_positions pos3 - else case loop_positions of (* we found the first invariant after pos3 *) - (* Now check, if the next loop definition is after the invariant definition. - Otherwise there is no invariant for the given loop *) - (pos1::pos2::R) => if pos3 = pos1 andalso range_less_than_pos inv_pos pos2 then SOME inv - else get_for_position ((inv,inv_pos)::R_inv) (pos2::R) pos3 - | (pos1::R) => if pos3 = pos1 then SOME inv else NONE - | [] => NONE) - |get_for_position [] _ _ = NONE - fun get_invariant pos = (get_for_position (List.map (fn inv => (#2 inv, #3 inv)) invariants) loop_pos_sorted) pos - fun get_measure pos = (get_for_position (List.map (fn inv => (#2 inv, #3 inv)) measures) loop_pos_sorted) pos - fun get_loop_annotations pos = (get_invariant pos, get_measure pos) - - (*generic function to get the first ele*) - val get_precond = Option.map (fn (_,e,_) => e) (List.find (fn (a,_,_) => a = name) (#preconditions (Clean_Annotation.Data_Clean_Annotations.get ctxt))) - val get_postcond = Option.map (fn (_,e,_) => e) (List.find (fn (a,_,_) => a = name) (#postconditions (Clean_Annotation.Data_Clean_Annotations.get ctxt))) - - (*the translation of the precondition*) - fun get_translation NONE default ctxt= C11_Expr_2_Clean.lifted_term (StateMgt.get_state_type (ctxt)) default - | get_translation (SOME get_term) _ ctxt= let - val term = get_term (Context.Proof (remove_params_from_proof ctxt)) - val lifted = C11_Expr_2_Clean.lifted_term (StateMgt.get_state_type ctxt) term - in - Syntax.check_term ctxt lifted - end - (*The actual translation of the loop body*) - fun get_translated_fun_bdy ctx _ = let - val ctx' = remove_params_from_proof ctx - val v = ((C11_Ast_Lib.fold_cStatement - C11_Stmt_2_Clean.regroup - (C11_Stmt_2_Clean.convertStmt false - (StateMgt.get_state_type ctx') - (local_idents@param_idents@global_idents) - (Proof_Context.theory_of ctx') - name get_loop_annotations) - ast [])) - in hd v end - - val test_function_sem = {binding = Binding.name name, - locals = locals@[(Binding.name "dummylocalvariable","int", NoSyn)], (*There needs to be at least one local variable*) - params = params, - ret_type = transform_type ret_ty, - read_pre = get_translation get_precond (@{term True}), - read_post = get_translation get_postcond (Abs ("ret",ret_ty, @{term True})), - read_variant_opt = NONE, - read_body = get_translated_fun_bdy} - val decl = Function_Specification_Parser.checkNsem_function_spec_gen {recursive = recursive} test_function_sem - in decl end - -local open C_AbsEnv HOLogic in -fun handle_declarations translUnit ctxt = - (let - val env = (C_Module.Data_Last_Env.get ctxt) - (*First we need to get all previously defined global vars and functions*) - val m = (Symtab.dest (#idents(#var_table(env)))) - val prev_idents =map map_env_ident_to_identifier m - (*the new identifiers are returned in reverse \<rightarrow> thus reverse *) - val (new_idents, call_table) = C_AbsEnv.parseTranslUnitIdentifiers translUnit [] prev_idents Symtab.empty - - val identifiers = (rev new_idents)@prev_idents - val map_idents = List.map (fn C_AbsEnv.Identifier(name,_,typ,_) => (Binding.name name, transform_type typ, NoSyn)) - - fun get_declaration is_global idents = if null idents then I else StateMgt.new_state_record is_global (NONE,idents) - - val global_idents = (map_idents (List.filter (fn C_AbsEnv.Identifier(_,_,_,vis) => vis = C_AbsEnv.Global) new_idents)) - val global_declaration =get_declaration true global_idents - - val fun_asts = - List.map (fn C_AbsEnv.Identifier(name,_,ret_ty,C_AbsEnv.FunctionCategory ast) => - let fun is_recursive NONE = false - |is_recursive (SOME calls) = List.exists (fn x => x=name) calls - in - (name,the (snd ast),ret_ty, is_recursive (Symtab.lookup call_table name)) end) - (List.filter (fn a => case a of C_AbsEnv.Identifier(_,_,_,C_AbsEnv.FunctionCategory _) => true | _ => false) (rev new_idents)) - val function_declarations = List.map (fn (name,ast,ret_ty, recursive) => declare_function identifiers name ast ret_ty recursive ctxt) (fun_asts) - - val function_decl = fold (fn f => fn acc => f acc) function_declarations - in - Context.map_theory (function_decl o global_declaration) ctxt - end); -end -\<close> -ML\<open> -fun handle_declarations_wrapper ast v2 ctxt = - let val ctx1 = update_Root_Ast SOME ast v2 ctxt (*Note the call to the original callback - this somehow gets overwritten*) - in - case ast of (C_Ast.Left translUnit) => handle_declarations translUnit ctx1 - | _ => ctx1 - end -\<close> -setup \<open>Context.theory_map (C_Module.Data_Accept.put (handle_declarations_wrapper))\<close> - -(* Note: The hook "C_Module.C_Term.map_translation_unit" is not adequate, as it is - meant for the term antiquotation (its callback returns a term, not a theory/context *) - -setup \<open>C_Module.C_Term.map_expression - (fn cexpr => fn _ => fn ctxt => let - val sigma_i = (StateMgt.get_state_type o Context.proof_of )ctxt - val env = C_Module.Data_Surrounding_Env.get ctxt - val idents = (Symtab.dest (#idents(#var_table(env)))) - val A_env = List.map map_env_ident_to_identifier idents - val expr = (hd (C11_Ast_Lib.fold_cExpression (K I) - (C11_Expr_2_Clean.convertExpr true sigma_i A_env (Context.theory_of ctxt) "" (K NONE)) - cexpr [])) handle ERROR msg => (writeln("ERROR: "^(@{make_string}msg));@{term "1::int"}) -in - expr -(* @{term "1::int"}*) - end - -)\<close> declare [[C\<^sub>e\<^sub>n\<^sub>v\<^sub>0 = last]] declare [[C\<^sub>r\<^sub>u\<^sub>l\<^sub>e\<^sub>0 = "translation_unit"]] -ML\<open> -val a = (Abs ("\<sigma>", StateMgt.get_state_type ( @{context}), - Const ("Orderings.ord_class.greater_eq", @{typ "_"}) $ Const ("Groups.one_class.one", @{typ "int"}) $ - Const ("Groups.one_class.one", @{typ "int"}))) -val a' = absfree ("a",@{typ "int"}) (absfree ("b", @{typ "int"}) (Syntax.check_term @{context} a)) +C\<open> +int foo10(){ + int b = 0, d123=4, ex=13; +} +\<close> + +C\<open> +int foo11(){ + int var1,var2=3,var3, var4; +} +\<close> + +C\<open> +int forloop(){ + int b=3; + for(int i=0; i<10; i=i+1){ + b=b+1; + } + return b; +} +\<close> + +find_theorems d123 +find_theorems foo10_core +find_theorems forloop_core + +text\<open>Apparently currently it is decided based on the stack layout, whether an else branch exists. +So a previous assignment destroys this code.\<close> +C\<open> +int g; +int foo13(){ + if(1){ + } + if (g>0){ + g=1; + } +} +\<close> +C\<open> +int g; +int foo12(){ + g = 0; + if (g>0){ + g=1; + } +} +\<close> + + +C\<open> +int foo(int a, int b){ +} +int bar(int b){ + int a; + a = 2; +} +\<close> + +C\<open> +int foo1(unsigned par){ + unsigned tmp; + for (tmp = 0; tmp < tmp; tmp=tmp+1) { + } +} +\<close> + +text\<open>Assigning numbers to a non-int variable causes issues\<close> +C\<open> +int bar1(){ + unsigned tmp; + tmp = tmp+0; +} +\<close> -val b = HOLogic.mk_case_prod a' +C\<open> +unsigned glob_nat; +int bar2(){ + glob_nat = 3; +} \<close> C\<open> int multiply1(int a, int b){ - /*@ pre\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>1 \<ge> 1\<close> */ + /*@ pre\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>(1::int) \<ge> 1\<close> */ return a; }\<close> @@ -210,11 +110,11 @@ int fun_with_pre_test(int u){ int localvar; localvar = u; - /* pre\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>u\<close> > 1\<close> */ - /* post\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<lambda>ret::int.\<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>u\<close> > 1 \<and> ret > 0\<close> */ + /*@ pre\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>u\<close> > 1\<close> */ + /*@ post\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<lambda>ret::int.\<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>u\<close> > 1 \<and> ret > 0\<close> */ while(localvar>0){ - /* inv\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>u\<close> \<ge> \<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>localvar\<close> \<close> */ + /*@ inv\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>u\<close> \<ge> \<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>localvar\<close> \<close> */ /*@ measure\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open> \<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>nat1\<close>\<close> */ localvar = localvar -1; } @@ -289,7 +189,7 @@ term\<open>addPlusThree1\<close> subsection \<open>Recursive functions\<close> - +find_theorems global_integer rec_function_spec recursive_add1(n::int) returns unit pre "\<open>True\<close>" post "\<open>\<lambda>res::unit. True \<close>" @@ -335,7 +235,7 @@ text\<open>disclaimer: C_expr antiquotation does not yet work\<close> C\<open> int multiply(int a, int b){ - /*@ pre\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>1 \<ge> 1\<close> */ + /*@ pre\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>(1::int) \<ge> 1\<close> */ /*@ post\<^sub>C\<^sub>l\<^sub>e\<^sub>a\<^sub>n \<open>\<lambda>ret::int. ret = \<^C>\<^sub>e\<^sub>x\<^sub>p\<^sub>r\<open>a*b\<close>\<close> */ int s; int counter; @@ -357,7 +257,7 @@ int multiply(int a, int b){ return s; } \<close> - +find_theorems multiply_pre diff --git a/C11-BackEnds/Clean_wrapper/src/CleanCoder.thy b/C11-BackEnds/Clean_wrapper/src/CleanCoder.thy index 1938d7a4b58f034ce1c8f312da8bf89a63a6e226..edef56617a87f2369f5837c19c5b0ff8d0f35eb0 100644 --- a/C11-BackEnds/Clean_wrapper/src/CleanCoder.thy +++ b/C11-BackEnds/Clean_wrapper/src/CleanCoder.thy @@ -67,10 +67,9 @@ exception WrongFormat of string exception UnknownTyp of string -(*renvoie le type final d'une fonction, ou le type d'une constante*) -fun lastype_of (Type(_, [x])) = x | lastype_of (Type(_, [_, y])) = y (*renvoie le type du premier attribut d'une fonction, ou le type d'une constante*) -fun firstype_of (Type(_, [x])) = x | firstype_of (Type(_, x::_)) = x +fun firstype_of (Type(_, [x])) = x | firstype_of (Type(_, x::_)) = x + |firstype_of t = t (* Creates a result_update_term for the local state *) fun mk_result_update thy sigma_i= @@ -80,19 +79,17 @@ fun mk_result_update thy sigma_i= val s' = String.substring(s, 0, size s - size "_scheme")^".result_value_update" in Syntax.read_term_global thy s' end; -fun extract_ids long_id sigma_i = - let val id = List.last(String.tokens (fn x => x = #".") long_id) - val Type(ty_name, _) = sigma_i; - val ty_name = ty_name |> String.tokens (fn x => x = #".") |> tl |> hd - val local_state = String.substring (ty_name, 0, - String.size ty_name - - (String.size "_scheme")) - (*dangerous. will work only for the local case *) - in (id, local_state^"."^id) end - -fun read_N_coerce_global thy name ty = - (* a very dirty hack ... but reconstructs the true \<open>const_name\<close> Sign.consts_of thy + +fun read_N_coerce thy name ty = + (* a very dirty hack ... but reconstructs the true \<open>const_name\<close> along the subtype hierarchy, but coerces it to the current sigma*) + let val s = drop_dark_matter(Syntax.string_of_typ_global thy ty) + val str = name ^ " :: " ^ s + in Syntax.read_term_global thy str end + +fun read_N_coerce_global thy name = + (*this function is necessary, to ensure that a global variable is selected, in case + a local variable is defined later (as later vars would get selected by default)*) let val consts = Sign.consts_of thy fun filter_by_shortname (n, _) = @@ -101,17 +98,9 @@ fun read_N_coerce_global thy name ty = | _ => false) val longnames = List.filter filter_by_shortname (#constants (Consts.dest consts)) val longname = (fst o hd) longnames - val s = drop_dark_matter(Syntax.string_of_typ_global thy ty) - val str = longname ^ " :: " ^ s - in Syntax.read_term_global thy str end - + in read_N_coerce thy longname end -fun read_N_coerce thy name ty = - (* a very dirty hack ... but reconstructs the true \<open>const_name\<close> - along the subtype hierarchy, but coerces it to the current sigma*) - let val s = drop_dark_matter(Syntax.string_of_typ_global thy ty) - val str = name ^ " :: " ^ s - in Syntax.read_term_global thy str end +fun get_update_fun thy name = read_N_coerce thy (name^"_update") \<close> subsection\<open>C11 Expressions to Clean Terms\<close> @@ -141,11 +130,22 @@ fun node_content_parser (x : C11_Ast_Lib.node_content) = val id = hd(tl(String.tokens (fn x => x = #"\"")(drop_dark_matter a_markup))) in id end (* no type inference *); -fun convertExpr verbose (sigma_i: typ) env thy function_name get_loop_annotations +fun is_call a = case a of + Const (@{const_name "Clean.call\<^sub>C"},_) $_ $_ => true + |_ => false + +fun convertExpr verbose (sigma_i: typ) env thy function_name _ (a as { tag, sub_tag, args }:C11_Ast_Lib.node_content) (b: C_Ast.nodeInfo ) (c : term list) = ((if verbose then print_node_info a b c else ()); + let fun get_most_general_type t1 t2 = + if t1 = natT andalso t2=natT then natT else + if (t1 = natT orelse t1 = intT) andalso (t2=natT orelse t2=intT) then intT else + if t1 <> natT andalso t1<>intT then t1 else t2 (*this should be the fallback for rational numbers*) + fun get_ring_op_type t1 t2 = + if get_most_general_type t1 t2 = natT then intT else get_most_general_type t1 t2 + in case tag of (*variables*) (*here, we get the full name of the variable, then we return the term well named and typed. @@ -157,30 +157,26 @@ Bound 0 is usefull for the statements, and can easily be deleted if necessary*) SOME(identifier) => identifier | NONE => error("(convertExpr) identifier " ^ id ^ " not recognised") - val Type(local_state_scheme, _) = sigma_i; - val local_state = String.substring (local_state_scheme, 0, - String.size local_state_scheme - - (String.size "_scheme")) (*dangerous. will work only for the local case *) - val lid = local_state^"."^id in case cat of - C_AbsEnv.Global => read_N_coerce_global thy id (sigma_i --> ty) $ Free("\<sigma>",sigma_i) :: c + C_AbsEnv.Global => read_N_coerce_global thy id (sigma_i --> ty) $ Free("\<sigma>",sigma_i)::c | C_AbsEnv.Local(_) => Const(@{const_name "comp"}, (HOLogic.listT ty --> ty) --> (sigma_i --> HOLogic.listT ty) --> sigma_i --> ty) $ Const(@{const_name "hd"}, HOLogic.listT ty --> ty) - $ read_N_coerce thy lid (sigma_i --> HOLogic.listT ty) + $ read_N_coerce thy id (sigma_i --> HOLogic.listT ty) $ Free("\<sigma>",sigma_i) :: c | C_AbsEnv.Parameter(_) => Free (id, ty) :: c | C_AbsEnv.FunctionCategory(C_AbsEnv.MutuallyRecursive(_), _) => error("Mutual recursion is not supported in Clean") - | C_AbsEnv.FunctionCategory(a, b) => + | C_AbsEnv.FunctionCategory(_, _) => let fun get_call_const id = Syntax.read_term_global thy id + (* There is no term corresponding to the function. Hence skip the + initialization of the type and infer it from the call args (see CCall0)*) fun get_rec_call_ident id= Free(id, (TVar (("'a", 0), [])) --> sigma_i --> (Type (@{type_name "option"}, [mk_tupleT [ty, sigma_i]]))) in (if function_name = id then get_rec_call_ident id else get_call_const id) :: c end - | c => error("(convertExpr) unrecognised category : " ^ @{make_string} c) end) |"Vars0" => c |"CVar0" => c @@ -189,10 +185,10 @@ Bound 0 is usefull for the statements, and can easily be deleted if necessary*) (*binary operations*) |"CBinary0" => (case (drop_dark_matter sub_tag, c) of (*arithmetic operations*) - ("CAddOp0",b::a::R) => (Const(@{const_name "plus"}, fastype_of a --> fastype_of b --> intT) $ a $ b :: R) - | ("CMulOp0",b::a::R) => (Const(@{const_name "times"}, fastype_of a --> fastype_of b --> intT) $ a $ b :: R) - | ("CDivOp0",b::a::R) => (Const(@{const_name "divide"}, fastype_of a --> fastype_of b --> intT) $ a $ b :: R) - | ("CSubOp0",b::a::R) => (Const(@{const_name "minus"}, fastype_of a --> fastype_of b --> intT) $ a $ b :: R) + ("CAddOp0",b::a::R) => let val ty = get_most_general_type (fastype_of a) (fastype_of b) in (Const(@{const_name "plus"}, ty --> ty --> ty) $ a $ b :: R) end + | ("CMulOp0",b::a::R) => let val ty = get_most_general_type (fastype_of a) (fastype_of b) in (Const(@{const_name "times"}, ty --> ty --> ty) $ a $ b :: R) end + | ("CDivOp0",b::a::R) => let val ty = get_ring_op_type (fastype_of a) (fastype_of b) in (Const(@{const_name "divide"}, ty --> ty --> ty) $ a $ b :: R) end + | ("CSubOp0",b::a::R) => let val ty = get_ring_op_type (fastype_of a) (fastype_of b) in (Const(@{const_name "minus"}, ty --> ty --> ty) $ a $ b :: R) end (*boolean operations*) (*for boolean operations, because in C boolean are in fact integers, we need to translate integers in booleans. That's what term_to_bool t do. @@ -208,18 +204,22 @@ translate integers in booleans. That's what term_to_bool t do. | ("CEqOp0", b::a::R) => (mk_eq ( a, b) :: R) | ("CNeqOp0", b::a::R) => (mk_not (mk_eq ( a, b))::R) (*comp*) - | ("CLeOp0", b::a::R) => (Const(@{const_name "less"}, - fastype_of a --> fastype_of b --> boolT) - $ a $ b :: R) - | ("CGrOp0", b::a::R) => (Const(@{const_name "less"}, - fastype_of a --> fastype_of b --> boolT) - $ b $ a :: R) - | ("CLeqOp0", b::a::R) => (Const(@{const_name "less_eq"}, - fastype_of a --> fastype_of b --> boolT) - $ a $ b :: R) - | ("CGeqOp0", b::a::R) => (Const(@{const_name "less_eq"}, - fastype_of a --> fastype_of b --> boolT) - $ b $ a :: R) + | ("CLeOp0", b::a::R) => let val ty =get_most_general_type (fastype_of a) (fastype_of b) + in (Const(@{const_name "less"}, + ty --> ty --> boolT) + $ a $ b :: R) end + | ("CGrOp0", b::a::R) => let val ty =get_most_general_type (fastype_of a) (fastype_of b) + in (Const(@{const_name "less"}, + ty --> ty --> boolT) + $ b $ a :: R) end + | ("CLeqOp0", b::a::R) => let val ty =get_most_general_type (fastype_of a) (fastype_of b) + in (Const(@{const_name "less_eq"}, + ty --> ty --> boolT) + $ a $ b :: R) end + | ("CGeqOp0", b::a::R) => let val ty =get_most_general_type (fastype_of a) (fastype_of b) + in (Const(@{const_name "less_eq"}, + ty --> ty --> boolT) + $ b $ a :: R)end | _ => (writeln ("sub_tag all " ^sub_tag^" :>> "^ @{make_string} c);c )) (*unary operations*) |"CUnary0" => (case (drop_dark_matter sub_tag, c) of @@ -230,7 +230,7 @@ translate integers in booleans. That's what term_to_bool t do. (*for the constants, we can use the makers*) |"CConst0" => c (* skip this wrapper *) |"CInteger0" =>let val C11_Ast_Lib.data_int n = hd args - in (mk_number intT n)::c end + in (mk_number (if n>=0 then natT else intT) n)::c end |"CIntConst0"=> c (* skip this wrapper *) |"CString0" => let val C11_Ast_Lib.data_string s = hd args in (mk_string s)::c end @@ -274,17 +274,26 @@ translate integers in booleans. That's what term_to_bool t do. |"CFloatConst0"=> (c) (* skip this wrapper *) |"CChars0" => (warning "bizarre rule in context float: CChars0"; c) |"CExpr0" => c (* skip this wrapper *) - |"CTypeSpec0" => c (* skip this wrapper *) - |"CDeclr0" => c (* skip this wrapper *) - |"CInitExpr0" => error "init expression currently unsupported" (* skip this wrapper *) - |"CDecl0" => let fun handleDeclaration stack = tl stack + (*this is a very dirty trick: when declaring variables "int a,b=3,c,d=4;", the accesses to a and c lie + on the stack, polluting it. All non-assignments are thus removed, up until this item is met on the stack*) + |"CTypeSpec0" => ((Free ("--startofdeclarations--",@{typ unit}))::c) + |"CDeclr0" => c + |"CDecl0" => let fun is_assignment ((Const (@{const_name "assign_local"},_))$_$_) = true + |is_assignment ((Const (@{const_name "assign_global"},_))$_$_) = true + |is_assignment _ = false + fun remove_dead_idents [] = [] + |remove_dead_idents (Free("--startofdeclarations--",_)::R) = R + |remove_dead_idents (head::R) = if is_assignment head then (head::remove_dead_idents R) + else remove_dead_idents R in - handleDeclaration c + remove_dead_idents c end |"CCall0" => c (* skip this wrapper *) |"CNoArrSize0" => c |"CArrDeclr0" => c - | str => error("unsupported expression with parse tag: "^str)) (* global catch all *) + | str => error("unsupported expression with parse tag: "^str^"and subtag: "^sub_tag) +end) (* global catch all *) + fun lifted_term sigma_i term = Abs("\<sigma>", sigma_i, abstract_over (Free("\<sigma>", sigma_i), term)) @@ -349,12 +358,10 @@ fun convertStmt verbose sigma_i nEenv thy function_name get_loop_annotations (a as { tag, sub_tag, args }:C11_Ast_Lib.node_content) (b: C_Ast.nodeInfo ) (stack : term list) = - ((if verbose then (writeln("tag:"^tag);print_node_info a b stack) else ()); - case tag of - - "CAssign0" => (case stack of + + let fun handle_assign stack = (case stack of (rhs :: lhs :: R) => - ((let + ((let fun getLongId lhs = (case lhs of Const(name, _) $ _ => name | _ $ _ $ Const(name, _) $ _ => name @@ -362,83 +369,70 @@ fun convertStmt verbose sigma_i nEenv thy function_name get_loop_annotations | Const ("List.nth", _) $ lhs_candidat $ _ => (getLongId lhs_candidat) | _ => error("(convertStmt) CAssign0 does not recognise term: " ^(@{make_string} lhs)^"With stacK"^(@{make_string} stack))) - val long_id = getLongId lhs - val (id, lid) = extract_ids long_id sigma_i - fun is_id (C_AbsEnv.Identifier(id_name, _, _, _)) = id_name = id - val C_AbsEnv.Identifier(id, _, ty, cat) = + val ident_id = getLongId lhs + + val C_AbsEnv.Identifier(_, _, ty, cat) = let + fun is_id (C_AbsEnv.Identifier(id_name, _, _, _)) = id_name = Long_Name.base_name ident_id in case List.find is_id nEenv of SOME x => x - | _ => error("id not found: "^ long_id) + | _ => error("id not found: "^ ident_id) end + val (update_func_ty, mk_assign) = case cat of C_AbsEnv.Global => (((ty --> ty) --> sigma_i --> sigma_i), mk_assign_global_C) + |C_AbsEnv.Local _ => (((listT ty --> listT ty) --> sigma_i --> sigma_i), mk_assign_local_C) + | _ => error ("Assignment to "^ident_id^" not possible (is it a parameter?)") + val update_func = get_update_fun thy ident_id update_func_ty fun get_base_type lhs ty = - case lhs of Const ("List.nth", typedef) $ lhs_part1 $ idx_term => + case lhs of Const ("List.nth", _) $ lhs_part1 $ _ => get_base_type lhs_part1 (dest_listTy ty) | _ => ((if (is_listTy ty) then warning "Assigning list of elements to variable. This is not possible in C, however supported by Clean" else ());ty) val tempvarn = "tmpvar" + val tempvart = (get_base_type lhs ty) val is_fun_assignment = (case rhs of Const (@{const_name "Clean.call\<^sub>C"},_) $_ $_ => true | _ => false) - val rhs_old = rhs - val tempvart = (get_base_type lhs ty) - val rhs = (if is_fun_assignment then Free (tempvarn, tempvart) else rhs) - fun mk_list_type ty = Type(@{type_name "list"}, [ty]) (* This is from "isa_termstypes.ML" *) + (*Here comes the array part. Since only entire "rows" of arrays can be replaced, + for the expression A[1][2] = b, the right hand side of the CLEAN-statement has + to include parts of the LHS, which makes this transformation rather ugly, especially + in combination with function calls. + Based on the LHS, the function get_array_assignment provides, for the above example, + a function: + \<lambda>rhs. A[1:= (A!1 [2:= rhs]) + *) fun mk_list_update_t ty = Const(@{const_name "List.list_update"}, (* This is from "isa_termstypes.ML" *) - mk_list_type ty --> natT --> - ty --> mk_list_type ty) - fun transform_rhs_list_assignment lhs_part value ty= - case lhs_part of Const ("List.nth", typedef) $ lhs_part1 $ idx_term => ( + listT ty --> natT --> ty --> listT ty) + fun transform_rhs_list_assignment lhs_part ty value= + case lhs_part of Const ("List.nth", _) $ lhs_part1 $ idx_term => ( let - val lst_update_t = mk_list_update_t ty val updated = lst_update_t $ lhs_part1 $ idx_term $ value in - transform_rhs_list_assignment lhs_part1 updated (listT ty) + transform_rhs_list_assignment lhs_part1 (listT ty) updated end ) - | _ => value - - fun transform_lhs_for_rhs_transformation lhs_part final_term = - case lhs_part of Const (@{const_name "nth"}, typedef) $ lhs_part1 $ idx_term => - Const (@{const_name "nth"}, typedef) $ (transform_lhs_for_rhs_transformation lhs_part1 final_term) $ idx_term - | _ => final_term - - val access_term = case cat of C_AbsEnv.Global => (read_N_coerce_global thy id (sigma_i --> ty) $ Free("\<sigma>",sigma_i)) - |_ => Const(@{const_name "comp"}, - (HOLogic.listT ty --> ty) - --> (sigma_i --> HOLogic.listT ty) - --> sigma_i --> ty) - $ Const(@{const_name "hd"}, HOLogic.listT ty --> ty) - $ read_N_coerce thy lid (sigma_i --> HOLogic.listT ty) - $ Free("\<sigma>",sigma_i) - - - val lhs_tmp = transform_lhs_for_rhs_transformation lhs access_term - - val new_rhs = transform_rhs_list_assignment lhs_tmp rhs (get_base_type lhs ty) - - val (id, lid) = (id ^ "_update", lid ^ "_update") - - - in case cat of - C_AbsEnv.Global => (if is_fun_assignment then ( mk_seq_assign_C rhs_old (((mk_assign_global_C - (read_N_coerce_global thy id - ((ty --> ty) --> sigma_i --> sigma_i))) - (lifted_term sigma_i new_rhs))) tempvarn tempvart) - else ( - ((mk_assign_global_C - (read_N_coerce_global thy id - ((ty --> ty) --> sigma_i --> sigma_i))) - (lifted_term sigma_i new_rhs))))::R - | C_AbsEnv.Parameter(_) => error "assignment to parameter not allowed in Clean" - | C_AbsEnv.Local(_) => (if is_fun_assignment then (mk_seq_assign_C rhs_old (mk_assign_local_C - (read_N_coerce thy lid - ((listT ty --> listT ty) --> sigma_i --> sigma_i)) - (lifted_term sigma_i new_rhs) ) tempvarn tempvart) - else ((mk_assign_local_C - (read_N_coerce thy lid - ((listT ty --> listT ty) --> sigma_i --> sigma_i)) - (lifted_term sigma_i new_rhs) )))::R - | s => error("(convertStmt) CAssign0 with cat " - ^ @{make_string} s ^ " is unrecognised") + | _ => value + + val get_array_assignment = transform_rhs_list_assignment lhs (get_base_type lhs ty) + + + val assignment =if is_fun_assignment then ( mk_seq_assign_C + rhs + (((mk_assign update_func) + (lifted_term sigma_i (get_array_assignment (Free (tempvarn,tempvart)))))) + tempvarn + tempvart) + else ( + ((mk_assign + update_func) + (lifted_term sigma_i (get_array_assignment rhs)))) + val inferred_assignment = Syntax.check_term (Proof_Context.init_global thy) assignment + in assignment::R end)) |_ => raise WrongFormat("assign")) + + in ((if verbose then (writeln("tag:"^tag);print_node_info a b stack) else ()); + if tag="CBinary0" andalso + case stack of (head::_) => is_call head |_=>false + then error ("Function call only allowed on RHS of assignment. Tag: "^tag) else (); + case tag of + "CAssign0" => handle_assign stack + |"CInitExpr0" => handle_assign stack (*statements*) (*for return, skip and break, we have makers except that they need types and terms that i didn't understand so it's unfinished here*) @@ -459,8 +453,12 @@ if ... then ... else skip*) | "CBlockStmt0" => stack | "CBlockDecl0" => stack | "CNestedFunDef0" => error"Nested Function Declarations not allowed in Clean" - | "CIf0" => (case stack of - (a::b::cond::R) => mk_if_C (lifted_term sigma_i cond) b a :: R + | "CIf0" => (case stack of (*checking based on how many elements are on the stack is wrong. + instead check the type of the condition. It must be a value (i.e. no function)*) + (a::b::c::R) => (case fastype_of b of Type ("fun",_)=> mk_if_C (lifted_term sigma_i c) b a :: R (*b is not the condition*) + | _ => (mk_if_C (lifted_term sigma_i b) (*b is the cond no else*) + (a) + (mk_skip_C sigma_i)::R)) | (a::cond::R) => (mk_if_C (lifted_term sigma_i cond) (a) (mk_skip_C sigma_i)::R) @@ -507,24 +505,29 @@ for(ini, cond, evol){body} is translated as ini; while(cond){body; evol;}*) in ((mk_seq_C init C'))::R end) |_ => raise WrongFormat("for")) end | "CCall0" => (let fun extract_fun_args (t :: R) args = - case t of + (case t of (* very bad way of checking if term represents a function *) Const(id, ty) => if not (firstype_of ty = sigma_i) then (args, Const(id, ty), R) else extract_fun_args R (Const(id, ty) :: args) - | Free(id, ty) => if id = function_name + | Free(id, ty) => if id = function_name (*recursive call*) then (args, Free(id, ty), R) else extract_fun_args R (Free(id, ty) :: args) - | arg => extract_fun_args R (arg :: args) + | arg => extract_fun_args R (arg :: args)) + |extract_fun_args [] _ = error ("\"CCall0\": couldnt find function in stack: "^(@{make_string} stack)) val (args, f, R) = extract_fun_args stack [] - val Type (_, [arg_ty,r_ty]) = fastype_of f - val Type (_,[old_sigma_ty, r_ty]) = r_ty - val Type (_,[Type(_, [ret_ty, old_sigma1_ty])]) = r_ty + val ret_ty = case fastype_of f of Type (_, [_, (*args \<rightarrow>*) + Type (_, [_, (*sigma \<rightarrow>*) + Type (_, [ (*'a option*) + Type(_, [ret_ty, _])])])]) => ret_ty (* (ret_type, sigma)*) + | _ => error ("function type has wrong format: "^(@{make_string} (fastype_of f))) + val new_args_ty = mk_tupleT (List.map fastype_of args) val new_ty = new_args_ty --> sigma_i --> (Type (@{type_name "option"},[Type (@{type_name "prod"}, [ret_ty,sigma_i])])) fun swap_ty (Const (name, _)) n_ty = Const (name, n_ty) |swap_ty (Free (name, _)) n_ty = Free (name, n_ty) + |swap_ty _ _ = error "unexpected term at swap_ty" val f_new = swap_ty f new_ty val fun_args_term = mk_tuple args @@ -535,6 +538,7 @@ end (*** -------------- ***) +end end \<close> diff --git a/C11-BackEnds/Clean_wrapper/src/CleanCoderTypAEnv.thy b/C11-BackEnds/Clean_wrapper/src/CleanCoderTypAEnv.thy index 8c883fb7d66665419ffc666c99c5c22381e47aba..0773f0e28df698a70a4c6b41bdcbaf2cd33f4ace 100644 --- a/C11-BackEnds/Clean_wrapper/src/CleanCoderTypAEnv.thy +++ b/C11-BackEnds/Clean_wrapper/src/CleanCoderTypAEnv.thy @@ -555,9 +555,21 @@ fun parseExternalDeclaration (selectFromNodeContent ["Ident0", "CTypeSpec0", "CArrDeclr0", "CDeclr0", "CCall0"]) statement []) - val (newIdentList, functionCategory, newFunctionCallTable) = + (*we need to sort out the local identifiers of previous functions, as they are no longer accessible*) + fun sortIdentifiers [] = ([],[]) + |sortIdentifiers (ident::R) = let + val (prev_glob, prev_loc) = sortIdentifiers R + in case ident of Identifier (_,_,_,Global)=> (ident::prev_glob, prev_loc) + |Identifier (_,_,_,FunctionCategory _) => (ident::prev_glob, prev_loc) + |_ => (prev_glob, ident::prev_loc) + + end + + val (previous_global_identifiers, previous_local_identifiers) = sortIdentifiers (identList) + val (newIdentList', functionCategory, newFunctionCallTable) = parseLocals statementContentList functionName functionCallTable - (paramIdentifiers @ identList) oldIdents + (paramIdentifiers@previous_global_identifiers) oldIdents + val newIdentList = newIdentList'@previous_local_identifiers in (Identifier(functionName, posL, functionReturnHOLType, FunctionCategory(functionCategory, SOME(statement))) :: newIdentList, newFunctionCallTable) diff --git a/C11-BackEnds/Clean_wrapper/src/CleanTranslationHook.thy b/C11-BackEnds/Clean_wrapper/src/CleanTranslationHook.thy new file mode 100644 index 0000000000000000000000000000000000000000..7dfae361f48c2aea08aac0e80938e3220f603ef3 --- /dev/null +++ b/C11-BackEnds/Clean_wrapper/src/CleanTranslationHook.thy @@ -0,0 +1,192 @@ +theory "CleanTranslationHook" + imports "../src/CleanCoder" (* Coder_Test_Env_AEnv *) + "../src/compiler/Clean_Annotation" +begin +ML\<open> +(*This is an override for the update_Root_Ast function that is registered in C_Command.*) + +fun transform_type typ = if typ = HOLogic.intT then "int" + else if typ = HOLogic.natT then "nat" + else if is_listTy typ then (transform_type (dest_listTy typ))^" list" + else if typ = HOLogic.unitT then "unit" + else error "Unknown variable type" + +local open C_AbsEnv HOLogic in +fun get_hol_type (C_Env.Parsed ret) params = let + val base_type =the (C11_TypeSpec_2_CleanTyp.conv_cDeclarationSpecifier_typ (SOME ret)) + fun transform_type ((C_Ast.CArrDeclr0 _)::R) base_type = listT (transform_type R base_type) + | transform_type [] base_type = base_type + | transform_type ps _ = error ("First type parameter unknown (maybe pointers): "^(@{make_string} ps)) + in transform_type params base_type end + |get_hol_type a _ = error ("Can not get type of \""^(@{make_string} a)^"\"") +fun map_env_ident_to_identifier (name,(positions,_,data)) = + let fun get_ident_scope C_Env.Global = Global + |get_ident_scope C_Env.Local = Local "" + |get_ident_scope C_Env.Parameter = Parameter "" + in + case #functionArgs data of C_Ast.None => Identifier(name, if null positions then @{here} else hd positions,get_hol_type (#ret data) (#params data),get_ident_scope (#scope data)) + |_=> Identifier(name, @{here},intT,FunctionCategory (Final, NONE)) (*this line is wrong because of different function types*) + end +end + +fun declare_function idents name ast ret_ty recursive ctxt = + let val param_idents = filter (fn i => case i of C_AbsEnv.Identifier(_,_,_, C_AbsEnv.Parameter f_name) => f_name = name |_=>false) idents + val local_idents = filter (fn i => case i of C_AbsEnv.Identifier(_,_,_, C_AbsEnv.Local f_name) => f_name = name |_=>false) idents + val global_idents = filter (fn i => case i of C_AbsEnv.Identifier(_,_,_, C_AbsEnv.Global) => true + | C_AbsEnv.Identifier(_,_,_,C_AbsEnv.FunctionCategory _)=>true + | _ => false) idents + + (*Obtain the parameters and local variables*) + val params = map (fn C_AbsEnv.Identifier(name,pos,typ, _) => (Binding.make (name, pos), transform_type typ)) (param_idents) + val locals = map (fn C_AbsEnv.Identifier(name,pos,typ, _) => (Binding.make (name, pos), transform_type typ, NoSyn)) (local_idents) + + (*This is necessary, as parameters are represented as free variables. + When the Invariants, post- and preconditions are read through the term antiquotations, + Syntax.parse_term (Syntax.read_term does this too) would substitute them by another const, + which could be a local or global variable*) + fun remove_params_from_proof ctx = let + val param_names = List.map (fn C_AbsEnv.Identifier(n,_,_,_) => n) param_idents + fun filter_by_shortname param_names (n, _) = + List.exists (fn ele => ele = Long_Name.base_name n) param_names + val longnames = List.filter (filter_by_shortname param_names) (#constants (Consts.dest (Sign.consts_of (Proof_Context.theory_of ctx)))) + val thy0 = Proof_Context.theory_of ctx + val thy' = List.foldl (fn (longname, thy')=> thy' |> Sign.hide_const true longname) thy0 (List.map fst longnames) + in Proof_Context.init_global thy' end + + (*Invariants and measuress need to be matched to a loop. This is done by comparing the parse locations of all while loops. + The following are helper methods, to obtain the function get_invariant::positiona \<rightarrow> (context\<rightarrow>term) option*) + val invariants:((string*(Context.generic -> term)*Position.range) list) = List.filter (fn (f_name,_,_) => f_name = name) + (#invariants (Clean_Annotation.Data_Clean_Annotations.get ctxt)) + val measures:((string*(Context.generic -> term)*Position.range) list) = List.filter (fn (f_name,_,_) => f_name = name) + (#measures (Clean_Annotation.Data_Clean_Annotations.get ctxt)) + val loop_pos =Library.distinct (op =) (C11_Ast_Lib.fold_cStatement (fn a => fn b => a@b) C11_Unit_2_Clean.get_loop_positions ast []) + fun compare_pos ((C_Ast.Position0 (pos1,_,_,_)),(C_Ast.Position0 (pos2,_,_,_))) = Int.compare (pos1,pos2) + |compare_pos a = error ("Unable to compare positions (for invariants and measures): "^(@{make_string} a)) + val loop_pos_sorted = Library.sort compare_pos loop_pos + fun range_less_than_pos (range:Position.range) (C_Ast.Position0 (pos,_,_,_)) = the (Position.offset_of (fst range)) < pos + |range_less_than_pos a b = error ("Unable to compare positions (for invariants and measures): "^(@{make_string} (a,b))) + fun get_for_position (((inv,inv_pos)::R_inv): ((Context.generic -> term)*Position.range)list) + (loop_positions: C_Ast.positiona list) + (pos3: C_Ast.positiona) + (* search the first invariant, which is not declared before pos3 *) + = (if range_less_than_pos inv_pos pos3 then get_for_position R_inv loop_positions pos3 + else case loop_positions of (* we found the first invariant after pos3 *) + (* Now check, if the next loop definition is after the invariant definition. + Otherwise there is no invariant for the given loop *) + (pos1::pos2::R) => if pos3 = pos1 andalso range_less_than_pos inv_pos pos2 then SOME inv + else get_for_position ((inv,inv_pos)::R_inv) (pos2::R) pos3 + | (pos1::_) => if pos3 = pos1 then SOME inv else NONE + | [] => NONE) + |get_for_position [] _ _ = NONE + fun get_invariant pos = (get_for_position (List.map (fn inv => (#2 inv, #3 inv)) invariants) loop_pos_sorted) pos + fun get_measure pos = (get_for_position (List.map (fn inv => (#2 inv, #3 inv)) measures) loop_pos_sorted) pos + fun get_loop_annotations pos = (get_invariant pos, get_measure pos) + + (*generic function to get the first ele*) + val get_precond = Option.map (fn (_,e,_) => e) (List.find (fn (a,_,_) => a = name) (#preconditions (Clean_Annotation.Data_Clean_Annotations.get ctxt))) + val get_postcond = Option.map (fn (_,e,_) => e) (List.find (fn (a,_,_) => a = name) (#postconditions (Clean_Annotation.Data_Clean_Annotations.get ctxt))) + + (*the translation of the precondition*) + fun get_translation NONE default ctxt= C11_Expr_2_Clean.lifted_term (StateMgt.get_state_type (ctxt)) default + | get_translation (SOME get_term) _ ctxt= let + val term = get_term (Context.Proof (remove_params_from_proof ctxt)) + val lifted = C11_Expr_2_Clean.lifted_term (StateMgt.get_state_type ctxt) term + in + Syntax.check_term ctxt lifted + end + (*The actual translation of the loop body*) + fun get_translated_fun_bdy ctx _ = let + val ctx' = remove_params_from_proof ctx + val v = ((C11_Ast_Lib.fold_cStatement + C11_Stmt_2_Clean.regroup + (C11_Stmt_2_Clean.convertStmt false + (StateMgt.get_state_type ctx') + (local_idents@param_idents@global_idents) + (Proof_Context.theory_of ctx') + name get_loop_annotations) + ast [])) + in ( hd) v end + + val test_function_sem = {binding = Binding.name name, + locals = locals@[(Binding.name "dummylocalvariable","int", NoSyn)], (*There needs to be at least one local variable*) + params = params, + ret_type = transform_type ret_ty, + read_pre = get_translation get_precond (@{term True}), + read_post = get_translation get_postcond (Abs ("ret",ret_ty, @{term True})), + read_variant_opt = NONE, + read_body = get_translated_fun_bdy} + val decl = Function_Specification_Parser.checkNsem_function_spec_gen {recursive = recursive} test_function_sem + in decl end + +local open C_AbsEnv HOLogic in +fun handle_declarations translUnit ctxt = + (let + (*get the OLD environment, which simplifies the parseTranslUnitIdentifiers by a lot.*) + val env = (C_Module.Data_Last_Env.get ctxt) + (*First we need to get all previously defined global vars and functions*) + val prev_idents =map map_env_ident_to_identifier (Symtab.dest (#idents(#var_table(env)))) + (*the new identifiers are returned in reverse \<rightarrow> thus reverse *) + val (new_idents, call_table) = C_AbsEnv.parseTranslUnitIdentifiers translUnit [] prev_idents Symtab.empty + val identifiers = (rev new_idents)@prev_idents + val map_idents = List.map (fn C_AbsEnv.Identifier(name,_,typ,_) => (Binding.name name, transform_type typ, NoSyn)) + + fun get_declaration is_global idents = if null idents then I else StateMgt.new_state_record is_global (NONE,idents) + + val global_idents = (map_idents (List.filter (fn C_AbsEnv.Identifier(_,_,_,vis) => vis = C_AbsEnv.Global) new_idents)) + val global_declaration =get_declaration true global_idents + + val fun_asts = + List.map (fn C_AbsEnv.Identifier(name,_,ret_ty,C_AbsEnv.FunctionCategory ast) => + let fun is_recursive NONE = false + |is_recursive (SOME calls) = List.exists (fn x => x=name) calls + in + (name,the (snd ast),ret_ty, is_recursive (Symtab.lookup call_table name)) end + | ident => error ("Expected function identifier. Instead: "^(@{make_string} ident))) + + (List.filter (fn a => case a of C_AbsEnv.Identifier(_,_,_,C_AbsEnv.FunctionCategory _) => true | _ => false) (rev new_idents)) + val function_declarations = List.map (fn (name,ast,ret_ty, recursive) => declare_function identifiers name ast ret_ty recursive ctxt) (fun_asts) + val function_decl = fold (fn f => fn acc => f acc) function_declarations + in + Context.map_theory (function_decl o global_declaration) ctxt + end); +end +\<close> +ML\<open> +fun handle_declarations_wrapper ast v2 ctxt = + let val ctx1 = update_Root_Ast SOME ast v2 ctxt (*Note the call to the original callback - this somehow gets overwritten*) + in + case ast of (C_Ast.Left translUnit) => handle_declarations translUnit ctx1 + | _ => ctx1 + end +\<close> +setup \<open>C_Module.C_Term.map_expression + (fn cexpr => fn _ => fn ctxt => let + val sigma_i = (StateMgt.get_state_type o Context.proof_of )ctxt + val env = C_Module.Data_Surrounding_Env.get ctxt + val idents = (Symtab.dest (#idents(#var_table(env)))) + val A_env = List.map map_env_ident_to_identifier idents + val expr = (hd (C11_Ast_Lib.fold_cExpression (K I) + (C11_Expr_2_Clean.convertExpr false sigma_i A_env (Context.theory_of ctxt) "" (K NONE)) + cexpr [])) handle ERROR msg => (writeln("ERROR: "^(@{make_string}msg));@{term "1::int"}) +in + expr + end)\<close> +setup \<open>Context.theory_map (C_Module.Data_Accept.put (handle_declarations_wrapper))\<close> + +(* Note: The hook "C_Module.C_Term.map_translation_unit" is not adequate, as it is + meant for the term antiquotation (its callback returns a term, not a theory/context *) + +setup \<open>C_Module.C_Term.map_expression + (fn cexpr => fn _ => fn ctxt => let + val sigma_i = (StateMgt.get_state_type o Context.proof_of )ctxt + val env = C_Module.Data_Surrounding_Env.get ctxt + val idents = (Symtab.dest (#idents(#var_table(env)))) + val A_env = List.map map_env_ident_to_identifier idents + val expr = (hd (C11_Ast_Lib.fold_cExpression (K I) + (C11_Expr_2_Clean.convertExpr false sigma_i A_env (Context.theory_of ctxt) "" (K NONE)) + cexpr [])) handle ERROR msg => (writeln("ERROR: "^(@{make_string}msg));@{term "1::int"}) +in + expr + end)\<close> + +end \ No newline at end of file diff --git a/C11-BackEnds/Clean_wrapper/src/compiler/Clean_Annotation.thy b/C11-BackEnds/Clean_wrapper/src/compiler/Clean_Annotation.thy index 84450ef852623ddc54d69d1f44eb6720501dbf0d..12df4f496390b528d0ce1bd54d94ccdf89c90cae 100644 --- a/C11-BackEnds/Clean_wrapper/src/compiler/Clean_Annotation.thy +++ b/C11-BackEnds/Clean_wrapper/src/compiler/Clean_Annotation.thy @@ -79,7 +79,7 @@ structure Data_Clean_Annotations = Generic_Data fun map_context_annotation_declaration annotation_type src range context0 = let - val current_env =snd (C_Stack.Data_Lang.get' context0) + val current_env =snd (C_Stack.Data_Lang.get' context0) (*important: antiquotation needs current env*) fun get_fun_name [(SOME (C_Ast.Ident0 (C_Ast.SS_base (C_Ast.ST name), _, _)),_)] = name | get_fun_name (_::R) = get_fun_name R | get_fun_name _ = (warning "unable to find name of surrounding function for CLEAN annotation";"") diff --git a/C11-FrontEnd/examples/C5.thy b/C11-FrontEnd/examples/C5.thy new file mode 100644 index 0000000000000000000000000000000000000000..1bb1e23de6c80ddebe8de084c9f847edba87c69e --- /dev/null +++ b/C11-FrontEnd/examples/C5.thy @@ -0,0 +1,100 @@ +theory C5 + imports "Isabelle_C.C_Main" +begin + +(*This file contains some ways to retrieve the C-environment*) + +ML\<open> +val SPY_ENV = Unsynchronized.ref(NONE:C_Env.env_lang option);\<close> +declare [[C\<^sub>e\<^sub>n\<^sub>v\<^sub>0 = last]] +declare [[C\<^sub>r\<^sub>u\<^sub>l\<^sub>e\<^sub>0 = "translation_unit"]] + +C\<open> +int globalvar1; +void test(int param1){ + int localvariable1; + + return 12; /*@ \<approx>setup \<open>fn _ => fn _ => fn env => + (*The environment can be retrieved using the generic setup command*) + ((SPY_ENV := SOME env);I) \<close> */; + int localvariable2; +} +int globalvar2; +\<close> + +ML\<open> +(*We can see that the saved env in fact has all the current variables*) +val saved_vars = (map (fn (a,(_,_,b)) => (a,#scope b)) (Symtab.dest ( + #idents(#var_table(the (!SPY_ENV)))) +)) +val final_vars = (map (fn (a,(_,_,b)) => (a,#scope b)) (Symtab.dest ( + #idents(#var_table(@{C\<^sub>e\<^sub>n\<^sub>v}))))) +\<close> + +(*There is a second way to achieve the same, using the context*) +C\<open> +int globalvar3; +void test2(int param1){ + int localvariable3; + + return 12; /*@ \<approx>setup \<open>fn _ => fn _ => fn _ => fn ctx => + (*The environment can be retrieved using the generic setup command*) + ((SPY_ENV := SOME (snd (C_Stack.Data_Lang.get' ctx)));ctx) \<close> */; + int localvariable4; +} +int globalvar4; +\<close> + +ML\<open> +(*We can see that the saved env in fact has all the current variables*) +val saved_vars = (map (fn (a,(_,_,b)) => (a,#scope b)) (Symtab.dest ( + #idents(#var_table(the (!SPY_ENV)))) +)) +\<close> + + +(*Declaring a seperate antiquotation *) + +ML\<open> +val env = @{C\<^sub>e\<^sub>n\<^sub>v}\<close> + +ML\<open> +Theory.setup + (C_Inner_Syntax.command_no_range + (C_Inner_Toplevel.generic_theory oo C_Inner_Isar_Cmd.setup + \<open>fn ((_, (_, pos1, pos2)) :: _) => + (fn _ => fn _ => + tap (fn ctx => + (SPY_ENV := SOME (snd (C_Stack.Data_Lang.get' ctx));Position.reports_text [((Position.range (pos1, pos2) + |> Position.range_position, Markup.intensify), "")]))) + | _ => fn _ => fn _ => I\<close>) + ("store_and_highlight", \<^here>, \<^here>)) +\<close> + +(*this is btw how all previous identifiers can get deleted*) +setup\<open>Context.theory_map (C_Module.Data_In_Env.put C_Env.empty_env_lang)\<close> + +C\<open> +int globalvar3; +void test2(int param1){ + int localvariable3;/*@ store_and_highlight */ +} +\<close> + +ML\<open> +val saved_vars = (map (fn (a,(_,_,b)) => (a,#scope b)) (Symtab.dest ( + #idents(#var_table(the (!SPY_ENV)))) (*NOTE: localvariable3 is in the environment*) +))\<close> + +setup\<open>Context.theory_map (C_Module.Data_In_Env.put C_Env.empty_env_lang)\<close> + +C\<open> +int globalvar3; +void test2(int param1){ + int localvariable3;/*@@@@@ store_and_highlight */ +} +\<close> +ML\<open> +val saved_vars = (map (fn (a,(_,_,b)) => (a,#scope b)) (Symtab.dest ( + #idents(#var_table(the (!SPY_ENV)))) (*NOTE: localvariable3 is NOT in the environment*) +))\<close> \ No newline at end of file diff --git a/C11-FrontEnd/src/C_Ast.thy b/C11-FrontEnd/src/C_Ast.thy index f5d9f2db8022386d9f5345887ba179133760eb39..09c55d92e67f848d915c1a22b6cf39fc94b83b8a 100644 --- a/C11-FrontEnd/src/C_Ast.thy +++ b/C11-FrontEnd/src/C_Ast.thy @@ -875,7 +875,7 @@ and fold_cExpression grp g ast st = |> g (TT"CCast0") a | (CUnary0(unop:cUnaryOp, ex: 'a cExpression, a)) => st |> fold_cExpression grp g ex - |> g (TT("CUnary0 "^toString_cUnaryOp unop)) a + |> g (TTT"CUnary0" (toString_cUnaryOp unop)) a | (CSizeofExpr0(ex:'a cExpression, a)) => st |> fold_cExpression grp g ex |> g (TT"CSizeofExpr0") a | (CSizeofType0(decl:'a cDeclaration,a)) =>