diff --git a/README.md b/README.md index 0a7dca8..57f3531 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # TIM - Titanium Virtual Machine +CanoScript is now in its own [repo](https://www.github.com/CobbCoding1/canoscript) + Implementation of a virtual machine in C. VM currently has 45 instructions as well as a some native functions. List can be found in tim.h. @@ -22,3 +24,4 @@ get_str 0 ; Index of the string on the data stack push STDOUT write ; length is inferred because the string is null-terminated ``` + diff --git a/canoscript/Makefile b/canoscript/Makefile deleted file mode 100644 index 08dcddf..0000000 --- a/canoscript/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -CC=gcc -CFLAGS=-Wall -Wextra -pedantic -ggdb2 -Werror -DEFINES= -INCLUDES= -LIBS= - -SRCDIR=src -BUILDDIR=build - -ifeq ($(BUILD_TYPE), DEBUG) -CFLAGS += -g -ggdb2 -endif - -SRC=$(wildcard $(SRCDIR)/*.c) -OBJ=$(patsubst $(SRCDIR)/%.c, $(BUILDDIR)/%.o, $(SRC)) - -BINARYNAME=main -BINARY=$(BUILDDIR)/$(BINARYNAME) - -.PHONY: all setup clean destroy - -all: $(BINARY) - -$(BINARY): $(BUILDDIR)/$(OBJ) - $(CC) $(CFLAGS) $(INCLUDES) $(OBJ) -o $(BINARY) $(LIBS) - -$(BUILDDIR)/%.o: $(SRCDIR)/%.c - $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@ - -setup: - mkdir -p $(BUILDDIR) - -clean: - rm -rf $(BINARY) - rm -rf $(OBJ) - -destroy: - rm -rf $(BUILDDIR) diff --git a/canoscript/src/arena.h b/canoscript/src/arena.h deleted file mode 100644 index 0245870..0000000 --- a/canoscript/src/arena.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef ARENA_H -#define ARENA_H -#include -#include -#include -#include -#include - -#ifndef ARENA_INIT_SIZE -#define ARENA_INIT_SIZE 128 -#endif - -typedef struct Arena { - struct Arena *next; - size_t capacity; - size_t size; - uint8_t *data; -} Arena; - - -Arena arena_init(size_t capacity); -void *arena_alloc(Arena *arena, size_t size); -void *arena_realloc(Arena *arena, void *old_ptr, size_t old_size, size_t new_size); -void arena_reset(Arena *arena); -void arena_free(Arena *arena); -void arena_print(const Arena *arena); - -#endif // ARENA_H - -#ifdef ARENA_IMPLEMENTATION -#define ARENA_IMPLEMENTATION - -#ifndef ARENA_ALLOC -void *custom_malloc(size_t size) { - void *ptr = malloc(sizeof(uint8_t) * size); - if(ptr == NULL) { - fprintf(stderr, "error: buy more ram"); - exit(1); - } - return ptr; -} -#define ARENA_ALLOC custom_malloc -#endif // ARENA_ALLOC - - -Arena arena_init(size_t capacity) { - void *data = ARENA_ALLOC(sizeof(uint8_t) * capacity); - Arena arena = { - .capacity = capacity, - .size = 0, - .data = data, - .next = NULL, - }; - return arena; -} - -void *arena_alloc(Arena *arena, size_t size) { - if(arena == NULL) return NULL; - Arena *current = arena; - while(!(current->size + size <= current->capacity)) { - if(current->next == NULL) { - Arena *next = ARENA_ALLOC(sizeof(Arena)); - Arena initted = arena_init(arena->capacity+size); - memcpy(next, &initted, sizeof(Arena)); - current->next = next; - } - current = current->next; - } - - uint8_t *data = ¤t->data[current->size]; - current->size += size; - return data; -} - -void *arena_realloc(Arena *arena, void *old_ptr, size_t old_size, size_t new_size) { - if (new_size <= old_size) return old_ptr; - - void *new_ptr = arena_alloc(arena, new_size); - if(old_ptr == NULL) return new_ptr; - uint8_t *new_ptr_char = new_ptr; - uint8_t *old_ptr_char = old_ptr; - - memcpy(new_ptr_char, old_ptr_char, sizeof(uint8_t)*old_size); - - return new_ptr; -} - -void arena_reset(Arena *arena) { - Arena *current = arena; - while(current != NULL) { - current->size = 0; - current = current->next; - } -} - -void arena_free(Arena *arena) { - free(arena->data); - arena->capacity = 0; - arena->size = 0; - Arena *current = arena->next; - while(current != NULL) { - Arena *tmp = current->next; - free(current->data); - free(current); - current = tmp; - } - arena->next = NULL; -} - -void arena_print(const Arena *arena) { - const Arena *current = arena; - while(current != NULL) { - printf("capacity: %zu, size: %zu, data ptr: %p -> ", current->capacity, current->size, current->data); - current = current->next; - } - printf("NULL\n"); -} - -#endif // ARENA_IMPEMENATION \ No newline at end of file diff --git a/canoscript/src/backend.c b/canoscript/src/backend.c deleted file mode 100644 index 978c5a7..0000000 --- a/canoscript/src/backend.c +++ /dev/null @@ -1,779 +0,0 @@ -#include "backend.h" - -char *node_types[TYPE_COUNT] = {"root", "native", "expr", "var_dec", "var_reassign", - "if", "else", "while", "then", "func_dec", "func_call", "return", "end"}; - -size_t data_type_s[DATA_COUNT] = {8, 1, 1, 1, 8, 8}; - -Node get_struct(Nodes structs, String_View name) { - for(size_t i = 0; i < structs.count; i++) { - if(view_cmp(name, structs.data[i].value.structs.name)) { - return structs.data[i]; - } - } - ASSERT(false, "unknown struct: "View_Print, View_Arg(name)); - PRINT_ERROR((Location){0}, "unknown struct\n"); -} - -Inst create_inst(Inst_Set type, Word value, DataType d_type) { - return (Inst) { - .type = type, - .value = value, - .data_type = d_type, - }; -} - -// TODO: add ASSERTs to all "popping" functions -void gen_push(Program_State *state, FILE *file, int value) { - Inst inst = create_inst(INST_PUSH, (Word){.as_int=value}, INT_TYPE); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "push %d\n", value); - state->stack_s++; -} - -void gen_push_float(Program_State *state, FILE *file, double value) { - Inst inst = create_inst(INST_PUSH, (Word){.as_float=value}, FLOAT_TYPE); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "push %f\n", value); - state->stack_s++; -} - -void gen_push_char(Program_State *state, FILE *file, String_View value) { - Inst inst = create_inst(INST_PUSH, (Word){.as_char=value.data[0]}, CHAR_TYPE); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "push '"View_Print"'\n", View_Arg(value)); - state->stack_s++; -} - -void gen_pop(Program_State *state, FILE *file) { - Inst inst = create_inst(INST_POP, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "pop\n"); - state->stack_s--; -} - -void gen_add(Program_State *state, FILE *file) { - Inst inst = create_inst(INST_ADD, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "add\n"); - state->stack_s--; -} - -void gen_sub(Program_State *state, FILE *file) { - Inst inst = create_inst(INST_SUB, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "sub\n"); - state->stack_s--; -} - -void gen_mul(Program_State *state, FILE *file) { - Inst inst = create_inst(INST_MUL, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "mul\n"); - state->stack_s--; -} - -void gen_div(Program_State *state, FILE *file) { - Inst inst = create_inst(INST_DIV, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "div\n"); - state->stack_s--; -} - -void gen_push_str(Program_State *state, FILE *file, String_View value) { - Inst inst = create_inst(INST_PUSH_STR, (Word){.as_int=state->machine.str_stack.count}, INT_TYPE); - DA_APPEND(&state->machine.instructions, inst); - DA_APPEND(&state->machine.str_stack, value); - fprintf(file, "push_str \""View_Print"\"\n", View_Arg(value)); - state->stack_s += 1; -} - -void gen_ss(Program_State *state, FILE *file) { - Inst inst = create_inst(INST_SS, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "ss\n"); - state->stack_s++; -} - -void gen_indup(Program_State *state, FILE *file, size_t value) { - gen_push(state, file, value); - Inst inst = create_inst(INST_INDUP, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "indup\n"); -} - -void gen_global_indup(Program_State *state, FILE *file, size_t value) { - gen_ss(state, file); - gen_push(state, file, value); - gen_sub(state, file); - Inst inst = create_inst(INST_INDUP, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "indup\n"); -} - -void gen_inswap(Program_State *state, FILE *file, size_t value) { - gen_push(state, file, value); - Inst inst = create_inst(INST_INSWAP, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "inswap\n"); - state->stack_s--; -} - -void gen_global_inswap(Program_State *state, FILE *file, size_t value) { - gen_ss(state, file); - gen_push(state, file, value); - gen_sub(state, file); - Inst inst = create_inst(INST_INSWAP, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "inswap\n"); - state->stack_s--; -} - -void gen_zjmp(Program_State *state, FILE *file, size_t label) { - Inst inst = create_inst(INST_ZJMP, (Word){.as_int=label}, INT_TYPE); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "zjmp label%zu\n", label); - state->stack_s--; -} - -void gen_jmp(Program_State *state, FILE *file, size_t label) { - Inst inst = create_inst(INST_JMP, (Word){.as_int=label}, INT_TYPE); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "jmp label%zu\n", label); -} - -void gen_while_jmp(Program_State *state, FILE *file, size_t label) { - Inst inst = create_inst(INST_JMP, (Word){.as_int=label}, PTR_TYPE); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "jmp while%zu\n", label); -} - -void gen_label(Program_State *state, FILE *file, size_t label) { - Inst inst = create_inst(INST_NOP, (Word){.as_int=0}, 0); - while(state->labels.count <= label) DA_APPEND(&state->labels, 0); - state->labels.data[label] = state->machine.instructions.count; - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "label%zu:\n", label); -} - -void gen_func_label(Program_State *state, FILE *file, String_View label) { - Inst inst = create_inst(INST_NOP, (Word){.as_int=0}, 0); - Function *function = get_func(state->functions, label); - function->label = state->machine.instructions.count; - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, View_Print":\n", View_Arg(label)); -} - -void gen_func_call(Program_State *state, FILE *file, String_View label) { - size_t loc = get_func_loc(state->functions, label); - Inst inst = create_inst(INST_CALL, (Word){.as_int=loc}, INT_TYPE); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "call "View_Print"\n", View_Arg(label)); -} - -void gen_while_label(Program_State *state, FILE *file, size_t label) { - Inst inst = create_inst(INST_NOP, (Word){.as_int=0}, 0); - while(state->while_labels.count <= label) DA_APPEND(&state->while_labels, 0); - state->while_labels.data[label] = state->machine.instructions.count; - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "while%zu:\n", label); -} - -void gen_alloc(Program_State *state, FILE *file, Expr *s, size_t type_s) { - gen_push(state, file, type_s); - gen_expr(state, file, s); - gen_mul(state, file); - Inst inst = create_inst(INST_ALLOC, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "alloc\n"); -} - -void gen_struct_alloc(Program_State *state, FILE *file, size_t total_s) { - gen_push(state, file, total_s); - Inst inst = create_inst(INST_ALLOC, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "alloc\n"); -} - -void gen_dup(Program_State *state, FILE *file) { - Inst inst = create_inst(INST_DUP, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "dup\n"); - state->stack_s++; -} - -void gen_offset(Program_State *state, FILE *file, size_t offset) { - gen_push(state, file, offset); - gen_add(state, file); - Inst inst = create_inst(INST_TOVP, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "tovp\n"); -} - -void gen_write(Program_State *state, FILE *file) { - Inst inst = create_inst(INST_WRITE, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "write\n"); - state->stack_s -= 3; -} - -void gen_read(Program_State *state, FILE *file) { - Inst inst = create_inst(INST_READ, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "read\n"); - state->stack_s -= 1; -} - -void gen_arr_offset(Program_State *state, FILE *file, size_t var_index, Expr *arr_index, Type_Type type) { - fprintf(file, "; offset\n"); - gen_indup(state, file, state->stack_s-var_index); - gen_expr(state, file, arr_index); - gen_push(state, file, data_type_s[type]); - gen_mul(state, file); - gen_add(state, file); - Inst inst = create_inst(INST_TOVP, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "tovp\n"); -} - -void gen_struct_offset(Program_State *state, FILE *file, Type_Type type, size_t offset) { - fprintf(file, "; offset\n"); - gen_dup(state, file); - gen_push(state, file, offset); - gen_push(state, file, data_type_s[type]); - gen_mul(state, file); - gen_add(state, file); - Inst inst = create_inst(INST_TOVP, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "tovp\n"); -} - -void gen_struct_value(Program_State *state, FILE *file, size_t field_pos, Node *field, Node *value) { - for(size_t i = 0; i < value->value.var.struct_value.count; i++) { - Arg var = value->value.var.struct_value.data[i]; - if(view_cmp(field->value.var.name, var.name)) { - gen_struct_offset(state, file, field->value.var.type, field_pos); - gen_expr(state, file, var.value.expr); - gen_push(state, file, data_type_s[field->value.var.type]); - gen_write(state, file); - } - } -} - -void strip_off_dot(char *str) { - while(*str != '\0' && *str != '.') { - str++; - } - *str = '\0'; -} - -char *append_tasm_ext(char *filename) { - size_t filename_s = strlen(filename); - char *output = custom_realloc(NULL, sizeof(char)*filename_s); - strncpy(output, filename, filename_s); - strip_off_dot(output); - char *output_filename = custom_realloc(NULL, sizeof(char)*strlen(output)+sizeof(".tasm")); - sprintf(output_filename, "%s.tasm", output); - free(output); - return output_filename; -} - -char *op_types[] = {"add", "sub", "mul", "div", "mod", "cmpe", "cmpne", "cmpge", "cmple", "cmpg", "cmpl"}; -Inst_Set op_types_inst[] = {INST_ADD, INST_SUB, INST_MUL, INST_DIV, INST_MOD, INST_CMPE, - INST_CMPNE, INST_CMPGE, INST_CMPLE, INST_CMPG, INST_CMPL}; - -Function *get_func(Functions functions, String_View name) { - for(size_t i = 0; i < functions.count; i++) { - if(view_cmp(functions.data[i].name, name)) { - return &functions.data[i]; - } - } - return false; -} - -size_t get_func_loc(Functions functions, String_View name) { - for(size_t i = 0; i < functions.count; i++) { - if(view_cmp(functions.data[i].name, name)) { - return i; - } - } - ASSERT(false, "unexpected function name"); -} - -bool is_func_arg(Program_State *state, String_View name) { - if(state->functions.count == 0) return false; - size_t index = state->functions.count-1; - for(size_t i = 0; i < state->functions.data[index].args.count; i++) { - if(view_cmp(name, state->functions.data[index].args.data[i].value.var.name)) return true; - } - return false; -} - - -bool is_current_func(Program_State *state, String_View func) { - if(state->functions.count == 0) return false; - if(view_cmp(func, state->functions.data[state->functions.count-1].name)) return true; - return false; - -} - -int get_variable_location(Program_State *state, String_View name) { - for(size_t i = 0; i < state->vars.count; i++) { - if(view_cmp(state->vars.data[i].name, name) && (state->vars.data[i].global || - is_func_arg(state, name) || true || - is_current_func(state, state->vars.data[i].function) - )) { - return state->vars.data[i].stack_pos; - } - } - return -1; -} - -Variable get_variable(Program_State *state, String_View name) { - for(size_t i = 0; i < state->vars.count; i++) { - if(view_cmp(state->vars.data[i].name, name)) { - return state->vars.data[i]; - } - } - ASSERT(false, "unknown variable: "View_Print, View_Arg(name)); -} - -Type_Type get_variable_type(Program_State *state, String_View name) { - return get_variable(state, name).type; -} - -void gen_builtin(Program_State *state, FILE *file, Expr *expr) { - ASSERT(expr->type == EXPR_BUILTIN, "type is incorrect"); - for(size_t i = 0; i < expr->value.builtin.value.count; i++) { - gen_expr(state, file, expr->value.builtin.value.data[i]); - } - switch(expr->value.builtin.type) { - case BUILTIN_ALLOC: { - Inst inst = create_inst(INST_ALLOC, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "alloc\n"); - } break; - case BUILTIN_DEALLOC: { - Inst inst = create_inst(INST_DEALLOC, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "dealloc\n"); - state->stack_s--; - } break; - case BUILTIN_TOVP: { - Inst inst = create_inst(INST_TOVP, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "tovp\n"); - } break; - case BUILTIN_STORE: { - if(expr->value.builtin.value.count != 3) { - PRINT_ERROR(expr->loc, "incorrect arg amounts for store"); - } - Inst inst = create_inst(INST_WRITE, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "write\n"); - state->stack_s -= 3; - } break; - case BUILTIN_GET: { - if(expr->value.builtin.value.count != 2) { - PRINT_ERROR(expr->loc, "incorrect arg amounts for get"); - } - Inst inst = create_inst(INST_READ, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "read\n"); - state->stack_s -= 1; - } break; - } -} - -void gen_field_offset(Program_State *state, FILE *file, Struct structure, String_View var) { - size_t offset = 0; - size_t i; - for(i = 0; !view_cmp(structure.values.data[i].value.var.name, var); i++) { - if(i == structure.values.count) PRINT_ERROR((Location){0}, "unknown field: "View_Print" of struct: "View_Print, View_Arg(var), View_Arg(structure.name)); - offset += (1 * data_type_s[structure.values.data[i].value.var.type]); - } - gen_offset(state, file, offset); - gen_push(state, file, data_type_s[structure.values.data[i].value.var.type]); -} - -void gen_struct_field_offset(Program_State *state, FILE *file, String_View struct_name, String_View var) { - Variable struct_var = get_variable(state, struct_name); - Struct structure = get_struct(state->structs, struct_var.struct_name).value.structs; - gen_indup(state, file, state->stack_s-struct_var.stack_pos); - gen_field_offset(state, file, structure, var); -} - -void gen_expr(Program_State *state, FILE *file, Expr *expr) { - switch(expr->type) { - case EXPR_BIN: - gen_expr(state, file, expr->value.bin.lhs); - gen_expr(state, file, expr->value.bin.rhs); - Inst inst = create_inst(op_types_inst[expr->value.bin.op.type], (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "%s\n", op_types[expr->value.bin.op.type]); - state->stack_s--; - break; - case EXPR_INT: - gen_push(state, file, expr->value.integer); - break; - case EXPR_FLOAT: - gen_push_float(state, file, expr->value.floating); - break; - case EXPR_STR: - gen_push_str(state, file, expr->value.string); - break; - case EXPR_CHAR: - gen_push_char(state, file, expr->value.string); - break; - case EXPR_VAR: { - int index = get_variable_location(state, expr->value.variable); - if(index == -1) { - PRINT_ERROR(expr->loc, "variable `"View_Print"` referenced before assignment", View_Arg(expr->value.variable)); - } - if(get_variable(state, expr->value.variable).global) gen_global_indup(state, file, index); - else gen_indup(state, file, state->stack_s-index); - } break; - case EXPR_FUNCALL: { - Function *function = get_func(state->program.functions, expr->value.func_call.name); - if(!function) { - PRINT_ERROR(expr->loc, "function `"View_Print"` referenced before assignment\n", View_Arg(expr->value.func_call.name)); - } - if(function->args.count != expr->value.func_call.args.count) { - PRINT_ERROR(expr->loc, "args count do not match for function `"View_Print"`\n", View_Arg(function->name)); - } - for(size_t i = 0; i < expr->value.func_call.args.count; i++) { - gen_expr(state, file, expr->value.func_call.args.data[i]); - } - gen_func_call(state, file, expr->value.func_call.name); - for(size_t i = 0; i < expr->value.func_call.args.count; i++) { - state->stack_s--; - } - if(function->type != TYPE_VOID) state->stack_s++; - } break; - case EXPR_ARR: { - int index = get_variable_location(state, expr->value.array.name); - if(index == -1) { - PRINT_ERROR(expr->loc, "variable `"View_Print"` referenced before assignment", View_Arg(expr->value.array.name)); - } - Type_Type type = get_variable_type(state, expr->value.array.name); - gen_arr_offset(state, file, index, expr->value.array.index, type); - gen_push(state, file, data_type_s[type]); - gen_read(state, file); - } break; - case EXPR_FIELD_ARR: { - int index = get_variable_location(state, expr->value.array.name); - if(index == -1) { - PRINT_ERROR(expr->loc, "variable `"View_Print"` referenced before assignment", View_Arg(expr->value.array.name)); - } - Type_Type type = get_variable_type(state, expr->value.array.name); - Variable var = get_variable(state, expr->value.array.name); - gen_arr_offset(state, file, index, expr->value.array.index, type); - gen_push(state, file, data_type_s[type]); - gen_read(state, file); - Struct structure = get_struct(state->structs, var.struct_name).value.structs; - String_View var_name = expr->value.array.var_name; - gen_field_offset(state, file, structure, var_name); - gen_read(state, file); - } break; - case EXPR_FIELD: { - String_View structure = expr->value.field.structure; - String_View var_name = expr->value.field.var_name; - gen_struct_field_offset(state, file, structure, var_name); - gen_read(state, file); - } break; - case EXPR_BUILTIN: { - gen_builtin(state, file, expr); - } break; - default: - ASSERT(false, "UNREACHABLE, %d\n", expr->type); - } -} - -void scope_end(Program_State *state, FILE *file) { - ASSERT(state->scope_stack.count > 0, "scope stack count == 0"); - size_t target = state->scope_stack.data[state->scope_stack.count-1]; - while(state->stack_s > target) { - gen_pop(state, file); - } - while(state->vars.count > 0 && state->vars.data[state->vars.count-1].stack_pos > state->stack_s) { - state->vars.count--; - } -} - -void ret_scope_end(Program_State *state, FILE *file) { - ASSERT(state->ret_stack.count > 0, "scope stack count == 0"); - size_t target = state->ret_stack.data[state->ret_stack.count-1]; - if(state->stack_s > 0) state->stack_s--; - while(state->stack_s > target) { - gen_pop(state, file); - } -} - -void gen_var_dec(Program_State *state, FILE *file, Node *node) { - fprintf(file, "; var declaration "View_Print"\n", View_Arg(node->value.var.name)); - if(node->value.var.is_array && node->value.var.type != TYPE_STR) { - fprintf(file, "; array allocation\n"); - gen_alloc(state, file, node->value.var.array_s, data_type_s[node->value.var.type]); - for(size_t i = 0; i < node->value.var.value.count; i++) { - fprintf(file, "; index %zu expr\n", i); - gen_dup(state, file); - gen_offset(state, file, data_type_s[node->value.var.type]*i); - gen_expr(state, file, node->value.var.value.data[i]); - gen_push(state, file, data_type_s[node->value.var.type]); - gen_write(state, file); - } - } else if(node->value.var.is_struct) { - fprintf(file, "; struct allocation\n"); - Node cur_struct = get_struct(state->structs, node->value.var.struct_name); - size_t alloc_s = 0; - for(size_t i = 0; i < cur_struct.value.structs.values.count; i++) { - alloc_s += data_type_s[cur_struct.value.structs.values.data[i].value.var.type]; - } - gen_struct_alloc(state, file, alloc_s); - for(size_t i = 0; i < cur_struct.value.structs.values.count; i++) { - gen_struct_value(state, file, i, &cur_struct.value.structs.values.data[i], node); - } - } else { - fprintf(file, "; expr\n"); - gen_expr(state, file, node->value.var.value.data[0]); - } - node->value.var.stack_pos = state->stack_s; - DA_APPEND(&state->vars, node->value.var); -} - -void gen_vars(Program_State *state, Program *program, FILE *file) { - for(size_t i = 0; i < program->vars.count; i++) { - Node *node = &program->vars.data[i]; - switch(node->type) { - case TYPE_VAR_DEC: { - gen_var_dec(state, file, node); - node->value.var.global = true; - } break; - default: { - ASSERT(false, "unexpected node"); - } break; - } - } -} - -void gen_program(Program_State *state, Nodes nodes, FILE *file) { - for(size_t i = 0; i < nodes.count; i++) { - Node *node = &nodes.data[i]; - switch(node->type) { - case TYPE_NATIVE: - switch(node->value.native.type) { - case NATIVE_WRITE: { - if(node->value.native.args.count > 1) { - fprintf(stderr, "error: too many args\n"); - exit(1); - } - fprintf(file, "; write\n"); - gen_expr(state, file, node->value.native.args.data[0].value.expr); - gen_push(state, file, STDOUT); - Inst inst = create_inst(INST_NATIVE, (Word){.as_int=node->value.native.type}, INT_TYPE); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "native %d\n", node->value.native.type); - state->stack_s -= 2; - } break; - case NATIVE_EXIT: { - ASSERT(node->value.native.args.count == 1, "too many arguments"); - if(node->value.native.args.data[0].type != ARG_EXPR) { - PRINT_ERROR(node->loc, "expected type int, but found type %s", node_types[node->value.native.args.data[0].type]); - }; - fprintf(file, "; exit\n"); - fprintf(file, "; expr\n"); - gen_expr(state, file, node->value.native.args.data[0].value.expr); - Inst inst = create_inst(INST_NATIVE, (Word){.as_int=node->value.native.type}, INT_TYPE); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "native %d\n", node->value.native.type); - state->stack_s--; - } break; - default: - ASSERT(false, "unreachable"); - } - break; - case TYPE_VAR_DEC: { - gen_var_dec(state, file, node); - } break; - case TYPE_VAR_REASSIGN: { - fprintf(file, "; var reassign\n"); - fprintf(file, "; expr\n"); - gen_expr(state, file, node->value.var.value.data[0]); - int index = get_variable_location(state, node->value.var.name); - if(index == -1) { - PRINT_ERROR(node->loc, "variable `"View_Print"` referenced before assignment", View_Arg(node->value.var.name)); - } - if(get_variable(state, node->value.var.name).global) gen_global_inswap(state, file, index); - else gen_inswap(state, file, state->stack_s-index); - gen_pop(state, file); - } break; - case TYPE_FIELD_REASSIGN: { - fprintf(file, "; field reassign\n"); - fprintf(file, "; expr\n"); - String_View structure = node->value.field.structure; - String_View var_name = node->value.field.var_name; - gen_struct_field_offset(state, file, structure, var_name); - gen_expr(state, file, node->value.field.value.data[0]); - gen_inswap(state, file, 1); - gen_write(state, file); - // TODO: MIGHT NEED a GEN_POP HERE - } break; - case TYPE_ARR_INDEX: { - fprintf(file, "; arr index\n"); - int index = get_variable_location(state, node->value.array.name); - if(index == -1) { - PRINT_ERROR(node->loc, "array `"View_Print"` referenced before assignment", View_Arg(node->value.var.name)); - } - Type_Type type = get_variable_type(state, node->value.array.name); - gen_arr_offset(state, file, index, node->value.array.index, type); - fprintf(file, "; expr\n"); - gen_expr(state, file, node->value.array.value.data[0]); - fprintf(file, "; size\n"); - gen_push(state, file, data_type_s[type]); - gen_write(state, file); - } break; - case TYPE_FUNC_DEC: { - fprintf(file, "; function declaration\n"); - Function function = {0}; - memcpy(&function, &node->value.func_dec, sizeof(Function)); - DA_APPEND(&state->functions, function); - DA_APPEND(&state->block_stack, BLOCK_FUNC); - DA_APPEND(&state->ret_stack, state->stack_s); - DA_APPEND(&state->scope_stack, state->stack_s); - for(size_t i = 0; i < function.args.count; i++) { - Variable var = {0}; - var.stack_pos = ++state->stack_s; - var.name = function.args.data[i].value.var.name; - var.type = function.args.data[i].value.var.type; - DA_APPEND(&state->vars, var); - } - gen_jmp(state, file, node->value.func_dec.label); - gen_func_label(state, file, function.name); - } break; - case TYPE_FUNC_CALL: { - Function *function = get_func(state->program.functions, node->value.func_call.name); - if(!function) PRINT_ERROR(node->loc, "function `"View_Print"` referenced before assignment\n", View_Arg(node->value.func_call.name)); - if(function->args.count != node->value.func_call.args.count) { - PRINT_ERROR(node->loc, "args count do not match for function `"View_Print"`\n", View_Arg(function->name)); - } - for(size_t i = 0; i < node->value.func_call.args.count; i++) { - gen_expr(state, file, node->value.func_call.args.data[i]); - } - gen_func_call(state, file, node->value.func_call.name); - state->stack_s -= node->value.func_call.args.count; - // for the return value - if(function->type != TYPE_VOID) { - gen_pop(state, file); - state->stack_s++; - } - } break; - case TYPE_RET: { - fprintf(file, "; return\n"); - if(state->functions.count == 0) { - PRINT_ERROR(node->loc, "return without function definition"); - } - Function function = state->functions.data[state->functions.count-1]; - if(function.type == TYPE_VOID) { - PRINT_ERROR(node->loc, "function `"View_Print"` with return type of void returns value", View_Arg(function.name)); - } - // + 1 because we need to place it on the top of the stack after scope_end - size_t pos = state->ret_stack.data[state->ret_stack.count-1] + 1; - gen_expr(state, file, node->value.expr); - ASSERT(pos <= state->stack_s, "pos is too great"); - gen_inswap(state, file, state->stack_s-pos); - size_t pre_stack_s = state->stack_s; - ret_scope_end(state, file); - state->stack_s = pre_stack_s; - Inst inst = create_inst(INST_RET, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "ret\n"); - } break; - case TYPE_IF: { - fprintf(file, "; if statement\n"); - fprintf(file, "; expr\n"); - DA_APPEND(&state->block_stack, BLOCK_IF); - gen_expr(state, file, node->value.conditional); - } break; - case TYPE_ELSE: { - fprintf(file, "; else statement\n"); - ASSERT(state->block_stack.count > 0, "block stack underflowed"); - if(state->block_stack.data[--state->block_stack.count] == BLOCK_IF) { - gen_jmp(state, file, node->value.el.label2); - } else { - PRINT_ERROR(node->loc, "expected `if` but found `%d`\n", state->block_stack.data[state->block_stack.count]); - } - DA_APPEND(&state->block_stack, BLOCK_ELSE); - gen_label(state, file, node->value.el.label1); - } break; - case TYPE_WHILE: { - fprintf(file, "; while loop\n"); - fprintf(file, "; expr\n"); - DA_APPEND(&state->block_stack, BLOCK_WHILE); - DA_APPEND(&state->while_labels, state->while_label); - gen_while_label(state, file, state->while_label++); - gen_expr(state, file, node->value.conditional); - } break; - case TYPE_THEN: { - fprintf(file, "; then\n"); - gen_zjmp(state, file, node->value.label.num); - DA_APPEND(&state->scope_stack, state->stack_s); - } break; - case TYPE_END: { - fprintf(file, "; end\n"); - ASSERT(state->block_stack.count > 0, "block stack was underflowed"); - scope_end(state, file); - state->scope_stack.count--; - Block_Type block = state->block_stack.data[--state->block_stack.count]; - if(block == BLOCK_WHILE) { - fprintf(file, "; end while\n"); - gen_while_jmp(state, file, state->while_labels.data[--state->while_labels.count]); - } else if(block == BLOCK_FUNC) { - fprintf(file, "; end func\n"); - Inst inst = create_inst(INST_RET, (Word){.as_int=0}, 0); - DA_APPEND(&state->machine.instructions, inst); - fprintf(file, "ret\n"); - } - gen_label(state, file, node->value.label.num); - } break; - case TYPE_EXPR_STMT: { - gen_expr(state, file, node->value.expr_stmt); - if(node->value.expr_stmt->return_type != TYPE_VOID) gen_pop(state, file); - } break; - default: - break; - } - } - -} - -void gen_label_arr(Program_State *state) { - Insts instructions = state->machine.instructions; - for(size_t i = 0; i < instructions.count; i++) { - switch(instructions.data[i].type) { - case INST_JMP: - case INST_ZJMP: - case INST_NZJMP: - if(instructions.data[i].data_type == PTR_TYPE) { - instructions.data[i].data_type = INT_TYPE; - break; - } - instructions.data[i].value.as_int = state->labels.data[instructions.data[i].value.as_int]; - break; - case INST_CALL: - instructions.data[i].value.as_int = state->functions.data[instructions.data[i].value.as_int].label; - break; - default: - continue; - } - } -} - -void generate(Program_State *state, Program *program, char *filename) { - char *output = append_tasm_ext(filename); - FILE *file = fopen(output, "w"); - gen_vars(state, program, file); - gen_program(state, program->nodes, file); - gen_label_arr(state); - fclose(file); - free(output); -} diff --git a/canoscript/src/backend.h b/canoscript/src/backend.h deleted file mode 100644 index cc83dfa..0000000 --- a/canoscript/src/backend.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#ifndef BACKEND_H -#define BACKEND_H - -#include "defs.h" -#include "tim.h" - -typedef struct { - size_t *data; - size_t count; - size_t capacity; -} Labels; - -typedef struct { - Variables vars; - Functions functions; - size_t stack_s; - Size_Stack scope_stack; - Size_Stack ret_stack; - size_t while_label; - Size_Stack while_labels; - Block_Stack block_stack; - Nodes structs; - Program program; - Labels labels; - Machine machine; -} Program_State; - -void gen_push(Program_State *state, FILE *file, int value); -void gen_pop(Program_State *state, FILE *file); -void gen_push_str(Program_State *state, FILE *file, String_View value); -void gen_indup(Program_State *state, FILE *file, size_t value); -void gen_inswap(Program_State *state, FILE *file, size_t value); -void gen_zjmp(Program_State *state, FILE *file, size_t label); -void gen_jmp(Program_State *state, FILE *file, size_t label); -void gen_while_jmp(Program_State *state, FILE *file, size_t label); -void gen_label(Program_State *state, FILE *file, size_t label); -void gen_func_label(Program_State *state, FILE *file, String_View label); -void gen_func_call(Program_State *state, FILE *file, String_View label); -void gen_while_label(Program_State *state, FILE *file, size_t label); -void strip_off_dot(char *str); -char *append_tasm_ext(char *filename); -Function *get_func(Functions functions, String_View name); -size_t get_func_loc(Functions functions, String_View name); -int get_variable_location(Program_State *state, String_View name); -void gen_expr(Program_State *state, FILE *file, Expr *expr); -void scope_end(Program_State *state, FILE *file); -void gen_program(Program_State *state, Nodes nodes, FILE *file); -void generate(Program_State *state, Program *program, char *filename); - -#endif // BACKEND_H \ No newline at end of file diff --git a/canoscript/src/defs.h b/canoscript/src/defs.h deleted file mode 100644 index cacfc41..0000000 --- a/canoscript/src/defs.h +++ /dev/null @@ -1,369 +0,0 @@ -#pragma once -#ifndef DEFS_H -#define DEFS_H - -#include -#include -#include -#include - -#include "view.h" -#include "arena.h" - -#define DATA_START_CAPACITY 16 - -#define NATIVE_OPEN 0 -#define NATIVE_WRITE 1 -#define NATIVE_EXIT 60 - -#define STDOUT 1 - -#define ASSERT(cond, ...) \ - do { \ - if (!(cond)) { \ - fprintf(stderr, "%s:%d: ASSERTION FAILED: ", __FILE__, __LINE__); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - exit(1); \ - } \ - } while (0) - -#define ADA_APPEND(arena, da, item) do { \ - if ((da)->count >= (da)->capacity) { \ - (da)->capacity = (da)->capacity == 0 ? DATA_START_CAPACITY : (da)->capacity*2; \ - (da)->data = arena_realloc((arena), (da)->data, (da)->count*sizeof(*(da)->data), (da)->capacity*sizeof(*(da)->data)); \ - ASSERT((da)->data != NULL, "outta ram"); \ - } \ - (da)->data[(da)->count++] = (item); \ -} while (0) - -#define DA_APPEND(da, item) do { \ - if ((da)->count >= (da)->capacity) { \ - (da)->capacity = (da)->capacity == 0 ? DATA_START_CAPACITY : (da)->capacity*2; \ - (da)->data = custom_realloc((da)->data, (da)->capacity*sizeof(*(da)->data)); \ - ASSERT((da)->data != NULL, "outta ram"); \ - } \ - (da)->data[(da)->count++] = (item); \ -} while (0) - -#define PRINT_ERROR(loc, ...) \ - do { \ - fprintf(stderr, "%s:%zu:%zu: error: ", loc.filename, loc.row, loc.col); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - exit(1); \ - } while(0) - -typedef enum { - BUILTIN_ALLOC = 0, - BUILTIN_DEALLOC, - BUILTIN_STORE, - BUILTIN_TOVP, - BUILTIN_GET, -} Builtin_Type; - -typedef struct { - char *data; - size_t count; - size_t capacity; -} Dynamic_Str; - -typedef enum { - TYPE_INT, - TYPE_STR, - TYPE_VOID, - TYPE_CHAR, - TYPE_FLOAT, - TYPE_PTR, - DATA_COUNT, -} Type_Type; - -typedef struct { - size_t row; - size_t col; - char *filename; -} Location; - - -typedef enum { - OP_PLUS, - OP_MINUS, - OP_MULT, - OP_DIV, - OP_MOD, - OP_EQ, - OP_NOT_EQ, - OP_GREATER_EQ, - OP_LESS_EQ, - OP_GREATER, - OP_LESS, -} Operator_Type; - -typedef enum { - PREC_0 = 0, - PREC_1, - PREC_2, - PREC_COUNT, -} Precedence; - -typedef struct { - Operator_Type type; - Precedence precedence; -} Operator; - -struct Expr; -struct Node; - -typedef struct { - struct Expr *lhs; - struct Expr *rhs; - Operator op; -} Bin_Expr; - -typedef struct { - struct Expr **data; - size_t count; - size_t capacity; -} Exprs; - -typedef struct { - Builtin_Type type; - Exprs value; - Type_Type return_type; -} Builtin; - -typedef struct { - String_View name; - Exprs args; -} Func_Call; - -typedef struct { - String_View name; - struct Expr *index; - String_View var_name; -} Array; - -typedef struct { - String_View structure; - String_View var_name; - Exprs value; -} Field; - -typedef enum { - EXPR_BIN, - EXPR_INT, - EXPR_FLOAT, - EXPR_STR, - EXPR_CHAR, - EXPR_VAR, - EXPR_FUNCALL, - EXPR_ARR, - EXPR_FIELD, - EXPR_FIELD_ARR, - EXPR_BUILTIN, - EXPR_COUNT, -} Expr_Type; - -typedef union { - Bin_Expr bin; - int integer; - double floating; - Field field; - Array array; - String_View variable; - String_View string; - Func_Call func_call; - Builtin builtin; -} Expr_Value; - -typedef struct Expr { - Expr_Value value; - Expr_Type type; - Type_Type return_type; - Location loc; -} Expr; - - -typedef enum { - VAR_STRING, - VAR_INT, -} Var_Type; - -typedef struct { - String_View string; - Expr *expr; -} Arg_Value; - -typedef enum { - ARG_STRING, - ARG_EXPR, -} Arg_Type; - -typedef struct { - Arg_Type type; - Arg_Value value; - String_View name; -} Arg; - -typedef struct { - Arg *data; - size_t count; - size_t capacity; -} Args; - -typedef struct { - Args args; - int type; -} Native_Call; - -typedef struct { - struct Node *data; - size_t count; - size_t capacity; -} Nodes; - -typedef struct { - String_View name; - Nodes args; - Type_Type type; - Nodes body; - size_t label; -} Func_Dec; - -// TODO: rename TYPE_* to NODE_* -typedef enum { - TYPE_ROOT = 0, - TYPE_NATIVE, - TYPE_EXPR, - TYPE_EXPR_STMT, - TYPE_VAR_DEC, - TYPE_VAR_REASSIGN, - TYPE_FIELD_REASSIGN, - TYPE_IF, - TYPE_ELSE, - TYPE_WHILE, - TYPE_THEN, - TYPE_FUNC_DEC, - TYPE_FUNC_CALL, - TYPE_STRUCT, - TYPE_ARR_INDEX, - TYPE_RET, - TYPE_END, - TYPE_COUNT, -} Node_Type; - -typedef struct { - String_View name; - String_View struct_name; - String_View function; - Args struct_value; - Type_Type type; - Exprs value; - size_t stack_pos; - bool is_array; - bool is_struct; - bool global; - Expr *array_s; -} Variable; - -typedef struct { - String_View name; - Nodes args; - Type_Type type; - size_t label; -} Function; - -typedef struct { - Function *data; - size_t count; - size_t capacity; -} Functions; - -typedef struct { - String_View name; - Nodes values; -} Struct; - -typedef struct { - Variable *data; - size_t count; - size_t capacity; -} Variables; - -typedef struct { - String_View name; - Expr *index; - Exprs value; -} Array_Index; - -typedef struct { - size_t label1; - size_t label2; -} Else_Label; - -typedef struct { - size_t num; - String_View function; -} Label; - -typedef union { - Native_Call native; - Expr *expr; - Expr *conditional; - Expr *expr_stmt; - Variable var; - Array_Index array; - Label label; - Else_Label el; - Func_Dec func_dec; - Func_Call func_call; - Struct structs; - Field field; -} Node_Value; - -typedef struct Node { - Node_Type type; - Node_Value value; - Location loc; -} Node; - -typedef enum { - BLOCK_IF, - BLOCK_ELSE, - BLOCK_WHILE, - BLOCK_FUNC, -} Block_Type; - -typedef struct { - Block_Type *data; - size_t count; - size_t capacity; -} Block_Stack; - -typedef struct { - size_t *data; - size_t count; - size_t capacity; -} Size_Stack; - -typedef struct { - String_View value; - Block_Type type; -} Block; - -typedef struct { - Block *data; - size_t count; - size_t capacity; -} Blocks; - -typedef struct { - Nodes nodes; - Functions functions; - Nodes structs; - Nodes vars; -} Program; - -void *custom_realloc(void *ptr, size_t size); - -#endif // DEFS_H diff --git a/canoscript/src/frontend.c b/canoscript/src/frontend.c deleted file mode 100644 index 531b3a8..0000000 --- a/canoscript/src/frontend.c +++ /dev/null @@ -1,1006 +0,0 @@ -#include "frontend.h" - -char *token_types[TT_COUNT] = {"none", "write", "exit", "builtin", "ident", - ":", "(", ")", "[", "]", "{", "}", ",", ".", "=", "==", "!=", ">=", "<=", ">", "<", "+", "-", "*", "/", "%", - "string", "char", "integer", "float", "struct", "void", "type", "if", "else", "while", "then", - "return", "end"}; - -String_View data_types[DATA_COUNT] = { - {.data="int", .len=3}, - {.data="str", .len=3}, - {.data="void", .len=4}, - {.data="char", .len=4}, - {.data="float", .len=5}, - {.data="ptr", .len=3}, -}; - -bool is_valid_escape(char c){ - switch(c){ - case 'n': - case 't': - case 'v': - case 'b': - case 'r': - case 'f': - case 'a': - case '\\': - case '?': - case '\'': - case '\"': - case '0': - return true; - default: - return false; - } -} - -char get_escape(char c){ - switch(c){ - case 'n': - return '\n'; - case 't': - return '\t'; - case 'v': - return '\v'; - case 'b': - return '\b'; - case 'r': - return '\r'; - case 'f': - return '\f'; - case 'a': - return '\a'; - case '\\': - return '\\'; - case '?': - return '\?'; - case '\'': - return '\''; - case '\"': - return '\"'; - case '0': - return '\0'; - default: - ASSERT(false, "unexpected escape character"); - } -} - -String_View read_file_to_view(Arena *arena, char *filename) { - FILE *file = fopen(filename, "r"); - - fseek(file, 0, SEEK_END); - size_t len = ftell(file); - fseek(file, 0, SEEK_SET); - - char *data = arena_alloc(arena, sizeof(char)*len); - fread(data, sizeof(char), len, file); - - fclose(file); - return (String_View){.data=data, .len=len}; -} - -bool isword(char c) { - return isalpha(c) || isdigit(c) || c == '_'; -} - -typedef struct { - String_View text; - int type; -} Keyword; - -Keyword keyword_list[] = { - {LITERAL_VIEW("write"), TT_WRITE}, - {LITERAL_VIEW("exit"), TT_EXIT}, - {LITERAL_VIEW("if"), TT_IF}, - {LITERAL_VIEW("else"), TT_ELSE}, - {LITERAL_VIEW("if"), TT_IF}, - {LITERAL_VIEW("while"), TT_WHILE}, - {LITERAL_VIEW("then"), TT_THEN}, - {LITERAL_VIEW("return"), TT_RET}, - {LITERAL_VIEW("end"), TT_END}, - {LITERAL_VIEW("struct"), TT_STRUCT}, -}; -#define KEYWORDS_COUNT sizeof(keyword_list)/sizeof(*keyword_list) - -Token_Type get_token_type(String_View view) { - for(size_t i = 0; i < KEYWORDS_COUNT; i++) { - if(view_cmp(view, keyword_list[i].text)) { - return keyword_list[i].type; - } - } - return TT_NONE; -} - -Keyword builtins_list[] = { - {LITERAL_VIEW("alloc"), BUILTIN_ALLOC}, - {LITERAL_VIEW("dealloc"), BUILTIN_DEALLOC}, - {LITERAL_VIEW("store"), BUILTIN_STORE}, - {LITERAL_VIEW("tovp"), BUILTIN_TOVP}, - {LITERAL_VIEW("get"), BUILTIN_GET}, -}; -#define BUILTIN_COUNT sizeof(builtins_list)/sizeof(*builtins_list) - -Token token_get_builtin(Token token, String_View view) { - for(size_t i = 0; i < BUILTIN_COUNT; i++) { - if(view_cmp(view, builtins_list[i].text)) { - token.type = TT_BUILTIN; - token.value.builtin = builtins_list[i].type; - return token; - } - } - return token; -} - -Token handle_data_type(Token token, String_View str) { - for(size_t i = 0; i < DATA_COUNT; i++) { - if(view_cmp(str, data_types[i])) { - token.type = TT_TYPE; - token.value.type = (Type_Type)i; - } - } - return token; -} - -bool is_operator(String_View view) { - switch(*view.data) { - case '+': - case '-': - case '*': - case '/': - case '>': - case '<': - case '%': - return true; - case '=': - if(view.len > 1 && view.data[1] == '=') return true; - return false; - case '!': - if(view.len > 1 && view.data[1] == '=') return true; - return false; - default: - return false; - } -} - -Token create_operator_token(char *filename, size_t row, size_t col, String_View *view) { - Token token = {0}; - token.loc = (Location){ - .filename = filename, - .row = row, - .col = col, - }; - switch(*view->data) { - case '+': - token.type = TT_PLUS; - break; - case '-': - token.type = TT_MINUS; - break; - case '*': - token.type = TT_MULT; - break; - case '/': - token.type = TT_DIV; - break; - case '%': - token.type = TT_MOD; - break; - case '=': - if(view->len > 1 && view->data[1] == '=') { - *view = view_chop_left(*view); - token.type = TT_DOUBLE_EQ; - } - break; - case '!': - if(view->len > 1 && view->data[1] == '=') { - *view = view_chop_left(*view); - token.type = TT_NOT_EQ; - } - break; - case '>': - if(view->len > 1 && view->data[1] == '=') { - *view = view_chop_left(*view); - token.type = TT_GREATER_EQ; - } else { - *view = view_chop_left(*view); - token.type = TT_GREATER; - } - break; - case '<': - if(view->len > 1 && view->data[1] == '=') { - *view = view_chop_left(*view); - token.type = TT_LESS_EQ; - } else { - *view = view_chop_left(*view); - token.type = TT_LESS; - } - break; - default: - ASSERT(false, "unreachable"); - } - return token; -} - -void print_token_arr(Token_Arr arr) { - for(size_t i = 0; i < arr.count; i++) { - printf("%zu:%zu: %s, "View_Print"\n", arr.data[i].loc.row, arr.data[i].loc.col, token_types[arr.data[i].type], View_Arg(arr.data[i].value.string)); - } -} - -Dynamic_Str generate_string(Arena *arena, String_View *view, Token token, char delim) { - Dynamic_Str word = {0}; - *view = view_chop_left(*view); - while(view->len > 0 && *view->data != delim) { - if(view->len > 1 && *view->data == '\\') { - //ADA_APPEND(arena, &word, *view->data); - *view = view_chop_left(*view); - if(!is_valid_escape(*view->data)) { - PRINT_ERROR(token.loc, "unexpected escape character: `%c`", *view->data); - } - ADA_APPEND(arena, &word, get_escape(*view->data)); - } else { - ADA_APPEND(arena, &word, *(*view).data); - } - *view = view_chop_left(*view); - } - ADA_APPEND(arena, &word, '\0'); - return word; -} - -Token_Arr lex(Arena *arena, Arena *string_arena, char *filename, String_View view) { - size_t row = 1; - Token_Arr tokens = {0}; - const char *start = view.data; - while(view.len > 0) { - Token token = {0}; - token.loc = (Location){.filename = filename, .row=row, .col=view.data-start}; - switch(*view.data) { - case ':': - token.type = TT_COLON; - ADA_APPEND(arena, &tokens, token); - break; - case '(': - token.type = TT_O_PAREN; - ADA_APPEND(arena, &tokens, token); - break; - case ')': - token.type = TT_C_PAREN; - ADA_APPEND(arena, &tokens, token); - break; - case '[': - token.type = TT_O_BRACKET; - ADA_APPEND(arena, &tokens, token); - break; - case ']': - token.type = TT_C_BRACKET; - ADA_APPEND(arena, &tokens, token); - break; - case '{': - token.type = TT_O_CURLY; - ADA_APPEND(arena, &tokens, token); - break; - case '}': - token.type = TT_C_CURLY; - ADA_APPEND(arena, &tokens, token); - break; - case ',': - token.type = TT_COMMA; - ADA_APPEND(arena, &tokens, token); - break; - case '.': - token.type = TT_DOT; - ADA_APPEND(arena, &tokens, token); - break; - case '"': { - Dynamic_Str word = generate_string(string_arena, &view, token, '"'); - if(view.len == 0 && *view.data != '"') { - PRINT_ERROR(token.loc, "expected closing `\"`"); - }; - token.type = TT_STRING; - token.value.string = view_create(word.data, word.count); - ADA_APPEND(arena, &tokens, token); - } break; - case '\'': { - Dynamic_Str word = generate_string(string_arena, &view, token, '\''); - if(word.count > 2) { - PRINT_ERROR(token.loc, "character cannot be made up of multiple characters"); - } - if(view.len == 0 && *view.data != '\'') { - PRINT_ERROR(token.loc, "expected closing `'` quote"); - }; - token.type = TT_CHAR_LIT; - token.value.string = view_create(word.data, word.count); - ADA_APPEND(arena, &tokens, token); - } break; - case '\n': - row++; - start = view.data; - break; - default: { - if(isalpha(*view.data)) { - Dynamic_Str word = {0}; - ADA_APPEND(string_arena, &word, *view.data); - view = view_chop_left(view); - while(view.len > 0 && isword(*view.data)) { - ADA_APPEND(string_arena, &word, *view.data); - view = view_chop_left(view); - } - view.data--; - view.len++; - String_View view = view_create(word.data, word.count); - token.type = get_token_type(view); - token = handle_data_type(token, view); - token = token_get_builtin(token, view); - if(token.type == TT_NONE) { - token.type = TT_IDENT; - token.value.ident = view; - }; - ADA_APPEND(arena, &tokens, token); - } else if(isdigit(*view.data)) { - Dynamic_Str num = {0}; - token.type = TT_INT; - while(view.len > 0 && (isdigit(*view.data) || *view.data == '.')) { - if(*view.data == '.') token.type = TT_FLOAT_LIT; - ADA_APPEND(arena, &num, *view.data); - view = view_chop_left(view); - } - view.data--; - view.len++; - - ADA_APPEND(arena, &num, '\0'); - if(token.type == TT_FLOAT_LIT) token.value.floating = atof(num.data); - else token.value.integer = atoi(num.data); - ADA_APPEND(arena, &tokens, token); - } else if(is_operator(view)) { - token = create_operator_token(filename, row, view.data-start, &view); - ADA_APPEND(arena, &tokens, token); - } else if(*view.data == '=') { - token.type = TT_EQ; - ADA_APPEND(arena, &tokens, token); - } else if(isspace(*view.data)) { - view = view_chop_left(view); - continue; - } else { - PRINT_ERROR(token.loc, "unexpected token `%c`", *view.data); - } - } - } - view = view_chop_left(view); - } - return tokens; -} - -Token token_consume(Token_Arr *tokens) { - ASSERT(tokens->count != 0, "out of tokens"); - tokens->count--; - return *tokens->data++; -} - -Token token_peek(Token_Arr *tokens, size_t peek_by) { - if(tokens->count <= peek_by) { - return (Token){0}; - } - return tokens->data[peek_by]; -} - -Token expect_token(Token_Arr *tokens, Token_Type type) { - Token token = token_consume(tokens); - if(token.type != type) { - PRINT_ERROR(token.loc, "expected type: `%s`, but found type `%s`\n", - token_types[type], token_types[token.type]); - }; - return token; -} - -Node *create_node(Arena *arena, Node_Type type) { - Node *node = arena_alloc(arena, sizeof(Node)); - node->type = type; - return node; -} - -Precedence op_get_prec(Token_Type type) { - switch(type) { - case TT_PLUS: - case TT_MINUS: - case TT_DOUBLE_EQ: - case TT_NOT_EQ: - case TT_GREATER_EQ: - case TT_LESS_EQ: - case TT_GREATER: - case TT_LESS: - return PREC_1; - case TT_MULT: - case TT_DIV: - case TT_MOD: - return PREC_2; - break; - default: - return PREC_0; - } -} - -Operator create_operator(Token_Type type) { - Operator op = {0}; - op.precedence = op_get_prec(type); - switch(type) { - case TT_PLUS: - op.type = OP_PLUS; - break; - case TT_MINUS: - op.type = OP_MINUS; - break; - case TT_MULT: - op.type = OP_MULT; - break; - case TT_DIV: - op.type = OP_DIV; - break; - case TT_MOD: - op.type = OP_MOD; - break; - case TT_DOUBLE_EQ: - op.type = OP_EQ; - break; - case TT_NOT_EQ: - op.type = OP_NOT_EQ; - break; - case TT_GREATER_EQ: - op.type = OP_GREATER_EQ; - break; - case TT_LESS_EQ: - op.type = OP_LESS_EQ; - break; - case TT_GREATER: - op.type = OP_GREATER; - break; - case TT_LESS: - op.type = OP_LESS; - break; - default: - return (Operator){0}; - } - return op; -} - -bool token_is_op(Token token) { - switch(token.type) { - case TT_PLUS: - case TT_MINUS: - case TT_MULT: - case TT_DIV: - return true; - default: - return false; - } -} - -void print_expr(Expr *expr) { - if(expr->type == EXPR_INT) { - printf("int: %d\n", expr->value.integer); - } else { - print_expr(expr->value.bin.lhs); - print_expr(expr->value.bin.rhs); - } -} - -Builtin parse_builtin_node(Arena *arena, Token_Arr *tokens, Builtin_Type type, Nodes *structs) { - Builtin builtin = { - .type = type, - }; - ADA_APPEND(arena, &builtin.value, parse_expr(arena, tokens, structs)); - while(token_peek(tokens, 0).type == TT_COMMA) { - token_consume(tokens); - ADA_APPEND(arena, &builtin.value, parse_expr(arena, tokens, structs)); - } - switch(type) { - case BUILTIN_TOVP: - case BUILTIN_GET: - case BUILTIN_ALLOC: - builtin.return_type = TYPE_PTR; - break; - case BUILTIN_STORE: - case BUILTIN_DEALLOC: - builtin.return_type = TYPE_VOID; - break; - } - return builtin; -} - -Expr *parse_primary(Arena *arena, Token_Arr *tokens, Nodes *structs) { - Token token = token_consume(tokens); - if(token.type != TT_INT && token.type != TT_BUILTIN && token.type != TT_FLOAT_LIT && token.type != TT_O_PAREN && token.type != TT_STRING && token.type != TT_CHAR_LIT && token.type != TT_IDENT) { - PRINT_ERROR(token.loc, "expected int, string, char, or ident but found %s", token_types[token.type]); - } - Expr *expr = arena_alloc(arena, sizeof(Expr)); - switch(token.type) { - case TT_INT: - *expr = (Expr){ - .type = EXPR_INT, - .value.integer = token.value.integer, - .loc = token.loc, - }; - break; - case TT_FLOAT_LIT: - *expr = (Expr){ - .type = EXPR_FLOAT, - .value.floating = token.value.floating, - .loc = token.loc, - }; - break; - case TT_STRING: - *expr = (Expr){ - .type = EXPR_STR, - .value.string = token.value.string, - }; - break; - case TT_CHAR_LIT: - *expr = (Expr){ - .type = EXPR_CHAR, - .value.string = token.value.string, - }; - break; - case TT_BUILTIN: { - Builtin value = parse_builtin_node(arena, tokens, token.value.builtin, structs); - *expr = (Expr) { - .type = EXPR_BUILTIN, - .value.builtin = value, - .loc = token.loc, - }; - if(expr->value.builtin.return_type == TYPE_VOID) expr->return_type = TYPE_VOID; - } break; - case TT_O_PAREN: - expr = parse_expr(arena, tokens, structs); - if(token_consume(tokens).type != TT_C_PAREN) { - PRINT_ERROR(token.loc, "expected `)`"); - } - break; - case TT_IDENT: - if(token_peek(tokens, 0).type == TT_O_PAREN) { - *expr = (Expr){ - .type = EXPR_FUNCALL, - .value.func_call.name = token.value.ident, - }; - if(token_peek(tokens, 1).type == TT_C_PAREN) { - token_consume(tokens); - token_consume(tokens); - return expr; - } - while(tokens->count > 0 && token_consume(tokens).type != TT_C_PAREN) { - Expr *arg = parse_expr(arena, tokens, structs); - ADA_APPEND(arena, &expr->value.func_call.args, arg); - } - } else if(token_peek(tokens, 0).type == TT_O_BRACKET) { - *expr = (Expr){ - .type = EXPR_ARR, - .value.array.name = token.value.ident, - }; - token_consume(tokens); // open bracket - expr->value.array.index = parse_expr(arena, tokens, structs); - if(token_consume(tokens).type != TT_C_BRACKET) { - PRINT_ERROR(tokens->data[0].loc, "expected `]` but found `%s`\n", token_types[tokens->data[0].type]); - } - if(token_peek(tokens, 0).type == TT_DOT) { - token_consume(tokens); - expr->type = EXPR_FIELD_ARR; - token = token_consume(tokens); // field name - expr->value.array.var_name = token.value.ident; - } - } else if(token_peek(tokens, 0).type == TT_DOT) { - *expr = (Expr){ - .type = EXPR_FIELD, - .value.field.structure = token.value.ident, - }; - token_consume(tokens); // dot - token = token_consume(tokens); // field name - expr->value.field.var_name = token.value.ident; - } else { - *expr = (Expr){ - .type = EXPR_VAR, - .value.variable = token.value.ident, - }; - } - break; - default: - ASSERT(false, "unexpected token"); - } - return expr; -} - - -Expr *parse_expr_1(Arena *arena, Token_Arr *tokens, Expr *lhs, Precedence min_precedence, Nodes *structs) { - Token lookahead = token_peek(tokens, 0); - // make sure it's an operator - while(op_get_prec(lookahead.type) >= min_precedence) { - Operator op = create_operator(lookahead.type); - if(tokens->count > 0) { - token_consume(tokens); - Expr *rhs = parse_primary(arena, tokens, structs); - lookahead = token_peek(tokens, 0); - while(op_get_prec(lookahead.type) > op.precedence) { - rhs = parse_expr_1(arena, tokens, rhs, op.precedence+1, structs); - lookahead = token_peek(tokens, 0); - } - // allocate new lhs node to ensure old lhs does not point - // at itself, getting stuck in a loop - Expr *new_lhs = arena_alloc(arena, sizeof(Expr)); - *new_lhs = (Expr) { - .type = EXPR_BIN, - .value.bin.lhs = lhs, - .value.bin.rhs = rhs, - .value.bin.op = op, - }; - lhs = new_lhs; - } - } - return lhs; -} -Expr *parse_expr(Arena *arena, Token_Arr *tokens, Nodes *structs) { - return parse_expr_1(arena, tokens, parse_primary(arena, tokens, structs), 1, structs); -} - -char *expr_types[EXPR_COUNT] = {"bin", "int", "str", "char", "var", "func", "arr"}; - -Expr_Type expr_type_check(Location loc, Expr *expr) { - return expr->type; - if(expr->type != EXPR_BIN) return expr->type; - Expr_Type typel = expr_type_check(loc, expr->value.bin.lhs); - Expr_Type typer = expr_type_check(loc, expr->value.bin.rhs); - if(typel != typer && typel != EXPR_VAR && typer != EXPR_VAR && - typel != EXPR_ARR && typer != EXPR_ARR && typel != EXPR_FUNCALL && typer != EXPR_FUNCALL) { - PRINT_ERROR(loc, "expected type `%s` but found type `%s`", expr_types[typel], expr_types[typer]); - } - return typel; -} - -Node parse_native_node(Arena *arena, Token_Arr *tokens, int native_value, Nodes *structs) { - Node node = {.type = TYPE_NATIVE, .loc = tokens->data[0].loc}; - token_consume(tokens); - Native_Call call = {0}; - Arg arg = {0}; - arg = (Arg){.type=ARG_EXPR, .value.expr=parse_expr(arena, tokens, structs)}; - expr_type_check(node.loc, arg.value.expr); - ADA_APPEND(arena, &call.args, arg); - call.type = native_value; - node.value.native = call; - return node; -} - -bool is_struct(Token_Arr *tokens, Nodes *structs) { - Token token = token_peek(tokens, 0); - if(token.type != TT_IDENT) PRINT_ERROR(token.loc, "expected identifier but found `%s`\n", token_types[token.type]); - for(size_t i = 0; i < structs->count; i++) { - if(view_cmp(structs->data[i].value.structs.name, token.value.ident)) return true; - } - return false; -} - - -Node parse_var_dec(Arena *arena, Token_Arr *tokens, Nodes *structs) { - Node node = {0}; - node.type = TYPE_VAR_DEC; - node.loc = tokens->data[0].loc; - node.value.var.name = tokens->data[0].value.ident; - token_consume(tokens); - expect_token(tokens, TT_COLON); - Token name_t = token_peek(tokens, 0); - if(name_t.type == TT_TYPE) { - node.value.var.type = tokens->data[0].value.type; - } else if(is_struct(tokens, structs)) { - node.value.var.is_struct = true; - node.value.var.struct_name = name_t.value.ident; - } else { - PRINT_ERROR(token_peek(tokens, 0).loc, "expected `type` but found `%s`\n", token_types[token_peek(tokens, 0).type]); - } - node.value.var.is_array = token_peek(tokens, 1).type == TT_O_BRACKET || node.value.var.type == TYPE_STR; - if(token_peek(tokens, 1).type == TT_O_BRACKET) { - token_consume(tokens); - token_consume(tokens); - node.value.var.array_s = parse_expr(arena, tokens, structs); - expr_type_check(node.loc, node.value.var.array_s); - } - return node; -} - -Struct get_structure(Location loc, Nodes *structs, String_View name) { - for(size_t i = 0; i < structs->count; i++) { - if(view_cmp(name, structs->data[i].value.structs.name)) { - return structs->data[i].value.structs; - } - } - PRINT_ERROR(loc, "unknown struct\n"); -} - -bool is_field(Struct *structure, String_View field) { - for(size_t i = 0; i < structure->values.count; i++) { - if(view_cmp(structure->values.data[i].value.var.name, field)) return true; - } - return false; -} - -bool is_in_function(Blocks *blocks) { - for(size_t i = 0; i < blocks->count; i++) { - if(blocks->data[i].type == BLOCK_FUNC) return true; - } - return false; -} - -int parse_reassign_left(Token_Arr *tokens, Node *node, Nodes *structs, Arena *arena) { - Token token = token_peek(tokens, 1); - if(token.type == TT_EQ) { - node->type = TYPE_VAR_REASSIGN; - Token name_t = token_consume(tokens); - token_consume(tokens); // eq - node->value.var.name = name_t.value.ident; - } else if(token.type == TT_DOT) { - Token name_t = token_consume(tokens); // ident - expect_token(tokens, TT_DOT); - node->type = TYPE_FIELD_REASSIGN; - node->value.field.structure = name_t.value.ident; - } else if(token.type == TT_O_BRACKET) { - node->type = TYPE_ARR_INDEX; - node->value.array.name = tokens->data[0].value.ident; - token_consume(tokens); // ident - token_consume(tokens); // open bracket - node->value.array.index = parse_expr(arena, tokens, structs); - expr_type_check(node->loc, node->value.array.index); - expect_token(tokens, TT_C_BRACKET); - } else if(token.type == TT_O_PAREN) { - size_t i = 1; - while(i < tokens->count+1 && token_peek(tokens, i).type != TT_C_PAREN) i++; - if(i == tokens->count) { - PRINT_ERROR(tokens->data[0].loc, "expected `%s`\n", token_types[tokens->data[0].type]); - } - Token token = token_peek(tokens, i+1); - if(token.type == TT_COLON) { - // function dec - node->type = TYPE_FUNC_DEC; - node->value.func_dec.name = tokens->data[0].value.ident; - return i; - } else { - // function call - node->type = TYPE_FUNC_CALL; - node->value.func_call.name = tokens->data[0].value.ident; - token_consume(tokens); - if(token_peek(tokens, 1).type == TT_C_PAREN) { - // consume the open and close paren of empty funcall - token_consume(tokens); - token_consume(tokens); - } else { - while(tokens->count > 0 && token_consume(tokens).type != TT_C_PAREN && i > 2) { - Expr *arg = parse_expr(arena, tokens, structs); - ADA_APPEND(arena, &node->value.func_call.args, arg); - expr_type_check(node->loc, node->value.func_call.args.data[node->value.func_call.args.count - 1]); - } - } - } - } - return 0; -} - -Program parse(Arena *arena, Token_Arr tokens, Blocks *block_stack) { - // TODO: initialize the Program struct at the top of func - Nodes root = {0}; - Functions functions = {0}; - Nodes structs = {0}; - Nodes vars = {0}; - size_t cur_label = 0; - Size_Stack labels = {0}; - while(tokens.count > 0) { - Node node = {.loc=tokens.data[0].loc}; - switch(tokens.data[0].type) { - case TT_WRITE: { - node = parse_native_node(arena, &tokens, NATIVE_WRITE, &structs); - ADA_APPEND(arena, &root, node); - } break; - case TT_EXIT: { - node = parse_native_node(arena, &tokens, NATIVE_EXIT, &structs); - ADA_APPEND(arena, &root, node); - } break; - case TT_IDENT: { - Token token = token_peek(&tokens, 1); - if(token.type == TT_COLON) { - node = parse_var_dec(arena, &tokens, &structs); - token_consume(&tokens); - expect_token(&tokens, TT_EQ); - if(block_stack->count == 0) node.value.var.global = 1; - if(node.value.var.is_array && node.value.var.type != TYPE_STR) { - if(token_consume(&tokens).type != TT_O_BRACKET) { - PRINT_ERROR(tokens.data[0].loc, "expected `[` but found `%s`\n", token_types[tokens.data[0].type]); - } - while(tokens.count > 0) { - ADA_APPEND(arena, &node.value.var.value, parse_expr(arena, &tokens, &structs)); - expr_type_check(node.loc, node.value.var.value.data[node.value.var.value.count-1]); - Token next = token_consume(&tokens); - if(next.type == TT_COMMA) continue; - else if(next.type == TT_C_BRACKET) break; - else PRINT_ERROR(tokens.data[0].loc, "expected `,` but found `%s`\n", token_types[tokens.data[0].type]); - } - } else if(node.value.var.is_struct) { - expect_token(&tokens, TT_O_CURLY); - Struct structure = get_structure(node.loc, &structs, node.value.var.struct_name); - while(tokens.count > 0 && token_peek(&tokens, 0).type != TT_C_CURLY) { - Token identifier = expect_token(&tokens, TT_IDENT); - if(!is_field(&structure, identifier.value.ident)) PRINT_ERROR(identifier.loc, "unknown field: "View_Print, View_Arg(identifier.value.ident)); - Arg arg = {.name = identifier.value.ident, .type = ARG_EXPR}; - expect_token(&tokens, TT_EQ); - arg.value.expr = parse_expr(arena, &tokens, &structs); - Token comma_t = token_consume(&tokens); - ADA_APPEND(arena, &node.value.var.struct_value, arg); - if(comma_t.type == TT_C_CURLY) break; - if(comma_t.type != TT_COMMA) PRINT_ERROR(comma_t.loc, "expected `,` but found %s\n", token_types[comma_t.type]); - } - if(token_peek(&tokens, 0).type == TT_C_CURLY) token_consume(&tokens); - } else { - ADA_APPEND(arena, &node.value.var.value, parse_expr(arena, &tokens, &structs)); - expr_type_check(node.loc, node.value.var.value.data[node.value.var.value.count-1]); - } - if(is_in_function(block_stack)) { - ASSERT(functions.count > 0, "Block stack got messed up frfr"); - node.value.var.function = functions.data[functions.count-1].name; - ADA_APPEND(arena, &root, node); - } else { - ADA_APPEND(arena, &vars, node); - } - break; - } else { - int i = parse_reassign_left(&tokens, &node, &structs, arena); - if(node.type == TYPE_VAR_REASSIGN) { - ADA_APPEND(arena, &node.value.var.value, parse_expr(arena, &tokens, &structs)); - expr_type_check(node.loc, node.value.var.value.data[node.value.var.value.count-1]); - } else if(node.type == TYPE_FIELD_REASSIGN) { - expect_token(&tokens, TT_EQ); - ADA_APPEND(arena, &node.value.field.value, parse_expr(arena, &tokens, &structs)); - expr_type_check(node.loc, node.value.field.value.data[node.value.field.value.count-1]); - } else if(node.type == TYPE_ARR_INDEX) { - Token token = token_peek(&tokens, 0); - if(token.type == TT_EQ) { - token_consume(&tokens); - ADA_APPEND(arena, &node.value.array.value, parse_expr(arena, &tokens, &structs)); - expr_type_check(node.loc, node.value.array.value.data[node.value.array.value.count - 1]); - } else if(token.type == TT_DOT) { - ASSERT(false, "unimplemented"); - } else { - PRINT_ERROR(node.loc, "unexpected token %s\n", token_types[token.type]); - } - } else if(node.type == TYPE_FUNC_DEC) { - Function function = {0}; - function.name = node.value.func_dec.name; - Block block = {.type = BLOCK_FUNC, .value = node.value.func_dec.name}; - ADA_APPEND(arena, block_stack, block); - token_consume(&tokens); - while(tokens.count > 0 && token_consume(&tokens).type != TT_C_PAREN && i > 2) { - Node arg = parse_var_dec(arena, &tokens, &structs); - arg.value.var.function = node.value.func_dec.name; - ADA_APPEND(arena, &node.value.func_dec.args, arg); - ADA_APPEND(arena, &function.args, arg); - token_consume(&tokens); - } - token_consume(&tokens); - if(i == 2) token_consume(&tokens); - node.value.func_dec.type = tokens.data[0].value.type; - function.type = node.value.func_dec.type; - token_consume(&tokens); - node.value.func_dec.label = cur_label; - ADA_APPEND(arena, &functions, function); - ADA_APPEND(arena, &labels, cur_label++); - } else if(node.type == TYPE_FUNC_CALL) { - // function call - if(token_peek(&tokens, 0).type == TT_DOT) { - ASSERT(false, "unimplemented"); - } - } else { - PRINT_ERROR(token.loc, "unexpected token `%s`\n", token_types[token.type]); - } - ADA_APPEND(arena, &root, node); - } - } break; - case TT_STRUCT: { - node.type = TYPE_STRUCT; - token_consume(&tokens); - Token name_t = expect_token(&tokens, TT_IDENT); - node.value.structs.name = name_t.value.ident; - expect_token(&tokens, TT_O_CURLY); - while(tokens.count > 0 && token_peek(&tokens, 0).type != TT_C_CURLY) { - Node arg = parse_var_dec(arena, &tokens, &structs); - ADA_APPEND(arena, &node.value.structs.values, arg); - token_consume(&tokens); - expect_token(&tokens, TT_COMMA); - } - token_consume(&tokens); - ADA_APPEND(arena, &structs, node); - } break; - case TT_RET: { - node.type = TYPE_RET; - token_consume(&tokens); - node.value.expr = parse_expr(arena, &tokens, &structs); - expr_type_check(node.loc, node.value.expr); - ADA_APPEND(arena, &root, node); - } break; - case TT_IF: { - node.type = TYPE_IF; - ADA_APPEND(arena, block_stack, (Block){.type=BLOCK_IF}); - token_consume(&tokens); - node.value.conditional = parse_expr(arena, &tokens, &structs); - expr_type_check(node.loc, node.value.conditional); - ADA_APPEND(arena, &root, node); - } break; - case TT_ELSE: { - node.type = TYPE_ELSE; - token_consume(&tokens); - if(labels.count == 0 || block_stack->count == 0 || block_stack->data[block_stack->count-1].type != BLOCK_IF) PRINT_ERROR(node.loc, "`else` statement without prior `if`"); - ADA_APPEND(arena, block_stack, (Block){.type=BLOCK_ELSE}); - block_stack->count--; - node.value.el.label1 = labels.data[--labels.count]; - node.value.el.label2 = cur_label; - ADA_APPEND(arena, &labels, cur_label++); - ADA_APPEND(arena, &root, node); - } break; - case TT_WHILE: { - node.type = TYPE_WHILE; - token_consume(&tokens); - ADA_APPEND(arena, block_stack, (Block){.type=BLOCK_WHILE}); - node.value.conditional = parse_expr(arena, &tokens, &structs); - expr_type_check(node.loc, node.value.conditional); - ADA_APPEND(arena, &root, node); - } break; - case TT_THEN: { - node.type = TYPE_THEN; - token_consume(&tokens); - node.value.label.num = cur_label; - ADA_APPEND(arena, &labels, cur_label++); - ADA_APPEND(arena, &root, node); - } break; - case TT_END: { - node.type = TYPE_END; - token_consume(&tokens); - if(labels.count == 0 || block_stack->count == 0) PRINT_ERROR(node.loc, "`end` without an opening block"); - --block_stack->count; - node.value.label.num = labels.data[--labels.count]; - ADA_APPEND(arena, &root, node); - } break; - case TT_STRING: - case TT_CHAR_LIT: - case TT_INT: - case TT_FLOAT_LIT: - case TT_BUILTIN: { - node.type = TYPE_EXPR_STMT; - node.value.expr_stmt = parse_expr(arena, &tokens, &structs); - ADA_APPEND(arena, &root, node); - } break; - case TT_VOID: - case TT_PLUS: - case TT_COLON: - case TT_EQ: - case TT_DOUBLE_EQ: - case TT_NOT_EQ: - case TT_O_PAREN: - case TT_C_PAREN: - case TT_O_BRACKET: - case TT_C_BRACKET: - case TT_O_CURLY: - case TT_C_CURLY: - case TT_COMMA: - case TT_DOT: - case TT_GREATER_EQ: - case TT_LESS_EQ: - case TT_GREATER: - case TT_LESS: - case TT_TYPE: - case TT_MINUS: - case TT_MULT: - case TT_DIV: - case TT_MOD: - case TT_NONE: - case TT_COUNT: - PRINT_ERROR(tokens.data[0].loc, "unexpected token: %s", token_types[tokens.data[0].type]); - default: - ASSERT(false, "invalid token detected, something went wrong in the parsing..."); - } - } - Program program = {0}; - program.nodes = root; - program.functions = functions; - program.structs = structs; - program.vars = vars; - return program; -} diff --git a/canoscript/src/frontend.h b/canoscript/src/frontend.h deleted file mode 100644 index 0da3d56..0000000 --- a/canoscript/src/frontend.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once -#ifndef FRONTEND_H -#define FRONTEND_H - -#include "defs.h" - -// Lexing -typedef enum { - TT_NONE = 0, - TT_WRITE, - TT_EXIT, - TT_BUILTIN, - TT_IDENT, - TT_COLON, - TT_O_PAREN, - TT_C_PAREN, - TT_O_BRACKET, - TT_C_BRACKET, - TT_O_CURLY, - TT_C_CURLY, - TT_COMMA, - TT_DOT, - TT_EQ, - TT_DOUBLE_EQ, - TT_NOT_EQ, - TT_GREATER_EQ, - TT_LESS_EQ, - TT_GREATER, - TT_LESS, - TT_PLUS, - TT_MINUS, - TT_MULT, - TT_DIV, - TT_MOD, - TT_STRING, - TT_CHAR_LIT, - // TODO TT_INT_LIT - TT_INT, - TT_FLOAT_LIT, - TT_STRUCT, - TT_VOID, - TT_TYPE, - TT_IF, - TT_ELSE, - TT_WHILE, - TT_THEN, - TT_RET, - TT_END, - TT_COUNT, -} Token_Type; - -typedef union { - String_View string; - String_View ident; - int integer; - double floating; - Type_Type type; - Builtin_Type builtin; -} Token_Value; - -typedef struct { - Token_Value value; - Token_Type type; - Location loc; -} Token; - -typedef struct { - Token *data; - size_t count; - size_t capacity; -} Token_Arr; - -bool is_valid_escape(char c); -String_View read_file_to_view(Arena *arena, char *filename); -bool isword(char c); -Token_Type get_token_type(String_View str); -Token handle_data_type(Token token, String_View str); -bool is_operator(String_View view); -Token create_operator_token(char *filename, size_t row, size_t col, String_View *view); -void print_token_arr(Token_Arr arr); -Token_Arr lex(Arena *arena, Arena *string_arena, char *filename, String_View view); -Token token_consume(Token_Arr *tokens); -Token token_peek(Token_Arr *tokens, size_t peek_by); -Token expect_token(Token_Arr *tokens, Token_Type type); -Node *create_node(Arena *arena, Node_Type type); -Precedence op_get_prec(Token_Type type); -Operator create_operator(Token_Type type); -Expr *parse_expr(Arena *arena, Token_Arr *tokens, Nodes *structs); -Expr *parse_primary(Arena *arena, Token_Arr *tokens, Nodes *structs); -Expr *parse_expr_1(Arena *arena, Token_Arr *tokens, Expr *lhs, Precedence min_precedence, Nodes *structs); -Node parse_native_node(Arena *arena, Token_Arr *tokens, int native_value, Nodes *structs); -Node parse_var_dec(Arena *arena, Token_Arr *tokens, Nodes *structs); -Program parse(Arena *arena, Token_Arr tokens, Blocks *block_stack); -Struct get_structure(Location loc, Nodes *structs, String_View name); -bool is_field(Struct *structure, String_View field); - -#endif // FRONTEND_H diff --git a/canoscript/src/main.c b/canoscript/src/main.c deleted file mode 100644 index 750c565..0000000 --- a/canoscript/src/main.c +++ /dev/null @@ -1,51 +0,0 @@ -#define ARENA_IMPLEMENTATION -#include "main.h" - -#define TIM_IMPLEMENTATION -#define TIM_H -#include "tim.h" - -void usage(char *file) { - fprintf(stderr, "usage: %s \n", file); - exit(1); -} - -void *custom_realloc(void *ptr, size_t size) { - void *new_ptr = realloc(ptr, size); - ASSERT(new_ptr != NULL, "Out of memory, maybe close some programs? Alternatively you could buy some more RAM."); - ptr = new_ptr; - return new_ptr; -} - -int main(int argc, char *argv[]) { - if(argc != 2) { - usage(argv[0]); - } - char *filename = argv[1]; - Arena token_arena = arena_init(sizeof(Token)*ARENA_INIT_SIZE); - String_View view = read_file_to_view(&token_arena, filename); - Arena string_arena = arena_init(sizeof(char)*ARENA_INIT_SIZE); - Token_Arr tokens = lex(&token_arena, &string_arena, filename, view); - Blocks block_stack = {0}; - Arena node_arena = arena_init(sizeof(Node)*ARENA_INIT_SIZE); - Program program = parse(&node_arena, tokens, &block_stack); - - arena_free(&token_arena); - - Program_State state = {0}; - state.program = program; - state.structs = program.structs; - generate(&state, &program, filename); - - state.machine.program_size = state.machine.instructions.count; - write_program_to_file(&state.machine, "out.tim"); - - arena_free(&node_arena); - arena_free(&string_arena); - free(state.vars.data); - free(state.functions.data); - free(state.scope_stack.data); - free(state.block_stack.data); - free(state.ret_stack.data); - free(state.while_labels.data); -} diff --git a/canoscript/src/main.h b/canoscript/src/main.h deleted file mode 100644 index 65d4266..0000000 --- a/canoscript/src/main.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef MAIN_H -#define MAIN_H - -#include "frontend.h" -#define DEFS_H -#include "backend.h" - -#endif // MAIN_H \ No newline at end of file diff --git a/canoscript/src/tim.h b/canoscript/src/tim.h deleted file mode 100644 index 5921514..0000000 --- a/canoscript/src/tim.h +++ /dev/null @@ -1,1156 +0,0 @@ -#ifndef TIM_H -#define TIM_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "defs.h" - -#define MAX_STACK_SIZE 1024 -#define DATA_START_CAPACITY 16 - -typedef enum { - INST_NOP = 0, - INST_PUSH, - INST_PUSH_STR, - INST_MOV, - INST_REF, - INST_DEREF, - INST_ALLOC, - INST_DEALLOC, - INST_WRITE, - INST_READ, - INST_POP, - INST_DUP, - INST_INDUP, - INST_SWAP, - INST_INSWAP, - INST_ADD, - INST_SUB, - INST_MUL, - INST_DIV, - INST_MOD, - // TODO GET RID OF _F OPERATIONS AND REPLACE WITH SWITCH OVER DATA_TYPE - INST_ADD_F, - INST_SUB_F, - INST_MUL_F, - INST_DIV_F, - INST_MOD_F, - INST_CMPE, - INST_CMPNE, - INST_CMPG, - INST_CMPL, - INST_CMPGE, - INST_CMPLE, - INST_ITOF, - INST_FTOI, - INST_ITOC, - INST_TOI, - INST_TOF, - INST_TOC, - INST_TOVP, - INST_CALL, - INST_RET, - INST_JMP, - INST_ZJMP, - INST_NZJMP, - INST_PRINT, - INST_NATIVE, - INST_ENTRYPOINT, - INST_SS, - INST_HALT, - INST_COUNT, -} Inst_Set; - -typedef enum { - INT_TYPE = 0, - FLOAT_TYPE, - CHAR_TYPE, - PTR_TYPE, - REGISTER_TYPE, - TOP_TYPE, -} DataType; - -typedef union { - int64_t as_int; - double as_float; - char as_char; - void *as_pointer; -} Word; - -typedef struct { - Word word; - DataType type; -} Data; - -typedef struct { - Inst_Set type; - Word value; - DataType data_type; - size_t register_index; -} Inst; - -#define CMP_AS_TYPE(type, op) \ - do{ \ - if(b.word.type op a.word.type){ \ - push(machine, yes, INT_TYPE); \ - } else { \ - push(machine, no, INT_TYPE); \ - } \ - } while(0) - -#define MATH_OP(as_type, op, data_type) \ - do { \ - b = pop(machine); \ - a = pop(machine); \ - Word c = {.as_type = a.word.as_type op b.word.as_type}; \ - push(machine, c, data_type); \ - } while(0) - -#define ASSERT(cond, ...) \ - do { \ - if (!(cond)) { \ - fprintf(stderr, "%s:%d: ASSERTION FAILED: ", __FILE__, __LINE__); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - exit(1); \ - } \ - } while (0) - - -#define TIM_ERROR(...) do { \ - fprintf(stderr, __VA_ARGS__); exit(1); \ -} while (0) - - -#define AMOUNT_OF_REGISTERS 16 -#define MAX_STRING_SIZE 256 - -typedef struct { - Word data; - DataType data_type; -} Register; - -typedef struct { - int8_t *data; - size_t count; - size_t capacity; -} Memory_Cell; - -typedef struct Memory { - struct Memory *next; - Memory_Cell cell; -} Memory; - -typedef struct { - Inst *data; - size_t count; - size_t capacity; -} Insts; - -typedef struct { - String_View *data; - size_t count; - size_t capacity; -} Str_Stack; - -typedef struct { - Data stack[MAX_STACK_SIZE]; - int stack_size; - Str_Stack str_stack; - size_t return_stack[MAX_STACK_SIZE]; - int return_stack_size; - size_t program_size; - - Memory *memory; - - size_t entrypoint; - bool has_entrypoint; - - Register registers[AMOUNT_OF_REGISTERS]; - - Insts instructions; -} Machine; - -// helper functions - -char *reverse_string(char *str); -int int_to_str(char *str, int *str_index, int64_t x); -void *get_stream(Word stream); - -// natives - -void native_open(Machine *machine); -void native_write(Machine *machine); -void native_read(Machine *machine); -void native_close(Machine *machine); -void native_malloc(Machine *machine); -void native_free(Machine *machine); -void native_exit(Machine *machine); -void native_itoa(Machine *machine); - -// reverse_string - -void push_ptr(Machine *machine, Word *value); -void push(Machine *machine, Word value, DataType type); -void push_str(Machine *machine, char *value); -Data pop(Machine *machine); -void index_swap(Machine *machine, int64_t index); -void index_dup(Machine *machine, int64_t index); -void print_stack(Machine *machine); -void write_program_to_file(Machine *machine, char *file_path); -Machine *read_program_from_file(Machine *machine, char *file_path); -void machine_disasm(Machine *machine); -void run_instructions(Machine *machine); - - -#endif // TIM_H - -#ifdef TIM_IMPLEMENTATION - -char *str_types[] = {"int", "float", "char", "ptr", "reg", "top"}; - -char *instructions[INST_COUNT] = { - "nop", - "push", - "push_str", - "mov", - "ref", - "deref", - "alloc", - "dealloc", - "write", - "read", - "pop", - "dup", - "indup", - "swap", - "inswap", - "add", - "sub", - "mul", - "div", - "mod", - "add_f", - "sub_f", - "mul_f", - "div_f", - "mod_f", - "cmpe", - "cmpne", - "cmpg", - "cmpl", - "cmpge", - "cmple", - "itof", - "ftoi", - "itoc", - "toi", - "tof", - "toc", - "tovp", - "call", - "ret", - "jmp", - "zjmp", - "nzjmp", - "print", - "native", - "entrypoint", - "ss", - "halt", -}; - -bool has_operand[INST_COUNT] = { - false, // "nop", - true, // "push", - true, // "push_str", - true, // "mov", - false, // "ref", - false, // "deref", - false, // "alloc", - false, // "dealloc", - false, // "write", - false, // "read", - false, // "pop", - false, // "dup", - false, // "indup", - false, // "swap", - false, // "inswap", - false, // "add", - false, // "sub", - false, // "mul", - false, // "div", - false, // "mod", - false, // "add_f", - false, // "sub_f", - false, // "mul_f", - false, // "div_f", - false, // "mod_f", - false, // "cmpe", - false, // "cmpne", - false, // "cmpg", - false, // "cmpl", - false, // "cmpge", - false, // "cmple", - false, // "itof", - false, // "ftoi", - false, // "itoc", - false, // "toi", - false, // "tof", - false, // "toc", - false, // "tovp", - true, // "call", - false, // "ret", - true, // "jmp", - true, // "zjmp", - true, // "nzjmp", - false, // "print", - true, // "native", - true, // "entrypoint", - false, // "ss", - false, // "halt", -}; - -void free_cell(Memory *cell) { - free(cell->cell.data); - free(cell); -} - -void free_memory(Machine *machine, void *ptr) { - Memory *cur = machine->memory; - if(cur == NULL) goto defer; - if(cur->cell.data == ptr) { - machine->memory = cur->next; - free_cell(cur); - return; - } - while(cur->next != NULL) { - if(cur->next->cell.data == ptr) { - Memory *cell = cur->next; - cur->next = cur->next->next; - free_cell(cell); - return; - } - cur = cur->next; - } -defer: - TIM_ERROR("could not free pointer\n"); -} - -void insert_memory(Machine *machine, size_t size) { - Memory *new = malloc(sizeof(Memory)); - memset(new, 0, sizeof(Memory)); - new->cell.data = malloc(sizeof(*new->cell.data)*size); - memset(new->cell.data, 0, sizeof(*new->cell.data)*size); - new->next = machine->memory; - machine->memory = new; -} - -int64_t my_trunc(double num){ - return (int64_t)num; -} - -int64_t my_pow(int64_t base, int64_t num2){ - int64_t result = 1; - for(size_t i = 0; i < (size_t)num2; i++){ - result *= base; - } - return result; -} - -double my_fmod(double num1, double num2){ - return num1 - my_trunc(num1 / num2) * num2; -} - -char *reverse_string(char *str){ - int length = strlen(str); - int start = 0; - int end = length - 1; - char temp; - - while (start < end) { - temp = str[start]; - str[start] = str[end]; - str[end] = temp; - start++; - end--; - } - return str; -} - -int int_to_str(char *str, int *str_index, int64_t x){ - if(x < 0){ - str[*str_index] = '-'; - *str_index += 1; - x = -x; - } - if(x > 9){ - int64_t new = x / 10; - int_to_str(str, str_index, new); - } - x = (x % 10) + '0'; - str[*str_index] = (char)(x); - *str_index += 1; - return 0; -} - -int float_to_str(char *str, int *str_index, double x, int afterpoint){ - int ipart = (int64_t)x; - float fpart = x - (float)ipart; - - int_to_str(str, str_index, ipart); - if(afterpoint != 0){ - str[*str_index] = '.'; - *str_index += 1; - - fpart = fpart * my_pow(10, afterpoint); - if(fpart < 0){ - fpart = -fpart; - } - int_to_str(str, str_index, (int64_t)fpart); - } - return 0; -} - -void *get_stream(Word stream){ - switch(stream.as_int){ - case 0: - return stdin; - break; - case 1: - return stdout; - break; - case 2: - return stderr; - break; - default: - return stream.as_pointer; - break; - } -} - -// native functions - -#define MODES_LENGTH 7 -char *open_modes[MODES_LENGTH] = {"r", "w", "wr", "a", "rb", "wb", "ab"}; - -void native_open(Machine *machine){ - Word flag_mode = pop(machine).word; - if(flag_mode.as_int > MODES_LENGTH - 1){ - fprintf(stderr, "error: mode %" PRId64 "out of bounds\n", flag_mode.as_int); - exit(1); - } - Word path = pop(machine).word; - char *mode = open_modes[flag_mode.as_int]; - void *fd = fopen(path.as_pointer, mode); - Word w = {.as_pointer=fd}; - push(machine, w, PTR_TYPE); -} - -void native_write(Machine *machine){ - Word stream = pop(machine).word; - char *str = (char*)pop(machine).word.as_pointer; - stream.as_pointer = get_stream(stream); - int length = strlen(str); - fwrite(str, 1, length, stream.as_pointer); -} - -void native_read(Machine *machine){ - Word ptr = pop(machine).word; - ptr.as_pointer = get_stream(ptr); - int length = pop(machine).word.as_int; - char *buffer = pop(machine).word.as_pointer; - fread(buffer, 1, length, ptr.as_pointer); - buffer[length] = '\0'; - push_ptr(machine, (Word*)buffer); -} - -void native_close(Machine *machine){ - void *stream = pop(machine).word.as_pointer; - fclose(stream); -} - -void native_malloc(Machine *machine){ - int num_of_bytes = pop(machine).word.as_int; - void *ptr = malloc(sizeof(char) * num_of_bytes); - push_ptr(machine, ptr); -} - -void native_realloc(Machine *machine){ - void *ptr = pop(machine).word.as_pointer; - int num_of_bytes = pop(machine).word.as_int; - void *result = realloc(ptr, sizeof(char) * num_of_bytes); - push_ptr(machine, result); -} - -void native_free(Machine *machine){ - Word ptr = pop(machine).word; - free(ptr.as_pointer); -} - -void native_scanf(Machine *machine){ - char *buffer = pop(machine).word.as_pointer; - scanf("%s", buffer); - push_ptr(machine, (Word*)buffer); -} - -void native_pow(Machine *machine){ - int64_t power = pop(machine).word.as_int; - int64_t num = pop(machine).word.as_int; - int64_t result = my_pow(power, num); - Word w = {.as_int=result}; - push(machine, w, INT_TYPE); -} - -void native_time(Machine *machine){ - time_t seconds; - seconds = time(NULL); - Word w = {.as_int=seconds}; - push(machine, w, INT_TYPE); -} - -void native_exit(Machine *machine){ - int64_t code = pop(machine).word.as_int; - exit(code); -} - -// end native functions - -void push(Machine *machine, Word value, DataType type){ - if(machine->stack_size >= MAX_STACK_SIZE){ - TIM_ERROR("error: stack overflow\n"); - } - Data data; - data.word = value; - data.type = type; - machine->stack[machine->stack_size++] = data; -} - -void push_ptr(Machine *machine, Word *value){ - if(machine->stack_size >= MAX_STACK_SIZE){ - TIM_ERROR("error: stack overflow\n"); - } - machine->stack[machine->stack_size].type = PTR_TYPE; - machine->stack[machine->stack_size++].word.as_pointer = value; -} - -Data pop(Machine *machine){ - if(machine->stack_size <= 0){ - TIM_ERROR("error: stack underflow\n"); - } - machine->stack_size--; - return machine->stack[machine->stack_size]; -} - -void index_swap(Machine *machine, int64_t index){ - if(index > machine->stack_size || index < 0){ - TIM_ERROR("error: index out of range\n"); - } - Data temp_value = machine->stack[index]; - machine->stack[index] = machine->stack[machine->stack_size - 1]; - machine->stack[machine->stack_size - 1] = temp_value; -} - -void index_dup(Machine *machine, int64_t index){ - if(machine->stack_size <= 0){ - TIM_ERROR("error: stack underflow\n"); - } - if(index > machine->stack_size || index < 0){ - TIM_ERROR("error: index out of range\n"); - } - push(machine, machine->stack[index].word, machine->stack[index].type); -} - -void print_stack(Machine *machine){ - printf("------ STACK\n"); - for(int i = machine->stack_size - 1; i >= 0; i--){ - printf("as int: %" PRId64 ", as float: %f, as char: %c, as pointer: %p\n", machine->stack[i].word.as_int, - machine->stack[i].word.as_float, machine->stack[i].word.as_char, machine->stack[i].word.as_pointer); - } - printf("------ END OF STACK\n"); -} - -int cmp_types(Data a){ - switch(a.type){ - case INT_TYPE: - return 0; - case FLOAT_TYPE: - return 1; - case CHAR_TYPE: - return 2; - case PTR_TYPE: - return 3; - case REGISTER_TYPE: - case TOP_TYPE: - default: - return -1; - } -} - -void write_program_to_file(Machine *machine, char *file_path){ - FILE *file = fopen(file_path, "wb"); - if(file == NULL){ - TIM_ERROR("error: could not write to file\n"); - } - fwrite(&machine->str_stack.count, sizeof(size_t), 1, file); - for(int i = 0; i < (int)machine->str_stack.count; i++){ - String_View str = machine->str_stack.data[i]; - fwrite(&str.len, sizeof(size_t), 1, file); - fwrite(str.data, sizeof(char), str.len, file); - } - - fwrite(&machine->entrypoint, sizeof(size_t), 1, file); - fwrite(machine->instructions.data, sizeof(machine->instructions.data[0]), machine->program_size, file); - - fclose(file); -} - -Machine *read_program_from_file(Machine *machine, char *file_path){ - FILE *file = fopen(file_path, "rb"); - - if(file == NULL){ - TIM_ERROR("error: could not read from file\n"); - } - - int index = 0; - size_t length; - fread(&machine->str_stack.count, 1, sizeof(size_t), file); - for(size_t i = 0; i < machine->str_stack.count; i++) { - size_t len = 0; - fread(&len, 1, sizeof(size_t), file); - char *str = malloc(sizeof(char)*len); - fread(str, sizeof(char), len, file); - machine->str_stack.data[i] = view_create(str, len); - } - index = ftell(file); - - - fseek(file, 0, SEEK_END); - length = ftell(file); - fseek(file, index, SEEK_SET); - length = length - ftell(file); - fread(&machine->entrypoint, sizeof(size_t), 1, file); - Inst *instructions = malloc(sizeof(Inst) * length); - length = fread(instructions, sizeof(*instructions), length, file); - - machine->program_size = length; - machine->instructions.data = instructions; - - fclose(file); - return machine; -} - -void handle_char_print(char c) { - switch(c) { - case '\n': - putc('\\', stdout); - putc('n', stdout); - break; - case '\t': - putc('\\', stdout); - putc('t', stdout); - break; - case '\v': - putc('\v', stdout); - putc('n', stdout); - break; - case '\b': - putc('\b', stdout); - putc('n', stdout); - break; - case '\r': - putc('\\', stdout); - putc('r', stdout); - break; - case '\f': - putc('\\', stdout); - putc('f', stdout); - break; - case '\a': - putc('\\', stdout); - putc('a', stdout); - break; - case '\\': - putc('\\', stdout); - putc('\\', stdout); - break; - case '\?': - putc('\\', stdout); - putc('?', stdout); - break; - case '\'': - putc('\\', stdout); - putc('\'', stdout); - break; - case '\"': - putc('\\', stdout); - putc('"', stdout); - break; - case '\0': - putc('\\', stdout); - putc('0', stdout); - break; - default: - putc(c, stdout); - } -} - -void machine_disasm(Machine *machine) { - for(size_t i = machine->entrypoint; i < machine->program_size; i++) { - printf("%s", instructions[machine->instructions.data[i].type]); - if(has_operand[machine->instructions.data[i].type]) { - putc(' ', stdout); - switch(machine->instructions.data[i].data_type) { - case INT_TYPE: { - uint64_t value = machine->instructions.data[i].value.as_int; - if(machine->instructions.data[i].type == INST_PUSH_STR) { - String_View string = machine->str_stack.data[value]; - putc('"', stdout); - for(size_t j = 0; j < string.len-1; j++) { - handle_char_print(string.data[j]); - } - putc('"', stdout); - break; - } - printf("%ld", value); - } break; - case FLOAT_TYPE: { - printf("%f", machine->instructions.data[i].value.as_float); - } break; - case CHAR_TYPE: { - putc('\'', stdout); - handle_char_print(machine->instructions.data[i].value.as_char); - putc('\'', stdout); - } break; - case PTR_TYPE: { - printf("%p", machine->instructions.data[i].value.as_pointer); - } break; - default: - assert(false && "UNReaCHABLE"); - } - } - printf("\n"); - } -} - - -void run_instructions(Machine *machine) { - void (*native_ptrs[100])(Machine*) = {native_open, native_write, native_read, - native_close, native_malloc, native_realloc, - native_free, native_scanf, native_pow}; - native_ptrs[10] = native_time; - native_ptrs[60] = native_exit; - Data a, b; - Word yes; - yes.as_int = 1; - Word no; - no.as_int = 0; - for(size_t ip = machine->entrypoint; ip < machine->program_size; ip++){ - //print_stack(machine); - switch(machine->instructions.data[ip].type){ - case INST_NOP: - continue; - break; - case INST_PUSH: - if(machine->instructions.data[ip].data_type == REGISTER_TYPE){ - push(machine, machine->registers[machine->instructions.data[ip].register_index].data, - machine->registers[machine->instructions.data[ip].register_index].data_type); - } else { - push(machine, machine->instructions.data[ip].value, machine->instructions.data[ip].data_type); - } - break; - case INST_PUSH_STR: { - size_t index = machine->instructions.data[ip].value.as_int; - String_View str = machine->str_stack.data[index]; - insert_memory(machine, str.len); - for(size_t i = 0; i < str.len; i++) { - machine->memory->cell.data[i] = str.data[i]; - } - Word word; - word.as_pointer = machine->memory->cell.data; - push(machine, word, PTR_TYPE); - } break; - case INST_MOV: - if(machine->instructions.data[ip].data_type == TOP_TYPE){ - machine->registers[machine->instructions.data[ip].register_index].data = machine->stack[machine->stack_size - 1].word; - machine->registers[machine->instructions.data[ip].register_index].data_type = machine->stack[machine->stack_size - 1].type; - } else { - machine->registers[machine->instructions.data[ip].register_index].data = machine->instructions.data[ip].value; - machine->registers[machine->instructions.data[ip].register_index].data_type = machine->instructions.data[ip].data_type; - } - break; - case INST_REF: { - Word *ptr = &machine->stack[machine->stack_size - 1].word; - push_ptr(machine, ptr); - } break; - case INST_DEREF: { - Word *ptr = machine->stack[machine->stack_size - 1].word.as_pointer; - Data *ref = (Data*)ptr; - push(machine, ref->word, ref->type); - break; - } - case INST_ALLOC: { - a = pop(machine); - if(a.type != INT_TYPE) { - TIM_ERROR("error: expected int"); - } - if(a.word.as_int < 0) { - TIM_ERROR("error: size cannot be negative"); - } - insert_memory(machine, a.word.as_int); - Word word; - word.as_pointer = machine->memory->cell.data; - //push(machine, a.word, INT_TYPE); - push(machine, word, PTR_TYPE); - } break; - case INST_DEALLOC: { - Data ptr = pop(machine); - if(ptr.type != PTR_TYPE) { - TIM_ERROR("error: expected ptr"); - } - free_memory(machine, ptr.word.as_pointer); - } break; - case INST_WRITE: { - Data size = pop(machine); - Data data = pop(machine); - if(size.type != INT_TYPE) { - TIM_ERROR("error: expected int"); - } - if(size.word.as_int < 0) { - TIM_ERROR("error: size cannot be negative"); - } - Data ptr_data = pop(machine); - if(ptr_data.type != PTR_TYPE) { - TIM_ERROR("error: expected ptr"); - } - void *ptr = ptr_data.word.as_pointer; - memcpy(ptr, &data.word, size.word.as_int); - } break; - case INST_READ: { - Data size = pop(machine); - if(size.type != INT_TYPE) { - TIM_ERROR("error: expected int"); - } - if(size.word.as_int < 0) { - TIM_ERROR("error: size cannot be negative"); - } - Data ptr_data = pop(machine); - if(ptr_data.type != PTR_TYPE) { - TIM_ERROR("error: expected pointer"); - } - void *ptr = ptr_data.word.as_pointer; - Data data = {0}; - data.type = INT_TYPE; - memcpy(&data.word, ptr, size.word.as_int); - push(machine, data.word, data.type); - } break; - case INST_POP: - pop(machine); - break; - case INST_DUP: - a = machine->stack[machine->stack_size - 1]; - push(machine, a.word, a.type); - break; - case INST_INDUP: { - Data index = pop(machine); - if(index.type != INT_TYPE) { - TIM_ERROR("error: expected int"); - } - index_dup(machine, machine->stack_size-index.word.as_int-1); - } break; - case INST_SWAP: { - Data temp = machine->stack[machine->stack_size - 1]; - machine->stack[machine->stack_size - 1] = machine->stack[machine->stack_size - 2]; - machine->stack[machine->stack_size - 2] = temp; - } break; - case INST_INSWAP: { - Data index = pop(machine); - if(index.type != INT_TYPE) { - TIM_ERROR("error: expected int"); - } - index_swap(machine, machine->stack_size-index.word.as_int-1); - } break; - case INST_ADD: - // TODO: flesh this out a little more - // and make it work where it switches over both operands data types - // this will remove the need for INST_*_F, simplifying the bytecode greatly - if(machine->stack_size < 1) TIM_ERROR("error: stack underflow\n"); - switch(machine->stack[machine->stack_size-1].type) { - case CHAR_TYPE: - case PTR_TYPE: - case INT_TYPE: - MATH_OP(as_int, +, INT_TYPE); - break; - case FLOAT_TYPE: - MATH_OP(as_float, +, FLOAT_TYPE); - break; - default: - TIM_ERROR("error: not right...\n"); - } - //MATH_OP(as_int, +, INT_TYPE); - break; - case INST_SUB: - MATH_OP(as_int, -, INT_TYPE); - break; - case INST_MUL: - MATH_OP(as_int, *, INT_TYPE); - break; - case INST_DIV: - if(machine->stack[machine->stack_size - 1].word.as_int == 0){ - TIM_ERROR("error: cannot divide by 0\n"); - } - MATH_OP(as_int, /, INT_TYPE); - break; - case INST_MOD: - if(machine->stack[machine->stack_size - 1].word.as_int == 0){ - TIM_ERROR("error: cannot divide by 0\n"); - } - MATH_OP(as_int, %, INT_TYPE); - break; - case INST_ADD_F: - MATH_OP(as_float, +, FLOAT_TYPE); - break; - case INST_SUB_F: - MATH_OP(as_float, -, FLOAT_TYPE); - break; - case INST_MUL_F: - MATH_OP(as_float, *, FLOAT_TYPE); - break; - case INST_DIV_F: - if(machine->stack[machine->stack_size - 1].word.as_float == 0.0){ - TIM_ERROR("error: cannot divide by 0\n"); - } - MATH_OP(as_float, /, FLOAT_TYPE); - break; - case INST_MOD_F: - if(machine->stack[machine->stack_size - 1].word.as_float == 0.0){ - TIM_ERROR("error: cannot divide by 0\n"); - } - b = pop(machine); - a = pop(machine); - Word c = {.as_float=my_fmod(a.word.as_float, b.word.as_float)}; - push(machine, c, FLOAT_TYPE); - break; - case INST_CMPE: { - a = machine->stack[machine->stack_size - 1]; - b = machine->stack[machine->stack_size - 2]; - machine->stack_size -= 2; - int result = (int)a.type; - switch(result){ - case 0: - CMP_AS_TYPE(as_int, ==); - break; - case 1: - CMP_AS_TYPE(as_float, ==); - break; - case 2: - CMP_AS_TYPE(as_char, ==); - break; - case 3: - CMP_AS_TYPE(as_pointer, ==); - break; - } - break; - } - case INST_CMPNE: { - a = machine->stack[machine->stack_size - 1]; - b = machine->stack[machine->stack_size - 2]; - machine->stack_size -= 2; - int result = (int)a.type; - switch(result){ - case 0: - CMP_AS_TYPE(as_int, !=); - break; - case 1: - CMP_AS_TYPE(as_float, !=); - break; - case 2: - CMP_AS_TYPE(as_char, !=); - break; - case 3: - CMP_AS_TYPE(as_pointer, !=); - break; - } - break; - } - case INST_CMPG: { - a = machine->stack[machine->stack_size - 1]; - b = machine->stack[machine->stack_size - 2]; - machine->stack_size -= 2; - int result = (int)a.type; - switch(result){ - case 0: - CMP_AS_TYPE(as_int, >); - break; - case 1: - CMP_AS_TYPE(as_float, >); - break; - case 2: - CMP_AS_TYPE(as_char, >); - break; - case 3: - CMP_AS_TYPE(as_pointer, >); - break; - } - break; - } - case INST_CMPL: { - a = machine->stack[machine->stack_size - 1]; - b = machine->stack[machine->stack_size - 2]; - machine->stack_size -= 2; - int result = (int)a.type; - switch(result){ - case 0: - CMP_AS_TYPE(as_int, <); - break; - case 1: - CMP_AS_TYPE(as_float, <); - break; - case 2: - CMP_AS_TYPE(as_char, <); - break; - case 3: - CMP_AS_TYPE(as_pointer, <); - break; - } - break; - } - case INST_CMPGE: { - a = machine->stack[machine->stack_size - 1]; - b = machine->stack[machine->stack_size - 2]; - machine->stack_size -= 2; - int result = (int)a.type; - switch(result){ - case 0: - CMP_AS_TYPE(as_int, >=); - break; - case 1: - CMP_AS_TYPE(as_float, >=); - break; - case 2: - CMP_AS_TYPE(as_char, >=); - break; - case 3: - CMP_AS_TYPE(as_pointer, >=); - break; - } - break; - } - case INST_CMPLE: { - a = machine->stack[machine->stack_size - 1]; - b = machine->stack[machine->stack_size - 2]; - machine->stack_size -= 2; - int result = (int)a.type; - switch(result){ - case 0: - CMP_AS_TYPE(as_int, <=); - break; - case 1: - CMP_AS_TYPE(as_float, <=); - break; - case 2: - CMP_AS_TYPE(as_char, <=); - break; - case 3: - CMP_AS_TYPE(as_pointer, <=); - break; - } - break; - } - case INST_ITOF: - a = pop(machine); - a.word.as_float = (double)a.word.as_int; - push(machine, a.word, FLOAT_TYPE); - break; - case INST_FTOI: - a = pop(machine); - a.word.as_int = (int64_t)a.word.as_float; - push(machine, a.word, INT_TYPE); - break; - case INST_ITOC: - a = pop(machine); - a.word.as_char = (char)a.word.as_int; - push(machine, a.word, CHAR_TYPE); - break; - case INST_TOI: - machine->stack[machine->stack_size-1].type = INT_TYPE; - break; - case INST_TOF: - machine->stack[machine->stack_size-1].type = FLOAT_TYPE; - break; - case INST_TOC: - machine->stack[machine->stack_size-1].type = CHAR_TYPE; - break; - case INST_TOVP: - machine->stack[machine->stack_size-1].type = PTR_TYPE; - break; - case INST_CALL: - machine->return_stack[machine->return_stack_size++] = ip; - ip = machine->instructions.data[ip].value.as_int - 1; - break; - case INST_RET: - ip = machine->return_stack[--machine->return_stack_size]; - break; - case INST_JMP: - if(machine->instructions.data[ip].value.as_int == 0) TIM_ERROR("error: cannot jump to 0\n"); - ip = machine->instructions.data[ip].value.as_int - 1; - if(ip + 1 >= machine->program_size){ - TIM_ERROR("error: cannot jmp out of bounds to: %ld\n", machine->instructions.data[ip].value.as_int); - } - break; - case INST_ZJMP: - if(machine->instructions.data[ip].value.as_int == 0) TIM_ERROR("error: cannot jump to 0\n"); - if(pop(machine).word.as_int == 0){ - ip = machine->instructions.data[ip].value.as_int - 1; - if(ip + 1 >= machine->program_size){ - TIM_ERROR("error: cannot zjmp out of bounds to: %ld\n", machine->instructions.data[ip].value.as_int); - } - } else { - break; - } - break; - case INST_NZJMP: - if(machine->instructions.data[ip].value.as_int == 0) TIM_ERROR("error: cannot jump to 0\n"); - if(pop(machine).word.as_int != 0){ - ip = machine->instructions.data[ip].value.as_int - 1; - if(ip + 1 >= machine->program_size){ - TIM_ERROR("error: cannot nzjmp out of bounds to: %ld\n", machine->instructions.data[ip].value.as_int); - } - } else { - break; - } - break; - case INST_PRINT: - a = pop(machine); - printf("as float: %f, as int: %" PRId64 ", as char: %c, as pointer: %p, type: %s\n", - a.word.as_float, a.word.as_int, a.word.as_char, a.word.as_pointer, str_types[a.type]); - break; - case INST_SS: - push(machine, (Word){.as_int=machine->stack_size}, INT_TYPE); - break; - case INST_NATIVE: { - (*native_ptrs[machine->instructions.data[ip].value.as_int])(machine); - } break; - case INST_ENTRYPOINT: - assert(false); - break; - case INST_HALT: - ip = machine->program_size; - break; - case INST_COUNT: - assert(false); - } - } -} - -#endif // TIM_IMPLEMENTATION diff --git a/canoscript/src/view.c b/canoscript/src/view.c deleted file mode 100644 index 6650cb9..0000000 --- a/canoscript/src/view.c +++ /dev/null @@ -1,152 +0,0 @@ -#include "view.h" - -String_View view_create(const char *str, size_t len) { - String_View view = { - .data = str, - .len = len, - }; - return view; -} - -char *view_to_cstr(String_View view) { - char *str = malloc(sizeof(char) * view.len+1); - strncpy(str, view.data, view.len); - str[view.len] = '\0'; - return str; -} - -String_View view_trim_left(String_View view) { - size_t i = 0; - while(i < view.len && isspace(view.data[i])) { - i++; - } - return (String_View){ - .data = view.data + i, - .len = view.len - i, - }; -} - -String_View view_trim_right(String_View view) { - size_t i = view.len - 1; - while(i < view.len && isspace(view.data[i])) { - i--; - } - return (String_View){ - .data = view.data, - .len = i+1, - }; -} - -int view_cmp(String_View a, String_View b) { - if(a.len != b.len) return 0; - for(size_t i = 0; i < a.len; i++) { - if(a.data[i] != b.data[i]) { - return 0; - } - } - return 1; -} - -int view_starts_with_c(String_View view, char c) { - return view.data[0] == c; -} - -int view_starts_with_s(String_View a, String_View b) { - String_View compare = view_create(a.data, b.len); - return view_cmp(compare, b); -} - -int view_ends_with_c(String_View view, char c) { - return view.data[view.len-1] == c; -} - -int view_ends_with_s(String_View a, String_View b) { - String_View compare = view_create(a.data + a.len - b.len, b.len); - return view_cmp(compare, b); -} - -int view_contains(String_View haystack, String_View needle) { - if(needle.len > haystack.len) return 0; - String_View compare = view_create(haystack.data, needle.len); - for(size_t i = 0; i < haystack.len; i++) { - compare.data = haystack.data + i; - if(view_cmp(needle, compare)) { - return 1; - } - } - return 0; -} - -size_t view_first_of(String_View view, char target) { - for(size_t i = 0; i < view.len; i++) { - if(view.data[i] == target) { - return i; - } - } - return 0; -} - -size_t view_last_of(String_View view, char target) { - for(size_t i = view.len-1; i > 0; i--) { - if(view.data[i] == target) { - return i; - } - } - return 0; -} - -size_t view_split(String_View view, char c, String_View *arr, size_t arr_s) { - const char *cur = view.data; - size_t arr_index = 0; - size_t i; - for(i = 0; i < view.len; i++) { - if(view.data[i] == c) { - if(arr_index < arr_s-2) { - String_View new = {.data = cur, .len = view.data + i - cur}; - arr[arr_index++] = new; - cur = view.data + i + 1; - } else { - String_View new = {.data = view.data + i+1, .len = view.len - i-1}; - arr[arr_index++] = new; - return arr_index; - } - } - } - String_View new = {.data = cur, .len = view.data + i - cur}; - arr[arr_index++] = new; - return arr_index; -} - -String_View view_chop(String_View view, char c) { - size_t i = 0; - while(view.data[i] != c && i != view.len) { - i++; - } - if(i < view.len) { - i++; - } - return (String_View){ - .data = view.data + i, - .len = view.len - i, - }; -} - -size_t view_find(String_View haystack, String_View needle) { - if(needle.len > haystack.len) return 0; - String_View compare = view_create(haystack.data, needle.len); - for(size_t i = 0; i < haystack.len; i++) { - compare.data = haystack.data + i; - if(view_cmp(needle, compare)) { - return i; - } - } - return 0; -} - -String_View view_chop_left(String_View view) { - if(view.len > 0) { - view.data++; - view.len--; - } - return view; -} \ No newline at end of file diff --git a/canoscript/src/view.h b/canoscript/src/view.h deleted file mode 100644 index a58b8ca..0000000 --- a/canoscript/src/view.h +++ /dev/null @@ -1,223 +0,0 @@ -#ifndef VIEW_H -#define VIEW_H - -#include -#include -#include -#include -#include - -#ifndef VIEW_MALLOC -#define VIEW_MALLOC malloc -#endif - -typedef struct { - const char *data; - size_t len; -} String_View; - -#define View_Print "%.*s" -#define View_Arg(view) (int)view.len, view.data -#define LITERAL_CREATE(lit) view_create(lit, sizeof(lit)-1) -#define LITERAL_VIEW(str) {.data=(str), .len=sizeof((str))-1} - -String_View view_create(const char *str, size_t len); -char *view_to_cstr(String_View view); -String_View view_trim_left(String_View view); -String_View view_trim_right(String_View view); -int view_cmp(String_View a, String_View b); -int view_starts_with_c(String_View view, char c); -int view_starts_with_s(String_View a, String_View b); -int view_ends_with_c(String_View view, char c); -int view_ends_with_s(String_View a, String_View b); -int view_contains(String_View haystack, String_View needle); -size_t view_first_of(String_View view, char target); -size_t view_last_of(String_View view, char target); -size_t view_split(String_View view, char c, String_View *arr, size_t arr_s); -String_View view_chop(String_View view, char c); -String_View view_chop_left(String_View view); -size_t view_find(String_View haystack, String_View needle); -int view_to_int(String_View view); -float view_to_float(String_View view); - -#endif - -#ifdef VIEW_IMPLEMENTATION - -float power(float base, float exponent) { - float result = 1; - for(size_t i = 0; i < exponent; i++) { - result *= base; - } - return result; -} - -String_View view_create(const char *str, size_t len) { - String_View view = { - .data = str, - .len = len, - }; - return view; -} - -char *view_to_cstr(String_View view) { - char *str = VIEW_MALLOC(sizeof(char) * view.len+1); - strncpy(str, view.data, view.len); - str[view.len] = '\0'; - return str; -} - -String_View view_trim_left(String_View view) { - size_t i = 0; - while(i < view.len && isspace(view.data[i])) { - i++; - } - return (String_View){ - .data = view.data + i, - .len = view.len - i, - }; -} - -String_View view_trim_right(String_View view) { - size_t i = view.len - 1; - while(i < view.len && isspace(view.data[i])) { - i--; - } - return (String_View){ - .data = view.data, - .len = i+1, - }; -} - -int view_cmp(String_View a, String_View b) { - if(a.len != b.len) return 0; - return memcmp(a.data, b.data, a.len) == 0; -} - -int view_starts_with_c(String_View view, char c) { - return view.data[0] == c; -} - -int view_starts_with_s(String_View a, String_View b) { - String_View compare = view_create(a.data, b.len); - return view_cmp(compare, b); -} - -int view_ends_with_c(String_View view, char c) { - return view.data[view.len-1] == c; -} - -int view_ends_with_s(String_View a, String_View b) { - String_View compare = view_create(a.data + a.len - b.len, b.len); - return view_cmp(compare, b); -} - -int view_contains(String_View haystack, String_View needle) { - if(needle.len > haystack.len) return 0; - String_View compare = view_create(haystack.data, needle.len); - for(size_t i = 0; i < haystack.len; i++) { - compare.data = haystack.data + i; - if(view_cmp(needle, compare)) { - return 1; - } - } - return 0; -} - -size_t view_first_of(String_View view, char target) { - for(size_t i = 0; i < view.len; i++) { - if(view.data[i] == target) { - return i; - } - } - return 0; -} - -size_t view_last_of(String_View view, char target) { - for(size_t i = view.len-1; i > 0; i--) { - if(view.data[i] == target) { - return i; - } - } - return 0; -} - -// needs work -size_t view_split(String_View view, char c, String_View *arr, size_t arr_s) { - const char *cur = view.data; - size_t arr_index = 0; - size_t i; - for(i = 0; i < view.len; i++) { - if(view.data[i] == c) { - if(arr_index < arr_s-2) { - String_View new = {.data = cur, .len = view.data + i - cur}; - arr[arr_index++] = new; - cur = view.data + i + 1; - } else { - String_View new = {.data = view.data + i+1, .len = view.len - i-1}; - arr[arr_index++] = new; - return arr_index; - } - } - } - String_View new = {.data = cur, .len = view.data + i - cur}; - arr[arr_index++] = new; - return arr_index; -} - -String_View view_chop(String_View view, char c) { - size_t i = 0; - while(view.data[i] != c && i != view.len) i++; - if(i < view.len) { - i++; - } - return (String_View) { - .data = view.data + i, - .len = view.len - i, - }; -} - -String_View view_chop_left(String_View view) { - if(view.len > 0) { - view.data++; - view.len--; - } - return view; - } -} - -size_t view_find(String_View haystack, String_View needle) { - if(needle.len > haystack.len) return 0; - String_View compare = view_create(haystack.data, needle.len); - for(size_t i = 0; i < haystack.len; i++) { - compare.data = haystack.data + i; - if(view_cmp(needle, compare)) { - return i; - } - } - return 0; -} - -int view_to_int(String_View view) { - int result = 0; - for(size_t i = 0; i < view.len; i++) { - result = result * 10 + view.data[i] - '0'; - } - return result; -} - -float view_to_float(String_View view) { - float result = 0; - size_t dotpos = 0; - for(size_t i = 0; i < view.len; i++) { - if (view.data[i] == '.') { - dotpos = view.len - i - 1; - } else { - result = result * 10 + (view.data[i] - '0'); - } - } - result /= power(10, dotpos); - return result; -} - -#endif diff --git a/canoscript/tests/printint.cano b/canoscript/tests/printint.cano deleted file mode 100644 index b28cf6f..0000000 --- a/canoscript/tests/printint.cano +++ /dev/null @@ -1,12 +0,0 @@ -printint(n: int): void - if n > 9 then - new: int = n / 10 - printint(new) - end - string: str = " " - string[0] = n % 10 + 48 - write string -end - -printint(420) -write "\n" diff --git a/canoscript/tests/rule110.cano b/canoscript/tests/rule110.cano deleted file mode 100644 index 6b8f2d7..0000000 --- a/canoscript/tests/rule110.cano +++ /dev/null @@ -1,87 +0,0 @@ -data_s: int = 32 -data: int[data_s] = [0] -data[data_s-1] = 1 - -iter: int = 0 - -struct Pattern { - value: int, - pattern: str, -} - -strcmp(a: str, b: str): int - i: int = 0 - while a[i] == b[i] then - if a[i] == '\0' then - return 1 - end - i = i + 1 - end - return 0 -end - -print_state(): void - i: int = 0 - write "|" - while i < data_s then - if(data[i] == 0) then - write " " - else - write "*" - end - i = i + 1 - end - write "|\n" -end - -gen_next(): void - new: ptr = alloc data_s * 8 - new_s: int = 0 - i: int = 0 - while i < data_s then - prev_in: int = (i - 1 + data_s) % data_s - cur_in: int = (i + 0 + data_s) % data_s - next_in: int = (i + 1 + data_s) % data_s - cur: str = alloc 4 - cur[0] = data[prev_in] + '0' - cur[1] = data[cur_in] + '0' - cur[2] = data[next_in] + '0' - - if(strcmp("111", cur)) then - new[new_s] = 0 - end - if(strcmp("110", cur)) then - new[new_s] = 1 - end - if(strcmp("101", cur)) then - new[new_s] = 1 - end - if(strcmp("100", cur)) then - new[new_s] = 0 - end - if(strcmp("011", cur)) then - new[new_s] = 1 - end - if(strcmp("010", cur)) then - new[new_s] = 1 - end - if(strcmp("001", cur)) then - new[new_s] = 1 - end - if(strcmp("000", cur)) then - new[new_s] = 0 - end - - i = i + 1 - new_s = new_s + 1 - end - dealloc data - data = new -end - - -while iter < data_s then - print_state() - gen_next() - iter = iter + 1 -end diff --git a/canoscript/tests/strcmp.cano b/canoscript/tests/strcmp.cano deleted file mode 100644 index 8956783..0000000 --- a/canoscript/tests/strcmp.cano +++ /dev/null @@ -1,31 +0,0 @@ -x: str = "Same" -y: str = "Same" - -printint(n: int): int - if n > 9 then - new: int = n / 10 - printint(new) - end - string: str = " " - string[0] = n % 10 + 48 - write string - return 0 -end - -strcmp(a: str, b: str): int - i: int = 0 - while a[i] == b[i] then - if a[i] == '\0' then - return 1 - end - i = i + 1 - end - return 0 -end - -a: int = strcmp(x, y) - -printint(a) -write "\n" - -exit 0 diff --git a/canoscript/tests/strlen.cano b/canoscript/tests/strlen.cano deleted file mode 100644 index 7b05cfc..0000000 --- a/canoscript/tests/strlen.cano +++ /dev/null @@ -1,26 +0,0 @@ -y: str = "this string is x chars long" - -printint(n: int): int - if n > 9 then - new: int = n / 10 - printint(new) - end - string: str = " " - string[0] = n % 10 + 48 - write string - return 0 -end - -strlen(a: str): int - i: int = 0 - while a[i] != '\0' then - i = i + 1 - end - return i -end - -x: int = strlen(y) -printint(x) -write "\n" - -exit 0