F diff --git a/src/backend/backend.c b/src/backend/backend.c --- a/src/backend/backend.c +++ b/src/backend/backend.c/*traverse transitions and push them into the queue of their coresponding state*/for(i=0;i<transitions->size;++i){- hold_state=extract_state(transitions->transitions[i]->from,states);-- assert(hold_state!=NULL);-+ hold_state=transitions->transitions[i]->from;Queue_Push(qs+hold_state->number,transitions->transitions[i]);}size_t i;for(i=0;i<machine->transitions->size;++i){- machine->transitions->transitions[i]->from=anotate_expression(machine->transitions->transitions[i]->from,unit,machine,translation_data);+ machine->transitions->transitions[i]->statement=anotate_statement(machine->transitions->transitions[i]->statement,unit,machine,translation_data);}if(has_new_errors(translation_data)){delete_ast_machine(machine);}}+ struct AST* anotate_statement(struct AST *statement,struct AST_Translation_Unit *unit,struct AST_Machine *current_machine,struct Translation_Data *translation_data)+ {+ if(statement==NULL)return NULL;+ if(statement->type==AST_TYPE_IF)+ {+ ((struct AST_If_Statement*)statement)->condition=anotate_expression(((struct AST_If_Statement*)statement)->condition,unit,current_machine,translation_data);+ }else+ {+ return statement;+ }+ }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;}else{hold_left=(struct AST*)ast_check_state((struct AST_Unchecked_State*)hold_right,hold_machine->states,translation_data);- ((struct AST_State*)hold_left)->parent=hold_machine;- return hold_left;+ if(hold_left)+ {+ ((struct AST_State*)hold_left)->parent=hold_machine;+ delete_ast(hold_right);+ return hold_left;+ }else+ {+ push_error_with_token("state id from foreign machine is undefined",((struct AST_Unchecked_State*)hold_right)->name,translation_data);+ delete_ast(hold_right);+ return NULL;+ }}}else{F diff --git a/src/backend/backend.h b/src/backend/backend.h --- a/src/backend/backend.h +++ b/src/backend/backend.hvoid 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_statement(struct AST *statement,struct AST_Translation_Unit *unit,struct AST_Machine *current_machine,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);F 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.cast_event_to_c_enum(out,machine,vector->transitions[i]->event);fprintf(out,":\n");- ast_pipeline_to_c(out,3,vector->transitions[i]->pipeline);+ //ast_pipeline_to_c(out,3,vector->transitions[i]->pipeline);+ ast_statement_to_c(out,3,vector->transitions[i]->statement);fprintf(out,"\t\t\tmachine_states[");ast_token_to_c(out,machine->id);fprintf(out,"]=");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);++ }#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.hvoid 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_statement_to_c(FILE *out,size_t indentation,struct AST *statement);+ void ast_if_to_c(FILE *out,size_t indentation,struct AST_If_Statement *statement);+ void ast_expression_to_c(FILE *out,struct AST *expression);+ void ast_expression_state_to_c(FILE *out,struct AST_State *state);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);F diff --git a/src/backend/targets/print/print.c b/src/backend/targets/print/print.c --- a/src/backend/targets/print/print.c +++ b/src/backend/targets/print/print.ccase KW_NOT:printf("KW_NOT");break;+ case KW_IF:+ printf("KW_IF");+ break;+ case KW_ELSE:+ printf("KW_ELSE");+ break;default:printf("LEXERROR");}case AST_TYPE_UNFINISHED_STATE:printf("AST_TYPE_UNFINISHED_STATE");break;+ case AST_TYPE_IF:+ printf("AST_TYPE_IF");+ break;default:printf("AST_NOP");}case AST_TYPE_UNFINISHED_STATE:print_ast_unchecked_state((struct AST_Unchecked_State*)tree);break;+ case AST_TYPE_IF:+ print_ast_if_statement((struct AST_If_Statement*)tree);+ break;default:printf("noast");}assert(tree);printf("TRANSITION [\nFROM");- print_ast(tree->from);+ print_ast_state(tree->from);printf(" TO ");print_ast_state(tree->to);printf(" COMMAND {");- if(tree->pipeline==NULL)+ if(tree->statement==NULL){printf("NULL");}else{- print_ast_pipeline(tree->pipeline);+ print_ast(tree->statement);}}{print_token(tree->name);}+ void print_ast_if_statement(struct AST_If_Statement *tree)+ {+ printf("if <");+ print_ast(tree->condition);+ printf(">\n");+ print_ast(tree->body);+ if(tree->else_statement)+ print_ast(tree->else_statement);+ }#endifF diff --git a/src/backend/targets/print/print.h b/src/backend/targets/print/print.h --- a/src/backend/targets/print/print.h +++ b/src/backend/targets/print/print.hvoid print_ast_binary_expression(struct AST_Binary_Expression *tree);void print_ast_unary_expression(struct AST_Unary_Expression *tree);void print_ast_unchecked_state(struct AST_Unchecked_State *tree);+ void print_ast_if_statement(struct AST_If_Statement *tree);void print_error(struct Error *error);void print_errors(struct Translation_Data *translation_data);F diff --git a/src/frontend/lexer.c b/src/frontend/lexer.c --- a/src/frontend/lexer.c +++ b/src/frontend/lexer.c#define LEX_ERROR(x) {push_lexing_error(x,src,translation_data); return get_token(src->src+src->where_in_src,0,KW_NOP,src->current_row,src->current_column);}/*- * placeholder very slow lexer that I will probabbly not replace+ * placeholder very slow ( and very very bad ) lexer that I will probabbly not replace*/void lex(struct Queue *token_destination,struct Source *src,struct Translation_Data *translation_data){return get_token(src->src+src->where_in_src-sizeof("event")+1,sizeof("event")-1,KW_EVENT,src->current_row,src->current_column);if(check_and_move_if_on_word("transitions",sizeof("transitions")-1,src,1))return get_token(src->src+src->where_in_src-sizeof("transitions")+1,sizeof("transitions")-1,KW_TRANSITIONS,src->current_row,src->current_column);+ if(check_and_move_if_on_word("if",sizeof("if")-1,src,1))+ return get_token(src->src+src->where_in_src-sizeof("if")+1,sizeof("if")-1,KW_IF,src->current_row,src->current_column);--+ if(check_and_move_if_on_word("else",sizeof("else")-1,src,1))+ return get_token(src->src+src->where_in_src-sizeof("else")+1,sizeof("else")-1,KW_ELSE,src->current_row,src->current_column);F diff --git a/src/frontend/lexer.h b/src/frontend/lexer.h --- a/src/frontend/lexer.h +++ b/src/frontend/lexer.hKW_AND,KW_OR,KW_NOT,+ KW_IF,+ KW_ELSE,};struct token{F diff --git a/src/frontend/parser.c b/src/frontend/parser.c --- a/src/frontend/parser.c +++ b/src/frontend/parser.c{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){+ Map_Push(hold_machines_map,hold_machine->id->data,hold_machine->id->size,hold_machine);Queue_Push(machines,hold_machine);}elsewhile((hold_transition=parse_transition(translation_data,states,events))!=NULL){Queue_Push(transitions,hold_transition);- if(!get_and_check(translation_data,KW_SEMI_COLUMN))- break;}if(transitions->size==0)struct AST_Transition* parse_transition(struct Translation_Data *translation_data,struct AST_States *states,struct AST_Events *events){struct AST_Transition *ret;- struct AST *hold_from;+ struct AST_State *hold_from;struct AST_State *hold_to;struct AST_Event *hold_event;- struct AST_Pipeline *hold_pipeline=NULL;+ struct AST *hold_statement=NULL;struct token *hold_token;if(get_and_check(translation_data,KW_FROM)){- hold_from=parse_expression(translation_data);- if(hold_from!=NULL)+ if(get_kw(translation_data)==KW_ID){- if(get_and_check(translation_data,KW_TO))+ hold_token=Queue_Pop(translation_data->tokens);+ hold_from=Map_Check(states->states_map,hold_token->data,hold_token->size);+ if(hold_from!=NULL){- if(get_kw(translation_data)==KW_ID)+ if(get_and_check(translation_data,KW_TO)){- 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_kw(translation_data)==KW_ID){- if(get_and_check(translation_data,KW_ON) && get_and_check(translation_data,KW_EVENT) )+ 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_kw(translation_data)==KW_ID)+ if(get_and_check(translation_data,KW_ON) && get_and_check(translation_data,KW_EVENT) ){- 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_kw(translation_data)==KW_ID){- 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; }+ 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_SEMI_COLUMN) && (hold_statement=parse_statement(translation_data,states,events))==NULL)+ { push_parsing_error("in statement of transition",translation_data); return NULL; }++ /*GOAL!!!!!*/+ return get_ast_transition(hold_from,hold_to,hold_event,hold_statement);+ }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 state id in from field",translation_data); return NULL; }}else { return NULL; }}++ /*+ * statement : 'execute' pipeline ; | 'if' expression statement [ else statement ]+ */+ struct AST* parse_statement(struct Translation_Data *translation_data,struct AST_States *states,struct AST_Events *events)+ {+ struct AST *hold_expression;+ struct AST *hold_body;+ struct AST *hold_else=NULL;++ if(get_and_check(translation_data,KW_EXECUTE))+ {+ hold_body=(struct AST*)parse_pipeline(translation_data);+ if(get_and_check(translation_data,KW_SEMI_COLUMN))+ {+ return hold_body;+ }else+ {+ push_parsing_error("expected ';' at the end of pipeline",translation_data);+ delete_ast(hold_body);+ return NULL;+ }+ }else if(get_and_check(translation_data,KW_IF))+ {+ hold_expression=parse_expression(translation_data);+ hold_body=parse_statement(translation_data,states,events);+ if(hold_body)+ {+ if(get_and_check(translation_data,KW_ELSE))+ {+ hold_else=parse_statement(translation_data,states,events);+ if(hold_else==NULL)+ {+ push_parsing_error("expected a statement after else",translation_data);+ delete_ast(hold_expression);+ delete_ast(hold_body);+ return NULL;+ }+ }+ return (struct AST*)get_ast_if_statement(hold_expression,hold_body,hold_else);+ }else+ {+ push_parsing_error("expected body statement in if",translation_data);+ if(hold_expression)+ delete_ast(hold_expression);+ return NULL;+ }+ }else+ {+ return NULL;+ }+ }/** pipeline: [ command ( | command )* ]*return ret;}- struct AST_Transition* get_ast_transition(struct AST *from,struct AST_State *to,struct AST_Event *event,struct AST_Pipeline *pipeline)+ struct AST_Transition* get_ast_transition(struct AST_State *from,struct AST_State *to,struct AST_Event *event,struct AST *statement){struct AST_Transition *ret;ret=malloc(sizeof(struct AST_Transition));ret->from=from;ret->to=to;ret->event=event;- ret->pipeline=pipeline;+ ret->statement=statement;return ret;}case AST_TYPE_UNFINISHED_STATE:delete_ast_unchecked_state((struct AST_Unchecked_State*)ast);break;-+ case AST_TYPE_IF:+ delete_ast_if_statement((struct AST_If_Statement*)ast);+ break;}}void delete_ast_event(struct AST_Event* ast)void delete_ast_transition(struct AST_Transition* ast){if(ast==NULL)return;- if(ast->pipeline!=NULL)- delete_ast_pipeline(ast->pipeline);+ if(ast->statement!=NULL)+ delete_ast(ast->statement);free(ast);}void delete_ast_command(struct AST_Command* ast)return parse_primary_expression(translation_data);}/*- * primary-expression: (expression) | id | id.id+ * primary-expression: (expression) | id.id*/struct AST* parse_primary_expression(struct Translation_Data *translation_data){}}else{- return (struct AST*)hold_id1;+ delete_ast((struct AST*)hold_id1);+ push_parsing_error("expected a selector",translation_data);+ return NULL;}}else{return ret;}+ struct AST_If_Statement* get_ast_if_statement(struct AST *condition,struct AST *body,struct AST *else_statement)+ {+ struct AST_If_Statement *ret;++ ret=malloc(sizeof(struct AST_If_Statement));+ ret->type=AST_TYPE_IF;+ ret->condition=condition;+ ret->body=body;+ ret->else_statement=else_statement;++ 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);+ push_error_with_token("undefined state",state->name,translation_data);+ delete_ast_unchecked_state(state);return NULL;}else{+ delete_ast_unchecked_state(state);return ret;}}delete_token(ast->name);free(ast);}+ void delete_ast_if_statement(struct AST_If_Statement *ast)+ {+ delete_ast(ast->condition);+ delete_ast(ast->body);+ if(ast->else_statement)+ delete_ast(ast->else_statement);+ }#endifF diff --git a/src/frontend/parser.h b/src/frontend/parser.h --- a/src/frontend/parser.h +++ b/src/frontend/parser.hAST_TYPE_OP_NOT,AST_TYPE_OP_SELECTOR,AST_TYPE_UNFINISHED_STATE,+ AST_TYPE_IF,};struct AST{struct AST_Transition{enum AST_Type type;- struct AST *from;+ struct AST_State *from;struct AST_State *to;struct AST_Event *event;- struct AST_Pipeline *pipeline;+ struct AST *statement;};struct AST_Command{enum AST_Type type;struct token *name;};+ struct AST_If_Statement+ {+ enum AST_Type type;+ struct AST *condition;+ struct AST *body;+ struct AST *else_statement;+ };struct AST* parse_source(struct Translation_Data *translation_data);struct AST_Event* parse_event(struct Translation_Data *translation_data);struct AST_Transitions* parse_transitions_inner(struct Translation_Data *translation_data,struct AST_States *states,struct AST_Events *events );struct AST_Transition* parse_transition(struct Translation_Data *translation_data,struct AST_States *states,struct AST_Events *events);++ struct AST* parse_statement(struct Translation_Data *translation_data,struct AST_States *states,struct AST_Events *events);+struct AST_Pipeline* parse_pipeline(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_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 *from,struct AST_State *to,struct AST_Event *event,struct AST_Pipeline *pipeline);+ struct AST_Transition* get_ast_transition(struct AST_State *from,struct AST_State *to,struct AST_Event *event,struct AST *statement);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 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_If_Statement* get_ast_if_statement(struct AST *condition,struct AST *body,struct AST *else_statement);+struct AST_State* ast_check_state(struct AST_Unchecked_State *state,struct AST_States *states,struct Translation_Data *translation_data);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 delete_ast_if_statement(struct AST_If_Statement *ast);void pointer_array_fill(void **array,struct Queue *q);F diff --git a/tests/.test5.swp b/tests/.test5.swp deleted file mode 100644B Binary files a/tests/.test5.swp and /dev/null differF diff --git a/tests/.test6.swp b/tests/.test6.swp new file mode 100644B Binary files /dev/null and b/tests/.test6.swp differF diff --git a/tests/test4 b/tests/test4 --- a/tests/test4 +++ b/tests/test4starting on A;transitions[- from ( !A && !light_on ) to B on event A execute kek;+ from A to B on event A+ if !light_bulb.light_on+ execute kek;];];F diff --git a/tests/test5 b/tests/test5 --- a/tests/test5 +++ b/tests/test5starting on A;transitions[- from A to A on event A given (B.C && !C.D)- execute eke;+ from A to A on event A+ if (A.A && !A.A)+ execute eke;+ else+ execute asdf;];];F diff --git a/tests/test6 b/tests/test6 new file mode 100644 --- /dev/null +++ b/tests/test6+ 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 granted !light_bulb.light_on+ if !light_bulb.light_on+ execute kek;+ ];+ ];