From df0d6a4503a26508553510b4050eaa79f52e4e4e Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Sun, 18 Oct 2020 18:22:31 +0300 Subject: Another step to release. --- base/smack.c | 579 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 579 insertions(+) create mode 100644 base/smack.c (limited to 'base/smack.c') diff --git a/base/smack.c b/base/smack.c new file mode 100644 index 0000000..f6f9f30 --- /dev/null +++ b/base/smack.c @@ -0,0 +1,579 @@ +/* + Simple Macro Generator + created by exegete +*/ + +#include +#include +#include + +struct macro +{ + const char *lexem; + unsigned long long param_count; + const char *text; + struct macro *next; +}; + +struct macro_parameter +{ + char *lexem; + struct macro_parameter *next; +}; + +struct input_stream +{ + FILE *fd; + const struct macro *macro; + unsigned long long text_offset; + struct macro_parameter *param_list; + struct input_stream *next; +}; + +struct module +{ + const char *file_name; + struct module *next; +}; + +#define ERROR_STATUS_ARG 1 +#define ERROR_STATUS_OPEN 2 +#define ERROR_STATUS_CHDIR 3 +#define ERROR_STATUS_MALLOC 4 +#define ERROR_STATUS_EMPTY_STREAM_LIST 5 +#define ERROR_STATUS_INVALID_STREAM 6 +#define ERROR_STATUS_INVALID_MACRO 7 +#define ERROR_STATUS_INVALID_PARAMETER 8 +#define ERROR_STATUS_INVALID_CALL 9 +#define ERROR_STATUS_INVALID_INCLUDE 10 +#define ERROR_STATUS_INVALID_SHIELD 11 + +const char *error_msgs[] = +{ + "Please, specify input file", + "Unable to open file: ", + "Unable to change working directory: ", + "Unable to allocate memory", + "Input stream list is empty", + "Input stream is invalid", + "Macro definition is invalid", + "Macro parameter is invalid", + "Macro call is invalid", + "Invalid include/module argument", + "Invalid '#' argument" +}; + +void exit_error(int status, const char *msg) +{ + if(msg) + fprintf(stderr, "Error: %s%s\n", error_msgs[status - 1], msg); + else + fprintf(stderr, "Error: %s\n", error_msgs[status - 1]); + exit(status); +} + +void add_input_stream(struct input_stream **stream_list, + FILE *fd, const struct macro *macro) +{ + struct input_stream *head = *stream_list; + *stream_list = malloc(sizeof(struct input_stream)); + if(!*stream_list) + exit_error(ERROR_STATUS_MALLOC, NULL); + (*stream_list)->fd = fd; + (*stream_list)->macro = macro; + (*stream_list)->text_offset = 0; + (*stream_list)->param_list = NULL; + (*stream_list)->next = head; +} + +int delete_input_stream(struct input_stream **stream_list) +{ + struct input_stream *head = *stream_list; + if(!head) + exit_error(ERROR_STATUS_EMPTY_STREAM_LIST, NULL); + *stream_list = (*stream_list)->next; + if(head->fd) + fclose(head->fd); + while(head->param_list) + { + struct macro_parameter *param_head = head->param_list; + head->param_list = param_head->next; + free(param_head->lexem); + free(param_head); + } + free(head); + return *stream_list != NULL; +} + +void add_input_stream_parameter(struct input_stream *stream_list, char *lexem) +{ + struct macro_parameter **param = &stream_list->param_list; + while(*param) + param = &(*param)->next; + *param = malloc(sizeof(struct macro_parameter)); + if(!*param) + exit_error(ERROR_STATUS_MALLOC, NULL); + (*param)->lexem = lexem; + (*param)->next = NULL; +} + +const char *get_input_stream_parameter(struct input_stream *stream_list, + unsigned long long chosen) +{ + struct macro_parameter *param = stream_list->param_list; + if(!chosen) + return stream_list->macro->lexem; + chosen--; + for(; param && chosen > 0; chosen--) + param = param->next; + if(!param) + exit_error(ERROR_STATUS_INVALID_CALL, NULL); + return param->lexem; +} + +#define BUFFER_INITIAL_SIZE 4 + +int double_buffer(char **buffer, unsigned long long *buffer_size) +{ + char *tmp_pointer = *buffer; + unsigned long long tmp_size = *buffer_size; + + if(*buffer_size == 0) + *buffer_size = BUFFER_INITIAL_SIZE; + else + *buffer_size *= 2; + + *buffer = malloc(*buffer_size); + if(!*buffer) + return 0; + + for(; tmp_size > 0; tmp_size--) + (*buffer)[tmp_size - 1] = tmp_pointer[tmp_size - 1]; + + free(tmp_pointer); + return 1; +} + +int read_symb_from_text(struct input_stream *stream_list) +{ + char symb; + if(!stream_list->macro) + exit_error(ERROR_STATUS_INVALID_STREAM, NULL); + if(!stream_list->macro->text) + exit_error(ERROR_STATUS_INVALID_STREAM, NULL); + symb = stream_list->macro->text[stream_list->text_offset]; + if(!symb) + return EOF; + stream_list->text_offset++; + return symb; +} + +#define COMMENT_SYMB ';' + +int read_real_symb(struct input_stream *stream_list) +{ + int symb; + + if(!stream_list) + exit_error(ERROR_STATUS_EMPTY_STREAM_LIST, NULL); + + if(stream_list->fd) + symb = fgetc(stream_list->fd); + else + symb = read_symb_from_text(stream_list); + + if(symb == COMMENT_SYMB) + { + for(; symb != '\n' && symb != EOF; + symb = fgetc(stream_list->fd)) + {} + } + return symb; +} + +#define SHIELD_SYMB '\\' + +int read_symb(struct input_stream *stream_list, int *shield) +{ + int symb = read_real_symb(stream_list); + if(shield) + { + *shield = 0; + if(symb == SHIELD_SYMB) + { + symb = read_real_symb(stream_list); + *shield = 1; + } + } + return symb; +} + +int is_symb_hex(char symb) +{ + if(symb >= '0' && symb <= '9') + return symb - '0'; + else + if(symb >= 'A' && symb <= 'F') + return symb - 'A' + 10; + else + if(symb >= 'a' && symb <= 'f') + return symb - 'a' + 10; + else + return -1; +} + +int is_lexem_hex(const char *lexem, unsigned long long *dest) +{ + int sign = 0; + unsigned long long hex = 0; + if(*lexem == '-' && *(lexem + 1)) + { + sign = 1; + lexem++; + } + + for(; *lexem; lexem++) + { + int num = is_symb_hex(*lexem); + if(num != -1) + hex = (hex << 4) + num; + else + return 0; + } + hex = sign ? ~hex + 1 : hex; + if(dest) + *dest = hex; + return 1; +} + +int compare_lexems(const char *lexem_one, const char *lexem_two) +{ + for(; *lexem_one && *lexem_two; lexem_one++, lexem_two++) + if(*lexem_one != *lexem_two) + return 0; + return *lexem_one == *lexem_two; +} + +char *copy_lexem(const char *lexem) +{ + char *buffer = NULL; + unsigned long long buffer_size = 0; + unsigned long long index; + + for(index = 0;; index++) + { + if(index == buffer_size) + if(!double_buffer(&buffer, &buffer_size)) + exit_error(ERROR_STATUS_MALLOC, NULL); + buffer[index] = lexem[index]; + if(!lexem[index]) + break; + } + return buffer; +} + +#define EVAL_SYMB '%' + +unsigned long long get_eval_end(const char *lexem) +{ + unsigned long long counter = 0; + + for(; *lexem && *lexem != EVAL_SYMB; lexem++, counter++) + {} + if(!*lexem) + exit_error(ERROR_STATUS_INVALID_CALL, NULL); + return counter; +} + +char *param_eval(struct input_stream *stream_list, char *lexem) +{ + char *input_lexem = lexem; + char *buffer = NULL; + unsigned long long buffer_size = 0; + const char *param = NULL; + unsigned long long index = 0; + + for(;;) + { + char symb = param && *param ? *param : *lexem++; + param = !param || !*param ? NULL : param + 1; + if(symb == EVAL_SYMB) + { + unsigned long long param_offset = get_eval_end(lexem); + unsigned long long param_num; + *(lexem + param_offset) = 0; + if(!is_lexem_hex(lexem, ¶m_num)) + exit_error(ERROR_STATUS_INVALID_CALL, NULL); + lexem += param_offset + 1; + param = get_input_stream_parameter(stream_list, + param_num); + continue; + } + if(index == buffer_size) + if(!double_buffer(&buffer, &buffer_size)) + exit_error(ERROR_STATUS_MALLOC, NULL); + buffer[index] = symb; + if(!symb) + break; + index++; + } + free(input_lexem); + return buffer; +} + +int is_separator(int symb) +{ + return symb == ' ' || symb == '\n' || symb == '\t' || symb == '\r'; +} + +char *read_lexem(struct input_stream *stream_list) +{ + char *buffer = NULL; + unsigned long long buffer_size = 0; + int symb; + int shield; + unsigned long long index; + + for(;;) + { + symb = read_symb(stream_list, &shield); + if(is_separator(symb) && !shield) + continue; + if(symb == EOF) + return NULL; + break; + } + + for(index = 0;; index++) + { + if(index == buffer_size) + if(!double_buffer(&buffer, &buffer_size)) + exit_error(ERROR_STATUS_MALLOC, NULL); + if(symb == EOF || (is_separator(symb) && !shield)) + { + buffer[index] = 0; + break; + } + buffer[index] = symb; + symb = read_symb(stream_list, &shield); + } + buffer = param_eval(stream_list, buffer); + return buffer; +} + +#define MACRO_END_SYMB ']' + +const char *read_macro_text(struct input_stream *stream_list) +{ + char *buffer = NULL; + unsigned long long buffer_size = 0; + unsigned long long index; + + for(index = 0;; index++) + { + int shield; + int symb = read_symb(stream_list, &shield); + if(index == buffer_size) + if(!double_buffer(&buffer, &buffer_size)) + exit_error(ERROR_STATUS_MALLOC, NULL); + if(symb == EOF || (symb == MACRO_END_SYMB && !shield)) + { + buffer[index] = 0; + break; + } + buffer[index] = symb; + } + return buffer; +} + +void create_macro(struct input_stream *stream_list, struct macro **macro_list) +{ + char *param_count_lexem; + struct macro *head = *macro_list; + *macro_list = malloc(sizeof(struct macro)); + if(!*macro_list) + exit_error(ERROR_STATUS_MALLOC, NULL); + (*macro_list)->lexem = read_lexem(stream_list); + if(!(*macro_list)->lexem) + exit_error(ERROR_STATUS_INVALID_MACRO, NULL); + param_count_lexem = read_lexem(stream_list); + if(!param_count_lexem || !is_lexem_hex(param_count_lexem, + &(*macro_list)->param_count)) + exit_error(ERROR_STATUS_INVALID_MACRO, NULL); + free(param_count_lexem); + (*macro_list)->text = read_macro_text(stream_list); + (*macro_list)->next = head; +} + +int find_module(struct module *module_list, const char *file_name) +{ + for(; module_list; module_list = module_list->next) + if(compare_lexems(module_list->file_name, file_name)) + return 1; + return 0; +} + +void add_module(struct module **module_list, const char *file_name) +{ + struct module *head = *module_list; + *module_list = malloc(sizeof(struct module)); + if(!*module_list) + exit_error(ERROR_STATUS_MALLOC, NULL); + (*module_list)->file_name = file_name; + (*module_list)->next = head; +} + +void include_file(struct input_stream **stream_list, + struct module **module_list) +{ + char *file_name = read_lexem(*stream_list); + FILE *fd; + if(!file_name) + exit_error(ERROR_STATUS_INVALID_INCLUDE, NULL); + if(module_list && find_module(*module_list, file_name)) + { + free(file_name); + return; + } + fd = fopen(file_name, "r"); + if(!fd) + exit_error(ERROR_STATUS_OPEN, file_name); + if(module_list) + add_module(module_list, file_name); + else + free(file_name); + add_input_stream(stream_list, fd, NULL); +} + +void push_parameter(struct input_stream *input_stream, + struct input_stream *actual_stream) +{ + char *lexem = read_lexem(input_stream); + if(!lexem) + exit_error(ERROR_STATUS_INVALID_PARAMETER, NULL); + add_input_stream_parameter(actual_stream, lexem); +} + +int find_macro(struct input_stream **stream_list, struct macro *macro_list, + const char *lexem) +{ + for(; macro_list; macro_list = macro_list->next) + { + if(compare_lexems(macro_list->lexem, lexem)) + { + struct input_stream *old_stream = *stream_list; + unsigned long long param_count = + macro_list->param_count; + add_input_stream(stream_list, NULL, macro_list); + for(; param_count > 0; param_count--) + push_parameter(old_stream, *stream_list); + return 1; + } + } + return 0; +} + +#define DIRECTORY_SEPARATOR_SYMB '/' + +unsigned long long find_last_dir_separator_pos(const char *file_name) +{ + const char *orig_file_name = file_name; + unsigned long long pos = 0; + for(; *file_name; file_name++) + if(*file_name == DIRECTORY_SEPARATOR_SYMB) + pos = file_name - orig_file_name; + return pos; +} + +void initialize_stream(struct input_stream **stream_list, + const char *file_name) +{ + char *dir_path = copy_lexem(file_name); + unsigned long long dir_sep_pos = find_last_dir_separator_pos(dir_path); + FILE *fd = fopen(file_name, "r"); + if(!fd) + exit_error(ERROR_STATUS_OPEN, file_name); + add_input_stream(stream_list, fd, NULL); + if(dir_sep_pos) + { + dir_path[dir_sep_pos] = 0; + if(chdir(dir_path) == -1) + exit_error(ERROR_STATUS_CHDIR, NULL); + } + free(dir_path); +} + +void print_lexem(const char *lexem) +{ + printf("%s ", lexem); +} + +#define MACRO_SHIELD_LEXEM "#" +#define MACRO_START_LEXEM "[" +#define MACRO_INCLUDE_LEXEM "include" +#define MACRO_MODULE_LEXEM "module" +#define MACRO_LIT_LEXEM "literal" + +int main(int argc, char **argv) +{ + struct input_stream *stream_list = NULL; + struct macro *macro_list = NULL; + struct module *module_list = NULL; + char *lexem; + + if(argc <= 1) + exit_error(ERROR_STATUS_ARG, NULL); + else + initialize_stream(&stream_list, argv[1]); + + for(;; free(lexem)) + { + lexem = read_lexem(stream_list); + if(!lexem) + { + if(delete_input_stream(&stream_list)) + continue; + else + break; + } + if(compare_lexems(lexem, MACRO_SHIELD_LEXEM)) + { + free(lexem); + lexem = read_lexem(stream_list); + if(!lexem) + exit_error(ERROR_STATUS_INVALID_SHIELD, NULL); + print_lexem(lexem); + continue; + } + if(compare_lexems(lexem, MACRO_START_LEXEM)) + { + create_macro(stream_list, ¯o_list); + continue; + } + if(compare_lexems(lexem, MACRO_INCLUDE_LEXEM)) + { + include_file(&stream_list, NULL); + continue; + } + if(compare_lexems(lexem, MACRO_MODULE_LEXEM)) + { + include_file(&stream_list, &module_list); + continue; + } + if(is_lexem_hex(lexem, NULL)) + { + if(find_macro(&stream_list, macro_list, + MACRO_LIT_LEXEM)) + { + add_input_stream_parameter(stream_list, + copy_lexem(lexem)); + continue; + } + } + if(find_macro(&stream_list, macro_list, lexem)) + continue; + print_lexem(lexem); + } + + return 0; +} -- cgit v1.2.3