#ifndef PARSER_C #define PARSER_C PARSER_C #include struct AST* parse_source(struct Translation_Data *translation_data) { return (struct AST*)parse_translation_unit(translation_data); } /* * translation-unit: (machine)* */ struct AST_Translation_Unit* parse_translation_unit(struct Translation_Data *translation_data) { 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); } else { Map_Map(hold_command_map,(void (*)(void*))delete_ast_command); Map_Destroy(hold_command_map); while(machines->size>0) delete_ast_machine(Queue_Pop(machines)); return NULL; } } return get_ast_translation_unit(machines,hold_command_map,hold_machines_map); } /* * machine: 'machine' id '[' machine-inner ']' ';' * */ struct AST_Machine* parse_machine(struct Translation_Data *translation_data) { struct AST_Machine *ret; struct token *hold_id; if(get_and_check(translation_data,KW_MACHINE)) { if(get_kw(translation_data)==KW_ID) { hold_id=Queue_Pop(translation_data->tokens); if(get_and_check(translation_data,KW_OPEN_SQUARE)) { ret=(struct AST_Machine*)parse_machine_inner(hold_id,translation_data); if(has_new_errors(translation_data)) { delete_ast_machine(ret); touch_errors(translation_data); return NULL; } if(get_and_check(translation_data,KW_CLOSE_SQUARE)) { if(get_and_check(translation_data,KW_SEMI_COLUMN)) return ret; else { push_parsing_error("';' expected after machine definition",translation_data); delete_ast_machine(ret); return NULL; } }else { push_parsing_error("closing ']' expected",translation_data); delete_ast_machine(ret); return NULL; } }else { push_parsing_error("opening '[' expected",translation_data); return NULL; } }else { push_parsing_error("expected a name for the machine",translation_data); return NULL; } }else { push_parsing_error("'machine' expected",translation_data); return NULL; } } /* * machine-inner : 'states' '[' states-inner ']' ';' * 'events' '[' events-inner ']' ';' * 'transitions' '[' transitions-inner ']' ';' * 'starting' start-on-inner ';' */ struct AST_Machine* parse_machine_inner(struct token *machine_id,struct Translation_Data *translation_data) { struct AST_States *states=NULL; struct AST_Events *events=NULL; struct AST_Transitions *transitions=NULL; struct AST_State *starting_state=NULL; unsigned char i; for(i=0;i<4;++i) switch(get_kw(translation_data)) { case KW_STATES: if(states) { push_parsing_error("defining two sets of states",translation_data); goto error_cleanup; }else { chomp(translation_data); if(get_and_check(translation_data,KW_OPEN_SQUARE)) { states=parse_states_inner(translation_data); if(!get_and_check(translation_data,KW_CLOSE_SQUARE) || !get_and_check(translation_data,KW_SEMI_COLUMN)) { push_parsing_error("expected ']' and ';' at " "end of states definition",translation_data); goto error_cleanup; } }else { push_parsing_error("expected '[' ",translation_data); goto error_cleanup; } } break; case KW_TRANSITIONS: if(states==NULL && events==NULL) { push_parsing_error("defining transitions before states and events",translation_data); goto error_cleanup; }else if(transitions) { push_parsing_error("defining two sets of transitions",translation_data); goto error_cleanup; }else { chomp(translation_data); if(get_and_check(translation_data,KW_OPEN_SQUARE)) { transitions=parse_transitions_inner(translation_data,states,events); if(!get_and_check(translation_data,KW_CLOSE_SQUARE) || !get_and_check(translation_data,KW_SEMI_COLUMN)) { push_parsing_error("expected ']' and ';' at " "end of transitions definition",translation_data); goto error_cleanup; } }else { push_parsing_error("expected '[' ",translation_data); goto error_cleanup; } } break; case KW_EVENTS: if(events) { push_parsing_error("defining two sets of transitions",translation_data); goto error_cleanup; }else { chomp(translation_data); if(get_and_check(translation_data,KW_OPEN_SQUARE)) { events=parse_events_inner(translation_data); if(!get_and_check(translation_data,KW_CLOSE_SQUARE) || !get_and_check(translation_data,KW_SEMI_COLUMN)) { push_parsing_error("expected ']' and ';' at " "end of events definition",translation_data); goto error_cleanup; } }else { push_parsing_error("expected '[' ",translation_data); goto error_cleanup; } } break; case KW_STARTING: chomp(translation_data); if(!starting_state) { if(states) { starting_state=parse_start_on(translation_data,states); if(!get_and_check(translation_data,KW_SEMI_COLUMN)) { push_parsing_error("expected ';' at end " "of starting state declaration",translation_data); goto error_cleanup; } }else { push_parsing_error("states need to be defined" " before defining a starting one",translation_data); goto error_cleanup; } }else { push_parsing_error("starting state is defined",translation_data); goto error_cleanup; } break; default: push_parsing_error("expected states transitions or events",translation_data); goto error_cleanup; } return get_ast_machine(machine_id,states,events,transitions,starting_state); error_cleanup: push_parsing_error("in machine",translation_data); if(states)delete_ast_states(states); if(events)delete_ast_events(events); if(transitions)delete_ast_transitions(transitions); return NULL; } /* * states-inner: state (, state)* * */ struct AST_States* parse_states_inner(struct Translation_Data *translation_data) { struct Queue *ids; struct AST_State *hold_state; ids=parse_list((struct AST*(*)(struct Translation_Data*))parse_state,translation_data,KW_COMMA); if(ids->size==0) { push_parsing_error("there needs to be atleast one state",translation_data); free(ids); return NULL; }else { return get_ast_states(ids); } } /* * state : id * */ struct AST_State* parse_state(struct Translation_Data *translation_data) { if(get_kw(translation_data)==KW_ID) return get_ast_state(Queue_Pop(translation_data->tokens)); else return NULL; } /* * events-inner: id (, id)* * */ struct AST_Events* parse_events_inner(struct Translation_Data *translation_data) { struct Queue *ids; ids=parse_list((struct AST*(*)(struct Translation_Data*))parse_event,translation_data,KW_COMMA); if(ids->size==0) { push_parsing_error("there needs to be atleast one event",translation_data); return NULL; }else { return get_ast_events(ids); } } struct AST_Event* parse_event(struct Translation_Data *translation_data) { if(get_kw(translation_data)==KW_ID) return get_ast_event(Queue_Pop(translation_data->tokens)); else return NULL; } /* * transitions-inner: ( transition ;)* */ struct AST_Transitions* parse_transitions_inner(struct Translation_Data *translation_data,struct AST_States *states,struct AST_Events *events) { struct Queue *transitions; struct AST_Transition *hold_transition; transitions=malloc(sizeof(struct Queue)); Queue_Init(transitions); while((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) { 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); } } /* * transition: 'from' state_id 'to' state_id 'on' 'event' event_id [ 'execute' pipeline ] * */ struct AST_Transition* parse_transition(struct Translation_Data *translation_data,struct AST_States *states,struct AST_Events *events) { struct AST_Transition *ret; struct AST_State *hold_from; struct AST_State *hold_to; struct AST_Event *hold_event; struct AST_Pipeline *hold_pipeline=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_and_check(translation_data,KW_TO)) { 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) { if(get_and_check(translation_data,KW_ON) && get_and_check(translation_data,KW_EVENT) ) { 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) { 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; } } /* * pipeline: [ command ( | command )* ] * */ struct AST_Pipeline* parse_pipeline(struct Translation_Data *translation_data) { struct Queue *pipeline; pipeline=parse_list((struct AST*(*)(struct Translation_Data*))parse_command,translation_data,KW_PIPE); if(pipeline->size==0) { free(pipeline); push_parsing_error("pipeline is empty",translation_data); return NULL; }else { return get_ast_pipeline(pipeline); } } /* * command: id [ string ] * */ struct AST_Command* parse_command(struct Translation_Data *translation_data) { struct token *id; struct token *string=NULL; struct AST_Command *ret; if(get_kw(translation_data)==KW_ID) { id=Queue_Pop(translation_data->tokens); if(get_kw(translation_data)==KW_STRING) string=Queue_Pop(translation_data->tokens); ret=get_ast_command(id,string); 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; }else { push_parsing_error("expected command id",translation_data); return NULL; } } /* * starting-on-inner: 'on' id ; */ struct AST_State* parse_start_on(struct Translation_Data *translation_data,struct AST_States *states) { struct token *hold_id; struct AST_State *hold_state; if(get_and_check(translation_data,KW_ON)) { if(get_kw(translation_data)==KW_ID) { hold_id=Queue_Pop(translation_data->tokens); hold_state=Map_Check(states->states_map,hold_id->data,hold_id->size); free(hold_id); if(hold_state) { return hold_state; }else { push_parsing_error("starting state is not defined",translation_data); return NULL; } }else { push_parsing_error("expected an identifier for starting state",translation_data); return NULL; } }else { push_parsing_error("expected 'on'",translation_data); return NULL; } } struct AST_State* get_ast_state(struct token *id) { struct AST_State *ret; ret=malloc(sizeof(struct AST_State)); ret->name=id; /*number is assigned in get_ast_states*/ return ret; } struct AST_Event* get_ast_event(struct token *id) { struct AST_Event *ret; ret=malloc(sizeof(struct AST_Event)); ret->name=id; return ret; } struct AST_States* get_ast_states(struct Queue *states) { struct AST_States *ret; struct AST_State *hold_state; /*perhaps no states error should be handled here*/ assert(states && states->size>0); ret=malloc(sizeof(struct AST_States)+sizeof(struct AST_Event *[states->size])); ret->type=AST_TYPE_STATES; ret->number_of_states=states->size; ret->states_map=malloc(sizeof(struct Map)); Map_Init(ret->states_map); 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; } assert(states->size==0); free(states); return ret; } struct AST_Events* get_ast_events(struct Queue *events) { struct AST_Events *ret; struct AST_Event *hold_event; /*perhaps no events error should be handled here*/ assert(events && events->size>0); ret=malloc(sizeof(struct AST_Events)+sizeof(struct AST_Event *[events->size])); ret->type=AST_TYPE_EVENTS; ret->number_of_events=events->size; ret->events_map=malloc(sizeof(struct Map)); Map_Init(ret->events_map); 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; } assert(events->size==0); free(events); 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 *ret; ret=malloc(sizeof(struct AST_Transition)); ret->type=AST_TYPE_TRANSITION; ret->from=from; ret->to=to; ret->event=event; ret->pipeline=pipeline; return ret; } struct AST_Command* get_ast_command(struct token *function_name,struct token *argument) { struct AST_Command *ret; ret=malloc(sizeof(struct AST_Command)); ret->type=AST_TYPE_COMMAND; ret->function_name=function_name; ret->argument=argument; return ret; } struct AST_Pipeline* get_ast_pipeline(struct Queue *pipeline) { struct AST_Pipeline *ret; ret=malloc(sizeof(struct AST_Pipeline)+sizeof(struct AST_Command *[pipeline->size])); ret->type=AST_TYPE_PIPELINE; ret->size=pipeline->size; pointer_array_fill((void**)ret->pipeline,pipeline); assert(pipeline->size==0); free(pipeline); return ret; } 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_Machine *ret; ret=malloc(sizeof(struct AST_Machine)); ret->type=AST_TYPE_MACHINE; ret->id=id; ret->states=states; ret->events=events; ret->transitions=transitions; ret->starting_state=starting_state; return ret; } struct AST_Transitions* get_ast_transitions(struct Queue *transitions) { struct AST_Transitions *ret; ret=malloc(sizeof(struct AST_Transitions)+sizeof(struct AST_Transition *[transitions->size])); ret->type=AST_TYPE_TRANSITIONS; ret->size=transitions->size; pointer_array_fill((void**)ret->transitions,transitions); assert(transitions->size==0); free(transitions); return ret; } void delete_ast(struct AST* ast) { switch(ast->type) { case AST_TYPE_MACHINE: delete_ast_machine((struct AST_Machine*)ast); break; case AST_TYPE_STATE: delete_ast_state((struct AST_State*)ast); break; case AST_TYPE_STATES: delete_ast_states((struct AST_States*)ast); break; case AST_TYPE_EVENT: delete_ast_event((struct AST_Event*)ast); break; case AST_TYPE_EVENTS: delete_ast_events((struct AST_Events*)ast); break; case AST_TYPE_TRANSITION: delete_ast_transition((struct AST_Transition*)ast); break; case AST_TYPE_TRANSITIONS: delete_ast_transitions((struct AST_Transitions*)ast); break; case AST_TYPE_COMMAND: delete_ast_command((struct AST_Command*)ast); break; case AST_TYPE_PIPELINE: delete_ast_pipeline((struct AST_Pipeline*)ast); break; } } void delete_ast_event(struct AST_Event* ast) { if(ast==NULL)return; delete_token(ast->name); free(ast); } void delete_ast_states(struct AST_States* ast) { size_t i; if(ast==NULL)return; for(i=0;inumber_of_states;++i) delete_ast_state(ast->states[i]); free(ast); } void delete_ast_events(struct AST_Events* ast) { size_t i; if(ast==NULL)return; for(i=0;inumber_of_events;++i) delete_ast_event(ast->events[i]); free(ast); } void delete_ast_transition(struct AST_Transition* ast) { if(ast==NULL)return; if(ast->pipeline!=NULL) delete_ast_pipeline(ast->pipeline); free(ast); } void delete_ast_command(struct AST_Command* ast) { if(ast==NULL)return; delete_token(ast->function_name); if(ast->argument!=NULL) delete_token(ast->argument); free(ast); } void delete_ast_pipeline(struct AST_Pipeline* ast) { size_t i; if(ast==NULL)return; for(i=0;isize;++i) delete_ast_command(ast->pipeline[i]); free(ast); } void delete_ast_machine(struct AST_Machine* ast) { if(ast==NULL)return; if(ast->id!=NULL) delete_token(ast->id); if(ast->states!=NULL) delete_ast_states(ast->states); if(ast->events!=NULL) delete_ast_events(ast->events); if(ast->transitions!=NULL) delete_ast_transitions(ast->transitions); } void delete_ast_transitions(struct AST_Transitions* ast) { size_t i; if(ast==NULL)return; for(i=0;isize;++i) delete_ast_transition(ast->transitions[i]); free(ast); } void delete_ast_state(struct AST_State* ast) { if(ast==NULL)return; if(ast->name!=NULL) delete_token(ast->name); free(ast); } void pointer_array_fill(void **array,struct Queue *q) { size_t i; for(i=0;q->size>0;++i) array[i]=Queue_Pop(q); } struct Queue* parse_list(struct AST *(*parser)(struct Translation_Data*),struct Translation_Data *translation_data,enum Keyword delim) { struct Queue *q; struct AST* hold_ast; q=malloc(sizeof(struct Queue)); Queue_Init(q); while(hold_ast=parser(translation_data)) { Queue_Push(q,hold_ast); if(!get_and_check(translation_data,delim)) break; } return q; } void delete_ast_translation_unit(struct AST_Translation_Unit *ast) { size_t i; Map_Map(ast->used_commands_map,(void (*)(void*))delete_ast_command); Map_Destroy(ast->used_commands_map); for(i=0;inumber_of_machines;++i) { delete_ast_machine(ast->machines[i]); } free(ast->used_commands_map); free(ast); } 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) { hold_machine=Queue_Pop(machines); ret->machines[machines->size]=hold_machine; } 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); } #endif