diff --git a/Makefile b/Makefile index 4ea1b59..db75a2b 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ endif ifeq ($(PLATFORM), linux) PLATFORM_CFLAGS += $(shell pkg-config --cflags sdl2 2>/dev/null) LDFLAGS += $(shell pkg-config --libs sdl2 2>/dev/null) -lm - TARGET = $(BUILD_DIR)/zre-$(PLATFORM)$(TARGET_SUFFIX) + TARGET = $(BUILD_DIR)/undar-$(PLATFORM)$(TARGET_SUFFIX) endif # --- EMSCRIPTEN-SPECIFIC --- @@ -60,12 +60,12 @@ ifeq ($(PLATFORM), emscripten) endif # Output: HTML + JS + WASM - TARGET = $(BUILD_DIR)/zre.html + TARGET = $(BUILD_DIR)/undar.html endif # --- FALLBACK TARGET (if no platform matched) --- ifndef TARGET - TARGET = $(BUILD_DIR)/zre-$(PLATFORM)$(TARGET_SUFFIX) + TARGET = $(BUILD_DIR)/undar-$(PLATFORM)$(TARGET_SUFFIX) endif # --- VM CORE SOURCES --- @@ -80,8 +80,8 @@ ifeq ($(BUILD_MODE), deploy) else PLATFORM_SOURCE := $(ARCH_DIR)/main.c \ $(ARCH_DIR)/devices.c \ - $(SRC_DIR)/tools/test.c \ - $(SRC_DIR)/tools/parser.c + $(SRC_DIR)/tools/parser.c \ + $(SRC_DIR)/tools/assembler.c endif # --- OBJECT FILES --- @@ -159,5 +159,5 @@ help: @echo " make PLATFORM=avr -> (example) AVR-GCC" @echo "" @echo "Output:" - @echo " Linux: build/linux/zre-linux-" - @echo " Web: build/emscripten/zre.html (+ .js, .wasm)" + @echo " Linux: build/linux/undar-linux-" + @echo " Web: build/emscripten/undar.html (+ .js, .wasm)" diff --git a/README.org b/README.org index 3abb2d0..a2725f5 100644 --- a/README.org +++ b/README.org @@ -141,7 +141,7 @@ Devices are memory-mapped: - Function calls are equivelent to redraws - Child calls define spacial location in code as well as the UI -**3D Primitives** +**3D Primitives + Constructive solid geometry** Built-in support for: - =Cube(pos, size)= - =Plane(pos, radius)= @@ -203,7 +203,7 @@ cd undar-lang && make (label main (load $0 &terminal-str) (load $1 &hello-str) - (strlen $2 $1) + (string-length $2 $1) (syscall DEVICE_WRITE $0 $1 $2) (load $3 &new-line) (string-length $4 $3) diff --git a/bench/run.sh b/bench/run.sh index 44cfe8e..3b30e41 100755 --- a/bench/run.sh +++ b/bench/run.sh @@ -37,9 +37,9 @@ print_section "zlc ($FILENAME.zl)" echo "test input" | time zlc "$FILENAME.zl" #Old ZRE -print_section "zre ($FILENAME.ul)" +print_section "zre ($FILENAME.t.ul)" echo "test input" | time ../build/old/zre -t "$FILENAME.ul" -# ZRE Implementation -print_section "zre ($FILENAME.ul)" - echo "test input" | time ../build/linux/zre-linux-release -t "$FILENAME.ul" +# Undâr Implementation +#print_section "zre ($FILENAME.asm.lisp)" +# echo "test input" | time ../build/linux/zre-linux-release "../test/$FILENAME.asm.lisp" diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index 89c4d4d..8fd0574 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -1,4 +1,4 @@ -#include "../../tools/test.h" +#include "../../tools/assembler.h" #include "../../tools/parser.h" #include "../../vm/vm.h" #include "devices.h" @@ -40,8 +40,6 @@ static MouseDeviceData mouse_data = {0}; static KeyboardDeviceData keyboard_data = {0}; void compileFile(const char *path, VM *vm) { - USED(vm); - FILE *f = fopen(path, "rb"); if (!f) { perror("fopen"); @@ -60,80 +58,91 @@ void compileFile(const char *path, VM *vm) { size_t read = fread(source, 1, len, f); source[read] = '\0'; fclose(f); + ExprNode *ast = expr_parse(source, strlen(source)); + if (!ast) { + printf("Parse failed.\n"); + } else { + assemble(vm, ast); + expr_free(ast); + } } void repl(VM *vm) { - USED(vm); + USED(vm); - char buffer[1024 * 10] = {0}; // Larger buffer for multi-line input - char line[1024]; - - for (;;) { - // Count current parentheses balance - int paren_balance = 0; - for (int i = 0; buffer[i]; i++) { - if (buffer[i] == '(') paren_balance++; - else if (buffer[i] == ')') paren_balance--; - } - - // Show appropriate prompt - if (paren_balance > 0) { - printf(".. "); // Continuation prompt when unbalanced - } else { - printf("> "); // Normal prompt when balanced - } - fflush(stdout); + char buffer[1024 * 10] = {0}; // Larger buffer for multi-line input + char line[1024]; - if (!fgets(line, sizeof(line), stdin)) { - printf("\n"); - break; - } - - // Append the new line to buffer - strncat(buffer, line, sizeof(buffer) - strlen(buffer) - 1); - - // Recalculate balance after adding new line - paren_balance = 0; - for (int i = 0; buffer[i]; i++) { - if (buffer[i] == '(') paren_balance++; - else if (buffer[i] == ')') paren_balance--; - } - - // Only parse when parentheses are balanced - if (paren_balance == 0) { - // Check if buffer has actual content (not just whitespace) - int has_content = 0; - for (int i = 0; buffer[i]; i++) { - if (!isspace(buffer[i])) { - has_content = 1; - break; - } - } - - if (has_content) { - ExprNode *ast = expr_parse(buffer, strlen(buffer)); - if (!ast) { - printf("Parse failed.\n"); - } else { - printf("AST:\n"); - expr_print(ast, 0); - expr_free(ast); - } - } - - // Reset buffer for next input - buffer[0] = '\0'; - } - // If unbalanced, continue reading more lines + for (;;) { + // Count current parentheses balance + int paren_balance = 0; + for (int i = 0; buffer[i]; i++) { + if (buffer[i] == '(') + paren_balance++; + else if (buffer[i] == ')') + paren_balance--; } - exit(0); + + // Show appropriate prompt + if (paren_balance > 0) { + printf(".. "); // Continuation prompt when unbalanced + } else { + printf("> "); // Normal prompt when balanced + } + fflush(stdout); + + if (!fgets(line, sizeof(line), stdin)) { + printf("\n"); + break; + } + + // Append the new line to buffer + strncat(buffer, line, sizeof(buffer) - strlen(buffer) - 1); + + // Recalculate balance after adding new line + paren_balance = 0; + for (int i = 0; buffer[i]; i++) { + if (buffer[i] == '(') + paren_balance++; + else if (buffer[i] == ')') + paren_balance--; + } + + // Only parse when parentheses are balanced + if (paren_balance == 0) { + // Check if buffer has actual content (not just whitespace) + int has_content = 0; + for (int i = 0; buffer[i]; i++) { + if (!isspace(buffer[i])) { + has_content = 1; + break; + } + } + + if (has_content) { + ExprNode *ast = expr_parse(buffer, strlen(buffer)); + if (!ast) { + printf("Parse failed.\n"); + } else { + assemble(vm, ast); + while (step_vm(vm)) { + } + expr_free(ast); + } + } + + // Reset buffer for next input + buffer[0] = '\0'; + } + // If unbalanced, continue reading more lines + } + exit(0); } enum FlagType { FLAG_NONE = 0, - FLAG_TEST_MODE = 1, - FLAG_DUMP_ROM = 2, - FLAG_GUI_MODE = 4, + FLAG_DUMP_ROM = 1, + FLAG_GUI_MODE = 2, }; #define MAX_INPUT_FILES 16 /* Adjust based on your system's constraints */ @@ -161,8 +170,6 @@ i32 parse_arguments(i32 argc, char *argv[], struct CompilerConfig *config) { /* Long and short flag handling */ if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gui") == 0) { config->flags |= FLAG_GUI_MODE; - } else if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--test") == 0) { - config->flags |= FLAG_TEST_MODE; } else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--dump-rom") == 0) { config->flags |= FLAG_DUMP_ROM; @@ -178,6 +185,14 @@ i32 parse_arguments(i32 argc, char *argv[], struct CompilerConfig *config) { return -1; } config->input_files[config->input_file_count++] = argv[i]; + } else if (strstr(argv[i], ".lisp") != NULL) { + /* Collect input files */ + if (config->input_file_count >= MAX_INPUT_FILES) { + fprintf(stderr, "Too many input files. Maximum is %d\n", + MAX_INPUT_FILES); + return -1; + } + config->input_files[config->input_file_count++] = argv[i]; } } @@ -216,7 +231,7 @@ i32 main(i32 argc, char *argv[]) { struct CompilerConfig config = {0}; if (parse_arguments(argc, argv, &config) != 0) { - fprintf(stderr, "Usage: %s [-d] [-t] [-g] [-o] [file2.ul] ...\n", + fprintf(stderr, "Usage: %s [-d] [-g] [-o] [file2.ul] ...\n", argv[0]); return 64; } @@ -225,13 +240,9 @@ i32 main(i32 argc, char *argv[]) { if (config.input_file_count == 0) { repl(&vm); } else { - if (config.flags & FLAG_TEST_MODE) { - compile_internal_test(config.input_files[0], &vm); - } else { - i32 j; - for (j = 0; j < config.input_file_count; j++) { - compileFile(config.input_files[j], &vm); - } + i32 j; + for (j = 0; j < config.input_file_count; j++) { + compileFile(config.input_files[j], &vm); } if (config.flags & FLAG_DUMP_ROM) { diff --git a/src/tools/assembler.c b/src/tools/assembler.c new file mode 100644 index 0000000..3b3b581 --- /dev/null +++ b/src/tools/assembler.c @@ -0,0 +1,603 @@ +#include "assembler.h" + +Label labels[256]; // For simplicity +int label_count = 0; + +void add_label(const char *name, u32 address) { + Label *l = &labels[label_count++]; + l->name = strdup(name); + l->address = address; +} + +u32 find_label(const char *name) { + for (int i = 0; i < label_count; ++i) { + if (strcmp(labels[i].name, name) == 0) + return labels[i].address; + } + fprintf(stderr, "Error: Undefined label '%s'\n", name); + exit(1); +} + +u32 real_alloc(VM *vm, float v) { + i32 fixed = TO_FIXED(v); + u32 addr = vm->mp; + write_u32(vm, memory, vm->mp, fixed); + vm->mp += 4; + vm->frames[vm->fp].end += 4; + return addr; +} + +u32 nat_alloc(VM *vm, u32 v) { + u32 addr = vm->mp; + write_u32(vm, memory, vm->mp, v); + vm->mp += 4; + vm->frames[vm->fp].end += 4; + return addr; +} + +u32 int_alloc(VM *vm, i32 v) { + u32 addr = vm->mp; + write_u32(vm, memory, vm->mp, v); + vm->mp += 4; + vm->frames[vm->fp].end += 4; + return addr; +} + +void emit_byte(VM *vm, u8 byte) { vm->code[vm->cp++] = byte; } + +void emit_u32(VM *vm, u32 value) { + write_u32(vm, code, vm->cp, value); + vm->cp += 4; +} + +void emit_opcode(VM *vm, Opcode op) { emit_byte(vm, op); } + +int parse_register(const char *reg_str) { + if (reg_str[0] != '$') + return -1; + return atoi(reg_str + 1); +} + +u32 parse_memory_ref(const char *ref) { + if (ref[0] == '&') { + return find_label(ref + 1); + } + // Or parse as immediate number? + return 0; +} + +void codegen_expr(VM *vm, ExprNode *node); + +void codegen_code_block(VM *vm, ExprNode *block) { + for (size_t i = 0; i < block->child_count; ++i) { + ExprNode *stmt = block->children[i]; + codegen_expr(vm, stmt); + } +} + +static char *unwrap_string(const char *quoted_str) { + if (!quoted_str) + return NULL; + + size_t len = strlen(quoted_str); + if (len >= 2 && quoted_str[0] == '"' && quoted_str[len - 1] == '"') { + // Remove quotes and process escape sequences + const char *src = quoted_str + 1; + size_t src_len = len - 2; + + // First pass: calculate the actual length needed after escape processing + size_t actual_len = 0; + for (size_t i = 0; i < src_len; ++i) { + if (src[i] == '\\' && i + 1 < src_len) { + // Escape sequence + actual_len++; + i++; // Skip the next character + } else { + actual_len++; + } + } + + char *unwrapped = (char *)malloc(actual_len + 1); + size_t dst_idx = 0; + + // Second pass: process escape sequences + for (size_t i = 0; i < src_len; ++i) { + if (src[i] == '\\' && i + 1 < src_len) { + // Handle escape sequences + switch (src[i + 1]) { + case 'n': unwrapped[dst_idx++] = '\n'; break; + case 't': unwrapped[dst_idx++] = '\t'; break; + case 'r': unwrapped[dst_idx++] = '\r'; break; + case '\\': unwrapped[dst_idx++] = '\\'; break; + case '"': unwrapped[dst_idx++] = '"'; break; + case '\'': unwrapped[dst_idx++] = '\''; break; + default: + // Unknown escape, keep both characters + unwrapped[dst_idx++] = src[i]; + unwrapped[dst_idx++] = src[i + 1]; + break; + } + i++; // Skip the next character + } else { + unwrapped[dst_idx++] = src[i]; + } + } + unwrapped[dst_idx] = '\0'; + return unwrapped; + } + // Not quoted, return copy + return strdup(quoted_str); +} + +void codegen_data_block(VM *vm, ExprNode *block) { + for (size_t i = 0; i < block->child_count; ++i) { + ExprNode *item = block->children[i]; + if (strcmp(item->token, "label") == 0 && item->child_count >= 2) { + const char *name = item->children[0]->token; + ExprNode *val = item->children[1]; + + if (val->child_count == 0) { + if (strchr(val->token, '.')) { + float f = atof(val->token); + u32 addr = real_alloc(vm, f); + add_label(name, addr); + } else { + // Assume string + char *unwrapped = unwrap_string(val->token); + u32 addr = str_alloc(vm, &vm->frames[vm->fp], unwrapped, + strlen(unwrapped) + 1); + free(unwrapped); + add_label(name, addr); + } + } else { + // Complex expression? + fprintf(stderr, "Unsupported data item\n"); + } + } + } +} + +void codegen_expr(VM *vm, ExprNode *node) { + if (node->child_count == 0) + return; + + const char *opname = node->token; + + if (strcmp(opname, "label") == 0) { + if (node->child_count < 2) { + fprintf(stderr, "Error: label requires at least a name\n"); + return; + } + + const char *label_name = node->children[0]->token; + add_label(label_name, vm->cp); + + for (size_t i = 1; i < node->child_count; ++i) { + codegen_expr(vm, node->children[i]); + } + } else if (strcmp(opname, "halt") == 0) { + emit_opcode(vm, OP_HALT); + } else if (strcmp(opname, "jump") == 0) { + emit_opcode(vm, OP_JMP); + u32 addr = find_label(node->children[0]->token); + emit_u32(vm, addr); + } else if (strcmp(opname, "jump-if-flag") == 0) { + emit_opcode(vm, OP_JMPF); + u32 addr = find_label(node->children[0]->token); + emit_u32(vm, addr); + } else if (strcmp(opname, "call") == 0) { + emit_opcode(vm, OP_CALL); + u32 addr = find_label(node->children[0]->token); + emit_u32(vm, addr); + } else if (strcmp(opname, "return") == 0) { + emit_opcode(vm, OP_RETURN); + } else if (strcmp(opname, "load") == 0) { + emit_opcode(vm, OP_LOAD); + int reg = parse_register(node->children[0]->token); + u32 addr = parse_memory_ref(node->children[1]->token); + emit_byte(vm, reg); + emit_u32(vm, addr); + } else if (strcmp(opname, "load-immediate") == 0) { + emit_opcode(vm, OP_LOAD_IMM); + int reg = parse_register(node->children[0]->token); + if (strchr(node->children[1]->token, '&')) { + u32 addr = parse_memory_ref(node->children[1]->token); + emit_byte(vm, reg); + emit_u32(vm, addr); + } else { + u32 val = (u32)atoi(node->children[1]->token); + emit_byte(vm, reg); + emit_u32(vm, val); + } + } else if (strcmp(opname, "store") == 0) { + emit_opcode(vm, OP_STORE); + int reg = parse_register(node->children[0]->token); + u32 addr = parse_memory_ref(node->children[1]->token); + emit_byte(vm, reg); + emit_u32(vm, addr); + } else if (strcmp(opname, "push") == 0) { + emit_opcode(vm, OP_PUSH); + int reg = parse_register(node->children[0]->token); + emit_byte(vm, reg); + } else if (strcmp(opname, "pop") == 0) { + emit_opcode(vm, OP_POP); + int reg = parse_register(node->children[0]->token); + emit_byte(vm, reg); + } else if (strcmp(opname, "register-move") == 0) { + emit_opcode(vm, OP_REG_MOV); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "syscall") == 0) { + emit_opcode(vm, OP_SYSCALL); + + // Parse syscall ID + u32 syscall_id = 0; + const char *syscall_name = node->children[0]->token; + if (strcmp(syscall_name, "DEVICE-EXIT") == 0) + syscall_id = SYSCALL_EXIT; + else if (strcmp(syscall_name, "DEVICE-OPEN") == 0) + syscall_id = SYSCALL_DEVICE_OPEN; + else if (strcmp(syscall_name, "DEVICE-READ") == 0) + syscall_id = SYSCALL_DEVICE_READ; + else if (strcmp(syscall_name, "DEVICE-WRITE") == 0) + syscall_id = SYSCALL_DEVICE_WRITE; + else if (strcmp(syscall_name, "DEVICE-CLOSE") == 0) + syscall_id = SYSCALL_DEVICE_CLOSE; + else if (strcmp(syscall_name, "DEVICE-IOCTL") == 0) + syscall_id = SYSCALL_DEVICE_IOCTL; + + emit_u32(vm, syscall_id); + + // Emit register arguments + for (size_t i = 1; i < node->child_count; ++i) { + int reg = parse_register(node->children[i]->token); + emit_byte(vm, reg); + } + } else if (strcmp(opname, "add-int") == 0) { + emit_opcode(vm, OP_ADD_INT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "sub-int") == 0) { + emit_opcode(vm, OP_SUB_INT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "mul-int") == 0) { + emit_opcode(vm, OP_MUL_INT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "div-int") == 0) { + emit_opcode(vm, OP_DIV_INT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "add-nat") == 0) { + emit_opcode(vm, OP_ADD_UINT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "sub-nat") == 0) { + emit_opcode(vm, OP_SUB_UINT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "mul-nat") == 0) { + emit_opcode(vm, OP_MUL_UINT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "div-nat") == 0) { + emit_opcode(vm, OP_DIV_UINT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "add-real") == 0) { + emit_opcode(vm, OP_ADD_REAL); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "sub-real") == 0) { + emit_opcode(vm, OP_SUB_REAL); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "mul-real") == 0) { + emit_opcode(vm, OP_MUL_REAL); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "div-real") == 0) { + emit_opcode(vm, OP_DIV_REAL); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "int-to-real") == 0) { + emit_opcode(vm, OP_INT_TO_REAL); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "nat-to-real") == 0) { + emit_opcode(vm, OP_UINT_TO_REAL); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "real-to-int") == 0) { + emit_opcode(vm, OP_REAL_TO_INT); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "real-to-nat") == 0) { + emit_opcode(vm, OP_REAL_TO_UINT); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "jump-eq-int") == 0) { + emit_opcode(vm, OP_JEQ_INT); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-gt-int") == 0) { + emit_opcode(vm, OP_JGT_INT); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-lt-int") == 0) { + emit_opcode(vm, OP_JLT_INT); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-le-int") == 0) { + emit_opcode(vm, OP_JLE_INT); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-ge-int") == 0) { + emit_opcode(vm, OP_JGE_INT); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-eq-nat") == 0) { + emit_opcode(vm, OP_JEQ_UINT); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-gt-nat") == 0) { + emit_opcode(vm, OP_JGT_UINT); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-lt-nat") == 0) { + emit_opcode(vm, OP_JLT_UINT); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-le-nat") == 0) { + emit_opcode(vm, OP_JLE_UINT); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-ge-nat") == 0) { + emit_opcode(vm, OP_JGE_UINT); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-eq-real") == 0) { + emit_opcode(vm, OP_JEQ_REAL); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-gt-real") == 0) { + emit_opcode(vm, OP_JGT_REAL); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-lt-real") == 0) { + emit_opcode(vm, OP_JLT_REAL); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-le-real") == 0) { + emit_opcode(vm, OP_JLE_REAL); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "jump-ge-real") == 0) { + emit_opcode(vm, OP_JGE_REAL); + u32 addr = find_label(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_u32(vm, addr); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "string-length") == 0) { + emit_opcode(vm, OP_STRLEN); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "string-eq") == 0) { + emit_opcode(vm, OP_STREQ); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "string-concat") == 0) { + emit_opcode(vm, OP_STRCAT); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "string-get-char") == 0) { + emit_opcode(vm, OP_STR_GET_CHAR); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "string-find-char") == 0) { + emit_opcode(vm, OP_STR_FIND_CHAR); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + } else if (strcmp(opname, "string-slice") == 0) { + emit_opcode(vm, OP_STR_SLICE); + int dest = parse_register(node->children[0]->token); + int src1 = parse_register(node->children[1]->token); + int src2 = parse_register(node->children[2]->token); + int src3 = parse_register(node->children[3]->token); + emit_byte(vm, dest); + emit_byte(vm, src1); + emit_byte(vm, src2); + emit_byte(vm, src3); + } else if (strcmp(opname, "int-to-string") == 0) { + emit_opcode(vm, OP_INT_TO_STRING); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "nat-to-string") == 0) { + emit_opcode(vm, OP_UINT_TO_STRING); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "real-to-string") == 0) { + emit_opcode(vm, OP_REAL_TO_STRING); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "string-to-int") == 0) { + emit_opcode(vm, OP_STRING_TO_INT); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "string-to-nat") == 0) { + emit_opcode(vm, OP_STRING_TO_UINT); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else if (strcmp(opname, "string-to-real") == 0) { + emit_opcode(vm, OP_STRING_TO_REAL); + int dest = parse_register(node->children[0]->token); + int src = parse_register(node->children[1]->token); + emit_byte(vm, dest); + emit_byte(vm, src); + } else { + fprintf(stderr, "Unknown opcode: %s\n", opname); + } +} + +void assemble(VM *vm, ExprNode *program) { + // First pass: process data section to define all labels + for (size_t i = 0; i < program->child_count; ++i) { + ExprNode *section = program->children[i]; + if (strcmp(section->token, "data") == 0) { + codegen_data_block(vm, section); + } + } + + // Second pass: process code section now that all labels are defined + for (size_t i = 0; i < program->child_count; ++i) { + ExprNode *section = program->children[i]; + if (strcmp(section->token, "code") == 0) { + codegen_code_block(vm, section); + } + } +} \ No newline at end of file diff --git a/src/tools/assembler.h b/src/tools/assembler.h new file mode 100644 index 0000000..b7b0e34 --- /dev/null +++ b/src/tools/assembler.h @@ -0,0 +1,25 @@ +#ifndef ASSEMBLER_H +#define ASSEMBLER_H + +#include "../vm/common.h" +#include "../vm/vm.h" +#include "parser.h" + +#include +#include +#include +#include + +#define AS_FIXED(v) ((float)(i32)(v) / 65536.0f) +#define TO_FIXED(f) ((u32)((i32)( \ + ((f) >= 0.0f) ? ((f) * 65536.0f + 0.5f) : ((f) * 65536.0f - 0.5f) \ +))) + +typedef struct { + char *name; + u32 address; +} Label; + +void assemble(VM *vm, ExprNode *program); + +#endif diff --git a/src/gen/build.sh b/src/tools/build.sh similarity index 100% rename from src/gen/build.sh rename to src/tools/build.sh diff --git a/src/gen/math_gen.c b/src/tools/math_gen.c similarity index 100% rename from src/gen/math_gen.c rename to src/tools/math_gen.c diff --git a/src/tools/parser.c b/src/tools/parser.c index ca8af77..0a8233c 100644 --- a/src/tools/parser.c +++ b/src/tools/parser.c @@ -5,7 +5,7 @@ #include // Helper function to allocate memory and handle errors -static void *safe_malloc(size_t size) { +void *safe_malloc(size_t size) { void *ptr = malloc(size); if (!ptr) { fprintf(stderr, "Memory allocation failed\n"); diff --git a/src/tools/parser.h b/src/tools/parser.h index a58bd1c..149628d 100644 --- a/src/tools/parser.h +++ b/src/tools/parser.h @@ -24,4 +24,6 @@ void expr_free(ExprNode *node); // Debug: print AST (for dev) void expr_print(ExprNode *node, int indent); +void *safe_malloc(size_t size); + #endif \ No newline at end of file diff --git a/src/tools/test.c b/src/tools/test.c deleted file mode 100644 index 35c4f08..0000000 --- a/src/tools/test.c +++ /dev/null @@ -1,166 +0,0 @@ -#include "test.h" -#include "../vm/opcodes.h" -#include "../vm/vm.h" -#include "string.h" -#include - -u32 real_alloc(VM *vm, float v) { - i32 fixed = TO_FIXED(v); - u32 addr = vm->mp; - write_u32(vm, memory, vm->mp, fixed); - vm->mp += 4; - vm->frames[vm->fp].end += 4; - return addr; -} - -u32 nat_alloc(VM *vm, u32 v) { - u32 addr = vm->mp; - write_u32(vm, memory, vm->mp, v); - vm->mp += 4; - vm->frames[vm->fp].end += 4; - return addr; -} - -u32 int_alloc(VM *vm, i32 v) { - u32 addr = vm->mp; - write_u32(vm, memory, vm->mp, v); - vm->mp += 4; - vm->frames[vm->fp].end += 4; - return addr; -} - -/* Array of test mappings */ -struct TestMapping internal_tests[] = { - {"simple.ul", test_simple_compile}, - {"window.ul", test_window_click_compile}, - {NULL, NULL} /* Sentinel to mark end of array */ -}; - -bool compile_internal_test(const char *filename, VM *vm) { - i32 i; - for (i = 0; internal_tests[i].filename != NULL; i++) { - if (strcmp(internal_tests[i].filename, filename) == 0) { - return internal_tests[i].test_func(vm); - } - } - return false; -} - -bool test_simple_compile(VM *vm) { - u32 ptr; - u32 newline_addr = str_alloc(vm, &vm->frames[vm->fp], "\n", 2); - u32 terminal_path_addr = - str_alloc(vm, &vm->frames[vm->fp], "/dev/term/0", 12); - vm->code[vm->cp++] = OP_LOAD; - vm->code[vm->cp++] = 0; - ptr = real_alloc(vm, 1.0f); - write_u32(vm, code, vm->cp, ptr); - vm->cp += 4; - - vm->code[vm->cp++] = OP_LOAD; - vm->code[vm->cp++] = 1; - ptr = real_alloc(vm, 2.0f); - write_u32(vm, code, vm->cp, ptr); - vm->cp += 4; - - vm->code[vm->cp++] = OP_ADD_REAL; - vm->code[vm->cp++] = 2; - vm->code[vm->cp++] = 1; - vm->code[vm->cp++] = 0; /* let sum = 1 + 2; */ - - vm->code[vm->cp++] = OP_REAL_TO_STRING; - vm->code[vm->cp++] = 3; - vm->code[vm->cp++] = 2; - - vm->code[vm->cp++] = OP_STRLEN; - vm->code[vm->cp++] = 4; - vm->code[vm->cp++] = 3; - - vm->code[vm->cp++] = OP_LOAD_IMM; - vm->code[vm->cp++] = 5; - write_u32(vm, code, vm->cp, terminal_path_addr); - vm->cp += 4; - - vm->code[vm->cp++] = OP_SYSCALL; - write_u32(vm, code, vm->cp, AS_UINT(SYSCALL_DEVICE_WRITE)); - vm->cp += 4; - vm->code[vm->cp++] = 5; - vm->code[vm->cp++] = 3; - vm->code[vm->cp++] = 4; - - vm->code[vm->cp++] = OP_LOAD_IMM; - vm->code[vm->cp++] = 6; - write_u32(vm, code, vm->cp, newline_addr); - vm->cp += 4; - - vm->code[vm->cp++] = OP_STRLEN; - vm->code[vm->cp++] = 7; - vm->code[vm->cp++] = 6; - - vm->code[vm->cp++] = OP_SYSCALL; - write_u32(vm, code, vm->cp, AS_UINT(SYSCALL_DEVICE_WRITE)); - vm->cp += 4; - vm->code[vm->cp++] = 5; - vm->code[vm->cp++] = 6; - vm->code[vm->cp++] = 7; - - /* syscall_id=WRITE, device-str-ptr=5, ptr, length ; print(sum.toS()); */ - vm->code[vm->cp++] = OP_HALT; /* explicit halt */ - return true; -} - -bool test_window_click_compile(VM *vm) { - u32 test_pixel_addr, loop_start, - screen_path_addr = - str_alloc(vm, &vm->frames[vm->fp], "/dev/screen/0", 14); - - vm->code[vm->cp++] = OP_LOAD; /* R0 = screen path */ - vm->code[vm->cp++] = 0; - vm->code[vm->cp++] = nat_alloc(vm, screen_path_addr); - - vm->code[vm->cp++] = OP_LOAD; /* R1 = mode (0) */ - vm->code[vm->cp++] = 1; - vm->code[vm->cp++] = int_alloc(vm, 0); - - vm->code[vm->cp++] = OP_SYSCALL; - vm->code[vm->cp++] = SYSCALL_DEVICE_OPEN; - vm->code[vm->cp++] = 0; - vm->code[vm->cp++] = 1; - - test_pixel_addr = vm->mp; - vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); - vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); - vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); - vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); - vm->frames[vm->fp].end += 4; - - vm->code[vm->cp++] = OP_LOAD; - vm->code[vm->cp++] = 0; - vm->code[vm->cp++] = nat_alloc(vm, screen_path_addr); - - vm->code[vm->cp++] = OP_LOAD; - vm->code[vm->cp++] = 1; - vm->code[vm->cp++] = nat_alloc(vm, test_pixel_addr); - - vm->code[vm->cp++] = OP_LOAD; - vm->code[vm->cp++] = 2; - vm->code[vm->cp++] = int_alloc(vm, 1); - - vm->code[vm->cp++] = OP_LOAD; - vm->code[vm->cp++] = 3; - loop_start = vm->cp + 2; /* here + after alloc */ - vm->code[vm->cp++] = nat_alloc(vm, loop_start); - - vm->code[vm->cp++] = OP_SYSCALL; - vm->code[vm->cp++] = SYSCALL_DEVICE_WRITE; - vm->code[vm->cp++] = 0; - vm->code[vm->cp++] = 1; - vm->code[vm->cp++] = 2; - - vm->code[vm->cp++] = OP_JMP; - vm->code[vm->cp++] = 3; - - vm->code[vm->cp++] = OP_HALT; - - return true; -} \ No newline at end of file diff --git a/src/tools/test.h b/src/tools/test.h deleted file mode 100644 index f3e33bf..0000000 --- a/src/tools/test.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef ZRE_TEST_H -#define ZRE_TEST_H - -#include "../vm/opcodes.h" - -#define AS_FIXED(v) ((float)(i32)(v) / 65536.0f) -#define TO_FIXED(f) ((u32)((i32)( \ - ((f) >= 0.0f) ? ((f) * 65536.0f + 0.5f) : ((f) * 65536.0f - 0.5f) \ -))) - -/* Test function type definition */ -typedef bool (*TestFunction)(VM *vm); - -/* Test mapping structure */ -struct TestMapping { - const char* filename; - TestFunction test_func; -}; - -bool compile_internal_test(const char* filename, VM* vm); -bool test_simple_compile (VM *vm); -bool test_loop_compile (VM *vm); -bool test_add_function_compile(VM *vm); -bool test_recursive_function_compile(VM *vm); -bool test_window_click_compile(VM *vm); - -#endif diff --git a/test/add.asm.lisp b/test/add.asm.lisp index f41ced9..3da0459 100644 --- a/test/add.asm.lisp +++ b/test/add.asm.lisp @@ -8,7 +8,7 @@ (int-to-string $1 $0) (load $3 &terminal-str) (string-length $2 $1) - (syscall DEVICE-WRITE, $3, $1, $2) + (syscall DEVICE-WRITE $3 $1 $2) (halt)) (label add diff --git a/test/fib.asm.lisp b/test/fib.asm.lisp index 3e3ca6c..606b3ec 100644 --- a/test/fib.asm.lisp +++ b/test/fib.asm.lisp @@ -6,7 +6,7 @@ (pop $0) (int-to-string $1 $0) (load $2, &terminal-str) - (strlen $4, $3) + (string-length $4, $3) (syscall DEVICE-WRITE, $2, $1, $4) (halt)) (label fib diff --git a/test/hello.asm.lisp b/test/hello.asm.lisp index 6d60d49..0ba4237 100644 --- a/test/hello.asm.lisp +++ b/test/hello.asm.lisp @@ -2,11 +2,11 @@ (label main (load $0 &terminal-str) (load $1 &hello-str) - (strlen $2 $1) + (string-length $2 $1) (syscall DEVICE_WRITE $0 $1 $2) (load $3 &new-line) (string-length $4 $3) - (syscall DEVICE-WRITE, $0, $3, $4) + (syscall DEVICE-WRITE $0 $3 $4) (halt))) (data (label terminal-str "/dev/term/0") diff --git a/test/simple.asm.lisp b/test/simple.asm.lisp index f1a5286..1dcb24b 100644 --- a/test/simple.asm.lisp +++ b/test/simple.asm.lisp @@ -5,11 +5,11 @@ (add-real $2 $1 $0) (real-to-string $3 $2) (string-length $4 $3) - (load $5 &terminal-str) - (syscall DEVICE-WRITE, $5, $3, $4) - (load $6 &new-line) + (load-immediate $5 &terminal-str) + (syscall DEVICE-WRITE $5 $3 $4) + (load-immediate $6 &new-line) (string-length $7 $6) - (syscall DEVICE-WRITE, $5, $6, $7) + (syscall DEVICE-WRITE $5 $6 $7) (halt))) (data (label terminal-str "/dev/term/0") (label new-line "\n")