123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-2019 The MOPSA Project. *)(* *)(* This program is free software: you can redistribute it and/or modify *)(* it under the terms of the GNU Lesser General Public License as published *)(* by the Free Software Foundation, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)(**
C_print - Printing, converts C AST to valid C code
*)openC_ASTopenClang_utils(** {2 Config} *)letignore_implicit_casts=true(** Only print explicit casts, not implici ones. *)letprint_loc=reftrue(** Prints location information in comment for global declarations. *)letprint_comments=reftrue(** Prints comments attached to declarations. *)letprint_scope=false(** Prints scope update information (end of blocks & jumps). *)(** {2 Internal printing utilities} *)letbp=Printf.bprintfletbp_str=Buffer.add_stringletbp_char=Buffer.add_charletbp_optionnonefbufa=matchawith|None->bp_strbufnone|Somex->fbufxletbp_arrayfsepbufee=fori=0toArray.lengthee-1dobpbuf"%s%a"(ifi=0then""elsesep)fee.(i)doneletbp_listfsepbufee=letfirst=reftrueinList.iter(fune->bpbuf"%s%a"(if!firstthen""elsesep)fe;first:=false)eeletbp_parendoitfbufa=ifdoitthenbpbuf"(%a)"faelsefbufaletstring_from_bufferfa=letbuf=Buffer.create128infbufa;Buffer.contentsbufletinc_indentindent=indent^" "(* add one level of interation (i.e., some spaces) *)letbp_locindentbufloc=if!print_locthenbpbuf"%s/* %s */\n"indent(Clang_dump.string_of_locloc.Clang_AST.range_begin)(** {2 C pretty-printing} *)letstring_of_signedness=function|SIGNED->"signed"|UNSIGNED->"unsigned"letstring_of_integer_type=function|Char_->"char"|SIGNED_CHAR->"signed char"|UNSIGNED_CHAR->"unsigned char"|SIGNED_SHORT->"short"|UNSIGNED_SHORT->"unsigned short"|SIGNED_INT->"int"|UNSIGNED_INT->"unsigned int"|SIGNED_LONG->"long"|UNSIGNED_LONG->"unsigned long"|SIGNED_LONG_LONG->"long long"|UNSIGNED_LONG_LONG->"unsigned long long"|SIGNED_INT128->"__int128"|UNSIGNED_INT128->"unsigned __uint128"letinteger_suffix=function|CharSIGNED|SIGNED_CHAR|SIGNED_SHORT|SIGNED_INT->""|CharUNSIGNED|UNSIGNED_CHAR|UNSIGNED_SHORT|UNSIGNED_INT->"U"|SIGNED_LONG->"L"|UNSIGNED_LONG->"UL"|SIGNED_LONG_LONG|SIGNED_INT128->"LL"|UNSIGNED_LONG_LONG|UNSIGNED_INT128->"ULL"letstring_of_float_type=function|FLOAT->"float"|DOUBLE->"double"|LONG_DOUBLE->"long double"|FLOAT128->"__float128"letfloat_suffix=function|FLOAT->"F"|DOUBLE->""|LONG_DOUBLE->"L"|FLOAT128->"Q"letstring_of_record_kind=function|STRUCT->"struct"|UNION->"union"letstring_of_qualifierq=ifq.qual_is_constthen"const "else""letstring_of_binary_arithmetic=function|ADD->"+"|SUB->"-"|MUL->"*"|DIV->"/"|MOD->"%"|LEFT_SHIFT->"<<"|RIGHT_SHIFT->">>"|BIT_AND->"&"|BIT_OR->"|"|BIT_XOR->"^"letstring_of_binary_logical=function|LESS->"<"|LESS_EQUAL->"<="|GREATER->">"|GREATER_EQUAL->">="|EQUAL->"=="|NOT_EQUAL->"!="|LOGICAL_AND->"&&"|LOGICAL_OR->"||"letstring_of_binary_operator=function|O_arithmeticop->string_of_binary_arithmeticop|O_logicalop->string_of_binary_logicalopletstring_of_unary_operator=function|NEG->"-"|BIT_NOT->"~"|LOGICAL_NOT->"!"letstring_of_inc_direction=function|INC->"++"|DEC->"--"letrecprio_expr((e,_,_):expr)=matchewith|E_cast(ee,IMPLICIT)whenignore_implicit_casts->prio_expree|E_comma_->0|E_compound_assign_|E_assign_->1|E_conditional_|E_binary_conditional_->2|E_binary(O_logicalLOGICAL_OR,_,_)->3|E_binary(O_logicalLOGICAL_AND,_,_)->4|E_binary(O_arithmeticBIT_OR,_,_)->5|E_binary(O_arithmeticBIT_XOR,_,_)->6|E_binary(O_arithmeticBIT_AND,_,_)->7|E_binary(O_logical(EQUAL|NOT_EQUAL),_,_)->8|E_binary(O_logical(LESS|LESS_EQUAL|GREATER|GREATER_EQUAL),_,_)->9|E_binary(O_arithmetic(LEFT_SHIFT|RIGHT_SHIFT),_,_)->10|E_binary(O_arithmetic(ADD|SUB),_,_)->11|E_binary(O_arithmetic(MUL|DIV|MOD),_,_)->12|E_unary_|E_increment(_,PRE,_)|E_cast_|E_address_of_|E_deref_->13|E_increment(_,POST,_)|E_array_subscript_|E_member_access_|E_arrow_access_|E_call_->14|E_character_literal_|E_integer_literal_|E_float_literal_|E_string_literal_|E_compound_literal_|E_variable_|E_function_|E_predefined_|E_statement_|E_var_args_|E_atomic_|E_convert_vector_|E_vector_element_|E_shuffle_vector_->15(* get the natural priority of an experssion, to avoid spurious parentheses *)letforce_parenprio=prio==10||(prio>=3&&prio<=7)(* force the arguments of <<, >>, etc., to have parentheses, even when useless,
but this avoids compiler warnings *)letis_comma((e,_,_):expr)=matchewith|E_comma_->true|_->false(* comma expressions are special and require extra parentheses in many contexts *)letrecraw_buf_type_qualbuf(t,q)=bpbuf"%s%a"(string_of_qualifierq)raw_buf_typetandraw_buf_typebuf=function|T_void->bp_strbuf"void"|T_bool->bp_strbuf"_Bool"|T_integeri->bp_strbuf(string_of_integer_typei)|T_floatf->bp_strbuf(string_of_float_typef)|T_builtin_fn->bp_strbuf"__builtin_fn"|T_pointertq->bpbuf"ptr(%a)"raw_buf_type_qualtq|T_array(tq,l)->bpbuf"array(%a)"raw_buf_type_qualtq|T_bitfield(t,l)->bpbuf"bitfield%i(%a)"lraw_buf_typet|T_functionNone->bp_strbuf"func()"|T_function(Somef)->bpbuf"func(%a, { %a },%B)"raw_buf_type_qualf.ftype_return(bp_listraw_buf_type_qual", ")f.ftype_paramsf.ftype_variadic|T_typedeft->bpbuf"typedef %s"t.typedef_unique_name|T_enume->bpbuf"enum %s"e.enum_unique_name|T_recordr->bpbuf"%s %s"(string_of_record_kindr.record_kind)r.record_unique_name|T_complexf->bpbuf"%s _Complex"(string_of_float_typef)|T_vectorv->bpbuf"vector(%a, %i, %i)"raw_buf_type_qualv.vector_typev.vector_sizev.vector_kind|T_unknown_builtins->bp_strbufs(* raw (non-C) representation of a type, somewhat more clear than C sytnax *)(* these internal functions print to a buffer and use a current indentation string *)letrecc_buf_type_qualindent(var:string)(buf:Buffer.t)(tq:type_qual)=c_buf_type_basebuftq;ifvar<>""thenbp_strbuf" ";c_buf_type_suffixbufvarindentfalsebp_strtq(* prints the base type without pointers and arrays *)andc_buf_type_basebuf(t,q)=matchtwith|T_void->bpbuf"%svoid"(string_of_qualifierq)|T_bool->bpbuf"%s_Bool"(string_of_qualifierq)|T_integeri->bpbuf"%s%s"(string_of_qualifierq)(string_of_integer_typei)|T_floatf->bpbuf"%s%s"(string_of_qualifierq)(string_of_float_typef)|T_builtin_fn->bpbuf"%s__builtin_fn"(string_of_qualifierq)|T_pointertq->c_buf_type_basebuftq|T_array(tq,l)->c_buf_type_basebuftq|T_bitfield(t,l)->c_buf_type_basebuf(t,q)|T_functionNone->bpbuf"%svoid"(string_of_qualifierq)|T_function(Somef)->c_buf_type_basebuff.ftype_return|T_typedeft->bpbuf"%s%s"(string_of_qualifierq)t.typedef_unique_name|T_enume->bpbuf"%senum %s"(string_of_qualifierq)e.enum_unique_name|T_recordr->bpbuf"%s%s %s"(string_of_qualifierq)(string_of_record_kindr.record_kind)r.record_unique_name|T_complexf->bpbuf"%s%s _Complex"(string_of_qualifierq)(string_of_float_typef)|T_vectorv->bpbuf"%a"c_buf_type_basev.vector_type|T_unknown_builtins->bp_strbufs(* prints the rest of the type; inner prints the innermost part of the type *)andc_buf_type_suffixbufvarindentinptrinner(t,q)=matchtwith|T_void|T_bool|T_integer_|T_float_|T_builtin_fn|T_complex_->innerbufvar|T_pointertq->letinner'bufvar=bpbuf"*%s%a"(string_of_qualifierq)innervarinc_buf_type_suffixbufvarindenttrueinner'tq|T_array(tq,l)->letinner'bufvar=bpbuf"%a[%a]"(bp_pareninptrinner)var(lenindent)linc_buf_type_suffixbufvarindentfalseinner'tq|T_bitfield(t,l)->bpbuf"%a : %i"innervarl|T_functionNone->bpbuf"(%a)()"(bp_pareninptrinner)var|T_function(Somef)->letvariadic=iff.ftype_variadictheniff.ftype_params=[]then"..."else", ..."else""inletinner'bufvar=bpbuf"(%a)(%a%s)"innervar(bp_list(c_buf_type_qualindent"")", ")f.ftype_paramsvariadicinc_buf_type_suffixbufvarindenttrueinner'f.ftype_return|T_typedef_|T_enum_|T_record_->innerbufvar|T_vectorv->bpbuf"__attribute__((__vector_size__(%i)))"v.vector_size|T_unknown_builtin_->innerbufvar(* array length *)andlenindentbuf=function|No_length->()|Length_cstc->Z.bprintbufc|Length_expre->c_buf_exprindentbufeandc_buf_typeindent(var:string)(buf:Buffer.t)(t:typ)=c_buf_type_qualindentvarbuf(t,no_qual)(* helper for unary operations, cast, increment, dereference, etc *)andc_buf_expr_unaryprioindentbufpreepost=bpbuf"%s%a%s"pre(bp_paren(prio_expre<prio)(c_buf_exprindent))epost(* helper for binary operations, assign, array access,etc. *)(* one version for left-associative and another one for right associative *)andc_buf_expr_binary_leftprioindentbufpree1mide2post=bpbuf"%s%a%s%a%s"pre(bp_paren(force_parenprio||prio_expre1<prio)(c_buf_exprindent))e1mid(bp_paren(force_parenprio||prio_expre2<=prio)(c_buf_exprindent))e2postandc_buf_expr_binary_rightprioindentbufpree1mide2post=bpbuf"%s%a%s%a%s"pre(bp_paren(force_parenprio||prio_expre1<=prio)(c_buf_exprindent))e1mid(bp_paren(force_parenprio||prio_expre2<prio)(c_buf_exprindent))e2postandc_buf_exprindentbuf((e,t,_)asee:expr)=letprio=prio_expreeinmatchewith|E_conditional(e1,e2,e3)->bpbuf"%a ? %a : %a"(bp_paren(prio_expre1<=prio)(c_buf_exprindent))e1(bp_paren(prio_expre2<=prio)(c_buf_exprindent))e2(bp_paren(prio_expre3<=prio)(c_buf_exprindent))e3|E_binary_conditional(e1,e2)->bpbuf"%a ? : %a"(bp_paren(prio_expre1<=prio)(c_buf_exprindent))e1(bp_paren(prio_expre2<=prio)(c_buf_exprindent))e2|E_array_subscript(e1,e2)->bpbuf"%a[%a]"(bp_paren(prio_expre1<prio)(c_buf_exprindent))e1(c_buf_exprindent)e2|E_member_access(e1,_,n)->c_buf_expr_unaryprioindentbuf""e1("."^n)|E_arrow_access(e1,_,n)->c_buf_expr_unaryprioindentbuf""e1("->"^n)|E_compound_assign(e1,_,op,e2,_)->c_buf_expr_binary_rightprioindentbuf""e1(" "^(string_of_binary_arithmeticop)^"= ")e2""|E_binary(op,e1,e2)->c_buf_expr_binary_leftprioindentbuf""e1(" "^(string_of_binary_operatorop)^" ")e2""|E_assign(e1,e2)->c_buf_expr_binary_rightprioindentbuf""e1" = "e2""|E_comma(e1,e2)->c_buf_expr_binary_leftprioindentbuf""e1", "e2""|E_unary(op,e1)->c_buf_expr_unaryprioindentbuf((string_of_unary_operatorop)^" ")e1""|E_increment(op,dir,e1)->letinc=string_of_inc_directionopinletpre,post=ifdir=PREtheninc,""else"",incinc_buf_expr_unaryprioindentbufpree1post|E_address_ofe1->c_buf_expr_unaryprioindentbuf"&"e1""|E_derefe1->c_buf_expr_unaryprioindentbuf"*"e1""|E_cast(e1,IMPLICIT)whenignore_implicit_casts->c_buf_exprindentbufe1|E_cast(e1,ex)->bpbuf"(%a)%a"(c_buf_type_qualindent"")t(bp_paren(prio_expre1<prio)(c_buf_exprindent))e1|E_call(e1,el)->bpbuf"%a(%a)"(bp_paren(prio_expre1<prio)(c_buf_exprindent))e1(bp_array(funbufee->bp_paren(is_commaee)(c_buf_exprindent)bufee)", ")el|E_character_literal(c,_)->ifc>=Z.of_int32&&c<Z.of_int127thenbpbuf"'%a'"c_buf_char_literal(Char.chr(Z.to_intc))elseZ.bprintbufc|E_integer_literalc->Z.bprintbufc;bp_strbuf(integer_suffix(as_int_typet))|E_float_literals->bp_strbufs;bp_strbuf(float_suffix(as_float_typet))|E_string_literal(s,_)->bpbuf"\"%a\""c_buf_string_literals|E_compound_literali->bpbuf"(%a){ %a }"(c_buf_type_qualindent"")t(c_buf_initindent)i|E_variablev->bp_strbufv.var_unique_name|E_functionf->bp_strbuff.func_unique_name|E_predefineds->bpbuf"/* predefined */ \"%a\""c_buf_string_literals|E_statementb->bpbuf"({ %a })"(c_buf_statement_listindent)b.blk_stmts|E_var_argse1->bpbuf"__builtin_va_arg(%a,%a)"(bp_paren(is_commae1)(c_buf_exprindent))e1(c_buf_typeindent"")(fstt)|E_atomic(i,e1,e2)->bpbuf"__atomic_%i_TODO(%a,%a)"i(bp_paren(is_commae1)(c_buf_exprindent))e1(bp_paren(is_commae2)(c_buf_exprindent))e2|E_convert_vectore->bpbuf"__builtin_convertvector(%a,%a)"(bp_paren(is_commae)(c_buf_exprindent))e(c_buf_typeindent"")(fstt)|E_vector_element(e,s)->bpbuf"%a.%s"(bp_paren(is_commae)(c_buf_exprindent))es|E_shuffle_vectorea->bpbuf"__builtin_suffle(%a)"(bp_array(funbufee->bp_paren(is_commaee)(c_buf_exprindent)bufee)", ")eaandc_buf_expr_boolindentbufe=bpbuf"%a"(bp_paren(prio_expre==1)(c_buf_exprindent))e(* add parentheses around assignments in boolean context to avoid warnings *)andc_buf_char_literalbufc=leto=Char.codecinifc='\n'thenbp_strbuf"\\n"elseifc='\\'thenbp_strbuf"\\\\"elseifc='"'thenbp_strbuf"\\\""elseifc='\''thenbp_strbuf"\\\'"elseifo=0thenbp_strbuf"\\0"elseifo<32||o>=127thenbpbuf"\\x%02x"oelsebp_charbufcandc_buf_string_literalbufs=String.iter(c_buf_char_literalbuf)sandc_buf_initindentbufi=matchiwith|I_init_expre->c_buf_exprindentbufe|I_init_list(l,o)->bpbuf"{ %a }"(bp_list(c_buf_initindent)", ")l|I_init_implicittq->bp_strbuf"/*implicit*/"andc_buf_statement_listindentbufl=List.iter(c_buf_statementindentbuf)landc_buf_blockindentbufblk=matchblk.blk_stmtswith|[]->bp_strbuf";\n"(* | [s] -> bp buf "\n%a" (c_buf_statement (inc_indent indent)) s*)|l->bpbuf"{\n%a%a%s}\n"(c_buf_statement_list(inc_indentindent))l(c_buf_scope(inc_indentindent))blkindentandc_buf_scopeindentbufblk=letpbufv=bp_strbufv.var_unique_nameinifnotprint_scope||blk.blk_local_vars=[]then()elsebpbuf"%s/* to remove: %a */\n"indent(bp_listp",")blk.blk_local_varsandc_buf_updatebufupd=letpbufv=bp_strbufv.var_unique_nameinifprint_scope&&upd.scope_var_removed<>[]thenbpbuf" /* to remove: %a */"(bp_listp",")upd.scope_var_removed;ifprint_scope&&upd.scope_var_added<>[]thenbpbuf" /* to add: %a */"(bp_listp",")upd.scope_var_addedandc_buf_for_initindentbufb=matchb.blk_stmtswith|[]->()|[S_local_declarationv,_]->c_buf_var_decl_innerindentbufv|[S_expressione,_]->c_buf_exprindentbufe|_->c_buf_exprindentbuf(E_statementb,(T_void,no_qual),empty_range)andc_buf_statementindentbuf((s,r):statement)=letindent2=inc_indentindentinmatchswith|S_local_declarationv->c_buf_var_declindentbufv|S_expressione->bpbuf"%s%a;\n"indent(c_buf_exprindent2)e|S_blockl->bpbuf"%s{\n%a%a%s}\n"indent(c_buf_statement_listindent2)l.blk_stmts(c_buf_scopeindent2)lindent|S_if(e1,b1,{blk_stmts=[]})->bpbuf"%sif (%a) %a"indent(c_buf_expr_boolindent2)e1(c_buf_blockindent)b1|S_if(e1,b1,b2)->bpbuf"%sif (%a) %a%selse %a"indent(c_buf_expr_boolindent2)e1(c_buf_blockindent)b1indent(c_buf_blockindent)b2|S_while(e1,b1)->bpbuf"%swhile (%a) %a"indent(c_buf_expr_boolindent2)e1(c_buf_blockindent)b1|S_do_while(b1,e1)->bpbuf"%sdo %a%swhile (%a);\n"indent(c_buf_blockindent)b1indent(c_buf_expr_boolindent2)e1|S_for(b1,e1,e2,b2)->bpbuf"%sfor (%a; %a; %a) %a"indent(c_buf_for_initindent2)b1(bp_option""(c_buf_expr_boolindent2))e1(bp_option""(c_buf_exprindent2))e2(c_buf_blockindent)b2|S_jump(S_goto(s,u))->bpbuf"%sgoto %s;%a\n"indentsc_buf_updateu|S_jump(S_breaku)->bpbuf"%sbreak;%a\n"indentc_buf_updateu|S_jump(S_continueu)->bpbuf"%scontinue;%a\n"indentc_buf_updateu|S_jump(S_return(e1,u))->bpbuf"%sreturn %a;%a\n"indent(bp_option""(c_buf_exprindent2))e1c_buf_updateu|S_jump(S_switch(e1,b1))->bpbuf"%sswitch (%a) {\n%a%a%s}\n"indent(c_buf_exprindent2)e1(c_buf_statement_listindent)b1.blk_stmts(c_buf_scopeindent)b1indent|S_target(S_labels)->bpbuf"%s%s:;\n"indents|S_target(S_case([e1],u))->bpbuf"%scase %a:;%a\n"indent(c_buf_exprindent2)e1c_buf_updateu|S_target(S_case([],u))->assertfalse|S_target(S_case(e1::tl,u))->bpbuf"%scase %a:;%a\n"indent(c_buf_exprindent2)e1(c_buf_statementindent)(S_target(S_case(tl,u)),r)|S_target(S_defaultu)->bpbuf"%sdefault:;%a\n"indentc_buf_updateu|S_asma->bpbuf"%s__asm__%s%s(\"%a\" : %a %s %a %s %a %s %a);"indent(ifa.asm_is_volatilethen" __volatile__ "else"")(ifArray.lengtha.asm_labels>0then" goto "else"")c_buf_string_literala.asm_body(bp_array(funbufo->bpbuf"\"%a\" (%a)"(* already declared in output_string? *)(* (match o.asm_output_constraint with *)(* | ASM_OUTPUT_INOUT -> "+" *)(* | ASM_OUTPUT_OUT -> "=") *)c_buf_string_literalo.asm_output_string(c_buf_exprindent2)o.asm_output_expr)", ")a.asm_outputs(ifArray.lengtha.asm_inputs=0then""else":")(bp_array(funbufo->bpbuf"\"%a\" (%a)"c_buf_string_literalo.asm_input_string(c_buf_exprindent2)o.asm_input_expr)", ")a.asm_inputs(ifArray.lengtha.asm_clobbers=0then""else":")(bp_array(funbufc->bpbuf"\"%a\""c_buf_string_literalc)", ")a.asm_clobbers(ifArray.lengtha.asm_labels=0then""else":")(bp_array(funbufc->bpbuf"%s"c)", ")a.asm_labelsandc_buf_comindentbufv=if!print_commentsthenList.iter(func->bpbuf"%s%s\n"indentc.Clang_AST.com_text)vandc_buf_var_decl_innerindentbufv=letindent2=inc_indentindentinbpbuf"%s%a"(ifvariable_is_staticv.var_kindthen"static "else"")(c_buf_type_qualindent2v.var_unique_name)v.var_type;(matchv.var_initwith|None->()|Somei->bpbuf" = %a"(c_buf_initindent2)i)andc_buf_var_declindentbufv=ifvariable_is_globalv.var_kindthenbp_locindentbufv.var_range;c_buf_comindentbufv.var_com;bpbuf"%s%a;\n"indent(c_buf_var_decl_innerindent)vandc_buf_var_advance_declindentbufv=ifvariable_is_globalv.var_kindthenbp_locindentbufv.var_range;c_buf_comindentbufv.var_com;bpbuf"%s%s%a;\n"indent(ifv.var_kind=Variable_externthen"extern "else"")(c_buf_var_decl_innerindent){vwithvar_init=None;}andc_buf_func_declindentbuff=letindent2=inc_indentindentinbp_locindentbuff.func_range;c_buf_comindentbuf(List.mapfstf.func_com);letvariadic=iff.func_variadictheniff.func_parameters=[||]then"..."else", ..."else""andparambufv=c_buf_type_qualindentv.var_unique_namebufv.var_typeinletinnerbufvar=bpbuf"%a(%a%s)"bp_strvar(bp_arrayparam", ")f.func_parametersvariadiciniff.func_is_staticthenbp_strbuf"static ";c_buf_type_basebuff.func_return;bp_strbuf" ";c_buf_type_suffixbuff.func_unique_nameindentfalseinnerf.func_return;(matchf.func_bodywith|None->bp_strbuf";\n"|Somel->bpbuf"\n%s{\n%a%a%s}\n"indent(c_buf_statement_listindent2)l.blk_stmts(c_buf_scopeindent2)lindent)andc_buf_func_protoindentbuff=c_buf_func_declindentbuf{fwithfunc_body=None;}letc_buf_enum_declindentbufe=letindent2=inc_indentindentinletfbufv=c_buf_comindentbufv.enum_val_com;bpbuf"%s%s = %a,\n"indent2v.enum_val_unique_nameZ.bprintv.enum_val_valueinbp_locindentbufe.enum_range;c_buf_comindentbufe.enum_com;ife.enum_definedthenbpbuf"%senum %s { /* type: %s */\n%a%s};\n"indente.enum_unique_name(matche.enum_integer_typewith|None->"None"|Somes->string_of_integer_types)(bp_listf"")e.enum_valuesindentelsebpbuf"%senum %s;\n"indente.enum_unique_nameletc_buf_record_declindentbufr=letindent2=inc_indentindentinletfbufv=c_buf_comindentbufv.field_com;bpbuf"%s%a;\n"indent2(c_buf_type_qualindent2v.field_name)v.field_typeinbp_locindentbufr.record_range;c_buf_comindentbufr.record_com;ifr.record_definedthenbpbuf"%s%s %s { /* sizeof: %a, alignof: %a */\n%a%s};\n"indent(string_of_record_kindr.record_kind)r.record_unique_nameZ.bprintr.record_sizeofZ.bprintr.record_alignof(bp_arrayf"")r.record_fieldsindentelsebpbuf"%s%s %s;\n"indent(string_of_record_kindr.record_kind)r.record_unique_nameletc_buf_typedefindentbuft=letindent2=inc_indentindentinbp_locindentbuft.typedef_range;c_buf_comindentbuft.typedef_com;bpbuf"%stypedef %a;\n"indent(c_buf_type_qualindent2t.typedef_unique_name)t.typedef_defletstring_of_var_decl=string_from_buffer(c_buf_var_decl"")letstring_of_var_advance_decl=string_from_buffer(c_buf_var_advance_decl"")letstring_of_func_decl=string_from_buffer(c_buf_func_decl"")letstring_of_func_proto=string_from_buffer(c_buf_func_proto"")letstring_of_expr=string_from_buffer(c_buf_expr"")letstring_of_type=string_from_buffer(c_buf_type"""")letstring_of_type_qual=string_from_buffer(c_buf_type_qual"""")letstring_of_string_literal=string_from_bufferc_buf_string_literalletstring_of_enum_decl=string_from_buffer(c_buf_enum_decl"")letstring_of_record_decl=string_from_buffer(c_buf_record_decl"")letstring_of_typedef=string_from_buffer(c_buf_typedef"")letstring_of_statement=string_from_buffer(c_buf_statement"")(** {2 Full source printing} *)letbuiltin_typedef=["__NSConstantString";"__builtin_va_list";"__uint128_t";"__u128"](* some built-in typedef we should not print *)letbuiltin_funcs=["__builtin_va_start";"__builtin_va_end";"__builtin_va_copy";"__sigsetjmp";"_gl_verify_function2";"_gl_verify_function3";"_gl_verify_function4";"_gl_verify_function5";"_gl_verify_function6";"_gl_verify_function7";"_gl_verify_function8";"_gl_verify_function9";"_gl_verify_function10";"_gl_verify_function11";"_gl_verify_function12";"_gl_verify_function13";"_gl_verify_function14";"__builtin_mul_overflow";"__atomic_is_lock_free";](* some built-in functions, the declaration of which we should omit when printing *)letprint_types_ordered(ch:out_channel)(td_omit:stringlist)(td:typedefStringMap.t)(re_omit:stringlist)(re:record_typeStringMap.t)=letblack,gray=Hashtbl.create16,Hashtbl.create16inletrectypedeft=letrecexploret=matchtwith|T_typedeft->typedeft|T_void|T_bool|T_integer_|T_float_|T_complex_->()|T_pointer(t,_)->exploret|T_array((t,_),_)->(* array elements must have a complete type even in typedefs *)exploret;letrecdef=function|T_typedeftt->def(fsttt.typedef_def)|T_recordr->recordtruer|T_array((tt,_),_)->deftt|_->()indeft|T_bitfield(t,_)->exploret|T_functionNone->()|T_function(Somef)->explore(fstf.ftype_return);List.iter(fun(t,_)->exploret)f.ftype_params|T_builtin_fn->()|T_recordr->()|T_enum_->()|T_vectorv->explore(fstv.vector_type)|T_unknown_builtin_->()inifnot(Hashtbl.memblackt.typedef_uid)then(ifHashtbl.memgrayt.typedef_uidtheninvalid_arg"cyclic type dependencies";Hashtbl.addgrayt.typedef_uid();ifnot(List.memt.typedef_org_nametd_omit)then(explore(fstt.typedef_def);output_stringch(string_of_typedeft););Hashtbl.addblackt.typedef_uid())andrecordmustdefr=letrecexploremustdeft=matchtwith|T_typedeft->exploremustdef(fstt.typedef_def)|T_void|T_bool|T_integer_|T_float_|T_complex_->()|T_pointer(t,_)->explorefalset|T_array((t,_),_)->exploremustdeft|T_bitfield(t,_)->exploremustdeft|T_functionNone->()|T_function(Somef)->exploretrue(fstf.ftype_return);List.iter(fun(t,_)->exploretruet)f.ftype_params|T_builtin_fn->()|T_recordr->ifmustdefthenrecordtruer|T_enum_->()|T_vectorv->exploremustdef(fstv.vector_type)|T_unknown_builtin_->()inifnot(Hashtbl.memblackr.record_uid)then(ifHashtbl.memgrayr.record_uidtheninvalid_arg"cyclic type dependencies";Hashtbl.addgrayr.record_uid();ifnot(List.memr.record_org_namere_omit)then(Array.iter(funf->exploremustdef(fstf.field_type))r.record_fields;output_stringch(string_of_record_declr));Hashtbl.addblackr.record_uid();)inStringMap.iter(fun_->typedef)td;StringMap.iter(fun_->recordtrue)re(* internal function to print records and typedefs in correct order of dependency *)letprint_project?(verbose=true)(ch:out_channel)(p:project)=letold_pl,old_pc=!print_loc,!print_commentsinifnotverbosethen(print_loc:=false;print_comments:=false;);letprf_x=output_stringch(fx)inletpf=Printf.fprintfin(* types *)output_stringch"\n/* enum definitions */\n\n";StringMap.iter(prstring_of_enum_decl)p.proj_enums;output_stringch"\n/* struct and union declarations */\n\n";StringMap.iter(fun_r->pfch"%s %s;\n"(string_of_record_kindr.record_kind)r.record_unique_name)p.proj_records;output_stringch"\n/* struct, union and typedefs */\n\n";print_types_orderedchbuiltin_typedefp.proj_typedefs[]p.proj_records;(* variable declarations and prototype *)letvars=StringMap.filter(fun_v->variable_is_globalv.var_kind)p.proj_varsinoutput_stringch"\n/* global variable declarations */\n\n";StringMap.iter(prstring_of_var_advance_decl)vars;output_stringch"\n/* function declarations */\n\n";letfuncs=StringMap.filter(fun_f->not(List.memf.func_org_namebuiltin_funcs))p.proj_funcsinStringMap.iter(prstring_of_func_proto)funcs;(* variable with initializer and functions with bodies *)output_stringch"\n/* global variable definitions */\n\n";letvars=StringMap.filter(fun_v->v.var_init<>None)varsinStringMap.iter(prstring_of_var_decl)vars;output_stringch"\n/* functions definitions */\n\n";letfuncs=StringMap.filter(fun_v->v.func_body<>None)funcsinStringMap.iter(prstring_of_func_decl)funcs;ifnotverbosethen(print_loc:=old_pl;print_comments:=old_pc;)