#ifndef AST_TO_C_C #define AST_TO_C_C AST_TO_C_C #include #include void ast_to_c(char *output_name,struct AST_Translation_Unit *tree,struct Options *options) { size_t output_name_length; char *hold_name; FILE *hold_out; if(output_name!=NULL) { output_name_length=strnlen(output_name,1000); hold_name=calloc(output_name_length+100,1); memcpy(hold_name,output_name,output_name_length); memcpy(hold_name+output_name_length,".h",sizeof(".h")); hold_out=fopen(hold_name,"w"); ast_translation_unit_to_c_print_header_part(hold_out,output_name,(struct AST_Translation_Unit*)tree,options); fclose(hold_out); memcpy(hold_name+output_name_length,".c",sizeof(".c")); hold_out=fopen(hold_name,"w"); ast_translation_unit_to_c_print_body_part(hold_out,output_name,(struct AST_Translation_Unit*)tree,options); fclose(hold_out); memcpy(hold_name+output_name_length,"_external.h",sizeof("_external.h")); hold_out=fopen(hold_name,"w"); ast_translation_unit_to_c_print_external_part(hold_out,output_name,(struct AST_Translation_Unit*)tree,options); fclose(hold_out); free(hold_name); }else { ast_translation_unit_to_c_print_external_part(stdout,NULL,(struct AST_Translation_Unit*)tree,options); ast_translation_unit_to_c_print_header_part(stdout,NULL,(struct AST_Translation_Unit*)tree,options); ast_translation_unit_to_c_print_body_part(stdout,NULL,(struct AST_Translation_Unit*)tree,options); } } void ast_translation_unit_to_c_print_base_name(FILE *out, char *base_name) { size_t i; for(i=0;i<1000 && base_name[i]!='\0';++i) fprintf(out,"%c",toupper(base_name[i])); } void ast_translation_unit_to_c_print_header_string(FILE *out,char *base_name,char *file_suffix) { fprintf(out,"#ifndef "); ast_translation_unit_to_c_print_base_name(out,base_name); fprintf(out,"%s\n#define ",file_suffix); ast_translation_unit_to_c_print_base_name(out,base_name); fprintf(out,"%s ",file_suffix); ast_translation_unit_to_c_print_base_name(out,base_name); fprintf(out,"%s\n",file_suffix); } void ast_translation_unit_to_c_print_footer_string(FILE *out,char *base_name,char *file_suffix) { fprintf(out,"\n#endif //#ifndef "); ast_translation_unit_to_c_print_base_name(out,base_name); fprintf(out,"%s",file_suffix); } void ast_translation_unit_to_c_print_header_part(FILE *out,char *base_name,struct AST_Translation_Unit *translation_unit,struct Options *options) { size_t i; if(base_name) { ast_translation_unit_to_c_print_header_string(out,base_name,"_H"); fprintf(out,"#include\n\n"); } ast_to_c_print_internal_stuff_for_header(out,translation_unit,options); for(i=0;inumber_of_machines;++i) ast_machine_to_c_make_header_part(out,translation_unit->machines[i],options); if(base_name) ast_translation_unit_to_c_print_footer_string(out,base_name,"_H"); } void ast_translation_unit_to_c_print_body_part(FILE *out,char *base_name,struct AST_Translation_Unit *translation_unit,struct Options *options) { size_t i; if(base_name) { ast_translation_unit_to_c_print_header_string(out,base_name,"_C"); fprintf(out,"#include \"%s.h\"\n",base_name); fprintf(out,"#include \"%s_external.h\"\n\n",base_name); } ast_to_c_print_internal_stuff_for_body(out,translation_unit,options); for(i=0;inumber_of_machines;++i) ast_machine_to_c_make_body_part(out,translation_unit->machines[i],options); if(base_name) ast_translation_unit_to_c_print_footer_string(out,base_name,"_C"); } void ast_translation_unit_to_c_print_external_part(FILE *out,char *base_name,struct AST_Translation_Unit *translation_unit,struct Options *options) { if(base_name) { ast_translation_unit_to_c_print_header_string(out,base_name,"_EXTERNAL_H"); fprintf(out,"#include \"%s.h\"\n\n",base_name); } if(options->providing_own_queue_implementation) { if(options->has_context) { fprintf(out, "extern void machine_push_to_event_queue(machine_conotext_t *context, machine_buffer_t *input,int event,enum MACHINES_ENUM target_machine);\n"); fprintf(out, "extern void machine_pop_from__event_queue(machine_context_t *context);\n"); }else { fprintf(out, "extern void machine_push_to_global_event_queue(machine_buffer_t *input,int event,enum MACHINES_ENUM target_machine);\n"); fprintf(out, "extern void machine_pop_from_global_event_queue();\n"); fprintf(out, "extern struct machine_queue_t machine_queue_global;\n"); } } if(options->providing_own_buffer_implementation) { fprintf(out, "//extern machine_buffer_t* get_machine_buffer(void *content,size_t size);\n"); fprintf(out, "\nextern void delete_machine_buffer(machine_buffer_t *buffer);\n"); } if(options->has_mutex) { fprintf(out, "extern void machine_mutex_lock(machine_buffer_t *input,int event, enum MACHINES_ENUM target_machine); \n"); fprintf(out, "extern void machine_mutex_unlock(int event, enum MACHINES_ENUM target_machine); \n"); } Map_Map_Extended(translation_unit->used_commands_map,(void (*)(void*,void*))ast_command_to_c_extern_declaration,out); if(base_name) { ast_translation_unit_to_c_print_footer_string(out,base_name,"_EXTERNAL_H"); } } void ast_machine_to_c(FILE *out,struct AST_Machine *machine,struct Options *options) { assert(out!=NULL && machine!=NULL && machine->type==AST_TYPE_MACHINE); ast_machine_to_c_make_header_part(out,machine,options); ast_machine_to_c_make_body_part(out,machine,options); } void ast_machine_to_c_make_body_part(FILE *out,struct AST_Machine *machine,struct Options *options) { size_t i; struct State_And_Transitions **table; table=extract_transition_table(machine->states,machine->transitions); for(i=0;istates->number_of_states;++i) { ast_state_to_c_signature(out,machine,machine->states->states[i],options); fprintf(out,"\n{\n"); ast_transitions_of_state_to_c(out,machine,table[i],options); fprintf(out,"\n}\n"); } } void ast_machine_to_c_make_header_part(FILE *out,struct AST_Machine *machine,struct Options *options) { ast_events_to_c(out,machine,options); ast_states_to_c(out,machine,options); } void ast_events_to_c(FILE *out,struct AST_Machine *machine,struct Options *options) { size_t i; assert(out!=NULL && machine!=NULL && machine->type==AST_TYPE_MACHINE); fprintf(out,"enum "); ast_machine_enum_tag(out,machine); fprintf(out,"\n{\n"); for(i=0;ievents->number_of_events;++i) { fprintf(out,"\t"); ast_event_to_c_enum(out,machine,machine->events->events[i]); fprintf(out,",\n"); } fprintf(out,"};\n"); } void ast_states_to_c(FILE *out,struct AST_Machine *machine,struct Options *options) { size_t i; assert(out!=NULL && machine!=NULL && machine->type==AST_TYPE_MACHINE); for(i=0;istates->number_of_states;++i) { fprintf(out,"extern "); ast_state_to_c_signature(out,machine,machine->states->states[i],options); fprintf(out,";\n"); } } void ast_transitions_of_state_to_c(FILE *out,struct AST_Machine *machine,struct State_And_Transitions *vector,struct Options *options) { size_t i; short indentation=3; const char *context_arrow=""; if(options->has_context) context_arrow="context->"; //fprintf(out,"\tmachine_buffer_t *hold_buffer;\n\thold_buffer=input;\n\n"); if(vector->number_of_transitions>0) { fprintf(out,"\n\t%smachine_states_lock=1;\n\n",context_arrow); ast_statement_to_c(out,1,vector->state->on_exit_statement,options); fprintf(out,"\n"); fprintf(out,"\tswitch(event)\n\t{\n"); for(i=0;inumber_of_transitions;++i) { fprintf(out,"\t\tcase "); ast_event_to_c_enum(out,machine,vector->transitions[i]->event); fprintf(out,":\n"); if(vector->transitions[i]->granted) { fprintf(out,"\t\t\tif("); ast_expression_to_c(out,vector->transitions[i]->granted,options); fprintf(out,")\n\t\t\t{\n"); indentation++; } //ast_pipeline_to_c(out,3,vector->transitions[i]->pipeline); ast_statement_to_c(out,indentation,vector->transitions[i]->statement,options); ast_statement_to_c(out,indentation,vector->transitions[i]->to->on_entry_statement,options); ast_to_c_print_tabs(out,indentation); fprintf(out,"%smachine_states[",context_arrow); ast_token_to_c(out,machine->id); fprintf(out,"]="); ast_state_to_c_function_name(out,machine,vector->transitions[i]->to); fprintf(out,";\n"); ast_to_c_print_tabs(out,indentation); fprintf(out,"break;\n"); if(vector->transitions[i]->granted) { fprintf(out,"\t\t\t}\n"); } } fprintf(out,"\t}\n"); } fprintf(out,"\tdelete_machine_buffer(input);\n"); fprintf(out,"\n\t%smachine_states_lock=0;\n",context_arrow); } /*prints the enum tag for the given machine*/ void ast_machine_enum_tag(FILE *out,struct AST_Machine *machine) { fprintf(out,"MACHINE_"); ast_token_to_c(out,machine->id); fprintf(out,"_EVENTS_ENUM"); } void ast_state_to_c_signature(FILE *out,struct AST_Machine *machine,struct AST_State *state,struct Options *options) { fprintf(out,"void "); ast_state_to_c_function_name(out,machine,state); fprintf(out,"(%sint event,machine_buffer_t *input)",(options->has_context?"machine_context_t *context,":"")); } void ast_token_to_c(FILE *out,struct token *token) { size_t i; assert(out!=NULL && token!=NULL); for(i=0;isize;++i) fprintf(out,"%c",token->data[i]); } void ast_pipeline_to_c(FILE *out,size_t indentation,struct AST_Pipeline *pipeline) { size_t i; if(pipeline==NULL) return; for(i=0;isize;++i) { ast_to_c_print_tabs(out,indentation); fprintf(out,"input="); ast_command_to_c(out,pipeline->pipeline[i],"input"); fprintf(out,";\n"); } //ast_to_c_print_tabs(out,indentation); } void ast_command_to_c(FILE *out,struct AST_Command *command,char *hold_buffer) { ast_token_to_c(out,command->function_name); fprintf(out,"("); if(command->argument==NULL) fprintf(out,"NULL"); else { fprintf(out,"get_machine_buffer(\""); ast_token_to_c(out,command->argument); fprintf(out,"\",sizeof(\""); ast_token_to_c(out,command->argument); fprintf(out,"\"))"); } fprintf(out,",%s)",hold_buffer); } void ast_command_to_c_extern_declaration(struct AST_Command *command,FILE *out) { fprintf(out,"extern machine_buffer_t* "); ast_token_to_c(out,command->function_name); fprintf(out,"(machine_buffer_t *arguments,machine_buffer_t *input);\n"); } void ast_to_c_print_tabs(FILE *out,size_t number_of_tabs) { size_t i; for(i=0;inumber_of_machines,(options->has_context?"machine_context_t *context,":"")); if(options->has_context==0) { fprintf(out,"={ "); for(i=0;inumber_of_machines;++i) { ast_state_to_c_function_name(out,translation_unit->machines[i],translation_unit->machines[i]->starting_state); fprintf(out,","); } fprintf(out,"}"); } fprintf(out,";\n"); ast_to_c_print_tabs(out,indent); fprintf(out,"_Bool machine_states_lock"); if(options->has_context==0) fprintf(out,"=0"); fprintf(out,";\n"); } void ast_machines_to_c_enum(FILE *out,struct AST_Translation_Unit *translation_unit) { size_t i; fprintf(out,"enum MACHINES_ENUM\n{\n"); for(i=0;inumber_of_machines;++i) { fprintf(out,"\t"); ast_token_to_c(out,translation_unit->machines[i]->id); fprintf(out,",\n"); } fprintf(out,"\tMACHINES_ENUM_END\n};\n"); } void ast_state_to_c_function_name(FILE *out,struct AST_Machine *machine,struct AST_State *state) { fprintf(out,"machine_"); ast_token_to_c(out,machine->id); fprintf(out,"_state_"); ast_token_to_c(out,state->name); } void ast_event_to_c_enum(FILE *out,struct AST_Machine *machine,struct AST_Event *event) { ast_token_to_c(out,machine->id); fprintf(out,"_EVENT_"); ast_token_to_c(out,event->name); } void ast_to_c_print_internal_stuff_for_header(FILE *out,struct AST_Translation_Unit *translation_unit,struct Options *options) { fprintf(out,"\n\n"); ast_machines_to_c_enum(out,translation_unit); fprintf(out,"\n\n"); if(options->providing_own_buffer_implementation) { fprintf(out,"typedef struct machine_buffer_t machine_buffer_t;\n"); }else { ast_print_machine_buffer_declarations(out); } if(!options->providing_own_queue_implementation) ast_to_c_print_event_struct_queue_declaration(out,options); /*the context struct should go here*/ if(options->has_context) { fprintf(out,"typedef struct machine_context_s machine_context_t;\n"); fprintf(out, "struct machine_context_s\n{\n"); ast_machines_to_c_array(out,translation_unit,options,1); fprintf(out,"\tstruct machine_queue_t machine_queue;\n"); fprintf(out, "};\n\n"); fprintf(out, "void machine_context_init(machine_context_t *context);\n"); fprintf(out, "void machine_context_destroy(machine_context_t *context);\n"); } ast_to_c_print_event_functions_queue_declaration(out,options); ast_to_c_print_comment(out, "\tuse this function to pass an event to a machine\n" "\tthe input buffer is passed to the first executed function if any\n" "\tany remaining buffer after the pipeline has finished is passed\n" "\tto the delete_machine_buffer function\n" "\tinput can be NULL" ); if(options->has_context) fprintf(out,"extern void push_event_to_machine(machine_context_t *context,enum MACHINES_ENUM machine,int event,machine_buffer_t *input);\n\n"); else fprintf(out,"extern void push_event_to_machine(enum MACHINES_ENUM machine,int event,machine_buffer_t *input);\n\n"); } void ast_to_c_print_internal_stuff_for_body(FILE *out,struct AST_Translation_Unit *translation_unit,struct Options *options) { const char *context_arrow=""; const char *context_comma=""; const char *context=""; const char *global="_global"; if(options->has_context==0) { ast_machines_to_c_array(out,translation_unit,options,0); fprintf(out,"struct machine_queue_t machine_queue_global = { .first=NULL,.last=NULL,.size=0};\n"); }else { size_t which_machine; context_comma="context,"; context="context"; context_arrow="context->"; global=""; fprintf(out, "void machine_context_init(machine_context_t *context)\n{\n\tcontext->machine_queue=(struct machine_queue_t){ .first=NULL,.last=NULL,.size=0};\n"); fprintf(out, "\tcontext->machine_states_lock=0;\n"); for(which_machine=0;which_machinenumber_of_machines;++which_machine) { fprintf(out,"\tcontext->machine_states[%zu]=",which_machine); ast_state_to_c_function_name(out,translation_unit->machines[which_machine],translation_unit->machines[which_machine]->starting_state); fprintf(out,";\n"); } fprintf(out,"\n}\n"); fprintf(out, "void machine_context_destroy(machine_context_t *context)\n{\n\t" "\tstruct machine_queue_node_t *hold_node;\n" "\thold_node=context->machine_queue.first;\n" "\twhile(hold_node!=NULL)\n" "\t{\n" "\t\tcontext->machine_queue.first=context->machine_queue.first->prev;\n" "\t\tfree(hold_node);\n" "\t\thold_node=context->machine_queue.first;\n" "\t}\n" "\n}\n" ); } if(!options->providing_own_queue_implementation) ast_to_c_print_event_queue_definition(out,options); if(!options->providing_own_buffer_implementation) ast_print_machine_buffer_definitions(out); if(options->has_context) fprintf(out,"void push_event_to_machine(machine_context_t *context,enum MACHINES_ENUM machine,int event,machine_buffer_t *input)\n"); else fprintf(out,"void push_event_to_machine(enum MACHINES_ENUM machine,int event,machine_buffer_t *input)\n"); fprintf(out, "{\n" "\tif(machinehas_mutex) fprintf(out,"\t\tmachine_mutex_lock(input,event,machine);\n"); fprintf(out, "\n\t\tif(%smachine_states_lock)" "\n\t\t{" "\n\t\t\tmachine_push_to%s_event_queue(%sinput,event,machine);" "\n\t\t}else" "\n\t\t{" "\n\t\t\t%smachine_states[machine](%sevent,input);" "\n\t\t\twhile(%smachine_queue%s.size>0)machine_pop_from%s_event_queue(%s);" "\n\t\t}" "\n\t}" ,context_arrow,global,context_comma,context_arrow,(options->has_context?"context,":""),context_arrow,global,global,context ); if(options->has_mutex) fprintf(out,"\t\tmachine_mutex_unlock(event,machine);\n"); fprintf(out, "\n}\n" ); } void ast_to_c_print_comment(FILE *out,char *comment) { fprintf(out,"/*\n"); fprintf(out,"%s\n",comment); fprintf(out,"*/\n"); } void ast_statement_to_c(FILE *out,size_t indentation,struct AST *statement,struct Options *options) { if(statement==NULL)return; if(statement->type==AST_TYPE_PIPELINE) ast_pipeline_to_c(out,indentation,(struct AST_Pipeline*)statement); else if(statement->type==AST_TYPE_IF) ast_if_to_c(out,indentation,(struct AST_If_Statement*)statement,options); else assert(0); } void ast_if_to_c(FILE *out,size_t indentation,struct AST_If_Statement *statement,struct Options *options) { ast_to_c_print_tabs(out,indentation); fprintf(out,"if"); ast_expression_to_c(out,statement->condition,options); fprintf(out,"\n"); ast_to_c_print_tabs(out,indentation); fprintf(out,"{\n"); ast_statement_to_c(out,indentation+1,statement->body,options); ast_to_c_print_tabs(out,indentation); fprintf(out,"}"); if(statement->else_statement) { fprintf(out,"else{\n"); ast_statement_to_c(out,indentation+1,statement->else_statement,options); ast_to_c_print_tabs(out,indentation); fprintf(out,"}"); } fprintf(out,"\n"); } void ast_expression_to_c(FILE *out,struct AST *expression,struct Options *options) { fprintf(out,"("); switch(expression->type) { case AST_TYPE_OP_OR: ast_expression_to_c(out,AS_BIN_EXPR_PTR(expression)->left,options); fprintf(out,"||"); ast_expression_to_c(out,AS_BIN_EXPR_PTR(expression)->right,options); break; case AST_TYPE_OP_NOT: fprintf(out,"!"); ast_expression_to_c(out,AS_UN_EXPR_PTR(expression)->operand,options); break; case AST_TYPE_OP_AND: ast_expression_to_c(out,AS_BIN_EXPR_PTR(expression)->left,options); fprintf(out,"&&"); ast_expression_to_c(out,AS_BIN_EXPR_PTR(expression)->right,options); break; case AST_TYPE_STATE: ast_expression_state_to_c(out,(struct AST_State*)expression,options); break; case AST_TYPE_OP_SELECTOR: assert(!"selector in final product!\n"); default: assert(0); } fprintf(out,")"); } void ast_expression_state_to_c(FILE *out,struct AST_State *state,struct Options *options) { fprintf(out,"%smachine_states[",(options->has_context?"context->":"")); ast_token_to_c(out,state->parent->id); fprintf(out,"]=="); ast_state_to_c_function_name(out,state->parent,state); } void ast_to_c_print_event_struct_queue_declaration(FILE *out,struct Options *options) { const char *queue="global_event_queue"; ast_to_c_print_comment(out, "\tthis queue is used when an event is received for a machine that is\n" "\tcurrently in transit\n" "\tdoes not guarantee any thread safety,\n" "\tbut preserves intuitive order of execution\n" "\tdo not use these manually" ); fprintf(out, "struct machine_queue_node_t\n" "{\n" "\tstruct machine_queue_node_t *prev;\n" "\tmachine_buffer_t *input;\n" "\tint event;\n" "\tenum MACHINES_ENUM target_machine;\n" "};\n" ); fprintf(out, "struct machine_queue_t\n" "{\n" "\tstruct machine_queue_node_t *first,*last;\n" "\tsize_t size;\n" "};\n" ); } void ast_to_c_print_event_functions_queue_declaration(FILE *out,struct Options *options) { const char *queue="global_event_queue"; if(options->has_context) queue="event_queue"; fprintf(out, "extern void machine_push_to_%s(",queue); if(options->has_context) fprintf(out,"machine_context_t *context,"); fprintf(out,"machine_buffer_t *input,int event,enum MACHINES_ENUM target_machine);\n"); fprintf(out,"extern void machine_pop_from_%s(",queue); if(options->has_context) fprintf(out,"machine_context_t *context"); fprintf(out,");\n"); } void ast_to_c_print_event_queue_definition(FILE *out,struct Options *options) { const char *queue="machine_queue_global"; const char *machines_stuff=""; fprintf(out, "void machine_push_to_"); if(options->has_context) { fprintf(out,"event_queue(machine_context_t *context,"); queue="context->machine_queue"; machines_stuff="context->"; }else { fprintf(out,"global_event_queue("); } fprintf(out, "machine_buffer_t *input,int event,enum MACHINES_ENUM target_machine)\n" "{\n" "\tif(%s.size==0)\n" "\t{\n" "\t\t%s.first=%s.last=malloc(sizeof(struct machine_queue_node_t));\n" "\t\t%s.last->input=input;\n" "\t\t%s.last->event=event;\n" "\t\t%s.last->target_machine=target_machine;\n" "\t\t%s.size=1;\n" "\t}else\n" "\t{\n" "\t\t%s.last=%s.last->prev=malloc(sizeof(struct machine_queue_node_t));\n" "\t\t%s.last->input=input;\n" "\t\t%s.last->event=event;\n" "\t\t%s.last->target_machine=target_machine;\n" "\t\t++%s.size;\n" "\t}\n" "}\n",queue,queue,queue,queue,queue,queue,queue,queue,queue,queue,queue,queue,queue,queue,queue ); fprintf(out, "void machine_pop_from"); if(options->has_context) { fprintf(out,"_event_queue(machine_context_t *context)\n"); }else { fprintf(out,"_global_event_queue()\n"); } fprintf(out, "{\n" "\tstruct machine_queue_node_t *hold_node;\n" "\thold_node=%s.first;\n" "\t%s.first=%s.first->prev;\n" "\tif(--%s.size==0)\n" "\t\t%s.last=NULL;\n" "\t%smachine_states[hold_node->target_machine](%shold_node->event,hold_node->input);\n" "\tfree(hold_node);\n" "}\n",queue,queue,queue,queue,queue,machines_stuff,(options->has_context?"context,":"") ); } void ast_print_machine_buffer_declarations(FILE *out) { ast_to_c_print_comment(out,"\tthis is the structure that facilitates data exchange"); fprintf(out,"typedef struct machine_buffer_t \n{" "\n\tsize_t size;\n\tunsigned char buffer[];\n} machine_buffer_t;\n\n"); ast_to_c_print_comment(out, "\tthis function creates a buffer structure in the heap\n" "\tit COPIES the contents of content \n" "\tsize is in bytes" ); fprintf(out,"extern machine_buffer_t* get_machine_buffer(void *content,size_t size);\n\n"); ast_to_c_print_comment(out,"\tfrees the buffer from the heap"); fprintf(out,"extern void delete_machine_buffer(machine_buffer_t *buffer);\n\n"); } void ast_print_machine_buffer_definitions(FILE *out) { fprintf(out, "machine_buffer_t* get_machine_buffer(void *content,size_t size)\n" "{\n" "\tmachine_buffer_t *ret;\n" "\tsize_t i;\n" "\t\n" "\tret=malloc(sizeof(machine_buffer_t)+size);\n" "\tret->size=size;\n" "\tfor(i=0;ibuffer[i]=((unsigned char*)content)[i];\n" "\treturn ret;\n" "}\n"); fprintf(out, "\nvoid delete_machine_buffer(machine_buffer_t *buffer)\n" "{\n" "\tif(buffer)\n" "\t{\n" "\t\tfree(buffer);\n" "\t}\n}\n" ); } #endif