#ifndef PARSER_C #define PARSER_C PARSER_C #include /* * parse-unit: machine * */ struct AST* parse_unit(struct Translation_Data *translation_data) { return (struct AST*)parse_machine(translation_data); } /* * 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 { 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)) { if(get_kw(translation_data)==KW_ID) { 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_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 { push_parsing_error("expected id in transition expression",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; 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); return get_ast_command(id,string); }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->type=AST_TYPE_STATE; ret->id=id; return ret; } struct AST_Event* get_ast_event(struct token *id) { struct AST_Event *ret; ret=malloc(sizeof(struct AST_Event)); ret->type=AST_TYPE_EVENT; ret->id=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); Map_Push(ret->states_map,hold_state->id->data,hold_state->id->size,hold_state); ret->states[states->size]=hold_state; } 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); Map_Push(ret->events_map,hold_event->id->data,hold_event->id->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_State *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; 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->id); 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->id!=NULL) delete_token(ast->id); 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; } #endif