#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]); 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_machines_to_c_array(out,translation_unit); ast_to_c_print_internal_stuff_for_body(out,options); for(i=0;inumber_of_machines;++i) ast_machine_to_c_make_body_part(out,translation_unit->machines[i]); 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) { 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) { assert(out!=NULL && machine!=NULL && machine->type==AST_TYPE_MACHINE); ast_machine_to_c_make_header_part(out,machine); ast_machine_to_c_make_body_part(out,machine); } void ast_machine_to_c_make_body_part(FILE *out,struct AST_Machine *machine) { 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]); fprintf(out,"\n{\n"); ast_transitions_of_state_to_c(out,machine,table[i]); fprintf(out,"\n}\n"); } } void ast_machine_to_c_make_header_part(FILE *out,struct AST_Machine *machine) { ast_events_to_c(out,machine); ast_states_to_c(out,machine); } void ast_events_to_c(FILE *out,struct AST_Machine *machine) { 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) { 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]); fprintf(out,";\n"); } } void ast_transitions_of_state_to_c(FILE *out,struct AST_Machine *machine,struct State_And_Transitions *vector) { size_t i; short indentation=3; //fprintf(out,"\tmachine_buffer_t *hold_buffer;\n\thold_buffer=input;\n\n"); if(vector->number_of_transitions>0) { fprintf(out,"\n\tmachine_states_lock=1;\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); 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); ast_to_c_print_tabs(out,indentation); fprintf(out,"machine_states["); 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\tmachine_states_lock=0;"); } /*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) { fprintf(out,"void "); ast_state_to_c_function_name(out,machine,state); fprintf(out,"(int event,machine_buffer_t *input)"); } 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;++i) { ast_state_to_c_function_name(out,translation_unit->machines[i],translation_unit->machines[i]->starting_state); fprintf(out,","); } fprintf(out,"};\n"); fprintf(out,"_Bool machine_states_lock=0;\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\t\n"); }else { ast_print_machine_buffer_declarations(out); } if(!options->providing_own_queue_implementation) ast_to_c_print_event_queue_declaration(out); 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" ); fprintf(out,"extern void push_event_to_machine(enum MACHINES_ENUM machine,int event,machine_buffer_t *input);\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" ); } void ast_to_c_print_internal_stuff_for_body(FILE *out,struct Options *options) { if(!options->providing_own_queue_implementation) ast_to_c_print_event_queue_definition(out); if(!options->providing_own_buffer_implementation) ast_print_machine_buffer_definitions(out); fprintf(out, "void push_event_to_machine(enum MACHINES_ENUM machine,int event,machine_buffer_t *input)\n" "{\n" "\tif(machinehas_mutex) fprintf(out,"\t\tmachine_mutex_lock(input,event,machine);\n"); fprintf(out, "\n\t\tif(machine_states_lock)" "\n\t\t{" "\n\t\t\tmachine_push_to_global_event_queue(input,event,machine);" "\n\t\t}else" "\n\t\t{" "\n\t\t\tmachine_states[machine](event,input);" "\n\t\t\twhile(machine_queue_global.size>0)machine_pop_from_global_event_queue();" "\n\t\t}" "\n\t}" ); 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) { 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); else assert(0); } void ast_if_to_c(FILE *out,size_t indentation,struct AST_If_Statement *statement) { ast_to_c_print_tabs(out,indentation); fprintf(out,"if"); ast_expression_to_c(out,statement->condition); fprintf(out,"\n"); ast_to_c_print_tabs(out,indentation); fprintf(out,"{\n"); ast_statement_to_c(out,indentation+1,statement->body); 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); ast_to_c_print_tabs(out,indentation); fprintf(out,"}"); } fprintf(out,"\n"); } void ast_expression_to_c(FILE *out,struct AST *expression) { fprintf(out,"("); switch(expression->type) { case AST_TYPE_OP_OR: ast_expression_to_c(out,AS_BIN_EXPR_PTR(expression)->left); fprintf(out,"||"); ast_expression_to_c(out,AS_BIN_EXPR_PTR(expression)->right); break; case AST_TYPE_OP_NOT: fprintf(out,"!"); ast_expression_to_c(out,AS_UN_EXPR_PTR(expression)->operand); break; case AST_TYPE_OP_AND: ast_expression_to_c(out,AS_BIN_EXPR_PTR(expression)->left); fprintf(out,"&&"); ast_expression_to_c(out,AS_BIN_EXPR_PTR(expression)->right); break; case AST_TYPE_STATE: ast_expression_state_to_c(out,(struct AST_State*)expression); 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) { fprintf(out,"machine_states["); 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_queue_declaration(FILE *out) { 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" ); 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"); } void ast_to_c_print_event_queue_definition(FILE *out) { fprintf(out, "struct machine_queue_t machine_queue_global = { .first=NULL,.last=NULL,.size=0};\n"); fprintf(out, "void machine_push_to_global_event_queue(machine_buffer_t *input,int event,enum MACHINES_ENUM target_machine)\n" "{\n" "\tif(machine_queue_global.size==0)\n" "\t{\n" "\t\tmachine_queue_global.first=machine_queue_global.last=malloc(sizeof(struct machine_queue_node_t));\n" "\t\tmachine_queue_global.last->input=input;\n" "\t\tmachine_queue_global.last->event=event;\n" "\t\tmachine_queue_global.last->target_machine=target_machine;\n" "\t\tmachine_queue_global.size=1;\n" "\t}else\n" "\t{\n" "\t\tmachine_queue_global.last=machine_queue_global.last->prev=malloc(sizeof(struct machine_queue_node_t));\n" "\t\tmachine_queue_global.last->input=input;\n" "\t\tmachine_queue_global.last->event=event;\n" "\t\tmachine_queue_global.last->target_machine=target_machine;\n" "\t\t++machine_queue_global.size;\n" "\t}\n" "}\n" ); fprintf(out, "void machine_pop_from_global_event_queue()\n" "{\n" "\tstruct machine_queue_node_t *hold_node;\n" "\thold_node=machine_queue_global.first;\n" "\tmachine_queue_global.first=machine_queue_global.first->prev;\n" "\tif(--machine_queue_global.size==0)\n" "\t\tmachine_queue_global.last=NULL;\n" "\tmachine_states[hold_node->target_machine](hold_node->event,hold_node->input);\n" "\tfree(hold_node);\n" "}\n" ); } 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"); 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