F diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignoretags*.exe*.o+ buildF diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/CMakeLists.txt+ cmake_minimum_required (VERSION 3.13.4)+ project (AUTOMATA)++ include_directories(src/)+ include_directories(src/backend/)+ include_directories(src/frontend/)+ include_directories(src/misc/)+ include_directories(src/program/)++ set(SOURCES+ src/program/program.h+ src/program/program.c+ src/misc/queue.h+ src/misc/stack.h+ src/misc/map.h+ src/misc/queue.c+ src/misc/map.c+ src/misc/stack.c+ src/frontend/lexer.h+ src/frontend/parser.c+ src/frontend/lexer.c+ src/frontend/parser.h+ src/backend/print.h+ src/backend/print.c+ src/main.c+ )+ add_executable(main ${SOURCES})F diff --git a/lexer.c b/lexer.c deleted file mode 100644 --- a/lexer.c +++ /dev/null- #ifndef LEXER_C- #define LEXER_C- #include <lexer.h>-- #define IS_ID_CHAR(x) ( (x <= 'z' && x>='a') || ( x <= 'Z' && x >= 'A' ) || x=='_')- #define IS_DIGIT(x) ( x <= '9' && x >= '0' )- #define IS_ID_THING(x) ( IS_ID_CHAR(x) || IS_DIGIT(x))- #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- */- void lex(struct Queue *token_destination,struct Source *src,struct Translation_Data *translation_data)- {- skip_white_space(src);- while(src->where_in_src<src->src_size)- {- Queue_Push(token_destination,lex_step(src,translation_data));- if(has_new_errors(translation_data))- return;- else- skip_white_space(src);- }- Queue_Push(token_destination,get_token(NULL,0,KW_EOF,src->current_row,src->current_column));- }--- struct token* lex_step(struct Source *src,struct Translation_Data *translation_data)- {- if(check_and_move_if_on_word("machine",sizeof("machine")-1,src,1))- return get_token(src->src+src->where_in_src-sizeof("machine")+1,sizeof("machine")-1,KW_MACHINE,src->current_row,src->current_column);- if(check_and_move_if_on_word("from",sizeof("from")-1,src,1))- return get_token(src->src+src->where_in_src-sizeof("from")+1,sizeof("from")-1,KW_FROM,src->current_row,src->current_column);- if(check_and_move_if_on_word("to",sizeof("to")-1,src,1))- return get_token(src->src+src->where_in_src-sizeof("to")+1,sizeof("to")-1,KW_TO,src->current_row,src->current_column);- if(check_and_move_if_on_word("on",sizeof("on")-1,src,1))- return 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_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_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("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))- return get_token(src->src+src->where_in_src-sizeof("states")+1,sizeof("states")-1,KW_STATES,src->current_row,src->current_column);- if(check_and_move_if_on_word("events",sizeof("events")-1,src,1))- return get_token(src->src+src->where_in_src-sizeof("events")+1,sizeof("events")-1,KW_EVENTS,src->current_row,src->current_column);- if(check_and_move_if_on_word("execute",sizeof("execute")-1,src,1))- return get_token(src->src+src->where_in_src-sizeof("execute")+1,sizeof("execute")-1,KW_EXECUTE,src->current_row,src->current_column);- if(check_and_move_if_on_word("event",sizeof("event")-1,src,1))- 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(IS_ID_CHAR(src->src[src->where_in_src])) /*check for id*/- {- size_t i;-- ++src->where_in_src;- for( i=src->where_in_src ;- i < src->src_size && IS_ID_THING(src->src[i]);- ++i);--- i-=src->where_in_src;- src->where_in_src+=i;- return get_token(src->src + src->where_in_src - i - 1, i + 1, KW_ID,src->current_row,src->current_column);- }else if(src->src[src->where_in_src]=='"') /*check for string literal*/- {- size_t i;- ++src->where_in_src;- for( i=src->where_in_src ;- src->src[i]!='"' && i< src->src_size;- ++i);-- if(i==src->src_size)- {- LEX_ERROR("Unexpected end of file");- }else- {- i-=src->where_in_src;- src->where_in_src+=i+1;- return get_token(src->src + src->where_in_src-i-1, i, KW_STRING,src->current_row,src->current_column);- }-- }else- {- LEX_ERROR("Unexpected symbol");- }- }- struct token* get_token(char *data,size_t size,enum Keyword type,size_t row,size_t column)- {- struct token *ret;- ret=malloc(sizeof(struct token));- ret->data=data;- ret->size=size;- ret->type=type;- ret->row=row;- ret->column=column;-- return ret;- }- void delete_token(struct token *token)- {- free(token);- }-- /*word_size without the ending '\0' */- static char check_and_move_if_on_word(char *word,size_t word_size,struct Source *src,char needs_space_after)- {- size_t i;- if(src->where_in_src + word_size > src->src_size)- return 0;-- for(i=0;i<word_size && word[i]==src->src[src->where_in_src+i];++i);-- if(i<word_size)- {- return 0;- }- else if( (needs_space_after && isspace(src->src[src->where_in_src+i])) || !needs_space_after )- {- src->where_in_src+=i;- src->current_column+=i;- return 1;- }- else- {- return 0;- }- }- void skip_white_space(struct Source *src)- {- while(src->where_in_src<src->src_size && isspace(src->src[src->where_in_src]))- {- if(src->src[src->where_in_src]=='\n')- {- ++src->current_row;- src->current_column=0;- }- ++src->where_in_src;- }- }-- void push_token_into_map(struct token *token,struct Map *map,void *thing)- {- Map_Push(map,token->data,token->size,thing);- }- #endifF diff --git a/lexer.h b/lexer.h deleted file mode 100644 --- a/lexer.h +++ /dev/null- #ifndef LEXER_H- #define LEXER_H- #include <ctype.h> //isspace- #include <program.h>- #include <queue.h>- #include <map.h>-- struct Translation_Data;- struct Source;-- enum Keyword- {- KW_MACHINE,- KW_FROM,- KW_TO,- KW_ON,- KW_ID,- KW_STRING,- KW_NOP,- KW_EOF,- KW_OPEN_SQUARE,- KW_CLOSE_SQUARE,- KW_PIPE,- KW_SEMI_COLUMN,- KW_STARTING,- KW_STATES,- KW_EVENTS,- KW_EVENT,- KW_EXECUTE,- KW_TRANSITIONS,- KW_COMMA,- };- struct token- {- size_t size;- enum Keyword type;- char *data;- size_t row;- size_t column;- };-- void lex(struct Queue *token_destination,struct Source *src,struct Translation_Data *translation_data);- struct token* lex_step(struct Source *src,struct Translation_Data *translation_data);- struct token* get_token(char *data,size_t size,enum Keyword type,size_t row,size_t column);- void skip_white_space(struct Source *src);-- void push_token_into_map(struct token *token,struct Map *map,void *thing);--- void delete_token(struct token *token);- /*:X*/- static char check_and_move_if_on_word(char *word,size_t word_size,struct Source *src,char needs_space_after);-- #endifF diff --git a/main.c b/main.c deleted file mode 100644 --- a/main.c +++ /dev/null- #include <stdio.h>- #include <program.h>- #include <lexer.h>- #include <string.h>- #include <parser.h>- #include <print.h>---- int main(int argc,char **argv)- {- struct Options *options;- struct Source *source;- struct Program *program;- struct Translation_Data *translation_data;- struct AST* translation_unit;-- options=parse_command_line(argc,argv);- if(options->src_name==NULL)- {- printf("No source file specified\n");- return 0;- }- source=extract_source(strndup(options->src_name,100));- translation_data=get_translation_data();-- if(options->target==OPTION_TARGET_TOKENS || options->target==OPTION_TARGET_AST)- {- lex(translation_data->tokens,source,translation_data);- if(translation_data->errors->size>0)- {- printf("There was an error!\n");- print_tokens(translation_data->tokens);- return 1;- }else if(options->target==OPTION_TARGET_TOKENS)- {- print_tokens(translation_data->tokens);- }else if(options->target==OPTION_TARGET_AST) //we check because we will probably add more options- {- translation_unit=parse_unit(translation_data);- if(has_new_errors(translation_data))- {- print_errors(translation_data);- return 1;- }else- {- print_ast(translation_unit);- delete_ast(translation_unit);- }- }-- }else- {- assert(!"false");- }-- delete_source(source);- delete_options(options);- return 0;- }F diff --git a/makefile b/makefile deleted file mode 100644 --- a/makefile +++ /dev/null- INCLUDE_DIRS=-I .- CFLAGS="-g"- main.exe : main.c lexer.o queue.o print.o program.o parser.o map.o stack.o- gcc ${CFLAGS} main.c lexer.o queue.o print.o program.o parser.o map.o stack.o -o main.exe ${INCLUDE_DIRS}- lexer.o : lexer.c lexer.h- gcc ${CFLAGS} -c lexer.c -o lexer.o ${INCLUDE_DIRS}- queue.o : queue.c queue.h- gcc ${CFLAGS} -c queue.c -o queue.o ${INCLUDE_DIRS}- print.o : print.c print.h- gcc ${CFLAGS} -c print.c -o print.o ${INCLUDE_DIRS}- program.o : program.c program.h- gcc ${CFLAGS} -c program.c -o program.o ${INCLUDE_DIRS}- parser.o : parser.c parser.h- gcc ${CFLAGS} -c parser.c -o parser.o ${INCLUDE_DIRS}- map.o : map.c map.h- gcc ${CFLAGS} -c map.c -o map.o ${INCLUDE_DIRS}- stack.o : stack.c stack.h- gcc ${CFLAGS} -c stack.c -o stack.o ${INCLUDE_DIRS}- clear:- rm -rf lexer.o main.exe queue.o print.o program.o parser.o map.o stack.oF diff --git a/map.c b/map.c deleted file mode 100644 --- a/map.c +++ /dev/null- #ifndef GMAP_C- #define GMAP_C GMAP_C- #include <map.h>---- /*- * ID and residue and all of delta is assigned to NULL- * */- void Map_Init(Map *tree)- {- tree->is_final=0;- for(int i=0;i<256;++i)tree->delta[i] = NULL;- tree->ID = NULL;- }-- void Map_Scour(Map *tree,void *str,size_t size,size_t *where,Map **final_node)- {- for(- *where=0,*final_node=tree;- *where<size && final_node[0]->delta[((unsigned char*)str)[ where[0] ]]!=NULL;- ++where[0]- )- {- (*final_node) = (*final_node)->delta[((unsigned char*)str)[*where]];- }- }---- /*- * tree must not be null- * */- void Map_Push(Map *tree,void *str,size_t size,void *id)- {- size_t temp;- Map_Scour(tree,str,size,&temp,&tree);-- if(temp == size)- {- assert(tree->ID==NULL);- tree->ID=id;- tree->is_final=1;- return;- }- for(temp;temp<size;++temp)- {- tree=tree->delta[((unsigned char*)str)[temp]]=calloc(1,sizeof(Map));- /*- Map_Init(- tree=tree->delta[((unsigned char*)str)[temp]]=malloc(sizeof(Map))- );- */- }-- tree->ID=id;- tree->is_final=1;-- }--- /*- * scours the tree and returns the id of the node that recognises the str- * returns NULL if the string is not recognised- * */- void* Map_Check(Map *tree, void *str,size_t size)- {- size_t temp;- Map_Scour(tree,str,size,&temp,&tree);-- if(temp<size)- {- return NULL;- }else- {- return tree->ID; //this has been set to be the last reached node- }- }-- void Map_Remove(Map *tree, void *str,size_t size)- {- Stack stk;- Stack_Init(&stk);- size_t where;- char what_to_null=((char*)str)[0];-- Stack_Push(&stk,tree);-- for(where=0;where<size-1 && tree->delta[((unsigned char*)str)[where]]!=NULL;++where)- {- tree = tree->delta[((unsigned char*)str)[where]];- if(tree->is_final==1)- {- while(stk.size>0)Stack_Pop(&stk);- what_to_null=((char*)str)[where+1];- }- Stack_Push(&stk,tree);- }- if(tree->delta[((unsigned char*)str)[where]] == NULL)return;- free(tree->delta[((unsigned char*)str)[where]]);- while(stk.size>1)free(Stack_Pop(&stk));- tree=(Map*)Stack_Pop(&stk);- tree->delta[(unsigned char)what_to_null]=NULL;-- }- /*This function especially requires that the map has no loops*/- void Map_Map(Map *tree,void (*map)(void*))- {- if(tree->is_final==1)map(tree->ID);- for(int i=0;i<256;++i)- {- if(tree->delta[i]!=NULL)- {- Map_Map(tree->delta[i],map);- }- }- }-- /*first argument of map is the node id , the second is pass_data*/- void Map_Map_Extended(Map *tree,void (*map)(void*,void*),void* pass_data)- {- if(tree->is_final==1)map(tree->ID,pass_data);- for(int i=0;i<256;++i)- {- if(tree->delta[i]!=NULL)- {- Map_Map_Extended(tree->delta[i],map,pass_data);- }- }- }--- /*this does not destroy(free) any memory pointed to by a node in the Map. This does not free() the root (Map *tree) */- /*This function especially does not require that the map has no loop ( for example after grepification )*/- void Map_Destroy(Map *tree)- {- Stack path;- Stack nodes;- Map *current_node;- unsigned int i;--- Stack_Init(&path);- Stack_Init(&nodes);-- Stack_Push(&path,tree);- Stack_Push(&nodes,tree);-- /*- using DFS we fill up the nodes stack with all the used- (accessible) nodes.- */- while(path.size>0)- {- current_node=Stack_Pop(&path);- current_node->ID=&(current_node->ID);/*mark the node*/- for(i=0;i<256;++i)- {- if(current_node->delta[i]!=NULL && current_node->delta[i]->ID != &(current_node->delta[i]->ID) )- {- Stack_Push(&path,current_node->delta[i]);--- /*we mark the unmarked child of the current_node*/- current_node->delta[i]->ID=&(current_node->delta[i]->ID);- /*every node in nodes continues to be marked*/- Stack_Push(&nodes,current_node->delta[i]);- }- }-- }- /*- There should not be any duplicates in here- */- while(nodes.size>1)- {- current_node=Stack_Pop(&nodes);- /*Again the things that ID points to is not freed ( this structure is used to map the structure of data )- deletion of it is up to you.- */- free(current_node);- }- /*this is where the root is at- we don't delete it , but we must free the last stack node*/- Stack_Pop(&nodes);--- }-- /*requres that cpy has no loops*/- Map* Map_Copy(Map *cpy)- {- short i;- Map *ret;-- if(cpy==NULL)- {- return NULL;- }-- ret=malloc(sizeof(Map));- ret->is_final=cpy->is_final;- ret->ID=cpy->ID;-- for(i=0;i<256;++i)- {- ret->delta[i]=Map_Copy(cpy->delta[i]);- }- return ret;- }-- struct Map* Map_Check_And_Get(Map *tree, void *str,size_t size)- {- size_t temp;- Map_Scour(tree,str,size,&temp,&tree);-- if(temp<size)- {- return NULL;- }else- {- return tree;- }- }-- struct Map* Map_Push_And_Get(struct Map* tree,void *str,size_t size,void *id)- {- size_t temp;- Map_Scour(tree,str,size,&temp,&tree);-- if(temp == size)- {- if(tree->ID!=NULL)tree->ID=id;- tree->is_final=1;- return tree;- }-- for(temp;temp<size;++temp)- {- Map_Init(- tree=- tree->delta[((unsigned char*)str)[temp]]=- malloc(sizeof(Map))- );- }-- tree->ID=id;- tree->is_final=1;- return tree;- }-- void* Map_Check_And_Push(struct Map *tree,void *str,size_t size,void *id)- {- size_t temp;- Map_Scour(tree,str,size,&temp,&tree);-- if(temp == size)- {- if(!tree->is_final)- {- tree->ID=id;- tree->is_final=1;- }- return tree->ID;- }- for(temp;temp<size;++temp)- {- tree=tree->delta[((unsigned char*)str)[temp]]=calloc(1,sizeof(Map));- /*- Map_Init(- tree=tree->delta[((unsigned char*)str)[temp]]=malloc(sizeof(Map))- );- */- }-- tree->ID=id;- tree->is_final=1;- return NULL;- }- /*requires that the map has no loops. does not free the root node*/- /*TODO*/- void Map_Delete_Map(struct Map *tree)- {-- }- #endif //#ifndef GMAPF diff --git a/map.h b/map.h deleted file mode 100644 --- a/map.h +++ /dev/null- #ifndef GMAP_H- #define GMAP_H GMAP_H- #include <stdlib.h>- #include <stdio.h>- #include <stack.h>- #include <queue.h>- #include <assert.h>-- typedef struct Map Map;---- /*- * A looples automata with things attached to the nodes- * */- struct Map- {- char is_final;- Map *delta[256];- /*ID cannot point to itself ( this is used in the deletion of the map ) */- void *ID;- };-- void Map_Init(Map *tree);- void Map_Scour(Map *tree,void *str,size_t size,size_t *where,Map **final_node);- void Map_Push(Map *tree,void *str,size_t size,void *id);- void* Map_Check(Map *tree, void *str,size_t size);- struct Map* Map_Check_And_Get(Map *tree, void *str,size_t size);- void Map_Remove(Map *tree, void *str,size_t size);- void Map_Map(Map *tree,void (*map)(void*));- void Map_Map_Extended(Map *tree,void (*map)(void*,void*),void* pass_data);-- void Map_Destroy(Map *tree);- void Map_Delete_Map(struct Map *tree);- struct Condensed_Map* Map_Condense(Map* tree);-- struct Map* Map_Push_And_Get(struct Map* tree,void *str,size_t size,void *id);- /*returns NULL if id is not taken , returns pointer to taken id otherwise*/- void* Map_Check_And_Push(struct Map *tree,void *str,size_t size,void *id);-- #endifF diff --git a/parser.c b/parser.c deleted file mode 100644 --- a/parser.c +++ /dev/null- #ifndef PARSER_C- #define PARSER_C PARSER_C- #include <parser.h>-- /*- * 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;i<ast->number_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;i<ast->number_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;i<ast->size;++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;i<ast->size;++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;- }-- #endifF diff --git a/parser.h b/parser.h deleted file mode 100644 --- a/parser.h +++ /dev/null- #ifndef PARSER_H- #define PARSER_H PARSER_H- #include <program.h>- #include <stddef.h>- #include <assert.h>- #include <map.h>-- enum AST_Type- {- AST_TYPE_MACHINE,- AST_TYPE_STATE,- AST_TYPE_STATES,- AST_TYPE_EVENT,- AST_TYPE_EVENTS,- AST_TYPE_TRANSITION,- AST_TYPE_TRANSITIONS,- AST_TYPE_COMMAND,- AST_TYPE_PIPELINE,- };- struct AST- {- enum AST_Type type;- };- struct AST_State- {- enum AST_Type type;- struct token *id;- };- struct AST_Event- {- enum AST_Type type;- struct token *id;- };- struct AST_States- {- enum AST_Type type;- size_t number_of_states;- struct Map *states_map;- struct AST_State *states[];- };- struct AST_Events- {- enum AST_Type type;- size_t number_of_events;- struct Map *events_map;- struct AST_Event *events[];- };- struct AST_Transition- {- enum AST_Type type;- struct AST_State *from;- struct AST_State *to;- struct AST_Event *event;- struct AST_Pipeline *pipeline;- };- struct AST_Command- {- enum AST_Type type;- struct token *function_name;- struct token *argument;- };- struct AST_Pipeline- {- enum AST_Type type;- size_t size;- struct AST_Command *pipeline[];- };- struct AST_Machine- {- enum AST_Type type;- struct token *id;- struct AST_States *states;- struct AST_Events *events;- struct AST_Transitions *transitions;- };- struct AST_Transitions- {- enum AST_Type type;- size_t size;- struct AST_Transition *transitions[];- };--- struct AST* parse_unit(struct Translation_Data *translation_data);- struct AST_Machine* parse_machine(struct Translation_Data *translation_data);- struct AST_Machine* parse_machine_inner(struct token *machine_id,struct Translation_Data *translation_data);- struct AST_States* parse_states_inner(struct Translation_Data *translation_data);- struct AST_State* parse_state(struct Translation_Data *translation_data);- struct AST_Events* parse_events_inner(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_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_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_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);--- void delete_ast(struct AST* ast);- void delete_ast_event(struct AST_Event* ast);- void delete_ast_states(struct AST_States* ast);- void delete_ast_state(struct AST_State* ast);- void delete_ast_events(struct AST_Events* ast);- void delete_ast_transition(struct AST_Transition* ast);- void delete_ast_command(struct AST_Command* ast);- void delete_ast_pipeline(struct AST_Pipeline* ast);- void delete_ast_machine(struct AST_Machine* ast);- void delete_ast_transitions(struct AST_Transitions* 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);-- #endifF diff --git a/print.c b/print.c deleted file mode 100644 --- a/print.c +++ /dev/null- #ifndef PRINT_C- #define PRINT_C PRINT_C- #include<print.h>-- void print_keyword_enum(enum Keyword code)- {- switch(code)- {- case KW_MACHINE:- printf("KW_MACHINE");- break;- case KW_FROM:- printf("KW_FROM");- break;- case KW_TO:- printf("KW_TO");- break;- case KW_ON:- printf("KW_ON");- break;- case KW_ID:- printf("KW_ID");- break;- case KW_STRING:- printf("KW_STRING");- break;- case KW_NOP:- printf("KW_NOP");- break;- case KW_EOF:- printf("KW_EOF");- break;- case KW_OPEN_SQUARE:- printf("KW_OPEN_SQUARE");- break;- case KW_CLOSE_SQUARE:- printf("KW_CLOSE_SQUARE");- break;- case KW_PIPE:- printf("KW_PIPE");- break;- case KW_SEMI_COLUMN:- printf("KW_SEMI_COLUMN");- break;- case KW_STARTING:- printf("KW_STARTING");- break;- case KW_STATES:- printf("KW_STATES");- break;- case KW_EVENTS:- printf("KW_EVENTS");- break;- case KW_EVENT:- printf("KW_EVENT");- break;- case KW_TRANSITIONS:- printf("KW__TRANSITIONS");- break;- case KW_EXECUTE:- printf("KW_EXECUTE");- break;- case KW_COMMA:- printf("KW_COMMA");- break;- default:- printf("LEXERROR");- }- }- void print_token(struct token *token)- {- size_t i;- assert(token);-- printf("[ ");- print_keyword_enum(token->type);- printf(" ");- for(i=0;i<token->size;++i)- printf("%c",token->data[i]);- printf(" ] ");-- }- void print_tokens(struct Queue *tokens)- {- struct Queue_Node *it;- assert(tokens);-- for(it=tokens->first;it!=NULL;it=it->prev)- {- print_token( (struct token*)(it->data));- printf(" ");- }- }- void print_ast_enum(enum AST_Type type)- {- switch(type)- {- case AST_TYPE_MACHINE:- printf("AST_TYPE_MACHINE");- break;- case AST_TYPE_STATE:- printf("AST_TYPE_STATE");- break;- case AST_TYPE_STATES:- printf("AST_TYPE_STATES");- break;- case AST_TYPE_EVENT:- printf("AST_TYPE_EVENT");- break;- case AST_TYPE_EVENTS:- printf("AST_TYPE_EVENTS");- break;- case AST_TYPE_TRANSITION:- printf("AST_TYPE_TRANSITION");- break;- case AST_TYPE_TRANSITIONS:- printf("AST_TYPE_TRANSITIONS");- break;- case AST_TYPE_COMMAND:- printf("AST_TYPE_COMMAND");- break;- case AST_TYPE_PIPELINE:- printf("AST_TYPE_PIPELINE");- break;- default:- printf("AST_NOP");- }-- }- void print_ast(struct AST *tree)- {- assert(tree);-- switch(tree->type)- {- case AST_TYPE_MACHINE:- print_ast_machine((struct AST_Machine*)tree);- break;- case AST_TYPE_STATE:- print_ast_state((struct AST_State*)tree);- break;- case AST_TYPE_STATES:- print_ast_states((struct AST_States*)tree);- break;- case AST_TYPE_EVENT:- print_ast_event((struct AST_Event*)tree);- break;- case AST_TYPE_EVENTS:- print_ast_events((struct AST_Events*)tree);- break;- case AST_TYPE_TRANSITION:- print_ast_transition((struct AST_Transition*)tree);- break;- case AST_TYPE_TRANSITIONS:- print_ast_transitions((struct AST_Transitions*)tree);- break;- case AST_TYPE_COMMAND:- print_ast_command((struct AST_Command*)tree);- break;- case AST_TYPE_PIPELINE:- print_ast_pipeline((struct AST_Pipeline*)tree);- break;- default:- printf("noast");- }- }- void print_ast_state(struct AST_State* tree)- {- assert(tree);-- printf("[ STATE: ");- print_ast_enum(tree->type);- printf("]");- }- void print_ast_event(struct AST_Event* tree)- {- assert(tree);-- printf("[ EVENT: ");- print_ast_enum(tree->type);- printf("]");- }- void print_ast_states(struct AST_States* tree)- {- size_t i;- assert(tree);-- printf("STATES [\n");- for(i=0;i<tree->number_of_states;++i)- {- print_ast_state(tree->states[i]);- printf(" ");- }- printf("\n ] END STATES \n");- }- void print_ast_events(struct AST_Events* tree)- {- size_t i;- assert(tree);-- printf("EVENTS [\n");- for(i=0;i<tree->number_of_events;++i)- {- print_ast_event(tree->events[i]);- printf(" ");- }- printf("\n ] END EVENTS \n");- }- void print_ast_transition(struct AST_Transition* tree)- {- assert(tree);-- printf("TRANSITION [\nFROM");- print_ast_state(tree->from);- printf(" TO ");- print_ast_state(tree->to);- printf(" COMMAND {");- if(tree->pipeline==NULL)- {- printf("NULL");- }else- {- print_ast_pipeline(tree->pipeline);- }-- }- void print_ast_command(struct AST_Command* tree)- {- assert(tree);-- printf("( command ");- print_token(tree->function_name);- if(tree->argument==NULL)- {- printf(" NOARGUMENTS ");- }else- {- printf(" \"");- print_token(tree->argument);- printf("\" ");- }- printf(")");- }- void print_ast_pipeline(struct AST_Pipeline* tree)- {- size_t i;- assert(tree);- printf("PIPELINE <");- for(i=0;i<tree->size;++i)- {- print_ast_command(tree->pipeline[i]);- printf(" | ");- }- printf("> PIPELINE_END");- }- void print_ast_machine(struct AST_Machine* tree)- {- assert(tree);- printf("MACHINE ");- print_token(tree->id);- printf(" [\n");- print_ast_states(tree->states);- print_ast_events(tree->events);- print_ast_transitions(tree->transitions);- printf("] MACHINE_END\n");- }- void print_ast_transitions(struct AST_Transitions* tree)- {- size_t i;- assert(tree);- printf("TRANSITIONS [\n");- for(i=0;i<tree->size;++i)- {- print_ast_transition(tree->transitions[i]);- printf("\n");- }- printf("] TRANSITIONS_END\n");- }- void print_error(struct Error *error)- {- assert(error);- printf("Error: %s, line %ld row %ld\n",error->message,error->row,error->column);- }- void print_errors(struct Translation_Data *translation_data)- {- struct Queue_Node *it;- assert(translation_data);-- for(it=translation_data->errors->first;it!=NULL;it=it->prev)- {- print_error(it->data);- }- }- #endifF diff --git a/print.h b/print.h deleted file mode 100644 --- a/print.h +++ /dev/null- #ifndef PRINT_H- #define PRINT_H PRINT_H- #include <stdio.h>- #include <lexer.h>- #include <parser.h>- #include <queue.h>--- void print_keyword_enum(enum Keyword code);- void print_token(struct token *token);- void print_tokens(struct Queue *tokens);-- void print_ast_enum(enum AST_Type type);- void print_ast(struct AST *tree);- void print_ast_state(struct AST_State* tree);- void print_ast_event(struct AST_Event* tree);- void print_ast_states(struct AST_States* tree);- void print_ast_events(struct AST_Events* tree);- void print_ast_transition(struct AST_Transition* tree);- void print_ast_command(struct AST_Command* tree);- void print_ast_pipeline(struct AST_Pipeline* tree);- void print_ast_machine(struct AST_Machine* tree);- void print_ast_transitions(struct AST_Transitions* tree);-- void print_error(struct Error *error);- void print_errors(struct Translation_Data *translation_data);- #endifF diff --git a/program.c b/program.c deleted file mode 100644 --- a/program.c +++ /dev/null- #ifndef PROGRAM_C- #define PROGRAM_C- #include<program.h>-- struct Source* extract_source(char *src_name)- {- FILE *file;-- struct Source *ret;-- file=fopen(src_name,"r");- if(file==NULL)- return NULL;- if(fseek(file,0L,SEEK_END)!=0)- return NULL;-- ret=malloc(sizeof(struct Source));- ret->src_size=ftell(file);- ret->where_in_src=0;- ret->src_name=src_name;- ret->src=malloc(ret->src_size);- ret->current_column=0;- ret->current_row=0;-- fseek(file,0L,SEEK_SET);--- fread(ret->src,sizeof(char),ret->src_size,file);-- fclose(file);- return ret;- }- struct Options* parse_command_line(int argc,char **argv)- {- struct Options *ret;- int i;-- assert(argv!=NULL && argc>0);-- ret=malloc(sizeof(struct Options));- ret->target=OPTION_DEFAULT;- ret->src_name=NULL;- ret->is_quiet=0;-- for(i=0;i<argc;++i)- {- if(!strncmp(argv[i],"--print-tokens",sizeof("--print-tokens")))- ret->target=OPTION_TARGET_TOKENS;- else if(!strncmp(argv[i],"--print-ast",sizeof("--print-ast")))- ret->target=OPTION_TARGET_AST;- else if(!strncmp(argv[i],"-o",sizeof("-o")) || !strncmp(argv[i],"--output",sizeof("--output")))- {- if(++i<argc)- {- if(strnlen(argv[i],101)<100)- ret->src_name=argv[i];- else if(!ret->is_quiet)- {- fprintf(stderr,"Error: Output filename is too long");- exit(1);- }else- {- exit(1);- }- }- }else if(strnlen(argv[i],101)<100)- {- ret->src_name=argv[i];- }else if(!ret->is_quiet)- {- fprintf(stderr,"Error: Input filename is too long");- exit(1);- }else- {- exit(1);- }-- }-- if(ret->target==OPTION_DEFAULT)- ret->target=OPTION_TARGET_AST;-- return ret;- }- struct Translation_Data* get_translation_data()- {- struct Translation_Data *ret;- ret=malloc(sizeof(struct Translation_Data));- ret->errors=malloc(sizeof(struct Queue));- ret->tokens=malloc(sizeof(struct Queue));-- Queue_Init(ret->errors);- Queue_Init(ret->tokens);-- ret->hold_number_of_errors=0;-- return ret;- }- struct Error* get_error(char *message,size_t row,size_t column)- {- struct Error *ret;- ret=malloc(sizeof(struct Error));- ret->message=message;- ret->row=row+1;- ret->column=column+1;- }- void push_lexing_error(char *error_message,struct Source *src,struct Translation_Data *translation_data)- {- Queue_Push(translation_data->errors,get_error(error_message,src->current_row,src->current_column));- }- void push_parsing_error(char *error_message,struct Translation_Data *translation_data)- {- struct token *error_token;- error_token=Queue_Pop(translation_data->tokens);- Queue_Push(translation_data->errors,get_error(error_message,error_token->row,error_token->column));- }- char has_new_errors(struct Translation_Data *translation_data)- {- if(translation_data->hold_number_of_errors!=translation_data->errors->size)- {- translation_data->hold_number_of_errors=translation_data->errors->size;- return 1;- }else- {- return 0;- }- }-- void delete_translation_data(struct Translation_Data *data)- {- struct Error *hold_error;- struct token *hold_token;-- while(data->tokens->size>0)- delete_token(Queue_Pop(data->tokens));- free(data->tokens);- while(data->errors->size>0)- delete_error(Queue_Pop(data->errors));- free(data->errors);-- free(data);- }- void delete_source(struct Source *src)- {- free(src->src_name);- free(src->src);- free(src);- }- void delete_options(struct Options *options)- {- free(options);- }- void delete_error(struct Error *error)- {- free(error->message);- free(error);- }- char get_and_check(struct Translation_Data *translation_data,enum Keyword kw)- {- if( ( (struct token *)translation_data->tokens->first->data)->type==kw)- {- delete_token(Queue_Pop(translation_data->tokens));- return 1;- }else- {- return 0;- }- }- enum Keyword get_kw(struct Translation_Data *translation_data)- {- return ( (struct token*)translation_data->tokens->first->data)->type;- }- void chomp(struct Translation_Data *translation_data)- {- assert(translation_data->tokens->size>0);- delete_token(Queue_Pop(translation_data->tokens));- }- void touch_errors(struct Translation_Data *translation_data)- {- assert(translation_data->hold_number_of_errors>0);- --translation_data->hold_number_of_errors;- }- #endifF diff --git a/program.h b/program.h deleted file mode 100644 --- a/program.h +++ /dev/null- #ifndef PROGRAM_H- #define PROGRAM_H- #include <stdlib.h>- #include <stdio.h>- #include <string.h>- #include <queue.h>- #include <lexer.h>- #include <assert.h>-- struct token;- enum Keyword;-- enum Options_Target_Type- {- OPTION_TARGET_TOKENS,- OPTION_TARGET_AST,- OPTION_DEFAULT,- };-- struct Source- {- size_t src_size;- size_t where_in_src;- size_t current_column;- size_t current_row;- char *src_name;- char *src;-- };-- struct Options- {- enum Options_Target_Type target;- int is_quiet:1;- char *src_name;- };-- struct Error- {- char *message;- size_t row;- size_t column;- };-- struct Translation_Data- {- struct Queue *errors;- struct Queue *tokens;- size_t hold_number_of_errors;- };- struct Program- {- struct Source *source;-- };-- struct Source* extract_source(char *src_name);- struct Options* parse_command_line(int argc,char **argv);- struct Translation_Data* get_translation_data();- struct Error* get_error(char *message,size_t row,size_t column);-- void 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);- 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);- enum Keyword get_kw(struct Translation_Data *translation_data);- void chomp(struct Translation_Data *translation_data);-- void delete_translation_data(struct Translation_Data *data);- void delete_source(struct Source *src);- void delete_options(struct Options *options);- void delete_error(struct Error *error);--- #endifF diff --git a/queue.c b/queue.c deleted file mode 100644 --- a/queue.c +++ /dev/null- #ifndef GQUEUE_C- #define GQUEUE_C GQUEUE_C- #include<queue.h>--- void Queue_Init(struct Queue *q)- {- q->first=q->last=NULL;- q->size=0;- }- void Queue_Push(struct Queue *q,void *data)- {- if(q==NULL)return;- if(q->first==NULL)- {- q->first=q->last=malloc(sizeof(struct Queue_Node));-- q->first->data=data;- q->first->prev=NULL;-- ++q->size;- }else- {- struct Queue_Node *temp=malloc(sizeof(struct Queue_Node));- q->last->prev=temp;- temp->data=data;- temp->prev=NULL;- q->last=temp;- ++q->size;- }-- }- void* Queue_Pop(struct Queue *q)- {- if(q==NULL)return NULL;- if(q->size==0)return NULL;-- void *return_value=q->first->data;-- if(q->size==1)- {- free(q->last);- q->first=q->last=NULL;- q->size=0;- }else- {- struct Queue_Node *temp_first=q->first;- q->first=q->first->prev;- free(temp_first);- --q->size;- }- return return_value;- }- void Queue_Destroy(struct Queue *q)- {-- struct Queue_Node *temp_first;- while(q->first!=NULL)- {- temp_first=q->first;- q->first=q->first->prev;- free(temp_first->data);- free(temp_first);- }-- }- #endifF diff --git a/queue.h b/queue.h deleted file mode 100644 --- a/queue.h +++ /dev/null- #ifndef GQUEUE_H- #define GQUEUE_H GQUEUE_H- #include<stdlib.h>--- struct Queue_Node- {- void *data;- struct Queue_Node *prev;- };-- struct Queue- {- struct Queue_Node *first,*last;- size_t size;-- };-- void Queue_Init(struct Queue *q);- void Queue_Push(struct Queue *q,void *data);- void* Queue_Pop(struct Queue *q);- void Queue_Destroy(struct Queue *q);- #endifF diff --git a/src/backend/print.c b/src/backend/print.c new file mode 100644 --- /dev/null +++ b/src/backend/print.c+ #ifndef PRINT_C+ #define PRINT_C PRINT_C+ #include<print.h>++ void print_keyword_enum(enum Keyword code)+ {+ switch(code)+ {+ case KW_MACHINE:+ printf("KW_MACHINE");+ break;+ case KW_FROM:+ printf("KW_FROM");+ break;+ case KW_TO:+ printf("KW_TO");+ break;+ case KW_ON:+ printf("KW_ON");+ break;+ case KW_ID:+ printf("KW_ID");+ break;+ case KW_STRING:+ printf("KW_STRING");+ break;+ case KW_NOP:+ printf("KW_NOP");+ break;+ case KW_EOF:+ printf("KW_EOF");+ break;+ case KW_OPEN_SQUARE:+ printf("KW_OPEN_SQUARE");+ break;+ case KW_CLOSE_SQUARE:+ printf("KW_CLOSE_SQUARE");+ break;+ case KW_PIPE:+ printf("KW_PIPE");+ break;+ case KW_SEMI_COLUMN:+ printf("KW_SEMI_COLUMN");+ break;+ case KW_STARTING:+ printf("KW_STARTING");+ break;+ case KW_STATES:+ printf("KW_STATES");+ break;+ case KW_EVENTS:+ printf("KW_EVENTS");+ break;+ case KW_EVENT:+ printf("KW_EVENT");+ break;+ case KW_TRANSITIONS:+ printf("KW__TRANSITIONS");+ break;+ case KW_EXECUTE:+ printf("KW_EXECUTE");+ break;+ case KW_COMMA:+ printf("KW_COMMA");+ break;+ default:+ printf("LEXERROR");+ }+ }+ void print_token(struct token *token)+ {+ size_t i;+ assert(token);++ printf("[ ");+ print_keyword_enum(token->type);+ printf(" ");+ for(i=0;i<token->size;++i)+ printf("%c",token->data[i]);+ printf(" ] ");++ }+ void print_tokens(struct Queue *tokens)+ {+ struct Queue_Node *it;+ assert(tokens);++ for(it=tokens->first;it!=NULL;it=it->prev)+ {+ print_token( (struct token*)(it->data));+ printf(" ");+ }+ }+ void print_ast_enum(enum AST_Type type)+ {+ switch(type)+ {+ case AST_TYPE_MACHINE:+ printf("AST_TYPE_MACHINE");+ break;+ case AST_TYPE_STATE:+ printf("AST_TYPE_STATE");+ break;+ case AST_TYPE_STATES:+ printf("AST_TYPE_STATES");+ break;+ case AST_TYPE_EVENT:+ printf("AST_TYPE_EVENT");+ break;+ case AST_TYPE_EVENTS:+ printf("AST_TYPE_EVENTS");+ break;+ case AST_TYPE_TRANSITION:+ printf("AST_TYPE_TRANSITION");+ break;+ case AST_TYPE_TRANSITIONS:+ printf("AST_TYPE_TRANSITIONS");+ break;+ case AST_TYPE_COMMAND:+ printf("AST_TYPE_COMMAND");+ break;+ case AST_TYPE_PIPELINE:+ printf("AST_TYPE_PIPELINE");+ break;+ default:+ printf("AST_NOP");+ }++ }+ void print_ast(struct AST *tree)+ {+ assert(tree);++ switch(tree->type)+ {+ case AST_TYPE_MACHINE:+ print_ast_machine((struct AST_Machine*)tree);+ break;+ case AST_TYPE_STATE:+ print_ast_state((struct AST_State*)tree);+ break;+ case AST_TYPE_STATES:+ print_ast_states((struct AST_States*)tree);+ break;+ case AST_TYPE_EVENT:+ print_ast_event((struct AST_Event*)tree);+ break;+ case AST_TYPE_EVENTS:+ print_ast_events((struct AST_Events*)tree);+ break;+ case AST_TYPE_TRANSITION:+ print_ast_transition((struct AST_Transition*)tree);+ break;+ case AST_TYPE_TRANSITIONS:+ print_ast_transitions((struct AST_Transitions*)tree);+ break;+ case AST_TYPE_COMMAND:+ print_ast_command((struct AST_Command*)tree);+ break;+ case AST_TYPE_PIPELINE:+ print_ast_pipeline((struct AST_Pipeline*)tree);+ break;+ default:+ printf("noast");+ }+ }+ void print_ast_state(struct AST_State* tree)+ {+ assert(tree);++ printf("[ STATE: ");+ print_ast_enum(tree->type);+ printf("]");+ }+ void print_ast_event(struct AST_Event* tree)+ {+ assert(tree);++ printf("[ EVENT: ");+ print_ast_enum(tree->type);+ printf("]");+ }+ void print_ast_states(struct AST_States* tree)+ {+ size_t i;+ assert(tree);++ printf("STATES [\n");+ for(i=0;i<tree->number_of_states;++i)+ {+ print_ast_state(tree->states[i]);+ printf(" ");+ }+ printf("\n ] END STATES \n");+ }+ void print_ast_events(struct AST_Events* tree)+ {+ size_t i;+ assert(tree);++ printf("EVENTS [\n");+ for(i=0;i<tree->number_of_events;++i)+ {+ print_ast_event(tree->events[i]);+ printf(" ");+ }+ printf("\n ] END EVENTS \n");+ }+ void print_ast_transition(struct AST_Transition* tree)+ {+ assert(tree);++ printf("TRANSITION [\nFROM");+ print_ast_state(tree->from);+ printf(" TO ");+ print_ast_state(tree->to);+ printf(" COMMAND {");+ if(tree->pipeline==NULL)+ {+ printf("NULL");+ }else+ {+ print_ast_pipeline(tree->pipeline);+ }++ }+ void print_ast_command(struct AST_Command* tree)+ {+ assert(tree);++ printf("( command ");+ print_token(tree->function_name);+ if(tree->argument==NULL)+ {+ printf(" NOARGUMENTS ");+ }else+ {+ printf(" \"");+ print_token(tree->argument);+ printf("\" ");+ }+ printf(")");+ }+ void print_ast_pipeline(struct AST_Pipeline* tree)+ {+ size_t i;+ assert(tree);+ printf("PIPELINE <");+ for(i=0;i<tree->size;++i)+ {+ print_ast_command(tree->pipeline[i]);+ printf(" | ");+ }+ printf("> PIPELINE_END");+ }+ void print_ast_machine(struct AST_Machine* tree)+ {+ assert(tree);+ printf("MACHINE ");+ print_token(tree->id);+ printf(" [\n");+ print_ast_states(tree->states);+ print_ast_events(tree->events);+ print_ast_transitions(tree->transitions);+ printf("] MACHINE_END\n");+ }+ void print_ast_transitions(struct AST_Transitions* tree)+ {+ size_t i;+ assert(tree);+ printf("TRANSITIONS [\n");+ for(i=0;i<tree->size;++i)+ {+ print_ast_transition(tree->transitions[i]);+ printf("\n");+ }+ printf("] TRANSITIONS_END\n");+ }+ void print_error(struct Error *error)+ {+ assert(error);+ printf("Error: %s, line %ld row %ld\n",error->message,error->row,error->column);+ }+ void print_errors(struct Translation_Data *translation_data)+ {+ struct Queue_Node *it;+ assert(translation_data);++ for(it=translation_data->errors->first;it!=NULL;it=it->prev)+ {+ print_error(it->data);+ }+ }+ #endifF diff --git a/src/backend/print.h b/src/backend/print.h new file mode 100644 --- /dev/null +++ b/src/backend/print.h+ #ifndef PRINT_H+ #define PRINT_H PRINT_H+ #include <stdio.h>+ #include <lexer.h>+ #include <parser.h>+ #include <queue.h>+++ void print_keyword_enum(enum Keyword code);+ void print_token(struct token *token);+ void print_tokens(struct Queue *tokens);++ void print_ast_enum(enum AST_Type type);+ void print_ast(struct AST *tree);+ void print_ast_state(struct AST_State* tree);+ void print_ast_event(struct AST_Event* tree);+ void print_ast_states(struct AST_States* tree);+ void print_ast_events(struct AST_Events* tree);+ void print_ast_transition(struct AST_Transition* tree);+ void print_ast_command(struct AST_Command* tree);+ void print_ast_pipeline(struct AST_Pipeline* tree);+ void print_ast_machine(struct AST_Machine* tree);+ void print_ast_transitions(struct AST_Transitions* tree);++ void print_error(struct Error *error);+ void print_errors(struct Translation_Data *translation_data);+ #endifF diff --git a/src/frontend/lexer.c b/src/frontend/lexer.c new file mode 100644 --- /dev/null +++ b/src/frontend/lexer.c+ #ifndef LEXER_C+ #define LEXER_C+ #include <lexer.h>++ #define IS_ID_CHAR(x) ( (x <= 'z' && x>='a') || ( x <= 'Z' && x >= 'A' ) || x=='_')+ #define IS_DIGIT(x) ( x <= '9' && x >= '0' )+ #define IS_ID_THING(x) ( IS_ID_CHAR(x) || IS_DIGIT(x))+ #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+ */+ void lex(struct Queue *token_destination,struct Source *src,struct Translation_Data *translation_data)+ {+ skip_white_space(src);+ while(src->where_in_src<src->src_size)+ {+ Queue_Push(token_destination,lex_step(src,translation_data));+ if(has_new_errors(translation_data))+ return;+ else+ skip_white_space(src);+ }+ Queue_Push(token_destination,get_token(NULL,0,KW_EOF,src->current_row,src->current_column));+ }+++ struct token* lex_step(struct Source *src,struct Translation_Data *translation_data)+ {+ if(check_and_move_if_on_word("machine",sizeof("machine")-1,src,1))+ return get_token(src->src+src->where_in_src-sizeof("machine")+1,sizeof("machine")-1,KW_MACHINE,src->current_row,src->current_column);+ if(check_and_move_if_on_word("from",sizeof("from")-1,src,1))+ return get_token(src->src+src->where_in_src-sizeof("from")+1,sizeof("from")-1,KW_FROM,src->current_row,src->current_column);+ if(check_and_move_if_on_word("to",sizeof("to")-1,src,1))+ return get_token(src->src+src->where_in_src-sizeof("to")+1,sizeof("to")-1,KW_TO,src->current_row,src->current_column);+ if(check_and_move_if_on_word("on",sizeof("on")-1,src,1))+ return 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_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_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("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))+ return get_token(src->src+src->where_in_src-sizeof("states")+1,sizeof("states")-1,KW_STATES,src->current_row,src->current_column);+ if(check_and_move_if_on_word("events",sizeof("events")-1,src,1))+ return get_token(src->src+src->where_in_src-sizeof("events")+1,sizeof("events")-1,KW_EVENTS,src->current_row,src->current_column);+ if(check_and_move_if_on_word("execute",sizeof("execute")-1,src,1))+ return get_token(src->src+src->where_in_src-sizeof("execute")+1,sizeof("execute")-1,KW_EXECUTE,src->current_row,src->current_column);+ if(check_and_move_if_on_word("event",sizeof("event")-1,src,1))+ 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(IS_ID_CHAR(src->src[src->where_in_src])) /*check for id*/+ {+ size_t i;++ ++src->where_in_src;+ for( i=src->where_in_src ;+ i < src->src_size && IS_ID_THING(src->src[i]);+ ++i);+++ i-=src->where_in_src;+ src->where_in_src+=i;+ return get_token(src->src + src->where_in_src - i - 1, i + 1, KW_ID,src->current_row,src->current_column);+ }else if(src->src[src->where_in_src]=='"') /*check for string literal*/+ {+ size_t i;+ ++src->where_in_src;+ for( i=src->where_in_src ;+ src->src[i]!='"' && i< src->src_size;+ ++i);++ if(i==src->src_size)+ {+ LEX_ERROR("Unexpected end of file");+ }else+ {+ i-=src->where_in_src;+ src->where_in_src+=i+1;+ return get_token(src->src + src->where_in_src-i-1, i, KW_STRING,src->current_row,src->current_column);+ }++ }else+ {+ LEX_ERROR("Unexpected symbol");+ }+ }+ struct token* get_token(char *data,size_t size,enum Keyword type,size_t row,size_t column)+ {+ struct token *ret;+ ret=malloc(sizeof(struct token));+ ret->data=data;+ ret->size=size;+ ret->type=type;+ ret->row=row;+ ret->column=column;++ return ret;+ }+ void delete_token(struct token *token)+ {+ free(token);+ }++ /*word_size without the ending '\0' */+ static char check_and_move_if_on_word(char *word,size_t word_size,struct Source *src,char needs_space_after)+ {+ size_t i;+ if(src->where_in_src + word_size > src->src_size)+ return 0;++ for(i=0;i<word_size && word[i]==src->src[src->where_in_src+i];++i);++ if(i<word_size)+ {+ return 0;+ }+ else if( (needs_space_after && isspace(src->src[src->where_in_src+i])) || !needs_space_after )+ {+ src->where_in_src+=i;+ src->current_column+=i;+ return 1;+ }+ else+ {+ return 0;+ }+ }+ void skip_white_space(struct Source *src)+ {+ while(src->where_in_src<src->src_size && isspace(src->src[src->where_in_src]))+ {+ if(src->src[src->where_in_src]=='\n')+ {+ ++src->current_row;+ src->current_column=0;+ }+ ++src->where_in_src;+ }+ }++ void push_token_into_map(struct token *token,struct Map *map,void *thing)+ {+ Map_Push(map,token->data,token->size,thing);+ }+ #endifF diff --git a/src/frontend/lexer.h b/src/frontend/lexer.h new file mode 100644 --- /dev/null +++ b/src/frontend/lexer.h+ #ifndef LEXER_H+ #define LEXER_H+ #include <ctype.h> //isspace+ #include <program.h>+ #include <queue.h>+ #include <map.h>++ struct Translation_Data;+ struct Source;++ enum Keyword+ {+ KW_MACHINE,+ KW_FROM,+ KW_TO,+ KW_ON,+ KW_ID,+ KW_STRING,+ KW_NOP,+ KW_EOF,+ KW_OPEN_SQUARE,+ KW_CLOSE_SQUARE,+ KW_PIPE,+ KW_SEMI_COLUMN,+ KW_STARTING,+ KW_STATES,+ KW_EVENTS,+ KW_EVENT,+ KW_EXECUTE,+ KW_TRANSITIONS,+ KW_COMMA,+ };+ struct token+ {+ size_t size;+ enum Keyword type;+ char *data;+ size_t row;+ size_t column;+ };++ void lex(struct Queue *token_destination,struct Source *src,struct Translation_Data *translation_data);+ struct token* lex_step(struct Source *src,struct Translation_Data *translation_data);+ struct token* get_token(char *data,size_t size,enum Keyword type,size_t row,size_t column);+ void skip_white_space(struct Source *src);++ void push_token_into_map(struct token *token,struct Map *map,void *thing);+++ void delete_token(struct token *token);+ /*:X*/+ static char check_and_move_if_on_word(char *word,size_t word_size,struct Source *src,char needs_space_after);++ #endifF diff --git a/src/frontend/parser.c b/src/frontend/parser.c new file mode 100644 --- /dev/null +++ b/src/frontend/parser.c+ #ifndef PARSER_C+ #define PARSER_C PARSER_C+ #include <parser.h>++ /*+ * 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;i<ast->number_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;i<ast->number_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;i<ast->size;++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;i<ast->size;++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;+ }++ #endifF diff --git a/src/frontend/parser.h b/src/frontend/parser.h new file mode 100644 --- /dev/null +++ b/src/frontend/parser.h+ #ifndef PARSER_H+ #define PARSER_H PARSER_H+ #include <program.h>+ #include <stddef.h>+ #include <assert.h>+ #include <map.h>++ enum AST_Type+ {+ AST_TYPE_MACHINE,+ AST_TYPE_STATE,+ AST_TYPE_STATES,+ AST_TYPE_EVENT,+ AST_TYPE_EVENTS,+ AST_TYPE_TRANSITION,+ AST_TYPE_TRANSITIONS,+ AST_TYPE_COMMAND,+ AST_TYPE_PIPELINE,+ };+ struct AST+ {+ enum AST_Type type;+ };+ struct AST_State+ {+ enum AST_Type type;+ struct token *id;+ };+ struct AST_Event+ {+ enum AST_Type type;+ struct token *id;+ };+ struct AST_States+ {+ enum AST_Type type;+ size_t number_of_states;+ struct Map *states_map;+ struct AST_State *states[];+ };+ struct AST_Events+ {+ enum AST_Type type;+ size_t number_of_events;+ struct Map *events_map;+ struct AST_Event *events[];+ };+ struct AST_Transition+ {+ enum AST_Type type;+ struct AST_State *from;+ struct AST_State *to;+ struct AST_Event *event;+ struct AST_Pipeline *pipeline;+ };+ struct AST_Command+ {+ enum AST_Type type;+ struct token *function_name;+ struct token *argument;+ };+ struct AST_Pipeline+ {+ enum AST_Type type;+ size_t size;+ struct AST_Command *pipeline[];+ };+ struct AST_Machine+ {+ enum AST_Type type;+ struct token *id;+ struct AST_States *states;+ struct AST_Events *events;+ struct AST_Transitions *transitions;+ };+ struct AST_Transitions+ {+ enum AST_Type type;+ size_t size;+ struct AST_Transition *transitions[];+ };+++ struct AST* parse_unit(struct Translation_Data *translation_data);+ struct AST_Machine* parse_machine(struct Translation_Data *translation_data);+ struct AST_Machine* parse_machine_inner(struct token *machine_id,struct Translation_Data *translation_data);+ struct AST_States* parse_states_inner(struct Translation_Data *translation_data);+ struct AST_State* parse_state(struct Translation_Data *translation_data);+ struct AST_Events* parse_events_inner(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_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_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_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);+++ void delete_ast(struct AST* ast);+ void delete_ast_event(struct AST_Event* ast);+ void delete_ast_states(struct AST_States* ast);+ void delete_ast_state(struct AST_State* ast);+ void delete_ast_events(struct AST_Events* ast);+ void delete_ast_transition(struct AST_Transition* ast);+ void delete_ast_command(struct AST_Command* ast);+ void delete_ast_pipeline(struct AST_Pipeline* ast);+ void delete_ast_machine(struct AST_Machine* ast);+ void delete_ast_transitions(struct AST_Transitions* 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);++ #endifF diff --git a/src/main.c b/src/main.c new file mode 100644 --- /dev/null +++ b/src/main.c+ #include <stdio.h>+ #include <program.h>+ #include <lexer.h>+ #include <string.h>+ #include <parser.h>+ #include <print.h>++++ int main(int argc,char **argv)+ {+ struct Options *options;+ struct Source *source;+ struct Program *program;+ struct Translation_Data *translation_data;+ struct AST* translation_unit;++ options=parse_command_line(argc,argv);+ if(options->src_name==NULL)+ {+ printf("No source file specified\n");+ return 0;+ }+ source=extract_source(strndup(options->src_name,100));+ translation_data=get_translation_data();++ if(options->target==OPTION_TARGET_TOKENS || options->target==OPTION_TARGET_AST)+ {+ lex(translation_data->tokens,source,translation_data);+ if(translation_data->errors->size>0)+ {+ printf("There was an error!\n");+ print_tokens(translation_data->tokens);+ return 1;+ }else if(options->target==OPTION_TARGET_TOKENS)+ {+ print_tokens(translation_data->tokens);+ }else if(options->target==OPTION_TARGET_AST) //we check because we will probably add more options+ {+ translation_unit=parse_unit(translation_data);+ if(has_new_errors(translation_data))+ {+ print_errors(translation_data);+ return 1;+ }else+ {+ print_ast(translation_unit);+ delete_ast(translation_unit);+ }+ }++ }else+ {+ assert(!"false");+ }++ delete_source(source);+ delete_options(options);+ return 0;+ }F diff --git a/src/misc/map.c b/src/misc/map.c new file mode 100644 --- /dev/null +++ b/src/misc/map.c+ #ifndef GMAP_C+ #define GMAP_C GMAP_C+ #include <map.h>++++ /*+ * ID and residue and all of delta is assigned to NULL+ * */+ void Map_Init(Map *tree)+ {+ tree->is_final=0;+ for(int i=0;i<256;++i)tree->delta[i] = NULL;+ tree->ID = NULL;+ }++ void Map_Scour(Map *tree,void *str,size_t size,size_t *where,Map **final_node)+ {+ for(+ *where=0,*final_node=tree;+ *where<size && final_node[0]->delta[((unsigned char*)str)[ where[0] ]]!=NULL;+ ++where[0]+ )+ {+ (*final_node) = (*final_node)->delta[((unsigned char*)str)[*where]];+ }+ }++++ /*+ * tree must not be null+ * */+ void Map_Push(Map *tree,void *str,size_t size,void *id)+ {+ size_t temp;+ Map_Scour(tree,str,size,&temp,&tree);++ if(temp == size)+ {+ assert(tree->ID==NULL);+ tree->ID=id;+ tree->is_final=1;+ return;+ }+ for(temp;temp<size;++temp)+ {+ tree=tree->delta[((unsigned char*)str)[temp]]=calloc(1,sizeof(Map));+ /*+ Map_Init(+ tree=tree->delta[((unsigned char*)str)[temp]]=malloc(sizeof(Map))+ );+ */+ }++ tree->ID=id;+ tree->is_final=1;++ }+++ /*+ * scours the tree and returns the id of the node that recognises the str+ * returns NULL if the string is not recognised+ * */+ void* Map_Check(Map *tree, void *str,size_t size)+ {+ size_t temp;+ Map_Scour(tree,str,size,&temp,&tree);++ if(temp<size)+ {+ return NULL;+ }else+ {+ return tree->ID; //this has been set to be the last reached node+ }+ }++ void Map_Remove(Map *tree, void *str,size_t size)+ {+ Stack stk;+ Stack_Init(&stk);+ size_t where;+ char what_to_null=((char*)str)[0];++ Stack_Push(&stk,tree);++ for(where=0;where<size-1 && tree->delta[((unsigned char*)str)[where]]!=NULL;++where)+ {+ tree = tree->delta[((unsigned char*)str)[where]];+ if(tree->is_final==1)+ {+ while(stk.size>0)Stack_Pop(&stk);+ what_to_null=((char*)str)[where+1];+ }+ Stack_Push(&stk,tree);+ }+ if(tree->delta[((unsigned char*)str)[where]] == NULL)return;+ free(tree->delta[((unsigned char*)str)[where]]);+ while(stk.size>1)free(Stack_Pop(&stk));+ tree=(Map*)Stack_Pop(&stk);+ tree->delta[(unsigned char)what_to_null]=NULL;++ }+ /*This function especially requires that the map has no loops*/+ void Map_Map(Map *tree,void (*map)(void*))+ {+ if(tree->is_final==1)map(tree->ID);+ for(int i=0;i<256;++i)+ {+ if(tree->delta[i]!=NULL)+ {+ Map_Map(tree->delta[i],map);+ }+ }+ }++ /*first argument of map is the node id , the second is pass_data*/+ void Map_Map_Extended(Map *tree,void (*map)(void*,void*),void* pass_data)+ {+ if(tree->is_final==1)map(tree->ID,pass_data);+ for(int i=0;i<256;++i)+ {+ if(tree->delta[i]!=NULL)+ {+ Map_Map_Extended(tree->delta[i],map,pass_data);+ }+ }+ }+++ /*this does not destroy(free) any memory pointed to by a node in the Map. This does not free() the root (Map *tree) */+ /*This function especially does not require that the map has no loop ( for example after grepification )*/+ void Map_Destroy(Map *tree)+ {+ Stack path;+ Stack nodes;+ Map *current_node;+ unsigned int i;+++ Stack_Init(&path);+ Stack_Init(&nodes);++ Stack_Push(&path,tree);+ Stack_Push(&nodes,tree);++ /*+ using DFS we fill up the nodes stack with all the used+ (accessible) nodes.+ */+ while(path.size>0)+ {+ current_node=Stack_Pop(&path);+ current_node->ID=&(current_node->ID);/*mark the node*/+ for(i=0;i<256;++i)+ {+ if(current_node->delta[i]!=NULL && current_node->delta[i]->ID != &(current_node->delta[i]->ID) )+ {+ Stack_Push(&path,current_node->delta[i]);+++ /*we mark the unmarked child of the current_node*/+ current_node->delta[i]->ID=&(current_node->delta[i]->ID);+ /*every node in nodes continues to be marked*/+ Stack_Push(&nodes,current_node->delta[i]);+ }+ }++ }+ /*+ There should not be any duplicates in here+ */+ while(nodes.size>1)+ {+ current_node=Stack_Pop(&nodes);+ /*Again the things that ID points to is not freed ( this structure is used to map the structure of data )+ deletion of it is up to you.+ */+ free(current_node);+ }+ /*this is where the root is at- we don't delete it , but we must free the last stack node*/+ Stack_Pop(&nodes);+++ }++ /*requres that cpy has no loops*/+ Map* Map_Copy(Map *cpy)+ {+ short i;+ Map *ret;++ if(cpy==NULL)+ {+ return NULL;+ }++ ret=malloc(sizeof(Map));+ ret->is_final=cpy->is_final;+ ret->ID=cpy->ID;++ for(i=0;i<256;++i)+ {+ ret->delta[i]=Map_Copy(cpy->delta[i]);+ }+ return ret;+ }++ struct Map* Map_Check_And_Get(Map *tree, void *str,size_t size)+ {+ size_t temp;+ Map_Scour(tree,str,size,&temp,&tree);++ if(temp<size)+ {+ return NULL;+ }else+ {+ return tree;+ }+ }++ struct Map* Map_Push_And_Get(struct Map* tree,void *str,size_t size,void *id)+ {+ size_t temp;+ Map_Scour(tree,str,size,&temp,&tree);++ if(temp == size)+ {+ if(tree->ID!=NULL)tree->ID=id;+ tree->is_final=1;+ return tree;+ }++ for(temp;temp<size;++temp)+ {+ Map_Init(+ tree=+ tree->delta[((unsigned char*)str)[temp]]=+ malloc(sizeof(Map))+ );+ }++ tree->ID=id;+ tree->is_final=1;+ return tree;+ }++ void* Map_Check_And_Push(struct Map *tree,void *str,size_t size,void *id)+ {+ size_t temp;+ Map_Scour(tree,str,size,&temp,&tree);++ if(temp == size)+ {+ if(!tree->is_final)+ {+ tree->ID=id;+ tree->is_final=1;+ }+ return tree->ID;+ }+ for(temp;temp<size;++temp)+ {+ tree=tree->delta[((unsigned char*)str)[temp]]=calloc(1,sizeof(Map));+ /*+ Map_Init(+ tree=tree->delta[((unsigned char*)str)[temp]]=malloc(sizeof(Map))+ );+ */+ }++ tree->ID=id;+ tree->is_final=1;+ return NULL;+ }+ /*requires that the map has no loops. does not free the root node*/+ /*TODO*/+ void Map_Delete_Map(struct Map *tree)+ {++ }+ #endif //#ifndef GMAPF diff --git a/src/misc/map.h b/src/misc/map.h new file mode 100644 --- /dev/null +++ b/src/misc/map.h+ #ifndef GMAP_H+ #define GMAP_H GMAP_H+ #include <stdlib.h>+ #include <stdio.h>+ #include <stack.h>+ #include <queue.h>+ #include <assert.h>++ typedef struct Map Map;++++ /*+ * A looples automata with things attached to the nodes+ * */+ struct Map+ {+ char is_final;+ Map *delta[256];+ /*ID cannot point to itself ( this is used in the deletion of the map ) */+ void *ID;+ };++ void Map_Init(Map *tree);+ void Map_Scour(Map *tree,void *str,size_t size,size_t *where,Map **final_node);+ void Map_Push(Map *tree,void *str,size_t size,void *id);+ void* Map_Check(Map *tree, void *str,size_t size);+ struct Map* Map_Check_And_Get(Map *tree, void *str,size_t size);+ void Map_Remove(Map *tree, void *str,size_t size);+ void Map_Map(Map *tree,void (*map)(void*));+ void Map_Map_Extended(Map *tree,void (*map)(void*,void*),void* pass_data);++ void Map_Destroy(Map *tree);+ void Map_Delete_Map(struct Map *tree);+ struct Condensed_Map* Map_Condense(Map* tree);++ struct Map* Map_Push_And_Get(struct Map* tree,void *str,size_t size,void *id);+ /*returns NULL if id is not taken , returns pointer to taken id otherwise*/+ void* Map_Check_And_Push(struct Map *tree,void *str,size_t size,void *id);++ #endifF diff --git a/src/misc/queue.c b/src/misc/queue.c new file mode 100644 --- /dev/null +++ b/src/misc/queue.c+ #ifndef GQUEUE_C+ #define GQUEUE_C GQUEUE_C+ #include<queue.h>+++ void Queue_Init(struct Queue *q)+ {+ q->first=q->last=NULL;+ q->size=0;+ }+ void Queue_Push(struct Queue *q,void *data)+ {+ if(q==NULL)return;+ if(q->first==NULL)+ {+ q->first=q->last=malloc(sizeof(struct Queue_Node));++ q->first->data=data;+ q->first->prev=NULL;++ ++q->size;+ }else+ {+ struct Queue_Node *temp=malloc(sizeof(struct Queue_Node));+ q->last->prev=temp;+ temp->data=data;+ temp->prev=NULL;+ q->last=temp;+ ++q->size;+ }++ }+ void* Queue_Pop(struct Queue *q)+ {+ if(q==NULL)return NULL;+ if(q->size==0)return NULL;++ void *return_value=q->first->data;++ if(q->size==1)+ {+ free(q->last);+ q->first=q->last=NULL;+ q->size=0;+ }else+ {+ struct Queue_Node *temp_first=q->first;+ q->first=q->first->prev;+ free(temp_first);+ --q->size;+ }+ return return_value;+ }+ void Queue_Destroy(struct Queue *q)+ {++ struct Queue_Node *temp_first;+ while(q->first!=NULL)+ {+ temp_first=q->first;+ q->first=q->first->prev;+ free(temp_first->data);+ free(temp_first);+ }++ }+ #endifF diff --git a/src/misc/queue.h b/src/misc/queue.h new file mode 100644 --- /dev/null +++ b/src/misc/queue.h+ #ifndef GQUEUE_H+ #define GQUEUE_H GQUEUE_H+ #include<stdlib.h>+++ struct Queue_Node+ {+ void *data;+ struct Queue_Node *prev;+ };++ struct Queue+ {+ struct Queue_Node *first,*last;+ size_t size;++ };++ void Queue_Init(struct Queue *q);+ void Queue_Push(struct Queue *q,void *data);+ void* Queue_Pop(struct Queue *q);+ void Queue_Destroy(struct Queue *q);+ #endifF diff --git a/src/misc/stack.c b/src/misc/stack.c new file mode 100644 --- /dev/null +++ b/src/misc/stack.c+ #ifndef GSTACK_C+ #define GSTACK_C GSTACK_C+ #include "stack.h"++++ void Stack_Init(Stack *stack)+ {+ stack->size=0;+ stack->first=NULL;+ }+ void Stack_Push(Stack *stack,void* data)+ {+ struct Stack_Node *temp_node=malloc(sizeof(struct Stack_Node));+ temp_node->data=data;+ temp_node->next=stack->first;+ stack->first=temp_node;+ ++stack->size;+ }+ void* Stack_Pop(Stack *stack)+ {+ void* return_value=NULL;+ if(stack->first!=NULL)+ {+ struct Stack_Node *temp_first=stack->first;+ return_value=stack->first->data;++ --stack->size;+ stack->first=stack->first->next;+ free(temp_first);+ }++ return return_value;+ }++ #endif//#ifndef GSTACK_C+F diff --git a/src/misc/stack.h b/src/misc/stack.h new file mode 100644 --- /dev/null +++ b/src/misc/stack.h+ #ifndef GSTACK_H+ #define GSTACK_H GSTACK_H+ #include<stdlib.h>+ typedef struct Stack Stack;++ struct Stack_Node+ {+ struct Stack_Node *next;+ void *data;+ };+ struct Stack+ {+ struct Stack_Node *first;+ size_t size;+ };++ void Stack_Init(Stack *stack);+ void Stack_Push(Stack *stack,void* data);+ void* Stack_Pop(Stack *stack);+++ #endifF diff --git a/src/program/program.c b/src/program/program.c new file mode 100644 --- /dev/null +++ b/src/program/program.c+ #ifndef PROGRAM_C+ #define PROGRAM_C+ #include<program.h>++ struct Source* extract_source(char *src_name)+ {+ FILE *file;++ struct Source *ret;++ file=fopen(src_name,"r");+ if(file==NULL)+ return NULL;+ if(fseek(file,0L,SEEK_END)!=0)+ return NULL;++ ret=malloc(sizeof(struct Source));+ ret->src_size=ftell(file);+ ret->where_in_src=0;+ ret->src_name=src_name;+ ret->src=malloc(ret->src_size);+ ret->current_column=0;+ ret->current_row=0;++ fseek(file,0L,SEEK_SET);+++ fread(ret->src,sizeof(char),ret->src_size,file);++ fclose(file);+ return ret;+ }+ struct Options* parse_command_line(int argc,char **argv)+ {+ struct Options *ret;+ int i;++ assert(argv!=NULL && argc>0);++ ret=malloc(sizeof(struct Options));+ ret->target=OPTION_DEFAULT;+ ret->src_name=NULL;+ ret->is_quiet=0;++ for(i=0;i<argc;++i)+ {+ if(!strncmp(argv[i],"--print-tokens",sizeof("--print-tokens")))+ ret->target=OPTION_TARGET_TOKENS;+ else if(!strncmp(argv[i],"--print-ast",sizeof("--print-ast")))+ ret->target=OPTION_TARGET_AST;+ else if(!strncmp(argv[i],"-o",sizeof("-o")) || !strncmp(argv[i],"--output",sizeof("--output")))+ {+ if(++i<argc)+ {+ if(strnlen(argv[i],101)<100)+ ret->src_name=argv[i];+ else if(!ret->is_quiet)+ {+ fprintf(stderr,"Error: Output filename is too long");+ exit(1);+ }else+ {+ exit(1);+ }+ }+ }else if(strnlen(argv[i],101)<100)+ {+ ret->src_name=argv[i];+ }else if(!ret->is_quiet)+ {+ fprintf(stderr,"Error: Input filename is too long");+ exit(1);+ }else+ {+ exit(1);+ }++ }++ if(ret->target==OPTION_DEFAULT)+ ret->target=OPTION_TARGET_AST;++ return ret;+ }+ struct Translation_Data* get_translation_data()+ {+ struct Translation_Data *ret;+ ret=malloc(sizeof(struct Translation_Data));+ ret->errors=malloc(sizeof(struct Queue));+ ret->tokens=malloc(sizeof(struct Queue));++ Queue_Init(ret->errors);+ Queue_Init(ret->tokens);++ ret->hold_number_of_errors=0;++ return ret;+ }+ struct Error* get_error(char *message,size_t row,size_t column)+ {+ struct Error *ret;+ ret=malloc(sizeof(struct Error));+ ret->message=message;+ ret->row=row+1;+ ret->column=column+1;+ }+ void push_lexing_error(char *error_message,struct Source *src,struct Translation_Data *translation_data)+ {+ Queue_Push(translation_data->errors,get_error(error_message,src->current_row,src->current_column));+ }+ void push_parsing_error(char *error_message,struct Translation_Data *translation_data)+ {+ struct token *error_token;+ error_token=Queue_Pop(translation_data->tokens);+ Queue_Push(translation_data->errors,get_error(error_message,error_token->row,error_token->column));+ }+ char has_new_errors(struct Translation_Data *translation_data)+ {+ if(translation_data->hold_number_of_errors!=translation_data->errors->size)+ {+ translation_data->hold_number_of_errors=translation_data->errors->size;+ return 1;+ }else+ {+ return 0;+ }+ }++ void delete_translation_data(struct Translation_Data *data)+ {+ struct Error *hold_error;+ struct token *hold_token;++ while(data->tokens->size>0)+ delete_token(Queue_Pop(data->tokens));+ free(data->tokens);+ while(data->errors->size>0)+ delete_error(Queue_Pop(data->errors));+ free(data->errors);++ free(data);+ }+ void delete_source(struct Source *src)+ {+ free(src->src_name);+ free(src->src);+ free(src);+ }+ void delete_options(struct Options *options)+ {+ free(options);+ }+ void delete_error(struct Error *error)+ {+ free(error->message);+ free(error);+ }+ char get_and_check(struct Translation_Data *translation_data,enum Keyword kw)+ {+ if( ( (struct token *)translation_data->tokens->first->data)->type==kw)+ {+ delete_token(Queue_Pop(translation_data->tokens));+ return 1;+ }else+ {+ return 0;+ }+ }+ enum Keyword get_kw(struct Translation_Data *translation_data)+ {+ return ( (struct token*)translation_data->tokens->first->data)->type;+ }+ void chomp(struct Translation_Data *translation_data)+ {+ assert(translation_data->tokens->size>0);+ delete_token(Queue_Pop(translation_data->tokens));+ }+ void touch_errors(struct Translation_Data *translation_data)+ {+ assert(translation_data->hold_number_of_errors>0);+ --translation_data->hold_number_of_errors;+ }+ #endifF diff --git a/src/program/program.h b/src/program/program.h new file mode 100644 --- /dev/null +++ b/src/program/program.h+ #ifndef PROGRAM_H+ #define PROGRAM_H+ #include <stdlib.h>+ #include <stdio.h>+ #include <string.h>+ #include <queue.h>+ #include <lexer.h>+ #include <assert.h>++ struct token;+ enum Keyword;++ enum Options_Target_Type+ {+ OPTION_TARGET_TOKENS,+ OPTION_TARGET_AST,+ OPTION_DEFAULT,+ };++ struct Source+ {+ size_t src_size;+ size_t where_in_src;+ size_t current_column;+ size_t current_row;+ char *src_name;+ char *src;++ };++ struct Options+ {+ enum Options_Target_Type target;+ int is_quiet:1;+ char *src_name;+ };++ struct Error+ {+ char *message;+ size_t row;+ size_t column;+ };++ struct Translation_Data+ {+ struct Queue *errors;+ struct Queue *tokens;+ size_t hold_number_of_errors;+ };+ struct Program+ {+ struct Source *source;++ };++ struct Source* extract_source(char *src_name);+ struct Options* parse_command_line(int argc,char **argv);+ struct Translation_Data* get_translation_data();+ struct Error* get_error(char *message,size_t row,size_t column);++ void 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);+ 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);+ enum Keyword get_kw(struct Translation_Data *translation_data);+ void chomp(struct Translation_Data *translation_data);++ void delete_translation_data(struct Translation_Data *data);+ void delete_source(struct Source *src);+ void delete_options(struct Options *options);+ void delete_error(struct Error *error);+++ #endifF diff --git a/stack.c b/stack.c deleted file mode 100644 --- a/stack.c +++ /dev/null- #ifndef GSTACK_C- #define GSTACK_C GSTACK_C- #include "stack.h"---- void Stack_Init(Stack *stack)- {- stack->size=0;- stack->first=NULL;- }- void Stack_Push(Stack *stack,void* data)- {- struct Stack_Node *temp_node=malloc(sizeof(struct Stack_Node));- temp_node->data=data;- temp_node->next=stack->first;- stack->first=temp_node;- ++stack->size;- }- void* Stack_Pop(Stack *stack)- {- void* return_value=NULL;- if(stack->first!=NULL)- {- struct Stack_Node *temp_first=stack->first;- return_value=stack->first->data;-- --stack->size;- stack->first=stack->first->next;- free(temp_first);- }-- return return_value;- }-- #endif//#ifndef GSTACK_C-F diff --git a/stack.h b/stack.h deleted file mode 100644 --- a/stack.h +++ /dev/null- #ifndef GSTACK_H- #define GSTACK_H GSTACK_H- #include<stdlib.h>- typedef struct Stack Stack;-- struct Stack_Node- {- struct Stack_Node *next;- void *data;- };- struct Stack- {- struct Stack_Node *first;- size_t size;- };-- void Stack_Init(Stack *stack);- void Stack_Push(Stack *stack,void* data);- void* Stack_Pop(Stack *stack);--- #endifF diff --git a/test b/test deleted file mode 100644 --- a/test +++ /dev/null- machine flicker- [- states [ light_off , light_on ];-- starting on light_on;-- events [ one_second ];- transitions- [- from light_on to light_off on event one_second- execute turn_off_light;- from light_off to light_on on event one_second- execute turn_on_light;- ];- ];-F diff --git a/test2 b/test2 deleted file mode 100644 --- a/test2 +++ /dev/null- "1"- "12"F diff --git a/test3 b/test3 deleted file mode 100644 --- a/test3 +++ /dev/null- machine light_bulb- [- states [ light_on , light_off ];- events [ switch_state , turn_on , turn_off ];-- starting on light_off;-- 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 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();- ];- ];-- transition light_switch()- {-- }F diff --git a/tests/test b/tests/test new file mode 100644 --- /dev/null +++ b/tests/test+ machine flicker+ [+ states [ light_off , light_on ];++ starting on light_on;++ events [ one_second ];+ transitions+ [+ from light_on to light_off on event one_second+ execute turn_off_light;+ from light_off to light_on on event one_second+ execute turn_on_light;+ ];+ ];+F diff --git a/tests/test2 b/tests/test2 new file mode 100644 --- /dev/null +++ b/tests/test2+ "1"+ "12"F diff --git a/tests/test3 b/tests/test3 new file mode 100644 --- /dev/null +++ b/tests/test3+ machine light_bulb+ [+ states [ light_on , light_off ];+ events [ switch_state , turn_on , turn_off ];++ starting on light_off;++ 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 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();+ ];+ ];++ transition light_switch()+ {++ }