aboutsummaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/smack.c579
-rw-r--r--base/strans.c652
2 files changed, 1231 insertions, 0 deletions
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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+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, &param_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, &macro_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;
+}
diff --git a/base/strans.c b/base/strans.c
new file mode 100644
index 0000000..e3d834d
--- /dev/null
+++ b/base/strans.c
@@ -0,0 +1,652 @@
+/*
+ Simple Stack Translator
+ created by exegete
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+struct stack_elem
+{
+ unsigned long long value;
+ struct stack_elem *next;
+};
+
+struct identifier
+{
+ const char *lexem;
+ unsigned long long value;
+ struct identifier *next;
+};
+
+struct segment
+{
+ char *buffer;
+ unsigned long long real_size;
+ unsigned long long size;
+ unsigned long long pointer_address;
+ unsigned long long base_address;
+ unsigned long long base_offset;
+ int data_size;
+ int data_endianness;
+ struct segment *next;
+};
+
+struct environment
+{
+ struct stack_elem *stack;
+ struct identifier *id_list;
+ struct segment *seg_list;
+ unsigned long long chosen_segment;
+};
+
+struct operator
+{
+ void (*func)(struct environment *env);
+ const char *lexem;
+};
+
+#define ERROR_STATUS_STACK_OVERFLOW 1
+#define ERROR_STATUS_STACK_EMPTY 2
+#define ERROR_STATUS_ID_LIST_OVERFLOW 3
+#define ERROR_STATUS_SEG_LIST_OVERFLOW 4
+#define ERROR_STATUS_INVALID_SEGMENT 5
+#define ERROR_STATUS_WORD_BUFFER_OVERFLOW 6
+#define ERROR_STATUS_LEXEM_OVERFLOW 7
+#define ERROR_STATUS_UNDEFINED 8
+#define ERROR_STATUS_INVALID_ACCESS 9
+#define ERROR_STATUS_INVALID_WORD_SIZE 10
+#define ERROR_STATUS_WORD_ENDIANNESS_INVALID 11
+
+const char *error_msgs[] =
+{
+ "Stack overflow",
+ "Stack is empty",
+ "Identifier list overflow",
+ "Segment list overflow",
+ "Invalid chosen segment",
+ "Word buffer overflow",
+ "Lexem is too big",
+ "Undefined lexem: ",
+ "Invalid segment access",
+ "Invalid segment data size",
+ "Invalid segment data endianness"
+};
+
+void exit_error(int status, const char *lexem)
+{
+ if(lexem)
+ fprintf(stderr, "Error: %s%s\n", error_msgs[status - 1],
+ lexem);
+ else
+ fprintf(stderr, "Error: %s\n", error_msgs[status - 1]);
+ exit(status);
+}
+
+unsigned long long create_segment(struct environment *env)
+{
+ struct segment **chosen_segment = &env->seg_list;
+ unsigned long long segment_counter = 0;
+ for(; *chosen_segment; chosen_segment = &(*chosen_segment)->next)
+ segment_counter++;
+ *chosen_segment = malloc(sizeof(struct segment));
+ if(!*chosen_segment)
+ exit_error(ERROR_STATUS_SEG_LIST_OVERFLOW, NULL);
+ (*chosen_segment)->buffer = NULL;
+ (*chosen_segment)->real_size = 0;
+ (*chosen_segment)->size = 0;
+ (*chosen_segment)->pointer_address = 0;
+ (*chosen_segment)->base_address = 0;
+ (*chosen_segment)->base_offset = 0;
+ (*chosen_segment)->data_size = 1;
+ (*chosen_segment)->data_endianness = 0;
+ (*chosen_segment)->next = NULL;
+ return segment_counter;
+}
+
+struct segment *get_segment(struct environment *env)
+{
+ struct segment *chosen_segment = env->seg_list;
+ unsigned long long segment_counter = env->chosen_segment;
+ while(chosen_segment && segment_counter--)
+ chosen_segment = chosen_segment->next;
+ if(!chosen_segment)
+ exit_error(ERROR_STATUS_INVALID_SEGMENT, NULL);
+ return chosen_segment;
+}
+
+void initialize_environment(struct environment *env)
+{
+ env->stack = NULL;
+ env->id_list = NULL;
+ env->seg_list = NULL;
+ env->chosen_segment = 0;
+}
+
+int is_separator(int symb)
+{
+ return symb == ' ' || symb == '\n' || symb == '\t' || symb == '\r';
+}
+
+#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;
+}
+
+char *read_lexem()
+{
+ char *buffer = NULL;
+ unsigned long long buffer_size = 0;
+ int symb;
+ unsigned long long index;
+
+ while(is_separator(symb = getchar()))
+ {}
+
+ if(symb == EOF)
+ return NULL;
+
+ for(index = 0;; index++)
+ {
+ if(index == buffer_size)
+ if(!double_buffer(&buffer, &buffer_size))
+ exit_error(ERROR_STATUS_LEXEM_OVERFLOW, NULL);
+ if(symb == EOF || is_separator(symb))
+ {
+ buffer[index] = 0;
+ break;
+ }
+ buffer[index] = symb;
+ symb = getchar();
+ }
+ return buffer;
+}
+
+void push_stack_elem(struct stack_elem **stack, unsigned long long value)
+{
+ struct stack_elem *head = *stack;
+ *stack = malloc(sizeof(struct stack_elem));
+ if(!*stack)
+ exit_error(ERROR_STATUS_STACK_OVERFLOW, NULL);
+ (*stack)->value = value;
+ (*stack)->next = head;
+}
+
+unsigned long long pop_stack_elem(struct stack_elem **stack)
+{
+ struct stack_elem *head = *stack;
+ unsigned long long value;
+ if(!head)
+ exit_error(ERROR_STATUS_STACK_EMPTY, NULL);
+ value = head->value;
+ *stack = head->next;
+ free(head);
+ return value;
+}
+
+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(struct environment *env, const char *lexem)
+{
+ 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;
+ push_stack_elem(&env->stack, 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;
+}
+
+void add_identifier(struct identifier **id_list, const char *lexem,
+ unsigned long long value)
+{
+ struct identifier *head = *id_list;
+ *id_list = malloc(sizeof(struct identifier));
+ if(!id_list)
+ exit_error(ERROR_STATUS_ID_LIST_OVERFLOW, NULL);
+ (*id_list)->lexem = lexem;
+ (*id_list)->value = value;
+ (*id_list)->next = head;
+}
+
+int find_identifier(struct environment *env, const char *lexem)
+{
+ struct identifier *id_list = env->id_list;
+ for(; id_list; id_list = id_list->next)
+ {
+ if(compare_lexems(lexem, id_list->lexem))
+ {
+ push_stack_elem(&env->stack, id_list->value);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void segment_compile_byte(struct environment *env, char byte)
+{
+ unsigned long long index = get_segment(env)->size;
+ if(index == get_segment(env)->real_size)
+ if(!double_buffer(&get_segment(env)->buffer,
+ &get_segment(env)->real_size))
+ exit_error(ERROR_STATUS_WORD_BUFFER_OVERFLOW, NULL);
+ get_segment(env)->buffer[index] = byte;
+ get_segment(env)->size++;
+ get_segment(env)->pointer_address++;
+}
+
+void segment_compile(struct environment *env, unsigned long long value,
+ int size)
+{
+ int dir = get_segment(env)->data_endianness ? -1 : 1;
+ int index = get_segment(env)->data_endianness * (size - 1);
+ for(; index < size && index >= 0; index += dir)
+ segment_compile_byte(env, value >> index * 8);
+}
+
+unsigned long long convert_address(struct environment *env,
+ unsigned long long address, int size)
+{
+ unsigned long long pointer_address =
+ get_segment(env)->pointer_address;
+ unsigned long long base_address = get_segment(env)->base_address;
+ unsigned long long base_offset = get_segment(env)->base_offset;
+ if(address < base_address || address + size > pointer_address)
+ exit_error(ERROR_STATUS_INVALID_ACCESS, NULL);
+ return address - base_address + base_offset;
+}
+
+unsigned long long segment_read(struct environment *env,
+ unsigned long long address, int size)
+{
+ unsigned long long value = 0;
+ int dir = get_segment(env)->data_endianness ? 1 : -1;
+ int index = get_segment(env)->data_endianness ? 0 : (size - 1);
+ address = convert_address(env, address, size);
+ for(; index < size && index >= 0; index += dir)
+ value = (value << 8) +
+ (get_segment(env)->buffer[address + index] & 0xFF);
+ return value;
+}
+
+void segment_write(struct environment *env, unsigned long long value,
+ unsigned long long address, int size)
+{
+ int dir = get_segment(env)->data_endianness ? -1 : 1;
+ int index = get_segment(env)->data_endianness * (size - 1);
+ address = convert_address(env, address, size);
+ for(; index < size && index >= 0; index += dir)
+ {
+ get_segment(env)->buffer[address + index] = value;
+ value >>= 8;
+ }
+}
+
+void translator_drop(struct environment *env)
+{
+ pop_stack_elem(&env->stack);
+}
+
+void translator_dup(struct environment *env)
+{
+ unsigned long long value = pop_stack_elem(&env->stack);
+ push_stack_elem(&env->stack, value);
+ push_stack_elem(&env->stack, value);
+}
+
+void translator_over(struct environment *env)
+{
+ unsigned long long value_one = pop_stack_elem(&env->stack);
+ unsigned long long value_two = pop_stack_elem(&env->stack);
+ push_stack_elem(&env->stack, value_two);
+ push_stack_elem(&env->stack, value_one);
+ push_stack_elem(&env->stack, value_two);
+}
+
+void translator_swap(struct environment *env)
+{
+ unsigned long long value_one = pop_stack_elem(&env->stack);
+ unsigned long long value_two = pop_stack_elem(&env->stack);
+ push_stack_elem(&env->stack, value_one);
+ push_stack_elem(&env->stack, value_two);
+}
+
+void translator_add(struct environment *env)
+{
+ unsigned long long first = pop_stack_elem(&env->stack);
+ unsigned long long second = pop_stack_elem(&env->stack);
+ push_stack_elem(&env->stack, second + first);
+}
+
+void translator_sub(struct environment *env)
+{
+ unsigned long long first = pop_stack_elem(&env->stack);
+ unsigned long long second = pop_stack_elem(&env->stack);
+ push_stack_elem(&env->stack, second - first);
+}
+
+void translator_mul(struct environment *env)
+{
+ unsigned long long first = pop_stack_elem(&env->stack);
+ unsigned long long second = pop_stack_elem(&env->stack);
+ push_stack_elem(&env->stack, second * first);
+}
+
+void translator_div(struct environment *env)
+{
+ unsigned long long first = pop_stack_elem(&env->stack);
+ unsigned long long second = pop_stack_elem(&env->stack);
+ push_stack_elem(&env->stack, second / first);
+}
+
+void translator_mod(struct environment *env)
+{
+ unsigned long long first = pop_stack_elem(&env->stack);
+ unsigned long long second = pop_stack_elem(&env->stack);
+ push_stack_elem(&env->stack, second % first);
+}
+
+void translator_define_identifier(struct environment *env)
+{
+ unsigned long long value = pop_stack_elem(&env->stack);
+ add_identifier(&env->id_list, read_lexem(), value);
+}
+
+void translator_compile_one(struct environment *env)
+{
+ unsigned long long value = pop_stack_elem(&env->stack);
+ segment_compile(env, value, 1);
+}
+
+void translator_compile_two(struct environment *env)
+{
+ unsigned long long value = pop_stack_elem(&env->stack);
+ segment_compile(env, value, 2);
+}
+
+void translator_compile_four(struct environment *env)
+{
+ unsigned long long value = pop_stack_elem(&env->stack);
+ segment_compile(env, value, 4);
+}
+
+void translator_compile_eight(struct environment *env)
+{
+ unsigned long long value = pop_stack_elem(&env->stack);
+ segment_compile(env, value, 8);
+}
+
+void translator_compile(struct environment *env)
+{
+ unsigned long long value = pop_stack_elem(&env->stack);
+ segment_compile(env, value, get_segment(env)->data_size);
+}
+
+void translator_reserve(struct environment *env)
+{
+ unsigned long long count = pop_stack_elem(&env->stack);
+ while(count--)
+ segment_compile(env, 0, 1);
+}
+
+void translator_read_one(struct environment *env)
+{
+ unsigned long long value = segment_read(env,
+ pop_stack_elem(&env->stack), 1);
+ push_stack_elem(&env->stack, value);
+}
+
+void translator_read_two(struct environment *env)
+{
+ unsigned long long value = segment_read(env,
+ pop_stack_elem(&env->stack), 2);
+ push_stack_elem(&env->stack, value);
+}
+
+void translator_read_four(struct environment *env)
+{
+ unsigned long long value = segment_read(env,
+ pop_stack_elem(&env->stack), 4);
+ push_stack_elem(&env->stack, value);
+}
+
+void translator_read_eight(struct environment *env)
+{
+ unsigned long long value = segment_read(env,
+ pop_stack_elem(&env->stack), 8);
+ push_stack_elem(&env->stack, value);
+}
+
+void translator_read(struct environment *env)
+{
+ unsigned long long value = segment_read(env,
+ pop_stack_elem(&env->stack), get_segment(env)->data_size);
+ push_stack_elem(&env->stack, value);
+}
+
+void translator_write_one(struct environment *env)
+{
+ unsigned long long address = pop_stack_elem(&env->stack);
+ unsigned long long value = pop_stack_elem(&env->stack);
+ segment_write(env, value, address, 1);
+}
+
+void translator_write_two(struct environment *env)
+{
+ unsigned long long address = pop_stack_elem(&env->stack);
+ unsigned long long value = pop_stack_elem(&env->stack);
+ segment_write(env, value, address, 2);
+}
+
+void translator_write_four(struct environment *env)
+{
+ unsigned long long address = pop_stack_elem(&env->stack);
+ unsigned long long value = pop_stack_elem(&env->stack);
+ segment_write(env, value, address, 4);
+}
+
+void translator_write_eight(struct environment *env)
+{
+ unsigned long long address = pop_stack_elem(&env->stack);
+ unsigned long long value = pop_stack_elem(&env->stack);
+ segment_write(env, value, address, 8);
+}
+
+void translator_write(struct environment *env)
+{
+ unsigned long long address = pop_stack_elem(&env->stack);
+ unsigned long long value = pop_stack_elem(&env->stack);
+ segment_write(env, value, address, get_segment(env)->data_size);
+}
+
+void translator_create_segment(struct environment *env)
+{
+ push_stack_elem(&env->stack, create_segment(env));
+}
+
+void translator_choose_segment(struct environment *env)
+{
+ env->chosen_segment = pop_stack_elem(&env->stack);
+}
+
+void translator_set_base(struct environment *env)
+{
+ get_segment(env)->base_address = pop_stack_elem(&env->stack);
+ get_segment(env)->pointer_address = get_segment(env)->base_address;
+ get_segment(env)->base_offset = get_segment(env)->size;
+}
+
+#define WORD_SIZE_MAX 8
+
+void translator_set_data_size(struct environment *env)
+{
+ int target_size = pop_stack_elem(&env->stack);
+ if(target_size <= 0 || target_size > WORD_SIZE_MAX)
+ exit_error(ERROR_STATUS_INVALID_WORD_SIZE, NULL);
+ get_segment(env)->data_size = target_size;
+}
+
+void translator_set_data_endianness(struct environment *env)
+{
+ int endianness = pop_stack_elem(&env->stack);
+ if(endianness > 1)
+ exit_error(ERROR_STATUS_WORD_ENDIANNESS_INVALID, NULL);
+ get_segment(env)->data_endianness = endianness;
+}
+
+void translator_get_offset(struct environment *env)
+{
+ push_stack_elem(&env->stack, get_segment(env)->pointer_address);
+}
+
+void translator_get_base(struct environment *env)
+{
+ push_stack_elem(&env->stack, get_segment(env)->base_address);
+}
+
+void translator_print(struct environment *env)
+{
+ unsigned long long value = pop_stack_elem(&env->stack);
+ fprintf(stderr, "%llx\n", value);
+}
+
+const struct operator translator_operators[] =
+{
+ { &translator_drop, "?drop" },
+ { &translator_dup, "?dup" },
+ { &translator_over, "?over" },
+ { &translator_swap, "?swap" },
+ { &translator_add, "?+" },
+ { &translator_sub, "?-" },
+ { &translator_mul, "?*" },
+ { &translator_div, "?/" },
+ { &translator_mod, "?mod" },
+ { &translator_define_identifier, "??" },
+ { &translator_compile_one, "?'" },
+ { &translator_compile_one, "?1." },
+ { &translator_compile_two, "?2." },
+ { &translator_compile_four, "?4." },
+ { &translator_compile_eight, "?8." },
+ { &translator_compile, "?." },
+ { &translator_reserve, "?res" },
+ { &translator_read_one, "?1@" },
+ { &translator_read_two, "?2@" },
+ { &translator_read_four, "?4@" },
+ { &translator_read_eight, "?8@" },
+ { &translator_read, "?@" },
+ { &translator_write_one, "?1!" },
+ { &translator_write_two, "?2!" },
+ { &translator_write_four, "?4!" },
+ { &translator_write_eight, "?8!" },
+ { &translator_write, "?!" },
+ { &translator_create_segment, "?create" },
+ { &translator_choose_segment, "?choose" },
+ { &translator_set_base, "?org" },
+ { &translator_set_data_size, "?size" },
+ { &translator_set_data_endianness, "?endianness" },
+ { &translator_get_offset, "?$" },
+ { &translator_get_base, "?$$" },
+ { &translator_print, "?print" },
+};
+
+int execute_operator(struct environment *env, const char *lexem)
+{
+ int operators_count =
+ sizeof(translator_operators) / sizeof(*translator_operators);
+ int index;
+
+ for(index = 0; index < operators_count; index++)
+ {
+ if(compare_lexems(lexem, translator_operators[index].lexem))
+ {
+ (*translator_operators[index].func)(env);
+ break;
+ }
+ }
+
+ return index != operators_count;
+}
+
+void print_target_buffer(struct environment *env)
+{
+ struct segment *seg_list;
+ unsigned long long index;
+ for(seg_list = env->seg_list; seg_list; seg_list = seg_list->next)
+ for(index = 0; index < seg_list->size; index++)
+ putchar(seg_list->buffer[index]);
+}
+
+int main()
+{
+ struct environment env;
+ char *lexem;
+
+ initialize_environment(&env);
+
+ for(;; free(lexem))
+ {
+ lexem = read_lexem();
+ if(!lexem)
+ break;
+ if(find_identifier(&env, lexem))
+ continue;
+ if(is_lexem_hex(&env, lexem))
+ continue;
+ if(!execute_operator(&env, lexem))
+ exit_error(ERROR_STATUS_UNDEFINED, lexem);
+ }
+
+ print_target_buffer(&env);
+
+ return 0;
+}