aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGalin Simeonov <gts@volconst.com>2021-05-31 22:02:10 +0300
committerGalin Simeonov <gts@volconst.com>2021-07-15 18:00:15 +0300
commit255a49ba5a41b3854dbdfebdec75fb6229450507 (patch)
tree616ea5786cb91d03ef609d32b402941dc30e926b /src
parentf768d9bdb84e846d89aac66a4f3433a44241c298 (diff)
downloadMEGATRON-255a49ba5a41b3854dbdfebdec75fb6229450507.tar.gz
added cmake file
Diffstat (limited to 'src')
-rw-r--r--src/backend/print.c294
-rw-r--r--src/backend/print.h27
-rw-r--r--src/frontend/lexer.c160
-rw-r--r--src/frontend/lexer.h54
-rw-r--r--src/frontend/parser.c669
-rw-r--r--src/frontend/parser.h124
-rw-r--r--src/main.c60
-rw-r--r--src/misc/map.c285
-rw-r--r--src/misc/map.h41
-rw-r--r--src/misc/queue.c67
-rw-r--r--src/misc/queue.h23
-rw-r--r--src/misc/stack.c37
-rw-r--r--src/misc/stack.h22
-rw-r--r--src/program/program.c183
-rw-r--r--src/program/program.h76
15 files changed, 2122 insertions, 0 deletions
diff --git a/src/backend/print.c b/src/backend/print.c
new file mode 100644
index 0000000..614a6c9
--- /dev/null
+++ b/src/backend/print.c
@@ -0,0 +1,294 @@
+#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);
+ }
+}
+#endif
diff --git a/src/backend/print.h b/src/backend/print.h
new file mode 100644
index 0000000..54d47ce
--- /dev/null
+++ b/src/backend/print.h
@@ -0,0 +1,27 @@
+#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);
+#endif
diff --git a/src/frontend/lexer.c b/src/frontend/lexer.c
new file mode 100644
index 0000000..6dc348d
--- /dev/null
+++ b/src/frontend/lexer.c
@@ -0,0 +1,160 @@
+#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);
+}
+#endif
diff --git a/src/frontend/lexer.h b/src/frontend/lexer.h
new file mode 100644
index 0000000..320146c
--- /dev/null
+++ b/src/frontend/lexer.h
@@ -0,0 +1,54 @@
+#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);
+
+#endif
diff --git a/src/frontend/parser.c b/src/frontend/parser.c
new file mode 100644
index 0000000..3e4e449
--- /dev/null
+++ b/src/frontend/parser.c
@@ -0,0 +1,669 @@
+#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;
+}
+
+#endif
diff --git a/src/frontend/parser.h b/src/frontend/parser.h
new file mode 100644
index 0000000..ef82184
--- /dev/null
+++ b/src/frontend/parser.h
@@ -0,0 +1,124 @@
+#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);
+
+#endif
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..438f282
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,60 @@
+#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;
+}
diff --git a/src/misc/map.c b/src/misc/map.c
new file mode 100644
index 0000000..cd8272f
--- /dev/null
+++ b/src/misc/map.c
@@ -0,0 +1,285 @@
+#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 GMAP
diff --git a/src/misc/map.h b/src/misc/map.h
new file mode 100644
index 0000000..ced43a7
--- /dev/null
+++ b/src/misc/map.h
@@ -0,0 +1,41 @@
+#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);
+
+#endif
diff --git a/src/misc/queue.c b/src/misc/queue.c
new file mode 100644
index 0000000..b395acf
--- /dev/null
+++ b/src/misc/queue.c
@@ -0,0 +1,67 @@
+#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);
+ }
+
+}
+#endif
diff --git a/src/misc/queue.h b/src/misc/queue.h
new file mode 100644
index 0000000..651d4b0
--- /dev/null
+++ b/src/misc/queue.h
@@ -0,0 +1,23 @@
+#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);
+#endif
diff --git a/src/misc/stack.c b/src/misc/stack.c
new file mode 100644
index 0000000..272732f
--- /dev/null
+++ b/src/misc/stack.c
@@ -0,0 +1,37 @@
+#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
+
diff --git a/src/misc/stack.h b/src/misc/stack.h
new file mode 100644
index 0000000..14e557a
--- /dev/null
+++ b/src/misc/stack.h
@@ -0,0 +1,22 @@
+#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);
+
+
+#endif
diff --git a/src/program/program.c b/src/program/program.c
new file mode 100644
index 0000000..5cf8cc3
--- /dev/null
+++ b/src/program/program.c
@@ -0,0 +1,183 @@
+#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;
+}
+#endif
diff --git a/src/program/program.h b/src/program/program.h
new file mode 100644
index 0000000..d5e45b7
--- /dev/null
+++ b/src/program/program.h
@@ -0,0 +1,76 @@
+#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);
+
+
+#endif