F diff --git a/src/backend/backend.c b/src/backend/backend.c --- a/src/backend/backend.c +++ b/src/backend/backend.cstruct State_And_Transitions** extract_transition_table(struct AST_States *states,struct AST_Transitions *transitions){struct State_And_Transitions **ret;+ struct AST_State *hold_state;struct Queue *qs;size_t i;/*traverse transitions and push them into the queue of their coresponding state*/for(i=0;i<transitions->size;++i)- Queue_Push(qs+transitions->transitions[i]->from->number,transitions->transitions[i]);+ {+ hold_state=extract_state(transitions->transitions[i]->from,states);++ assert(hold_state!=NULL);++ Queue_Push(qs+hold_state->number,transitions->transitions[i]);+ }/*condense the queues into the arrays*/for(i=0;i<states->number_of_states;++i)return ret;}+ _Bool expression_is_binary(struct AST* expression)+ {+ return (expression->type==AST_TYPE_OP_OR || expression->type==AST_TYPE_OP_AND);+ }+ _Bool expression_is_unary(struct AST* expression)+ {+ return (expression->type==AST_TYPE_OP_NOT);+ }+ _Bool state_is_in_states(struct AST_State *state,struct AST_States *states)+ {+ return state==Map_Check(states->states_map,state->name->data,state->name->size);+ }++ struct AST_State* extract_state(struct AST *expression,struct AST_States *states)+ {+ struct AST_State *hold_state;++ assert(expression->type==AST_TYPE_OP_NOT || expression->type==AST_TYPE_OP_AND || expression->type==AST_TYPE_OP_OR+ || expression->type==AST_TYPE_STATE );++ if(expression->type==AST_TYPE_STATE)+ {+ if(state_is_in_states((struct AST_State*)expression,states))+ return (struct AST_State*)expression;+ else+ return NULL;+ }else if(expression_is_binary(expression))+ {+ hold_state=extract_state(((struct AST_Binary_Expression*)expression)->left,states);+ if(hold_state)+ return hold_state;+ else+ return extract_state(((struct AST_Binary_Expression*)expression)->right,states);+ }else+ {+ return extract_state(((struct AST_Unary_Expression*)expression)->operand,states);+ }+ }++ _Bool check_expression(struct AST *state,struct AST_Translation_Unit *unit)+ {++ }+ _Bool check_transition(struct AST *state,struct AST_Translation_Unit *unit)+ {++ }+ void anotate_unchecked_states(struct AST_Translation_Unit *unit,struct Translation_Data *translation_data)+ {+ size_t i;+ for(i=0;i<unit->number_of_machines;++i)+ {+ anotate_machine(unit->machines[i],unit);+ }+ if(has_new_errors(++ }+ void anotate_machine(struct AST_Machine *machine,struct AST_Translation_Unit *unit,struct Translation_Data *translation_data)+ {+ size_t i;+ for(i=0;i<machine->transitions->size;++i)+ {+ machine->transitions->transitions[i]->from=anotate_expression(machine->transitions->transitions[i]->from,machine,unit);+ }+ if(has_new_errors(translation_data))+ {+ push_error_with_token("in machine",translation_data,machine->id);+ delete_ast_machine(machine);+ }+ }+ struct AST* anotate_expression(struct AST *expression,struct AST_Translation_Unit *unit,struct AST_Machine *current_machine,struct Translation_Data *translation_data);+ {+ struct AST_Machine *hold_machine;+ struct AST *hold_left;+ struct AST *hold_right;++ if(expression_is_binary(expression))+ {+ left=((struct AST_Binary_Expression*)expression)->left;+ right=((struct AST_Binary_Expression*)expression)->right;++ if(expression->type==AST_TYPE_OP_SELECTOR)+ {+ hold_machine=Map_Check(unit->machines_map,((struct AST_Unchecked_State*)hold_left)->name->data,((struct AST_Unchecked_State*)hold_left)->name->size);+ if(hold_machine==NULL)+ {+ push_error_with_token("machine id is undefined",((struct AST_Unchecked_State*)hold_left)->name,translation_data);+ delete_ast(expression);+ return NULL;+ }else+ {+ return ast_check_state(hold_right,hold_machine->states,translation_data);+ }+ }else+ {+ AS_BIN_EXPR_PTR(expression)->right=anotate_expression(AS_BIN_EXPR_PTR(expression)->right,machine,unit);+ AS_BIN_EXPR_PTR(expression)->left=anotate_expression(AS_BIN_EXPR_PTR(expression)->left,machine,unit);+ return expression;+ }+ }else if(expression_is_unary(expression))+ {+ AS_UN_EXPR_PTR(expression)->operand=anotate_expression(AS_UN_EXPR_PTR(expression)->operand,machine,unit);+ }else if(expression->type==AST_TYPE_UNFINISHED_STATE)+ {+ return ast_check_state(AS_UNCK_EXPR_PTR(expression),machine->states,translation_data);+ }+ }#endifF diff --git a/src/backend/backend.h b/src/backend/backend.h --- a/src/backend/backend.h +++ b/src/backend/backend.h#define BACKEND_H BACKEND_H#include <parser.h>#include <ast_to_c.h>+ #include <map.h>/** describes a given state and the transitions coming out of it};/*returns an array of state_and_transition structs*/struct State_And_Transitions** extract_transition_table(struct AST_States *states,struct AST_Transitions *transitions);+ /*extracts a state from the expression that belongs in the states structure*/+ struct AST_State* extract_state(struct AST *expression,struct AST_States *states);++ void anotate_unchecked_states(struct AST_Translation_Unit *unit,struct Translation_Data *translation_data);+ void anotate_machine(struct AST_Machine *machine,struct AST_Translation_Unit *unit,struct Translation_Data *translation_data);+ struct AST* anotate_expression(struct AST *expression,struct AST_Translation_Unit *unit,struct AST_Machine *current_machine,struct Translation_Data *translation_data);++ _Bool expression_is_binary(struct AST* expression);+ _Bool expression_is_unary(struct AST* expression);+ _Bool state_is_in_states(struct AST_State *state,struct AST_States *states);+ _Bool check_expression(struct AST *state,struct AST_Translation_Unit *unit);+ _Bool check_transition(struct AST *state,struct AST_Translation_Unit *unit);#endifF diff --git a/src/backend/targets/C/ast_to_c.c b/src/backend/targets/C/ast_to_c.c --- a/src/backend/targets/C/ast_to_c.c +++ b/src/backend/targets/C/ast_to_c.c#include <ast_to_c.h>#include <print.h>- void ast_to_c(FILE *out,struct AST *tree)+ void ast_to_c(char *output_name,struct AST *tree){- assert(tree->type==AST_TYPE_MACHINE);- ast_machine_to_c(out,(struct AST_Machine*)tree);+ 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);+ 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);+ 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_commands(hold_out,output_name,(struct AST_Translation_Unit*)tree);+ fclose(hold_out);++ free(hold_name);++ }else+ {+ ast_translation_unit_to_c_print_external_commands(stdout,NULL,(struct AST_Translation_Unit*)tree);+ ast_translation_unit_to_c_print_header_part(stdout,NULL,(struct AST_Translation_Unit*)tree);+ ast_translation_unit_to_c_print_body_part(stdout,NULL,(struct AST_Translation_Unit*)tree);+ }++ }+ 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)+ {+ size_t i;+ if(base_name)+ {+ ast_translation_unit_to_c_print_header_string(out,base_name,"_H");+ fprintf(out,"#include<stdlib.h>\n\n");+ }++ ast_to_c_print_internal_stuff_for_header(out,translation_unit);++ for(i=0;i<translation_unit->number_of_machines;++i)+ ast_machine_to_c_make_header_part(out,translation_unit->machines[i]);++ ast_machines_to_c_array(out,translation_unit);++ 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)+ {+ 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);+ }++ for(i=0;i<translation_unit->number_of_machines;++i)+ ast_machine_to_c_make_body_part(out,translation_unit->machines[i]);++ ast_to_c_print_internal_stuff_for_body(out);++ if(base_name)+ ast_translation_unit_to_c_print_footer_string(out,base_name,"_C");+ }+ void ast_translation_unit_to_c_print_external_commands(FILE *out,char *base_name,struct AST_Translation_Unit *translation_unit)+ {+ 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);+ }++ 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){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){}void ast_machine_to_c_make_header_part(FILE *out,struct AST_Machine *machine){- fprintf(out,"typedef struct machine_buffer_t \n{"- "\n\tsize_t size;\n\tunsigned char buffer[];\n} machine_buffer_t;\n\n");ast_events_to_c(out,machine);ast_states_to_c(out,machine);}assert(out!=NULL && machine!=NULL && machine->type==AST_TYPE_MACHINE);fprintf(out,"enum ");- ast_event_name_to_c(out,machine);+ ast_machine_enum_tag(out,machine);fprintf(out,"\n{\n");for(i=0;i<machine->events->number_of_events;++i){fprintf(out,"\t");- ast_token_to_c(out,machine->id);- fprintf(out,"_EVENT_");- ast_token_to_c(out,machine->events->events[i]->name);+ ast_event_to_c_enum(out,machine,machine->events->events[i]);fprintf(out,",\n");}fprintf(out,"};\n");void ast_transitions_of_state_to_c(FILE *out,struct AST_Machine *machine,struct State_And_Transitions *vector){size_t i;- ast_state_to_c_signature(out,machine,vector->state);- fprintf(out,"\n{\n\n\tswitch(event)\n\t{\n");- for(i=0;i<vector->number_of_transitions;++i)+ //fprintf(out,"\tmachine_buffer_t *hold_buffer;\n\thold_buffer=input;\n\n");++ if(vector->number_of_transitions>0){- fprintf(out,"\t\tcase ");- ast_token_to_c(out,vector->transitions[i]->event->name);- fprintf(out,":\n");- ast_pipeline_to_c(out,3,vector->transitions[i]->pipeline);- fprintf(out,"\n\t\t\tbreak;\n");+ fprintf(out,"\tswitch(event)\n\t{\n");+ for(i=0;i<vector->number_of_transitions;++i)+ {+ fprintf(out,"\t\tcase ");+ ast_event_to_c_enum(out,machine,vector->transitions[i]->event);++ fprintf(out,":\n");+ ast_pipeline_to_c(out,3,vector->transitions[i]->pipeline);+ fprintf(out,"\t\t\tmachine_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\t\t\tbreak;\n");+ }+ fprintf(out,"\t}\n");}+ fprintf(out,"\tdelete_machine_buffer(input);\n");}- void ast_event_name_to_c(FILE *out,struct AST_Machine *machine)+ /*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);}void ast_state_to_c_signature(FILE *out,struct AST_Machine *machine,struct AST_State *state){- fprintf(out,"void machine_");- ast_token_to_c(out,machine->id);- fprintf(out,"_state_");- ast_token_to_c(out,state->name);- fprintf(out,"(enum ");- ast_event_name_to_c(out,machine);- fprintf(out," event)\n");+ 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;- ast_to_c_print_tabs(out,indentation);- fprintf(out,"machine_buffer_t *hold_buffer;\n");+ if(pipeline==NULL) return;for(i=0;i<pipeline->size;++i){ast_to_c_print_tabs(out,indentation);- fprintf(out,"hold_buffer=");- ast_command_to_c(out,pipeline->pipeline[i],"hold_buffer");+ fprintf(out,"input=");+ ast_command_to_c(out,pipeline->pipeline[i],"input");fprintf(out,";\n");}- ast_to_c_print_tabs(out,indentation);- fprintf(out,"delete_machine_buffer(hold_buffer);\n");+ //ast_to_c_print_tabs(out,indentation);}void ast_command_to_c(FILE *out,struct AST_Command *command,char *hold_buffer){fprintf(out,",%s)",hold_buffer);}- void ast_command_to_c_signature(FILE *out,struct AST_Command *command)+ void ast_command_to_c_extern_declaration(struct AST_Command *command,FILE *out){- fprintf(out,"machine_buffer_t* ");+ fprintf(out,"extern machine_buffer_t* ");ast_token_to_c(out,command->function_name);- fprintf(out,"machine_buffer_t *arguments,machine_buffer_t *input)");+ fprintf(out,"(machine_buffer_t *arguments,machine_buffer_t *input);\n");}void ast_to_c_print_tabs(FILE *out,size_t number_of_tabs){for(i=0;i<number_of_tabs;++i)fprintf(out,"\t");}+ void ast_machines_to_c_array(FILE *out,struct AST_Translation_Unit *translation_unit)+ {+ size_t i;++ fprintf(out,"void (*machine_states[])(int,machine_buffer_t*)={");+ for(i=0;i<translation_unit->number_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");+ }+ 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;i<translation_unit->number_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)+ {+ fprintf(out,"\n\n");+ ast_machines_to_c_enum(out,translation_unit);+ fprintf(out,"\n\n");+++ 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, "\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,"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"+ );++ fprintf(out,"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,"void delete_machine_buffer(machine_buffer_t *buffer);\n\n");+ }+ void ast_to_c_print_internal_stuff_for_body(FILE *out)+ {++ fprintf(out, "void push_event_to_machine(enum MACHINES_ENUM machine,int event,machine_buffer_t *input)\n"+ "{\n"+ "\tif(machine<MACHINES_ENUM_END)"+ "\n\t{"+ "\n\t\tmachine_states[machine](event,input);"+ "\n\t}"+ "\n}\n"+ );++ 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;i<size;++i)\n"+ "\t\tret->buffer[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}"+ );+ }+ void ast_to_c_print_comment(FILE *out,char *comment)+ {+ fprintf(out,"/*\n");+ fprintf(out,"%s\n",comment);+ fprintf(out,"*/\n");+ }#endifF diff --git a/src/backend/targets/C/ast_to_c.h b/src/backend/targets/C/ast_to_c.h --- a/src/backend/targets/C/ast_to_c.h +++ b/src/backend/targets/C/ast_to_c.h#include <parser.h>#include <backend.h>#include <ctype.h>+ #include <stdio.h>+ #include <string.h>struct State_And_Transitions;- void ast_to_c(FILE *out,struct AST *tree);+ void ast_to_c(char *output_name,struct AST *tree);++ void ast_translation_unit_to_c_print_header_part(FILE *out,char *base_name,struct AST_Translation_Unit *translation_unit);+ void ast_translation_unit_to_c_print_body_part(FILE *out,char *base_name,struct AST_Translation_Unit *translation_unit);+ void ast_translation_unit_to_c_print_external_commands(FILE *out,char *base_name,struct AST_Translation_Unit *translation_unit);++ void ast_translation_unit_to_c_print_base_name(FILE *out, char *base_name);+ void ast_translation_unit_to_c_print_header_string(FILE *out,char *base_name,char *file_suffix);+ void ast_translation_unit_to_c_print_footer_string(FILE *out,char *base_name,char *file_suffix);++ void ast_translation_unit_to_c(FILE *out,struct AST_Translation_Unit *translation_unit);void ast_machine_to_c(FILE *out,struct AST_Machine *machine);void ast_machine_to_c_make_header_part(FILE *out,struct AST_Machine *machine);void ast_machine_to_c_make_body_part(FILE *out,struct AST_Machine *machine);+void ast_events_to_c(FILE *out,struct AST_Machine *machine);void ast_states_to_c(FILE *out,struct AST_Machine *machine);- void ast_pipeline_to_c(FILE *out,size_t indentation,struct AST_Pipeline *pipeline);void ast_command_to_c(FILE *out,struct AST_Command *command,char *hold_buffer);- void ast_command_to_c_signature(FILE *out,struct AST_Command *command);++ /*note the ordering*/+ void ast_command_to_c_extern_declaration(struct AST_Command *command,FILE *out);++ void ast_pipeline_to_c(FILE *out,size_t indentation,struct AST_Pipeline *pipeline);void ast_transitions_of_state_to_c(FILE *out,struct AST_Machine *machine,struct State_And_Transitions *vector);void ast_token_to_c(FILE *out,struct token *token);- void ast_event_name_to_c(FILE *out,struct AST_Machine *machine);+ void ast_machine_enum_tag(FILE *out,struct AST_Machine *machine);void ast_state_to_c_signature(FILE *out,struct AST_Machine *machine,struct AST_State *state);+ void ast_state_to_c_function_name(FILE *out,struct AST_Machine *machine,struct AST_State *state);+ void ast_machines_to_c_array(FILE *out,struct AST_Translation_Unit *translation_unit);+ void ast_machines_to_c_enum(FILE *out,struct AST_Translation_Unit *translation_unit);+ void ast_event_to_c_enum(FILE *out,struct AST_Machine *machine,struct AST_Event *event);+++ void ast_to_c_print_internal_stuff_for_header(FILE *out,struct AST_Translation_Unit *translation_unit);+ void ast_to_c_print_internal_stuff_for_body(FILE *out);+ void ast_to_c_print_comment(FILE *out,char *comment);+++/* :X */void ast_to_c_print_tabs(FILE *out,size_t number_of_tabs);F diff --git a/src/frontend/lexer.c b/src/frontend/lexer.c --- a/src/frontend/lexer.c +++ b/src/frontend/lexer.creturn get_token(src->src+src->where_in_src-sizeof("on")+1,sizeof("on")-1,KW_ON,src->current_row,src->current_column);if(check_and_move_if_on_word("[",sizeof("[")-1,src,0))return get_token(src->src+src->where_in_src-sizeof("[")+1,sizeof("[")-1,KW_OPEN_SQUARE,src->current_row,src->current_column);+ if(check_and_move_if_on_word("(",sizeof("(")-1,src,0))+ return get_token(src->src+src->where_in_src-sizeof("(")+1,sizeof("(")-1,KW_OPEN_NORMAL,src->current_row,src->current_column);+ if(check_and_move_if_on_word(")",sizeof(")")-1,src,0))+ return get_token(src->src+src->where_in_src-sizeof(")")+1,sizeof(")")-1,KW_CLOSE_NORMAL,src->current_row,src->current_column);if(check_and_move_if_on_word(",",sizeof(",")-1,src,0))return get_token(src->src+src->where_in_src-sizeof(",")+1,sizeof(",")-1,KW_COMMA,src->current_row,src->current_column);+ if(check_and_move_if_on_word(".",sizeof(".")-1,src,0))+ return get_token(src->src+src->where_in_src-sizeof(".")+1,sizeof(".")-1,KW_DOT,src->current_row,src->current_column);if(check_and_move_if_on_word("]",sizeof("]")-1,src,0))return get_token(src->src+src->where_in_src-sizeof("]")+1,sizeof("]")-1,KW_CLOSE_SQUARE,src->current_row,src->current_column);if(check_and_move_if_on_word(";",sizeof(";")-1,src,0))return get_token(src->src+src->where_in_src-sizeof(";")+1,sizeof(";")-1,KW_SEMI_COLUMN,src->current_row,src->current_column);if(check_and_move_if_on_word("|",sizeof("|")-1,src,0))return get_token(src->src+src->where_in_src-sizeof("|")+1,sizeof("|")-1,KW_PIPE,src->current_row,src->current_column);+ if(check_and_move_if_on_word("||",sizeof("||")-1,src,0))+ return get_token(src->src+src->where_in_src-sizeof("||")+1,sizeof("||")-1,KW_OR,src->current_row,src->current_column);+ if(check_and_move_if_on_word("&&",sizeof("&&")-1,src,0))+ return get_token(src->src+src->where_in_src-sizeof("&&")+1,sizeof("&&")-1,KW_AND,src->current_row,src->current_column);+ if(check_and_move_if_on_word("!",sizeof("!")-1,src,0))+ return get_token(src->src+src->where_in_src-sizeof("!")+1,sizeof("!")-1,KW_NOT,src->current_row,src->current_column);if(check_and_move_if_on_word("starting",sizeof("starting")-1,src,1))return get_token(src->src+src->where_in_src-sizeof("starting")+1,sizeof("starting")-1,KW_STARTING,src->current_row,src->current_column);if(check_and_move_if_on_word("states",sizeof("states")-1,src,1)){Map_Push(map,token->data,token->size,thing);}+ void id_token_to_upper_case(struct token *token)+ {+ size_t i;+ for(i=0;i<token->size;++i)+ token->data[i]=toupper(token->data[i]);+ }#endifF diff --git a/src/frontend/lexer.h b/src/frontend/lexer.h --- a/src/frontend/lexer.h +++ b/src/frontend/lexer.hKW_EOF,KW_OPEN_SQUARE,KW_CLOSE_SQUARE,+ KW_OPEN_NORMAL,+ KW_CLOSE_NORMAL,KW_PIPE,KW_SEMI_COLUMN,KW_STARTING,KW_EXECUTE,KW_TRANSITIONS,KW_COMMA,+ KW_DOT,+ KW_AND,+ KW_OR,+ KW_NOT,};struct token{void skip_white_space(struct Source *src);void push_token_into_map(struct token *token,struct Map *map,void *thing);+ void id_token_to_upper_case(struct token *token);void delete_token(struct token *token);F diff --git a/src/frontend/parser.c b/src/frontend/parser.c --- a/src/frontend/parser.c +++ b/src/frontend/parser.c{struct Queue *machines;struct Map *hold_command_map;+ struct Map *hold_machines_map;struct AST_Machine *hold_machine;machines=calloc(1,sizeof(struct Queue));+hold_command_map=malloc(sizeof(struct Map));Map_Init(hold_command_map);+ hold_machines_map=malloc(sizeof(struct Map));+ Map_Init(hold_machines_map);+translation_data->hold_command_map=hold_command_map;+ translation_data->hold_machines_map=hold_machines_map;while(!get_and_check(translation_data,KW_EOF)){hold_machine=parse_machine(translation_data);+ /*TODO check for repeated machine ids*/+ Map_Push(hold_machines_map,hold_machine->id->data,hold_machine->id->size,hold_machine);if(hold_machine){Queue_Push(machines,hold_machine);return NULL;}}- return get_ast_translation_unit(machines,hold_command_map);+ return get_ast_translation_unit(machines,hold_command_map,hold_machines_map);}/** machine: 'machine' id '[' machine-inner ']' ';'{push_parsing_error("there are no transitions",translation_data);return NULL;+ }else if(has_new_errors(translation_data))+ {+ push_parsing_error("in transition",translation_data);+ return NULL;}else{return get_ast_transitions(transitions);if(get_and_check(translation_data,KW_FROM)){- if(get_kw(translation_data)==KW_ID)+ hold_from=parse_expression(translation_data);+ if(hold_from!=NULL){- hold_token=Queue_Pop(translation_data->tokens);- hold_from=Map_Check(states->states_map,hold_token->data,hold_token->size);- delete_token(hold_token);- if(hold_from!=NULL)+ if(get_and_check(translation_data,KW_TO)){- if(get_and_check(translation_data,KW_TO))+ if(get_kw(translation_data)==KW_ID){- if(get_kw(translation_data)==KW_ID)+ hold_token=Queue_Pop(translation_data->tokens);+ hold_to=Map_Check(states->states_map,hold_token->data,hold_token->size);+ delete_token(hold_token);+ if(hold_to!=NULL){- hold_token=Queue_Pop(translation_data->tokens);- hold_to=Map_Check(states->states_map,hold_token->data,hold_token->size);- delete_token(hold_token);- if(hold_to!=NULL)+ if(get_and_check(translation_data,KW_ON) && get_and_check(translation_data,KW_EVENT) ){- if(get_and_check(translation_data,KW_ON) && get_and_check(translation_data,KW_EVENT) )+ if(get_kw(translation_data)==KW_ID){- if(get_kw(translation_data)==KW_ID)+ hold_token=Queue_Pop(translation_data->tokens);+ hold_event=Map_Check(events->events_map,hold_token->data,hold_token->size);+ delete_token(hold_token);+ if(hold_event!=NULL){- hold_token=Queue_Pop(translation_data->tokens);- hold_event=Map_Check(events->events_map,hold_token->data,hold_token->size);- delete_token(hold_token);- if(hold_event!=NULL)- {- if(get_and_check(translation_data,KW_EXECUTE))- if((hold_pipeline=parse_pipeline(translation_data))==NULL)- { push_parsing_error("after execute",translation_data); return NULL; }- /*GOAL*/- return get_ast_transition(hold_from,hold_to,hold_event,hold_pipeline);- }else { push_parsing_error("event not defined",translation_data); return NULL; }- }else { push_parsing_error("no event name given in transition",translation_data); return NULL; }- }else { push_parsing_error("expected 'on event'",translation_data); return NULL; }- }else { push_parsing_error("using undefined to state in transition",translation_data); }- }else { push_parsing_error("expected id in transition expression",translation_data); return NULL; }- }else { push_parsing_error("expected 'to'",translation_data); return NULL; }- }else { push_parsing_error("using undefined from state in transition",translation_data); return NULL; }- }else { push_parsing_error("expected id in transition expression",translation_data); return NULL; }+ if(get_and_check(translation_data,KW_EXECUTE))+ if((hold_pipeline=parse_pipeline(translation_data))==NULL)+ { push_parsing_error("after execute",translation_data); return NULL; }+ /*GOAL*/+ return get_ast_transition(hold_from,hold_to,hold_event,hold_pipeline);+ }else { push_parsing_error("event not defined",translation_data); return NULL; }+ }else { push_parsing_error("no event name given in transition",translation_data); return NULL; }+ }else { push_parsing_error("expected 'on event'",translation_data); return NULL; }+ }else { push_parsing_error("using undefined to state in transition",translation_data); }+ }else { push_parsing_error("expected id in transition expression",translation_data); return NULL; }+ }else { push_parsing_error("expected 'to'",translation_data); return NULL; }+ }else { push_parsing_error("using undefined from state in transition",translation_data); return NULL; }}else { return NULL; }}/*if(get_kw(translation_data)==KW_STRING)string=Queue_Pop(translation_data->tokens);ret=get_ast_command(id,string);- Map_Push(translation_data->hold_command_map,ret->argument->data,ret->argument->size,ret);+ if(!Map_Check(translation_data->hold_command_map,ret->function_name->data,ret->function_name->size))+ Map_Push(translation_data->hold_command_map,ret->function_name->data,ret->function_name->size,ret);return ret;}elseret=malloc(sizeof(struct AST_State));ret->name=id;+/*number is assigned in get_ast_states*/return ret;while(states->size>0){hold_state=Queue_Pop(states);+ /*TODO check for redeclaration*/Map_Push(ret->states_map,hold_state->name->data,hold_state->name->size,hold_state);+ret->states[states->size]=hold_state;hold_state->number=states->size;}while(events->size>0){hold_event=Queue_Pop(events);+ /*TODO check for redeclaration*/Map_Push(ret->events_map,hold_event->name->data,hold_event->name->size,hold_event);ret->events[events->size]=hold_event;}return ret;}- struct AST_Transition* get_ast_transition(struct AST_State *from,struct AST_State *to,struct AST_Event *event,struct AST_Pipeline *pipeline)+ struct AST_Transition* get_ast_transition(struct AST *from,struct AST_State *to,struct AST_Event *event,struct AST_Pipeline *pipeline);{struct AST_Transition *ret;ret=malloc(sizeof(struct AST_Transition));ret->states=states;ret->events=events;ret->transitions=transitions;+ ret->starting_state=starting_state;return ret;}free(ast->used_commands_map);free(ast);}- struct AST_Translation_Unit* get_ast_translation_unit(struct Queue *machines,struct Map *command_map)+ struct AST_Translation_Unit* get_ast_translation_unit(struct Queue *machines,struct Map *command_map,struct Map *machines_map){struct AST_Translation_Unit *ret;struct AST_Machine *hold_machine;ret=malloc(sizeof(struct AST_Translation_Unit)+sizeof(struct AST_Machine *[machines->size]));ret->type=AST_TYPE_TRANSLATION_UNIT;ret->used_commands_map=command_map;+ ret->machines_map=machines_map;ret->number_of_machines=machines->size;while(machines->size>0)return ret;}+ /*+ * expression: or-expression+ */+ struct AST* parse_expression(struct Translation_Data *translation_data)+ {+ return parse_or_expression(translation_data);+ }+ /*+ * or-expression: and-expression [ || and-expression ]+ */+ struct AST* parse_or_expression(struct Translation_Data *translation_data)+ {+ struct AST *hold_left_expression;+ struct AST *hold_right_expression;++ hold_left_expression=parse_and_expression(translation_data);+ if(hold_left_expression==NULL)+ return NULL;++ if(get_and_check(translation_data,KW_OR))+ {+ hold_right_expression=parse_and_expression(translation_data);+ if(hold_right_expression==NULL)+ {+ push_parsing_error("expected expression in right side of ||",translation_data);+ delete_ast(hold_left_expression);+ return NULL;+ }+ return (struct AST*)get_ast_binary_expression(left,right,AST_TYPE_OP_OR);+ }else+ {+ return hold_left_expression;+ }++ }+ /*+ * and-expression: not-expression [ && not-expression ]+ */+ struct AST* parse_and_expression(struct Translation_Data *translation_data)+ {+ struct AST *hold_left_expression;+ struct AST *hold_right_expression;++ hold_left_expression=parse_not_expression(translation_data);+ if(hold_left_expression==NULL)+ return NULL;++ if(get_and_check(translation_data,KW_AND))+ {+ hold_right_expression=parse_not_expression(translation_data);+ if(hold_right_expression==NULL)+ {+ push_parsing_error("expected expression in right side of &&",translation_data);+ delete_ast(hold_left_expression);+ return NULL;+ }+ return (struct AST*)get_ast_binary_expression(left,right,AST_TYPE_OP_AND);+ }else+ {+ return hold_left_expression;+ }+ }+ /*+ * not-expression: [!]primary-expression+ */+ struct AST* parse_not_expression(struct Translation_Data *translation_data)+ {+ struct AST *hold_expression;+ if(get_and_check(translation_data,KW_NOT))+ {+ hold_expression=parse_primary_expression(translation_data);+ if(hold_expression!=NULL)+ {+ return get_ast_unary_expression(hold_expression,AST_TYPE_OP_NOT);+ }else+ {+ push_parsing_error("in '!' expression",translation_data);+ return NULL;+ }+ }+ return parse_primary_expression(translation_data);+ }+ /*+ * primary-expression: (expression) | id | id.id+ */+ struct AST* parse_primary_expression(struct Translation_Data *translation_data)+ {+ struct AST *hold_expression;+ struct AST_Unchecked_State *hold_id1;+ struct AST_Unchecked_State *hold_id2;++ if(get_and_check(translation_data,KW_OPEN_NORMAL))+ {+ hold_expression=parse_expression(translation_data);+ if(get_and_check(translation_data,KW_CLOSE_NORMAL))+ {+ return hold_expression;+ }else+ {+ push_parsing_error("expected ')' in expression",translation_data);+ delete_ast(hold_expression);+ return NULL;+ }++ }else if(get_kw(translation_data)==KW_ID)+ {+ hold_id1=get_ast_unchecked_state(Queue_Pop(translation_data->tokens));+ if(get_and_check(translation_data,KW_DOT))+ {+ if(get_kw(translation_data)==KW_ID)+ {+ hold_id2=get_ast_unchecked_state(Queue_Pop(translation_data->tokens));+ return get_ast_binary_expression(hold_id1,hold_id2,AST_TYPE_OP_SELECTOR);+ }else+ {+ push_parsing_error("expected a state id in selector",translation_data);+ delete_ast(hold_id1);+ return NULL;+ }+ }else+ {+ return hold_id1;+ }+ }else+ {+ push_parsing_error("expected an expression",translation_data);+ return NULL;+ }+ }+ struct AST_Binary_Expression* get_ast_binary_expression(struct AST *left,struct AST *right,enum AST_Type type)+ {+ struct AST_Binary_Expression *ret;++ ret=malloc(sizeof(struct AST_Binary_Expression));+ ret->type=type;+ ret->left=left;+ ret->right=right;++ return ret;+ }+ struct AST_Unary_Expression* get_ast_unary_expression(struct AST *operand,enum AST_Type type)+ {++ struct AST_Unary_Expression *ret;++ ret=malloc(sizeof(struct AST_Unary_Expression));++ ret->type=type;+ ret->operand=operand;++ return ret;+ }+ struct AST_Unchecked_State* get_ast_unchecked_state(struct token *name)+ {+ struct AST_Unchecked_State *ret;++ ret=malloc(sizeof(struct AST_Unchecked_State));+ ret->type=AST_TYPE_UNFINISHED_STATE;+ ret->name=name;++ return ret;+ }++ struct AST_State* ast_check_state(struct AST_Unchecked_State *state,struct AST_States *states,struct Translation_Data *translation_data)+ {+ struct AST_State *ret;+ ret=Map_Check(states->states_map,state->name->data,state->name->size);+ delete_ast_unchecked_state(state);+ if(ret==NULL)+ {+ push_parsing_error("undefined state",translation_data);+ return NULL;+ }else+ {+ return ret;+ }+ }++ void delete_ast_binary_expression(struct AST_Binary_Expression *ast)+ {+ if(ast->right)+ delete_ast(ast->right);+ if(ast->left)+ delete_ast(ast->left);+ free(ast);+ }+ void delete_ast_unary_expression(struct AST_Unary_Expression *ast)+ {+ if(ast->operand)+ delete_ast(ast->operand);+ free(ast);+ }+ void delete_ast_unchecked_state(struct AST_Unchecked_State *ast)+ {+ delete_token(ast->name);+ free(ast);+ }#endifF diff --git a/src/frontend/parser.h b/src/frontend/parser.h --- a/src/frontend/parser.h +++ b/src/frontend/parser.h#include <assert.h>#include <map.h>+ #define AS_BIN_EXPR_PTR(x) ((struct AST_Binary_Expression*)x)+ #define AS_UN_EXPR_PTR(x) ((struct AST_Unary_Expression*)x)+ #define AS_UNCK_EXPR_PTR(x) ((struct AST_Unchecked_State*)x)enum AST_Type{AST_TYPE_TRANSLATION_UNIT,AST_TYPE_TRANSITIONS,AST_TYPE_COMMAND,AST_TYPE_PIPELINE,+ AST_TYPE_OP_AND,+ AST_TYPE_OP_OR,+ AST_TYPE_OP_NOT,+ AST_TYPE_OP_SELECTOR,+ AST_TYPE_UNFINISHED_STATE,};struct AST{struct AST_Transition{enum AST_Type type;- struct AST_State *from;+ struct AST *from;struct AST_State *to;struct AST_Event *event;struct AST_Pipeline *pipeline;{enum AST_Type type;struct token *id;+ struct AST_State *starting_state;struct AST_States *states;struct AST_Events *events;struct AST_Transitions *transitions;{enum AST_Type type;struct Map *used_commands_map;+ struct Map *machines_map;size_t number_of_machines;struct AST_Machine *machines[];};+ struct AST_Binary_Expression+ {+ enum AST_Type type;+ struct AST *left;+ struct AST *right;+ };+ struct AST_Unary_Expression+ {+ enum AST_Type type;+ struct AST *operand;+ };+ struct AST_Unchecked_State+ {+ enum AST_Type type;+ struct token *name;+ };struct AST* parse_source(struct Translation_Data *translation_data);struct AST_Command* parse_command(struct Translation_Data *translation_data);struct AST_State* parse_start_on(struct Translation_Data *translation_data,struct AST_States *states);+ struct AST* parse_expression(struct Translation_Data *translation_data);+ struct AST* parse_or_expression(struct Translation_Data *translation_data);+ struct AST* parse_and_expression(struct Translation_Data *translation_data);+ struct AST* parse_not_expression(struct Translation_Data *translation_data);+ struct AST* parse_primary_expression(struct Translation_Data *translation_data);struct AST_State* get_ast_state(struct token *id);struct AST_Event* get_ast_event(struct token *id);struct AST_States* get_ast_states(struct Queue *states);struct AST_Events* get_ast_events(struct Queue *events);- struct AST_Transition* get_ast_transition(struct AST_State *from,struct AST_State *to,struct AST_Event *event,struct AST_Pipeline *pipeline);+ struct AST_Transition* get_ast_transition(struct AST *from,struct AST_State *to,struct AST_Event *event,struct AST_Pipeline *pipeline);struct AST_Command* get_ast_command(struct token *function_name,struct token *argument);struct AST_Pipeline* get_ast_pipeline(struct Queue *pipeline);struct AST_Machine* get_ast_machine(struct token *id,struct AST_States *states,struct AST_Events *events,struct AST_Transitions *transitions,struct AST_State *starting_state);struct AST_Transitions* get_ast_transitions(struct Queue *transitions);- struct AST_Translation_Unit* get_ast_translation_unit(struct Queue *machines,struct Map *command_map);+ struct AST_Translation_Unit* get_ast_translation_unit(struct Queue *machines,struct Map *command_map,struct Map *machines_map);++ struct AST_Binary_Expression* get_ast_binary_expression(struct AST *left,struct AST *right,enum AST_Type type);+ struct AST_Unary_Expression* get_ast_unary_expression(struct AST *operand,enum AST_Type type);+ struct AST_Unchecked_State* get_ast_unchecked_state(struct token *name);+ struct AST_State* ast_check_state(struct AST_Unchecked_State *state,struct AST_States *states,struct Translation_Data *translation_data);void delete_ast(struct AST* ast);void delete_ast_event(struct AST_Event* ast);void delete_ast_transitions(struct AST_Transitions* ast);void delete_ast_translation_unit(struct AST_Translation_Unit *ast);+ void delete_ast_binary_expression(struct AST_Binary_Expression *ast);+ void delete_ast_unary_expression(struct AST_Unary_Expression *ast);+ void delete_ast_unchecked_state(struct AST_Unchecked_State *ast);+void pointer_array_fill(void **array,struct Queue *q);struct Queue* parse_list(struct AST *(*parser)(struct Translation_Data*),struct Translation_Data *translation_data,enum Keyword delim);F diff --git a/src/main.c b/src/main.c --- a/src/main.c +++ b/src/main.cprint_ast(translation_unit);}else if(options->target==OPTION_TARGET_C){- ast_to_c(stdout,translation_unit);+ ast_to_c(options->output_name,translation_unit);}delete_ast(translation_unit);}F diff --git a/src/program/program.c b/src/program/program.c --- a/src/program/program.c +++ b/src/program/program.cret=malloc(sizeof(struct Options));ret->target=OPTION_DEFAULT;ret->src_name=NULL;+ ret->output_name=NULL;ret->is_quiet=0;for(i=0;i<argc;++i)if(++i<argc){if(strnlen(argv[i],101)<100)- ret->src_name=argv[i];+ ret->output_name=argv[i];else if(!ret->is_quiet){fprintf(stderr,"Error: Output filename is too long");assert(translation_data->hold_number_of_errors>0);--translation_data->hold_number_of_errors;}+ void push_error_with_token(char *error_message,struct Translation_Data *translation_data,struct token *token)+ {+ Queue_Push(translation_data->errors,get_error(error_message,token->row,token->column));+ }#endifF diff --git a/src/program/program.h b/src/program/program.h --- a/src/program/program.h +++ b/src/program/program.henum Options_Target_Type target;int is_quiet:1;char *src_name;+ char *output_name;};struct Errorvoid push_lexing_error(char *error_message,struct Source *src,struct Translation_Data *translation_data);void push_parsing_error(char *error_message,struct Translation_Data *translation_data);+ void push_error_with_token(char *error_message,struct Translation_Data *translation_data,struct token *token);char has_new_errors(struct Translation_Data *translation_data);void touch_errors(struct Translation_Data *translation_data);char get_and_check(struct Translation_Data *translation_data,enum Keyword kw);F diff --git a/tests/test2 b/tests/test2 --- a/tests/test2 +++ b/tests/test2- "1"- "12"+ machine light_bulb+ [+ states [ light_on , light_off ];+ events [ turn_on , turn_off , switch ];+ starting on light_off;+ transitions+ [+ from light_on to light_off on event turn_off execute kek2 | kek;+ from light_on to light_off on event switch;+ from light_off to light_on on event turn_on;+ from light_off to light_on on event switch execute kek;++ ];+ ];+ machine temp_switch+ [+ states [A,B];+ events [A];+ starting on A;+ transitions [from A to B on event A execute kek;];+ ];F diff --git a/tests/test3 b/tests/test3 --- a/tests/test3 +++ b/tests/test3- machine light_bulb+ machine SIREN[- states [ light_on , light_off ];- events [ switch_state , turn_on , turn_off ];-- starting on light_off;-+ states [ ON , OFF ];+ events [ ECHO , TURN_OFF , TURN_ON ];+ starting on ON ;transitions[- from light_on to light_off on event switch_state execute light_switch();- from light_off to light_on on event switch_state execute light_switch();+ from ON to OFF on event TURN_OFF;+ from OFF to ON on event TURN_ON;- from light_on to light_off on event turn_on execute light_switch();- from light_off to light_on on event turn_off execute light_switch();- ];- ];+ from ON to ON on event ECHO+ execute echo ;+ ];- transition light_switch()- {-- }+ ];F diff --git a/tests/test4 b/tests/test4 new file mode 100644 --- /dev/null +++ b/tests/test4+ machine light_bulb+ [+ states [ light_on , light_off ];+ events [ turn_on , turn_off , switch ];+ starting on light_off;+ transitions+ [+ from light_on to light_off on event turn_off execute kek2 | kek;+ from light_on to light_off on event switch;+ from light_off to light_on on event turn_on;+ from light_off to light_on on event switch execute kek;++ ];+ ];+ machine temp_switch+ [+ states [A,B];+ events [A];+ starting on A;+ transitions+ [+ from ( A && !light_on ) to B on event A execute kek;+ ];+ ];