F diff --git a/.gdb_history b/.gdb_history new file mode 100644 --- /dev/null +++ b/.gdb_history+ r < test+ where+ b main+ r < test+ n+ n+ n+ n+ r+ record+ n+ rs+ record off+ n+ record stop+ n+ n+ rs+ r+ n+ r+ s+ n+ n+ n+ r test+ n+ n+ n+ n+ s+ n+ print src+ print *src+ n+ n+ n+ n+ n+ n+ n+ n+ n+ n+ n+ n+ n+ n+ n+ n+ s+ n+ print it+ print *it+ print *(struct token *)it->data+ n+ n+ q+ r test+ n+ b main+ r test+ n+ s+ print tokens+ print *tokens+ n+ print i+ print it+ n+ print it+ n+ print it+ print *tokens+ n+ print it+ n+ print it+ b lex+ r test+ s+ n+ print src->src+ n+ n+ s+ n+ print src+ print *src+ n+ print *src+ rs+ r+ n+ s+ s+ n+ print word[0]+ print src->src[src->where_in_src+ print src->src[src->where_in_src]+ n+ print i+ print sizes+ print size+ print word_size+ n+ b lex+ d+ b main+ r test+ n+ n+ n+ r+ n+ s+ n+ s+ n+ r+ n+ s+ record+ n+ r+ record stop+ n+ s+ n+ s+ n+ n+ qF diff --git a/.gitignore b/.gitignore new file mode 100644 --- /dev/null +++ b/.gitignore+ tags+ *.exe+ *.oF diff --git a/lexer.c b/lexer.c --- a/lexer.c +++ b/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* get_token(char *data,size_t size)+++ 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("state",sizeof("state")-1,src,1))+ return get_token(src->src+src->where_in_src-sizeof("state")+1,sizeof("state")-1,KW_STATE,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_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(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;}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;+ 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]))+ ++src->where_in_src;+ }#endifF diff --git a/lexer.h b/lexer.h --- a/lexer.h +++ b/lexer.h#ifndef LEXER_H#define LEXER_H+ #include <ctype.h> //isspace#include <program.h>#include <queue.h>+ struct Translation_Data;+ struct Source;+enum Keyword{KW_MACHINE,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,};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* get_token(char *data,size_t size);- void delete_token(struct token *token);+ 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 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 --- a/main.c +++ b/main.c#include<stdio.h>+ #include<program.h>#include<lexer.h>+ #include<string.h>+ #include<print.h>- int main()+ int main(int argc,char **argv){+ struct Options *options;+ struct Source *source;+ struct Program *program;+ struct Translation_Data *translation_data;++ options=parse_command_line(argv);+ if(options->source==NULL)+ {+ printf("No source file specified\n");+ return 0;+ }+ source=extract_source(strdup(options->source));+ translation_data=get_translation_data();+++ if(options->print_tokens)+ {+ 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+ {+ print_tokens(translation_data->tokens);+ }++ }++ delete_source(source);+ delete_options(options);return 0;}F diff --git a/makefile b/makefile --- a/makefile +++ b/makefileINCLUDE_DIRS=-I .- main.exe : main.c lexer.o queue.o- gcc main.c lexer.o queue.o -o main.exe ${INCLUDE_DIRS}+ CFLAGS="-g"+ main.exe : main.c lexer.o queue.o print.o program.o+ gcc ${CFLAGS} main.c lexer.o queue.o print.o program.o -o main.exe ${INCLUDE_DIRS}lexer.o : lexer.c lexer.h- gcc -c lexer.c -o lexer.o ${INCLUDE_DIRS}+ gcc ${CFLAGS} -c lexer.c -o lexer.o ${INCLUDE_DIRS}queue.o : queue.c queue.h- gcc -c queue.c -o queue.o ${INCLUDE_DIRS}+ 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}+clear:- rm -rf lexer.o main.exe queue.o+ rm -rf lexer.o main.exe queue.o print.o program.oF diff --git a/print.c b/print.c new file mode 100644 --- /dev/null +++ b/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_STATE:+ printf("KW_STATE");+ 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;+ default:+ printf("LEXERROR");+ }+ }+ void print_token(struct token *token)+ {+ size_t i;++ 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;+ for(it=tokens->first;it!=NULL;it=it->prev)+ {+ print_token( (struct token*)(it->data));+ printf(" ");+ }+ }++ #endifF diff --git a/print.h b/print.h new file mode 100644 --- /dev/null +++ b/print.h+ #ifndef PRINT_H+ #define PRINT_H PRINT_H+ #include<stdio.h>+ #include<lexer.h>+ #include<queue.h>+++ void print_keyword_enum(enum Keyword code);+ void print_token(struct token *token);+ void print_tokens(struct Queue *tokens);+ #endifF diff --git a/program.c b/program.c --- a/program.c +++ b/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(char **argv)+ {+ struct Options *ret;+ size_t i;++ ret=malloc(sizeof(struct Options));+ ret->print_tokens=1;+ ret->source=argv[1];+ 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;+ ret->column=column;+ }+ 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 token *token ,struct Translation_Data *translation_data)+ {+ Queue_Push(translation_data->errors,get_error(error_message,token->row,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);+ }#endifF diff --git a/program.h b/program.h --- a/program.h +++ b/program.h#ifndef PROGRAM_H#define PROGRAM_H- #include "queue.h"+ #include <queue.h>+ #include <lexer.h>+ #include <stdlib.h>+ #include <stdio.h>++ struct token;struct Source{+ size_t src_size;+ size_t where_in_src;+ size_t current_column;+ size_t current_row;char *src_name;char *src;- size_t src_size;};struct Options{int print_tokens:1;+ char *source;};+ 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(char **argv);struct Translation_Data* get_translation_data();- struct Source* get_source();- struct Options* get_options();+ 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 token *token ,struct Translation_Data *translation_data);+ char has_new_errors(struct Translation_Data *translation_data);- void destroy_translation_data(struct Translation_Data *data);- void destroy_source(struct Source *src);- void destroy_options(struct Options *options);+ 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 --- a/queue.c +++ b/queue.cstruct Queue_Node *temp=malloc(sizeof(struct Queue_Node));q->last->prev=temp;temp->data=data;-+ temp->prev=NULL;q->last=temp;++q->size;}F diff --git a/test b/test new file mode 100644 --- /dev/null +++ b/test+ machine temp_switch+ [+ state above_treshold;+ starting state below_treshold;++ from below_treshold to above_treshold+ on event above_temperature "10";+ from above_treshold to below_treshold+ on event below_temperature "9";+ on state above_treshold+ on event get_temp | html_encase | http_out ;+ ];F diff --git a/test2 b/test2 new file mode 100644 --- /dev/null +++ b/test2+ "1"+ "12"