From 770d9d56fff47fdf27a407797a67f4b8fdbc0d2a Mon Sep 17 00:00:00 2001 From: zongor Date: Tue, 9 Sep 2025 21:15:39 -0700 Subject: [PATCH] Cleanup, get rid of all the prototyping stuff --- .gitattributes | 2 +- README.org | 76 ++-- docs/project-syntax-example/client.ul | 3 + docs/project-syntax-example/common.ul | 20 +- ...rsċieppan-w.svg => undârsċieppan-w.svg} | 0 ...undarsċieppan.svg => undârsċieppan.svg} | 0 src/Makefile | 2 +- src/arch/linux/devices.c | 4 +- src/arch/linux/main.c | 63 +-- src/common.h | 4 +- src/compiler.c | 377 ------------------ src/compiler.h | 47 --- src/device.h | 4 +- src/fixed.c | 201 ---------- src/fixed.h | 55 --- src/lexer.c | 248 ------------ src/lexer.h | 70 ---- src/opcodes.h | 10 +- src/test.c | 44 +- src/test.h | 6 +- src/vm.c | 47 ++- src/vm.h | 4 +- test/{add.lisp => add.asm} | 0 test/{fib.lisp => fib.asm} | 0 test/{hello.lisp => hello.asm} | 0 test/hello.ul | 9 +- test/{loop.lisp => loop.asm} | 0 test/run.sh | 4 +- test/{simple.lisp => simple.asm} | 0 29 files changed, 156 insertions(+), 1144 deletions(-) rename docs/{undarsċieppan-w.svg => undârsċieppan-w.svg} (100%) rename docs/{undarsċieppan.svg => undârsċieppan.svg} (100%) delete mode 100644 src/compiler.c delete mode 100644 src/compiler.h delete mode 100644 src/fixed.c delete mode 100644 src/fixed.h delete mode 100644 src/lexer.c delete mode 100644 src/lexer.h rename test/{add.lisp => add.asm} (100%) rename test/{fib.lisp => fib.asm} (100%) rename test/{hello.lisp => hello.asm} (100%) rename test/{loop.lisp => loop.asm} (100%) rename test/{simple.lisp => simple.asm} (100%) diff --git a/.gitattributes b/.gitattributes index 52a0dbc..321ac7a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -*.zrl linguist-language=fortran \ No newline at end of file +*.ul linguist-language=fortran \ No newline at end of file diff --git a/README.org b/README.org index dc92a80..92307b2 100644 --- a/README.org +++ b/README.org @@ -1,5 +1,4 @@ #+TITLE: A Language for Enduring Realities -#+SUBTITLE: "Shape realities that outlast their makers." #+AUTHOR: Zongor #+EMAIL: archive@undar-lang.org #+DATE: [2025-04-05] @@ -18,26 +17,26 @@ * The Reality Engine -The =Reality Engine= is a register-based virtual machine designed to render not just graphics, but *realities* - persistent, inspectable, reproducible computational worlds. +The =Reality Engine= is a register-based virtual machine designed to render not just graphics, but persistent, inspectable, reproducible computational worlds. It is: - Written in **C89** for maximum portability - **No dynamic allocation** - memory is static, frame-managed, zero-initialized -- **Deterministic by design** - identical input -> identical output, forever +- **Deterministic by design** - identical input -> identical output - **Self-inspectable** - symbol table, memory, and state are always accessible - Inspired by Uxn, Dis VM, Dusk OS, and Plan 9 **VM Architecture** -| Feature | Specification | -|-----------------------|----------------------------------------------------| -| Instruction Format | 1-byte opcode, 3-byte operand (CISC-like) | -| Register Set | 32 general-purpose registers (R0-R31) | -| Initialization | **ZII**: Zero Is Initialization | -| Memory Model | Frame-based arenas (function scope = frame) | -| Heap Behavior | Copy-on-write; allocations append to frame | -| Frame Exit | Pointer resets on return (stack-GC style) | -| Error Handling | Returns stub pointers to zeroed memory | +| Feature | Specification | +|--------------------+---------------------------------------------| +| Instruction Format | 1-byte opcode, 3-byte operand (CISC-like) | +| Register Set | 32 general-purpose registers (R0-R31) | +| Initialization | **ZII**: Zero Is Initialization | +| Memory Model | Frame-based arenas (function scope = frame) | +| Heap Behavior | Copy-on-write; allocations append to frame | +| Frame Exit | Pointer resets on return (stack-GC style) | +| Error Handling | Returns stub pointers to zeroed memory | This ensures: - No =malloc=, no =free=, no GC @@ -45,9 +44,9 @@ This ensures: - Perfect reproducibility - Safe failure modes -Undar is a permacomputing oriented, statically-typed language with **first-class arrays**, **immediate-mode semantics**, and **symbolic clarity** +Undâr is a permacomputing oriented, statically-typed language with **first-class arrays**, **immediate-mode semantics**, and **symbolic clarity** - =Constrained systems=: microcontrollers, retro consoles (PS1, N64, Mac Classic) -- =Portable environments=: Web (Emscripten), embedded, CLI +- =Portable environments=: Web (Emscripten), embedded, CLI Tui - =Permacomputing=: long-term survivability, sustainability, minimalism - =3D world-building=: built-in primitives for PS1/N64-style rendering - =Live development=: hot reloading, REPL, shadowing, symbol versioning @@ -59,14 +58,14 @@ You can view some examples in the =.lisp= files in =/test= **Core Types** -| Type | Description | -|--------|-----------------------------------------------| -| =int= | 32-bit signed integer | -| =nat= | 32-bit natural number (also used for pointers)| -| =real= | Q16.16 fixed-point real number | -| =str= | 4-byte packed string or fat pointer | -| =bool= | Compile-time flag | -| =ref= | Reference type for passing by reference | +| Type | Description | +|------+-------------------------------------------| +| =int= | 32-bit signed integer | +| =nat= | 32-bit natural number | +| =real= | Q16.16 fixed-point real number | +| =str= | 4-byte packed string or fat pointer | +| =bool= | Compile-time flag | +| =ref= | Reference prefix for passing by reference | **Array Semantics (Fortran-Style)** @@ -198,17 +197,17 @@ if (server.attach(auth)) { **Tunnel Operations** -| Op | Meaning | -|------------|-------------------------| -| =.attach()= | Authenticate and open | -| =.open()= | Open resource | -| =.read()= |Transfer data | -| =.write()= | Transfer data | -| =.walk()= | Navigate hierarchy | -| =.flush()= | Cancel long operation | -| =.clunk()= | Close connection | -| =.stat()= | Get metadata | -| =.version()=| Get protocol version | +| Op | Meaning | +|------------+-----------------------| +| =.attach()= | Authenticate and open | +| =.open()= | Open resource | +| =.read()= | Transfer data | +| =.write()= | Transfer data | +| =.walk()= | Navigate hierarchy | +| =.flush()= | Cancel long operation | +| =.clunk()= | Close connection | +| =.stat()= | Get metadata | +| =.version()= | Get protocol version | Tunnels make I/O **uniform, composable, and archival**. @@ -308,16 +307,12 @@ function main(int argc, str[] argv) { - Versioned plexes: forward/backward compatibility - Self-documenting syntax: just enough magic - Open standard: no vendor lock-in -- Archive formats: =.ul=, =.zbin=, =.zatom= +- Archive formats: =.ul=, =.ubin=, =.uatom= * License **MIT-0** - No restrictions, no warranty. -With an ethical understanding: - -> This software should not be used to accelerate obsolescence, exploit users, or harm ecosystems. Compute only to strengthen what lasts. - * Inspirations - [[https://wiki.xxiivv.com/site/uxn.html][Uxn]] - Minimalism, elegance @@ -336,15 +331,12 @@ With an ethical understanding: * Join the Effort The Reality Engine is a community project. We welcome: -- Compiler contributors - Port developers (Web, Game Boy, etc.) - Artists and game designers - Archivists and historians -> *"We are not making programs. We are writing Ages."* - * Contact - - Website: https://undar-lang.org - Email: archive@undar-lang.org - Repository: https://git.alfrescocavern.com/zongor/reality-engine.git + diff --git a/docs/project-syntax-example/client.ul b/docs/project-syntax-example/client.ul index 2b3de0d..3c1be45 100644 --- a/docs/project-syntax-example/client.ul +++ b/docs/project-syntax-example/client.ul @@ -4,6 +4,9 @@ function main(int argc, str[] argv) { nat screen_width = 800; nat screen_height = 450; + if (argv < 2) { + exits("usage: zre client.ul "); + } str username = argv[1]; str password = argv[2]; diff --git a/docs/project-syntax-example/common.ul b/docs/project-syntax-example/common.ul index cfed377..6eb7070 100644 --- a/docs/project-syntax-example/common.ul +++ b/docs/project-syntax-example/common.ul @@ -1,11 +1,11 @@ -/** - * Note that these look like classes but act like structs - * the methods actually have a implied struct as their first argument - */ +!! +! Note that these look like classes but act like structs +! the methods actually have a implied struct as their first argument +!! -/** - * Camera. - */ +!! +! Camera. +!! plex Camera { init(real[3] pos, real[3] look) { this.setting = "CAMERA_PERSPECTIVE"; @@ -16,9 +16,9 @@ plex Camera { } } -/** - * Player. - */ +!! +! Player. +!! plex Player { init(str username, real[3] pos, Color color) { this.client = Client("tcp://localhost:25565"); diff --git a/docs/undarsċieppan-w.svg b/docs/undârsċieppan-w.svg similarity index 100% rename from docs/undarsċieppan-w.svg rename to docs/undârsċieppan-w.svg diff --git a/docs/undarsċieppan.svg b/docs/undârsċieppan.svg similarity index 100% rename from docs/undarsċieppan.svg rename to docs/undârsċieppan.svg diff --git a/src/Makefile b/src/Makefile index 8912eda..dd69b4c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,7 +2,7 @@ # ----------------------- # Native build (gcc) CC_NATIVE = gcc -CFLAGS_NATIVE = -g -O2 -std=c89 -Wall -Wextra -Werror -Wno-unused-parameter -I. +CFLAGS_NATIVE = -g -std=c89 -Wall -Wextra -Werror -Wno-unused-parameter -I. #-O2 LDFLAGS_NATIVE = LDLIBS_NATIVE = -lSDL2 diff --git a/src/arch/linux/devices.c b/src/arch/linux/devices.c index f94fb34..585d129 100644 --- a/src/arch/linux/devices.c +++ b/src/arch/linux/devices.c @@ -18,7 +18,7 @@ int screen_open(void *data, uint32_t mode) { return -1; screen->texture = SDL_CreateTexture( - screen->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, + screen->renderer, SDL_PIXELFORMAT_RGB332, SDL_TEXTUREACCESS_STREAMING, screen->width, screen->height); if (!screen->texture) return -1; @@ -32,7 +32,7 @@ int screen_read(void *data, uint8_t *buffer, uint32_t size) { return -1; } int screen_write(void *data, const uint8_t *buffer, uint32_t size) { ScreenDeviceData *screen = (ScreenDeviceData *)data; - if (size > screen->framebuffer_size * sizeof(uint32_t)) { + if (size > screen->framebuffer_size * sizeof(uint8_t)) { return -1; } diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index 4e2b2ae..3a55cb9 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -1,4 +1,4 @@ -#include "../../compiler.h" +#include "../../assembler.h" #include "../../test.h" #include "../../vm.h" #include "devices.h" @@ -9,29 +9,23 @@ #define MAX_SRC_SIZE 16384 -static DeviceOps screen_ops = { - .open = screen_open, - .read = screen_read, - .write = screen_write, - .close = screen_close, - .ioctl = NULL -}; +static DeviceOps screen_ops = {.open = screen_open, + .read = screen_read, + .write = screen_write, + .close = screen_close, + .ioctl = NULL}; -static DeviceOps mouse_ops = { - .open = mouse_open, - .read = mouse_read, - .write = mouse_write, - .close = mouse_close, - .ioctl = NULL -}; +static DeviceOps mouse_ops = {.open = mouse_open, + .read = mouse_read, + .write = mouse_write, + .close = mouse_close, + .ioctl = NULL}; -static DeviceOps keyboard_ops= { - .open = keyboard_open, - .read = keyboard_read, - .write = keyboard_write, - .close = keyboard_close, - .ioctl = NULL -}; +static DeviceOps keyboard_ops = {.open = keyboard_open, + .read = keyboard_read, + .write = keyboard_write, + .close = keyboard_close, + .ioctl = NULL}; static ScreenDeviceData screen_data = {0}; static MouseDeviceData mouse_data = {0}; @@ -56,11 +50,19 @@ void compileFile(const char *path, VM *vm) { size_t read = fread(source, 1, len, f); source[read] = '\0'; fclose(f); +} - compile(source, vm); +bool test_fibonacci(VM *vm) { + Assembler zasm; + + while (step_vm(vm)); + return true; } void repl(VM *vm) { + + test_fibonacci(vm); + char line[1024]; for (;;) { printf("> "); @@ -75,7 +77,7 @@ void repl(VM *vm) { vm->pc = 0; vm->mp = 0; - compile(line, vm); + /* assemble(line, vm); */ while (step_vm(vm)) ; } @@ -126,7 +128,7 @@ int parse_arguments(int argc, char *argv[], struct CompilerConfig *config) { fprintf(stderr, "Unknown flag: %s\n", argv[i]); return -1; } - } else if (strstr(argv[i], ".zrl") != NULL) { + } else if (strstr(argv[i], ".ul") != NULL) { /* Collect input files */ if (config->input_file_count >= MAX_INPUT_FILES) { fprintf(stderr, "Too many input files. Maximum is %d\n", @@ -146,7 +148,7 @@ void register_sdl_devices(VM *vm) { screen_data.height = 480; screen_data.framebuffer_size = 640 * 480; screen_data.framebuffer_pos = vm->mp; - vm->mp += screen_data.framebuffer_size; /* advance memory pointer */ + vm->mp += screen_data.framebuffer_size / 4; /* advance memory pointer */ vm_register_device(vm, "/dev/screen/0", "screen", &screen_data, &screen_ops); @@ -169,14 +171,12 @@ int main(int argc, char *argv[]) { struct CompilerConfig config = {0}; if (parse_arguments(argc, argv, &config) != 0) { - fprintf(stderr, - "Usage: %s [-d] [-t] [-g] [-o] [file2.zrl] ...\n", + fprintf(stderr, "Usage: %s [-d] [-t] [-g] [-o] [file2.ul] ...\n", argv[0]); return 64; } VM vm = {0}; - if (config.input_file_count == 0) { repl(&vm); } else { @@ -218,9 +218,9 @@ int main(int argc, char *argv[]) { } bool running = true; - register_sdl_devices(&vm); if (config.flags & FLAG_GUI_MODE) { uint32_t i; + register_sdl_devices(&vm); while (running) { for (i = 0; i < vm.dc; i++) { Device *dev = &vm.devices[i]; @@ -269,7 +269,8 @@ int main(int argc, char *argv[]) { if (strcmp(dev->type, "screen") == 0) { ScreenDeviceData *screen = (ScreenDeviceData *)dev->data; if (screen->texture && screen->renderer) { - SDL_UpdateTexture(screen->texture, NULL, &vm.memory[screen->framebuffer_pos], + SDL_UpdateTexture(screen->texture, NULL, + &vm.memory[screen->framebuffer_pos], screen->width * sizeof(uint32_t)); SDL_RenderClear(screen->renderer); diff --git a/src/common.h b/src/common.h index 394c946..2d1036d 100644 --- a/src/common.h +++ b/src/common.h @@ -1,5 +1,5 @@ -#ifndef ZRL_COMMON_H -#define ZRL_COMMON_H +#ifndef ZRE_COMMON_H +#define ZRE_COMMON_H #include #include diff --git a/src/compiler.c b/src/compiler.c deleted file mode 100644 index fc45293..0000000 --- a/src/compiler.c +++ /dev/null @@ -1,377 +0,0 @@ -#include "compiler.h" -#include "vm.h" -#include - -typedef struct { - Token current; - Token previous; - bool hadError; - bool panicMode; -} Parser; - -typedef enum { - PREC_NONE, - PREC_ASSIGNMENT, /* = */ - PREC_OR, /* or */ - PREC_AND, /* and */ - PREC_EQUALITY, /* == != */ - PREC_COMPARISON, /* < > <= >= */ - PREC_TERM, /* + - */ - PREC_FACTOR, /* * / */ - PREC_UNARY, /* not */ - PREC_CALL, /* . () */ - PREC_PRIMARY -} Precedence; - -typedef void (*ParseFn)(VM *vm); - -typedef struct { - ParseFn prefix; - ParseFn infix; - Precedence precedence; -} ParseRule; - -Parser parser; -SymbolTable st; - -const char *internalErrorMsg = "FLAGRANT COMPILER ERROR\n\nCompiler over.\nBug = Very Yes."; - -void errorAt(Token *token, const char *message) { - if (parser.panicMode) - return; - parser.panicMode = true; - fprintf(stderr, "[line %d] Error", token->line); - - if (token->type == TOKEN_EOF) { - fprintf(stderr, " at end"); - } else if (token->type == TOKEN_ERROR) { - } else { - fprintf(stderr, " at '%.*s'", token->length, token->start); - } - - fprintf(stderr, ": %s\n", message); - parser.hadError = true; -} - -void error(const char *message) { errorAt(&parser.previous, message); } - -void errorAtCurrent(const char *message) { errorAt(&parser.current, message); } - -void advance() { - parser.previous = parser.current; - - for (;;) { - parser.current = nextToken(); - if (parser.current.type != TOKEN_ERROR) - break; - - errorAtCurrent(parser.current.start); - } -} - -void consume(TokenType type, const char *message) { - if (parser.current.type == type) { - advance(); - return; - } - - errorAtCurrent(message); -} - -static bool check(TokenType type) { return parser.current.type == type; } - -static bool match(TokenType type) { - if (!check(type)) - return false; - advance(); - return true; -} - -void emitOp(VM *vm, uint8_t opcode, uint8_t dest, uint8_t src1, uint8_t src2) { - vm->code[vm->cp++].u = OP(opcode, dest, src1, src2); -} - -void expression(VM *vm); -void statement(VM *vm); -void declaration(VM *vm); -ParseRule *getRule(TokenType type); -void parsePrecedence(VM *vm, Precedence precedence); - -void number(VM *vm) { - if (parser.previous.type == TOKEN_INT_LITERAL) { - char *endptr; - int32_t value = (int32_t)strtol(parser.previous.start, &endptr, 10); - emitOp(vm, OP_LOAD, vm->frames[vm->fp].rp++, 0, 0); - vm->code[vm->cp++].u = int_alloc(vm, value); - return; - } else if (parser.previous.type == TOKEN_UINT_LITERAL) { - long value = atol(parser.previous.start); - emitOp(vm, OP_LOAD, vm->frames[vm->fp].rp++, 0, 0); - vm->code[vm->cp++].u = nat_alloc(vm, value); - return; - } else if (parser.previous.type == TOKEN_FLOAT_LITERAL) { - float value = atof(parser.previous.start); - emitOp(vm, OP_LOAD, vm->frames[vm->fp].rp++, 0, 0); - vm->code[vm->cp++].u = real_alloc(vm, value); - return; - } - errorAtCurrent("Invalid number format"); -} - -void string(VM *vm) { - uint32_t length = parser.previous.length - 2; - uint32_t str_addr = vm->mp; - vm->memory[vm->mp++].u = length; - uint32_t i, j = 0; - for (i = 0; i < length; i++) { - vm->memory[vm->mp].c[i % 4] = parser.previous.start[i + 1]; - if (++j == 4) { - j = 0; - vm->mp++; - } - } - vm->frames[vm->fp].allocated.end += length / 4; - emitOp(vm, OP_LOAD, vm->frames[vm->fp].rp++, 0, 0); - vm->code[vm->cp++].u = str_addr; -} - -void grouping(VM *vm) { - expression(vm); - consume(TOKEN_RPAREN, "Expect ')' after expression."); -} - -void unary(VM *vm) { - TokenType operatorType = parser.previous.type; - - parsePrecedence(vm, PREC_UNARY); - - switch (operatorType) { - default: - return; - } -} - -static void literal(VM *vm) { - switch (parser.previous.type) { - case TOKEN_KEYWORD_NIL: { - emitOp(vm, OP_LOAD, vm->frames[vm->fp].rp++, 0, 0); - vm->code[vm->cp++].u = 0; - break; - } - case TOKEN_KEYWORD_FALSE: { - emitOp(vm, OP_LOAD, vm->frames[vm->fp].rp++, 0, 0); - vm->code[vm->cp++].u = 0; - break; - } - case TOKEN_KEYWORD_TRUE: { - emitOp(vm, OP_LOAD, vm->frames[vm->fp].rp++, 0, 0); - vm->code[vm->cp++].u = 1; - break; - } - default: - return; - } -} - -void binary(VM *vm) { - TokenType operatorType = parser.previous.type; - ParseRule *rule = getRule(operatorType); - parsePrecedence(vm, (Precedence)(rule->precedence + 1)); - TokenType operandType = parser.previous.type; - - Frame f = vm->frames[vm->fp]; - uint32_t src1 = f.rp--; - uint32_t src2 = f.rp--; - uint32_t dest = f.rp++; - - switch (operatorType) { - case TOKEN_PLUS: - if (operandType == TOKEN_UINT_LITERAL) { - emitOp(vm, OP_ADD_UINT, dest, src1, src2); - } else if (operandType == TOKEN_INT_LITERAL) { - emitOp(vm, OP_ADD_INT, dest, src1, src2); - } else if (operandType == TOKEN_FLOAT_LITERAL) { - emitOp(vm, OP_ADD_REAL, dest, src1, src2); - } else { - error("not numeric"); - } - break; - case TOKEN_MINUS: - if (operandType == TOKEN_UINT_LITERAL) { - emitOp(vm, OP_SUB_UINT, dest, src1, src2); - } else if (operandType == TOKEN_INT_LITERAL) { - emitOp(vm, OP_SUB_INT, dest, src1, src2); - } else if (operandType == TOKEN_FLOAT_LITERAL) { - emitOp(vm, OP_SUB_REAL, dest, src1, src2); - } else { - error("not numeric"); - } - break; - case TOKEN_STAR: - if (operandType == TOKEN_UINT_LITERAL) { - emitOp(vm, OP_MUL_UINT, dest, src1, src2); - } else if (operandType == TOKEN_INT_LITERAL) { - emitOp(vm, OP_MUL_INT, dest, src1, src2); - } else if (operandType == TOKEN_FLOAT_LITERAL) { - emitOp(vm, OP_MUL_REAL, dest, src1, src2); - } else { - error("not numeric"); - } - break; - case TOKEN_SLASH: - if (operandType == TOKEN_UINT_LITERAL) { - emitOp(vm, OP_DIV_UINT, dest, src1, src2); - } else if (operandType == TOKEN_INT_LITERAL) { - emitOp(vm, OP_DIV_INT, dest, src1, src2); - } else if (operandType == TOKEN_FLOAT_LITERAL) { - emitOp(vm, OP_DIV_REAL, dest, src1, src2); - } else { - error("not numeric"); - } - break; - default: - return; /* Unreachable. */ - } -} - -ParseRule rules[] = { - [TOKEN_LPAREN] = {grouping, NULL, PREC_NONE}, - [TOKEN_RPAREN] = {NULL, NULL, PREC_NONE}, - [TOKEN_LBRACE] = {NULL, NULL, PREC_NONE}, - [TOKEN_RBRACE] = {NULL, NULL, PREC_NONE}, - [TOKEN_COMMA] = {NULL, NULL, PREC_NONE}, - [TOKEN_DOT] = {NULL, NULL, PREC_NONE}, - [TOKEN_MINUS] = {NULL, binary, PREC_TERM}, - [TOKEN_PLUS] = {NULL, binary, PREC_TERM}, - [TOKEN_SEMICOLON] = {NULL, NULL, PREC_NONE}, - [TOKEN_SLASH] = {NULL, binary, PREC_FACTOR}, - [TOKEN_STAR] = {NULL, binary, PREC_FACTOR}, - [TOKEN_BANG] = {NULL, NULL, PREC_NONE}, - [TOKEN_BANG_EQ] = {NULL, NULL, PREC_NONE}, - [TOKEN_EQ] = {NULL, NULL, PREC_NONE}, - [TOKEN_EQ_EQ] = {NULL, NULL, PREC_NONE}, - [TOKEN_GT] = {NULL, NULL, PREC_NONE}, - [TOKEN_GTE] = {NULL, NULL, PREC_NONE}, - [TOKEN_LT] = {NULL, NULL, PREC_NONE}, - [TOKEN_LTE] = {NULL, NULL, PREC_NONE}, - [TOKEN_IDENTIFIER] = {NULL, NULL, PREC_NONE}, - [TOKEN_STRING_LITERAL] = {string, NULL, PREC_NONE}, - [TOKEN_INT_LITERAL] = {number, NULL, PREC_NONE}, - [TOKEN_UINT_LITERAL] = {number, NULL, PREC_NONE}, - [TOKEN_FLOAT_LITERAL] = {number, NULL, PREC_NONE}, - [TOKEN_KEYWORD_ELSE] = {NULL, NULL, PREC_NONE}, - [TOKEN_KEYWORD_FOR] = {NULL, NULL, PREC_NONE}, - [TOKEN_KEYWORD_FN] = {NULL, NULL, PREC_NONE}, - [TOKEN_KEYWORD_IF] = {NULL, NULL, PREC_NONE}, - [TOKEN_OPERATOR_AND] = {NULL, binary, PREC_NONE}, - [TOKEN_OPERATOR_OR] = {NULL, binary, PREC_NONE}, - [TOKEN_OPERATOR_NOT] = {unary, NULL, PREC_NONE}, - [TOKEN_KEYWORD_NIL] = {literal, NULL, PREC_NONE}, - [TOKEN_KEYWORD_TRUE] = {literal, NULL, PREC_NONE}, - [TOKEN_KEYWORD_FALSE] = {literal, NULL, PREC_NONE}, - [TOKEN_KEYWORD_PRINT] = {NULL, NULL, PREC_NONE}, - [TOKEN_KEYWORD_RETURN] = {NULL, NULL, PREC_NONE}, - [TOKEN_KEYWORD_THIS] = {NULL, NULL, PREC_NONE}, - [TOKEN_KEYWORD_LET] = {NULL, NULL, PREC_NONE}, - [TOKEN_KEYWORD_WHILE] = {NULL, NULL, PREC_NONE}, - [TOKEN_ERROR] = {NULL, NULL, PREC_NONE}, - [TOKEN_EOF] = {NULL, NULL, PREC_NONE}, -}; - -ParseRule *getRule(TokenType type) { return &rules[type]; } - -void parsePrecedence(VM *vm, Precedence precedence) { - advance(); - ParseFn prefixRule = getRule(parser.previous.type)->prefix; - if (prefixRule == NULL) { - error("Expect expression."); - return; - } - - prefixRule(vm); - - while (precedence <= getRule(parser.current.type)->precedence) { - advance(); - ParseFn infixRule = getRule(parser.previous.type)->infix; - infixRule(vm); - } -} - -void expression(VM *vm) { parsePrecedence(vm, PREC_ASSIGNMENT); } - -void printStatement(VM *vm) { - expression(vm); - consume(TOKEN_SEMICOLON, "Expect ';' after value."); - Frame f = vm->frames[vm->fp]; - vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, f.rp--, 0); -} - -static void expressionStatement(VM *vm) { - expression(vm); - consume(TOKEN_SEMICOLON, "Expect ';' after expression."); -} - -static void intDeclaration(VM *vm) { - /* insert variable name in symbol table */ - uint32_t length = parser.previous.length - 2; - if (length > SYMBOL_NAME_SIZE) { - error("Variable names cannot be longer than 24 characters."); - return; - } - st.symbols[st.sc].type = INT; - st.symbols[st.sc].frame = vm->fp; - - Frame f = vm->frames[vm->fp]; - st.symbols[st.sc].reg = f.rp; - - uint32_t i; - for (i = 0; i < length; i++) { - st.symbols[st.sc].name[i] = parser.previous.start[i + 1]; - } - st.sc++; - - if (match(TOKEN_EQ)) { - expression(vm); - } else { - /* initialize as zero/null */ - emitOp(vm, OP_LOAD, vm->frames[vm->fp].rp++, 0, 0); - vm->code[vm->cp++].i = 0; - } - - consume(TOKEN_SEMICOLON, "Expect ';' after expression."); -} - -void statement(VM *vm) { - if (match(TOKEN_KEYWORD_PRINT)) { - printStatement(vm); - } else if (match(TOKEN_TYPE_INT)) { - intDeclaration(vm); - } else { - expressionStatement(vm); - } -} - -void declaration(VM *vm) { statement(vm); } - -bool compile(const char *source, VM *vm) { - initLexer(source); - - parser.hadError = false; - parser.panicMode = false; - - st.sc = 0; - st.name[0] = 'm'; - st.name[1] = 'a'; - st.name[2] = 'i'; - st.name[3] = 'n'; - - advance(); - - while (!match(TOKEN_EOF)) { - declaration(vm); - } - - emitOp(vm, OP_HALT, 0, 0, 0); - - return !parser.hadError; -} diff --git a/src/compiler.h b/src/compiler.h deleted file mode 100644 index 156cb79..0000000 --- a/src/compiler.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef ZRL_COMPILER_H -#define ZRL_COMPILER_H - -#include "lexer.h" -#include "opcodes.h" - -typedef enum { INT, REAL, NATURAL, POINTER, STRING, ARRAY, PLEX } SymbolType; - -typedef struct plex_def_t { - SymbolType subtype; - uint32_t size; -} PlexDef; - -typedef struct array_def_t { - SymbolType subtype; - uint32_t length; -} ArrayDef; - -#define SYMBOL_NAME_SIZE 24 - -typedef struct symbol_t { - char name[SYMBOL_NAME_SIZE]; - SymbolType type; - union { - PlexDef pd; - ArrayDef ad; - }; - int8_t reg; - uint8_t flags[3]; /* only use for padding now, might be used later*/ - uint32_t frame; - uint32_t ptr; -} Symbol; - -#define MODULE_NAME_SIZE 32 -#define SYMBOL_COUNT 256 - -typedef struct symbol_table_t { - char name[MODULE_NAME_SIZE]; - Symbol symbols[SYMBOL_COUNT]; - uint32_t sc; -} SymbolTable; - -extern SymbolTable st; - -bool compile(const char *source, VM *vm); - -#endif diff --git a/src/device.h b/src/device.h index cf62804..882694c 100644 --- a/src/device.h +++ b/src/device.h @@ -1,5 +1,5 @@ -#ifndef ZRL_DEVICE_H -#define ZRL_DEVICE_H +#ifndef ZRE_DEVICE_H +#define ZRE_DEVICE_H #include "opcodes.h" diff --git a/src/fixed.c b/src/fixed.c deleted file mode 100644 index 47b3b8e..0000000 --- a/src/fixed.c +++ /dev/null @@ -1,201 +0,0 @@ -/* fixed.c - Q16.16 Fixed-Point Math Implementation */ - -#include "fixed.h" - -/* Conversion functions */ -fixed_t int_to_fixed(int32_t i) { - return i << 16; -} - -int32_t fixed_to_int(fixed_t f) { - return f >> 16; -} - -fixed_t float_to_fixed(float f) { - return (fixed_t)(f * 65536.0f); -} - -float fixed_to_float(fixed_t f) { - return (float)f / 65536.0f; -} - -fixed_t fixed_add(fixed_t a, fixed_t b) { - return a + b; -} - -fixed_t fixed_sub(fixed_t a, fixed_t b) { - return a - b; -} - -fixed_t fixed_mul(fixed_t a, fixed_t b) { - /* Extract high and low parts */ - int32_t a_hi = a >> 16; - uint32_t a_lo = (uint32_t)a & 0xFFFFU; - int32_t b_hi = b >> 16; - uint32_t b_lo = (uint32_t)b & 0xFFFFU; - - /* Compute partial products */ - int32_t p0 = (int32_t)(a_lo * b_lo) >> 16; /* Low * Low */ - int32_t p1 = a_hi * (int32_t)b_lo; /* High * Low */ - int32_t p2 = (int32_t)a_lo * b_hi; /* Low * High */ - int32_t p3 = (a_hi * b_hi) << 16; /* High * High */ - - /* Combine results */ - return p0 + p1 + p2 + p3; -} - -fixed_t fixed_div(fixed_t a, fixed_t b) { - if (b == 0) return 0; /* Handle division by zero */ - - /* Determine sign */ - int negative = ((a < 0) ^ (b < 0)); - - /* Work with absolute values */ - uint32_t ua = (a < 0) ? -a : a; - uint32_t ub = (b < 0) ? -b : b; - - /* Perform division using long division in base 2^16 */ - uint32_t quotient = 0; - uint32_t remainder = 0; - int i; - - for (i = 0; i < 32; i++) { - remainder <<= 1; - if (ua & 0x80000000U) { - remainder |= 1; - } - ua <<= 1; - - if (remainder >= ub) { - remainder -= ub; - quotient |= 1; - } - - if (i < 31) { - quotient <<= 1; - } - } - - return negative ? -(int32_t)quotient : (int32_t)quotient; -} - -int fixed_eq(fixed_t a, fixed_t b) { - return a == b; -} - -int fixed_ne(fixed_t a, fixed_t b) { - return a != b; -} - -int fixed_lt(fixed_t a, fixed_t b) { - return a < b; -} - -int fixed_le(fixed_t a, fixed_t b) { - return a <= b; -} - -int fixed_gt(fixed_t a, fixed_t b) { - return a > b; -} - -int fixed_ge(fixed_t a, fixed_t b) { - return a >= b; -} - -/* Unary operations */ -fixed_t fixed_neg(fixed_t f) { - return -f; -} - -fixed_t fixed_abs(fixed_t f) { - return (f < 0) ? -f : f; -} - -/* Square root using Newton-Raphson method */ -fixed_t fixed_sqrt(fixed_t f) { - if (f <= 0) return 0; - - fixed_t x = f; - fixed_t prev; - - /* Newton-Raphson iteration: x = (x + f/x) / 2 */ - do { - prev = x; - x = fixed_div(fixed_add(x, fixed_div(f, x)), int_to_fixed(2)); - } while (fixed_gt(fixed_abs(fixed_sub(x, prev)), 1)); /* Precision to 1/65536 */ - - return x; -} - -/* Sine function using Taylor series */ -fixed_t fixed_sin(fixed_t f) { - /* Normalize angle to [-π, π] */ - fixed_t pi2 = fixed_mul(FIXED_PI, int_to_fixed(2)); - while (fixed_gt(f, FIXED_PI)) f = fixed_sub(f, pi2); - while (fixed_lt(f, fixed_neg(FIXED_PI))) f = fixed_add(f, pi2); - - /* Taylor series: sin(x) = x - x³/3! + x⁵/5! - x⁷/7! + ... */ - fixed_t result = f; - fixed_t term = f; - fixed_t f_squared = fixed_mul(f, f); - - /* Calculate first few terms for reasonable precision */ - int i; - for (i = 3; i <= 11; i += 2) { - term = fixed_mul(term, f_squared); - term = fixed_div(term, int_to_fixed(i * (i - 1))); - - if ((i / 2) % 2 == 0) { - result = fixed_add(result, term); - } else { - result = fixed_sub(result, term); - } - } - - return result; -} - -/* Cosine function using Taylor series */ -fixed_t fixed_cos(fixed_t f) { - /* cos(x) = 1 - x²/2! + x⁴/4! - x⁶/6! + ... */ - fixed_t result = FIXED_ONE; - fixed_t term = FIXED_ONE; - fixed_t f_squared = fixed_mul(f, f); - - int i; - for (i = 2; i <= 12; i += 2) { - term = fixed_mul(term, f_squared); - term = fixed_div(term, int_to_fixed(i * (i - 1))); - - if ((i / 2) % 2 == 0) { - result = fixed_add(result, term); - } else { - result = fixed_sub(result, term); - } - } - - return result; -} - -/* Tangent function */ -fixed_t fixed_tan(fixed_t f) { - fixed_t cos_val = fixed_cos(f); - if (cos_val == 0) return 0; /* Handle undefined case */ - return fixed_div(fixed_sin(f), cos_val); -} - -/* Utility functions */ -fixed_t fixed_min(fixed_t a, fixed_t b) { - return (a < b) ? a : b; -} - -fixed_t fixed_max(fixed_t a, fixed_t b) { - return (a > b) ? a : b; -} - -fixed_t fixed_clamp(fixed_t f, fixed_t min_val, fixed_t max_val) { - if (f < min_val) return min_val; - if (f > max_val) return max_val; - return f; -} diff --git a/src/fixed.h b/src/fixed.h deleted file mode 100644 index 26dbb8b..0000000 --- a/src/fixed.h +++ /dev/null @@ -1,55 +0,0 @@ -/* fixed.h - Q16.16 Fixed-Point Math Library in C89 */ - -#ifndef FIXED_H -#define FIXED_H - -#include - -/* Q16.16 fixed-point type */ -typedef int32_t fixed_t; - -/* Constants */ -#define FIXED_ONE 0x00010000L /* 1.0 in Q16.16 */ -#define FIXED_ZERO 0x00000000L /* 0.0 in Q16.16 */ -#define FIXED_HALF 0x00008000L /* 0.5 in Q16.16 */ -#define FIXED_PI 0x0003243FL /* π ≈ 3.14159 */ -#define FIXED_E 0x0002B7E1L /* e ≈ 2.71828 */ -#define FIXED_MAX 0x7FFFFFFFL /* Maximum positive value */ -#define FIXED_MIN 0x80000000L /* Minimum negative value */ - -/* Conversion functions */ -fixed_t int_to_fixed(int32_t i); -int32_t fixed_to_int(fixed_t f); -fixed_t float_to_fixed(float f); -float fixed_to_float(fixed_t f); - -/* Basic arithmetic operations */ -fixed_t fixed_add(fixed_t a, fixed_t b); -fixed_t fixed_sub(fixed_t a, fixed_t b); -fixed_t fixed_mul(fixed_t a, fixed_t b); -fixed_t fixed_div(fixed_t a, fixed_t b); - -/* Comparison functions */ -int fixed_eq(fixed_t a, fixed_t b); -int fixed_ne(fixed_t a, fixed_t b); -int fixed_lt(fixed_t a, fixed_t b); -int fixed_le(fixed_t a, fixed_t b); -int fixed_gt(fixed_t a, fixed_t b); -int fixed_ge(fixed_t a, fixed_t b); - -/* Unary operations */ -fixed_t fixed_neg(fixed_t f); -fixed_t fixed_abs(fixed_t f); - -/* Advanced math functions */ -fixed_t fixed_sqrt(fixed_t f); -fixed_t fixed_sin(fixed_t f); /* f in radians */ -fixed_t fixed_cos(fixed_t f); /* f in radians */ -fixed_t fixed_tan(fixed_t f); /* f in radians */ - -/* Utility functions */ -fixed_t fixed_min(fixed_t a, fixed_t b); -fixed_t fixed_max(fixed_t a, fixed_t b); -fixed_t fixed_clamp(fixed_t f, fixed_t min, fixed_t max); - -#endif /* FIXED_H */ diff --git a/src/lexer.c b/src/lexer.c deleted file mode 100644 index b18f05a..0000000 --- a/src/lexer.c +++ /dev/null @@ -1,248 +0,0 @@ -#include - -#include "common.h" -#include "lexer.h" - -typedef struct { - const char *start; - const char *current; - int line; -} Lexer; - -Lexer lexer; - -void initLexer(const char *source) { - lexer.start = source; - lexer.current = source; - lexer.line = 1; -} - -static bool isAlpha(char c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; -} - -static bool isDigit(char c) { return c >= '0' && c <= '9'; } - -static bool isAtEnd() { return *lexer.current == '\0'; } - -static char advance() { - lexer.current++; - return lexer.current[-1]; -} - -static char peek() { return *lexer.current; } - -static char peekNext() { - if (isAtEnd()) - return '\0'; - return lexer.current[1]; -} - -static bool match(char expected) { - if (isAtEnd()) - return false; - if (*lexer.current != expected) - return false; - lexer.current++; - return true; -} - -static Token makeToken(TokenType type) { - Token token; - token.type = type; - token.start = lexer.start; - token.length = (int)(lexer.current - lexer.start); - token.line = lexer.line; - return token; -} - -static Token errorToken(const char *message) { - Token token; - token.type = TOKEN_ERROR; - token.start = message; - token.length = (int)strlen(message); - token.line = lexer.line; - return token; -} - -static void skipWhitespace() { - for (;;) { - char c = peek(); - switch (c) { - case ' ': - case '\r': - case '\t': - advance(); - break; - case '\n': - lexer.line++; - advance(); - break; - case '/': - if (peekNext() == '/') { - /* A comment goes until the end of the line. */ - while (peek() != '\n' && !isAtEnd()) - advance(); - } else { - return; - } - break; - default: - return; - } - } -} - -static TokenType checkKeyword(int start, int length, const char *rest, - TokenType type) { - if (lexer.current - lexer.start == start + length && - memcmp(lexer.start + start, rest, length) == 0) { - return type; - } - - return TOKEN_IDENTIFIER; -} - -static TokenType identifierType() { - switch (lexer.start[0]) { - case 'a': - return checkKeyword(1, 2, "nd", TOKEN_OPERATOR_AND); - case 'e': - return checkKeyword(1, 3, "lse", TOKEN_KEYWORD_ELSE); - case 'f': - if (lexer.current - lexer.start > 1) { - switch (lexer.start[1]) { - case 'a': - return checkKeyword(2, 3, "lse", TOKEN_KEYWORD_FALSE); - case 'o': - return checkKeyword(2, 1, "r", TOKEN_KEYWORD_FOR); - } - return checkKeyword(1, 1, "n", TOKEN_KEYWORD_FN); - } - break; - case 'i': - return checkKeyword(1, 1, "f", TOKEN_KEYWORD_IF); - case 'n': - return checkKeyword(1, 2, "il", TOKEN_KEYWORD_NIL); - case 'o': - return checkKeyword(1, 1, "r", TOKEN_OPERATOR_OR); - case 'p': - if (lexer.current - lexer.start > 1) { - switch (lexer.start[1]) { - case 'l': - return checkKeyword(2, 2, "ex", TOKEN_KEYWORD_PLEX); - case 'r': - return checkKeyword(2, 3, "int", TOKEN_KEYWORD_PRINT); - } - } - break; - case 'r': - return checkKeyword(1, 5, "eturn", TOKEN_KEYWORD_RETURN); - case 't': - if (lexer.current - lexer.start > 1) { - switch (lexer.start[1]) { - case 'h': - return checkKeyword(2, 2, "is", TOKEN_KEYWORD_THIS); - case 'r': - return checkKeyword(2, 2, "ue", TOKEN_KEYWORD_TRUE); - } - } - break; - case 'l': - return checkKeyword(1, 2, "et", TOKEN_KEYWORD_LET); - case 'w': - return checkKeyword(1, 4, "hile", TOKEN_KEYWORD_WHILE); - } - - return TOKEN_IDENTIFIER; -} - -static Token identifier() { - while (isAlpha(peek()) || isDigit(peek())) - advance(); - return makeToken(identifierType()); -} - -static Token number() { - while (isDigit(peek())) - advance(); - - /* Look for a fractional part. */ - if (peek() == '.' && isDigit(peekNext())) { - /* Consume the ".". */ - advance(); - - while (isDigit(peek())) - advance(); - - return makeToken(TOKEN_FLOAT_LITERAL); - } - - return makeToken(TOKEN_INT_LITERAL); -} - -static Token string() { - while (peek() != '"' && !isAtEnd()) { - if (peek() == '\n') - lexer.line++; - advance(); - } - - if (isAtEnd()) - return errorToken("Unterminated string."); - - /* The closing quote. */ - advance(); - return makeToken(TOKEN_STRING_LITERAL); -} - -Token nextToken() { - skipWhitespace(); - lexer.start = lexer.current; - - if (isAtEnd()) - return makeToken(TOKEN_EOF); - - char c = advance(); - if (isAlpha(c)) - return identifier(); - if (isDigit(c)) - return number(); - - switch (c) { - case '(': - return makeToken(TOKEN_LPAREN); - case ')': - return makeToken(TOKEN_RPAREN); - case '{': - return makeToken(TOKEN_LBRACE); - case '}': - return makeToken(TOKEN_RBRACE); - case ';': - return makeToken(TOKEN_SEMICOLON); - case ',': - return makeToken(TOKEN_COMMA); - case '.': - return makeToken(TOKEN_DOT); - case '-': - return makeToken(TOKEN_MINUS); - case '+': - return makeToken(TOKEN_PLUS); - case '/': - return makeToken(TOKEN_SLASH); - case '*': - return makeToken(TOKEN_STAR); - case '!': - return makeToken(match('=') ? TOKEN_BANG_EQ : TOKEN_BANG); - case '=': - return makeToken(match('=') ? TOKEN_EQ_EQ : TOKEN_EQ); - case '<': - return makeToken(match('=') ? TOKEN_LTE : TOKEN_LT); - case '>': - return makeToken(match('=') ? TOKEN_GTE : TOKEN_GT); - case '"': - return string(); - } - - return errorToken("Unexpected character."); -} diff --git a/src/lexer.h b/src/lexer.h deleted file mode 100644 index 30a4120..0000000 --- a/src/lexer.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef zre_lexer_h -#define zre_lexer_h - -typedef enum { - TOKEN_EOF, - TOKEN_IDENTIFIER, - TOKEN_INT_LITERAL, - TOKEN_UINT_LITERAL, - TOKEN_FLOAT_LITERAL, - TOKEN_STRING_LITERAL, - TOKEN_TYPE_INT, - TOKEN_TYPE_NAT, - TOKEN_TYPE_REAL, - TOKEN_TYPE_STR, - TOKEN_KEYWORD_PLEX, - TOKEN_KEYWORD_FN, - TOKEN_KEYWORD_LET, - TOKEN_KEYWORD_CONST, - TOKEN_KEYWORD_IF, - TOKEN_KEYWORD_ELSE, - TOKEN_KEYWORD_WHILE, - TOKEN_KEYWORD_FOR, - TOKEN_KEYWORD_RETURN, - TOKEN_KEYWORD_USE, - TOKEN_KEYWORD_INIT, - TOKEN_KEYWORD_THIS, - TOKEN_KEYWORD_PRINT, - TOKEN_KEYWORD_NIL, - TOKEN_KEYWORD_TRUE, - TOKEN_KEYWORD_FALSE, - TOKEN_OPERATOR_IS, - TOKEN_OPERATOR_NOT, - TOKEN_OPERATOR_AND, - TOKEN_OPERATOR_OR, - TOKEN_BANG, - TOKEN_BANG_EQ, - TOKEN_EQ, - TOKEN_EQ_EQ, - TOKEN_GT, - TOKEN_LT, - TOKEN_GTE, - TOKEN_LTE, - TOKEN_DOT, - TOKEN_COMMA, - TOKEN_COLON, - TOKEN_SEMICOLON, - TOKEN_PLUS, - TOKEN_MINUS, - TOKEN_STAR, - TOKEN_SLASH, - TOKEN_LPAREN, - TOKEN_RPAREN, - TOKEN_LBRACE, - TOKEN_RBRACE, - TOKEN_LBRACKET, - TOKEN_RBRACKET, - TOKEN_ERROR -} TokenType; - -typedef struct { - TokenType type; - const char *start; - int length; - int line; -} Token; - -void initLexer(const char *source); -Token nextToken(); - -#endif diff --git a/src/opcodes.h b/src/opcodes.h index e46dca4..028d43c 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -1,5 +1,5 @@ -#ifndef ZRL_OPCODES_H -#define ZRL_OPCODES_H +#ifndef ZRE_OPCODES_H +#define ZRE_OPCODES_H #include "common.h" #include @@ -63,13 +63,13 @@ typedef enum { OP_STRING_TO_UINT, /* stou : dest = src1 as uint */ OP_STRING_TO_REAL, /* stor : dest = src1 as real */ /* to remove (replace with device), just for testing for now */ - OP_DBG_PRINT_STRING, - OP_DBG_READ_STRING, + OP_DBG_PRINT_STRING, /* puts : write a string to stdout */ + OP_DBG_READ_STRING, /* gets : read a string from stdin */ } Opcode; /* defines a uint32 opcode */ #define OP(opcode, dest, src1, src2) \ - ((opcode << 24) | (dest << 16) | (src1 << 8) | src2) + ((opcode << 24) | (dest << 16) | (src1 << 8) | (src2)) #define OP_SYSCALL_OPCODE(syscall_id, arg_count, src) \ ((OP_SYSCALL << 24) | ((syscall_id & 0xFF) << 16) | (arg_count & 0xFF) | src) diff --git a/src/test.c b/src/test.c index 590a61f..1c2d031 100644 --- a/src/test.c +++ b/src/test.c @@ -4,11 +4,11 @@ /* Array of test mappings */ struct TestMapping internal_tests[] = { - {"simple.zrl", test_add_compile}, - {"loop.zrl", test_loop_compile}, - {"add.zrl", test_add_function_compile}, - {"fib.zrl", test_recursive_function_compile}, - {"window.zrl", test_window_click_compile}, + {"simple.ul", test_simple_compile}, + {"loop.ul", test_loop_compile}, + {"add.ul", test_add_function_compile}, + {"fib.ul", test_recursive_function_compile}, + {"window.ul", test_window_click_compile}, /* Add more test mappings here */ {NULL, NULL} /* Sentinel to mark end of array */ }; @@ -23,10 +23,10 @@ bool compile_internal_test(const char* filename, VM* vm) { return false; } -bool test_add_compile(VM *vm) { +bool test_simple_compile(VM *vm) { vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); vm->code[vm->cp++].u = nat_alloc(vm, 1); - vm->code[vm->cp++].u = OP(OP_LOAD, 1, 1, 0); + vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); vm->code[vm->cp++].u = nat_alloc(vm, 2); vm->code[vm->cp++].u = OP(OP_ADD_UINT, 2, 1, 0); /* let sum = 1 + 2; */ vm->code[vm->cp++].u = OP(OP_UINT_TO_STRING, 3, 2, 0); @@ -39,22 +39,23 @@ bool test_loop_compile(VM *vm) { vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* let a = 5.0 */ vm->code[vm->cp++].u = real_alloc(vm, 5.0f); vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); /* do (i = 50000, 0, -1) { */ - vm->code[vm->cp++].u = int_alloc(vm, 50000); + vm->code[vm->cp++].u = int_alloc(vm, 10000); vm->code[vm->cp++].u = OP(OP_LOAD, 2, 0, 0); /* loop check value */ vm->code[vm->cp++].u = int_alloc(vm, 0); vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0); /* loop incriment value */ vm->code[vm->cp++].u = int_alloc(vm, -1); + vm->code[vm->cp++].u = OP(OP_LOAD, 5, 0, 0); /* a */ + vm->code[vm->cp++].u = real_alloc(vm, 5.0f); vm->code[vm->cp++].u = OP(OP_LOAD, 4, 0, 0); /* loop start */ uint32_t addr = vm->cp + 1; vm->code[vm->cp++].u = int_alloc(vm, addr); - vm->code[vm->cp++].u = OP(OP_LOAD, 5, 0, 0); - vm->code[vm->cp++].u = real_alloc(vm, 5.0f); vm->code[vm->cp++].u = OP(OP_ADD_REAL, 0, 0, 5); /* a += 5.0; */ vm->code[vm->cp++].u = OP(OP_ADD_INT, 1, 1, 3); /* (implied by loop) i = i + (-1) */ vm->code[vm->cp++].u = OP(OP_JGE_INT, 4, 1, 2); /* } */ vm->code[vm->cp++].u = OP(OP_REAL_TO_UINT, 1, 0, 0); /* let b = a as nat; */ vm->code[vm->cp++].u = OP(OP_LOAD, 6, 0, 0); - vm->code[vm->cp++].u = str_alloc(vm, "Enter a string:", 0); + uint32_t str_addr = str_alloc(vm, "Enter a string:", 16); + vm->code[vm->cp++].u = nat_alloc(vm, str_addr); vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 6, 0); /* print("Enter a string: "); */ vm->code[vm->cp++].u = OP(OP_DBG_READ_STRING, 2, 0, 0); /* let user_string = gets(); */ vm->code[vm->cp++].u = OP(OP_UINT_TO_STRING, 3, 1, 0); @@ -69,11 +70,10 @@ bool test_loop_compile(VM *vm) { bool test_add_function_compile(VM *vm) { /* fn main() */ vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* 1 */ - uint32_t addr = int_alloc(vm, 1); - vm->code[vm->cp++].u = addr; + vm->code[vm->cp++].u = int_alloc(vm, 1); vm->code[vm->cp++].u = OP(OP_PUSH, 0, 0, 0); vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* 1 */ - vm->code[vm->cp++].u = addr; + vm->code[vm->cp++].u = int_alloc(vm, 1); vm->code[vm->cp++].u = OP(OP_PUSH, 0, 0, 0); vm->code[vm->cp++].u = OP(OP_CALL, 0, 0, 0); /* ); */ vm->code[vm->cp++].u = 12; @@ -136,7 +136,7 @@ bool test_window_click_compile(VM *vm) { /* Open screen device: R0=path, R1=mode */ vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* R0 = screen path */ - vm->code[vm->cp++].u = screen_path_addr; + vm->code[vm->cp++].u = nat_alloc(vm, screen_path_addr); vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); /* R1 = mode (0) */ vm->code[vm->cp++].u = int_alloc(vm, 0); vm->code[vm->cp++].u = OP(OP_SYSCALL, SYSCALL_DEVICE_OPEN, 0, 2); /* syscall_id, first_reg=0, arg_count=2 */ @@ -146,22 +146,26 @@ bool test_window_click_compile(VM *vm) { /* Create simple test pixel data */ uint32_t test_pixel_addr = vm->mp; - vm->memory[vm->mp++].u = 0x00FF0000; - + vm->memory[vm->mp].c[0] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); + vm->memory[vm->mp].c[1] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); + vm->memory[vm->mp].c[2] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); + vm->memory[vm->mp++].c[3] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64); + vm->frames[vm->fp].allocated.end++; + /* Main loop to check for mouse input */ uint32_t loop_start = vm->cp; /* Write to screen: R0=path, R1=buffer, R2=size */ vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); - vm->code[vm->cp++].u = screen_path_addr; + vm->code[vm->cp++].u = nat_alloc(vm, screen_path_addr); vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); - vm->code[vm->cp++].u = test_pixel_addr; + vm->code[vm->cp++].u = nat_alloc(vm, test_pixel_addr); vm->code[vm->cp++].u = OP(OP_LOAD, 2, 0, 0); vm->code[vm->cp++].u = int_alloc(vm, 1); vm->code[vm->cp++].u = OP(OP_SYSCALL, SYSCALL_DEVICE_WRITE, 0, 3); /* syscall_id, first_reg=0, arg_count=3 */ vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0); - vm->code[vm->cp++].u = loop_start; + vm->code[vm->cp++].u = nat_alloc(vm, loop_start); vm->code[vm->cp++].u = OP(OP_JMP, 3, 0, 0); /* Infinite loop for testing */ vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0); diff --git a/src/test.h b/src/test.h index e85a65e..800ab0b 100644 --- a/src/test.h +++ b/src/test.h @@ -1,5 +1,5 @@ -#ifndef ZRL_TEST_H -#define ZRL_TEST_H +#ifndef ZRE_TEST_H +#define ZRE_TEST_H #include "opcodes.h" @@ -13,7 +13,7 @@ struct TestMapping { }; bool compile_internal_test(const char* filename, VM* vm); -bool test_add_compile (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); diff --git a/src/vm.c b/src/vm.c index e636b87..49d7f13 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1,5 +1,6 @@ #include "vm.h" #include "device.h" +#include "opcodes.h" #include /* no inline fn in ANSI C :( */ @@ -108,7 +109,9 @@ bool step_vm(VM *vm) { return true; } case OP_LOAD: { - vm->frames[vm->fp].registers[dest].u = vm->code[vm->pc++].u; + uint32_t ptr = vm->code[vm->pc++].u; + Value v = vm->memory[ptr]; + vm->frames[vm->fp].registers[dest] = v; return true; } case OP_STORE: { @@ -166,6 +169,27 @@ bool step_vm(VM *vm) { vm->memory[dest_addr].u ^= vm->memory[src_addr].u; return true; } + case OP_REG_SWAP: { + vm->frames[vm->fp].registers[dest].u ^= + vm->frames[vm->fp].registers[src1].u; + vm->frames[vm->fp].registers[src1].u ^= + vm->frames[vm->fp].registers[dest].u; + vm->frames[vm->fp].registers[dest].u ^= + vm->frames[vm->fp].registers[src1].u; + return true; + } + case OP_REG_MOV: { + vm->frames[vm->fp].registers[dest].i = vm->frames[vm->fp].registers[src1].i; + return true; + } + case OP_GET_ACC: { + vm->frames[vm->fp].registers[dest].u = vm->acc; + return true; + } + case OP_GET_PC: { + vm->frames[vm->fp].registers[dest].u = vm->pc; + return true; + } case OP_SYSCALL: { uint32_t syscall_id = dest; uint32_t arg_count = src2; @@ -361,31 +385,10 @@ bool step_vm(VM *vm) { (float)(vm->frames[vm->fp].registers[src1].u); return true; } - case OP_REG_SWAP: { - vm->frames[vm->fp].registers[dest].u ^= - vm->frames[vm->fp].registers[src1].u; - vm->frames[vm->fp].registers[src1].u ^= - vm->frames[vm->fp].registers[dest].u; - vm->frames[vm->fp].registers[dest].u ^= - vm->frames[vm->fp].registers[src1].u; - return true; - } - case OP_REG_MOV: { - vm->frames[vm->fp].registers[dest].i = vm->frames[vm->fp].registers[src1].i; - return true; - } - case OP_GET_ACC: { - vm->frames[vm->fp].registers[dest].u = vm->acc; - return true; - } case OP_JMP: { vm->pc = vm->frames[vm->fp].registers[dest].u; /* Jump to address */ return true; } - case OP_GET_PC: { - vm->frames[vm->fp].registers[dest].u = vm->pc; - return true; - } case OP_JEQ_UINT: { COMPARE_AND_JUMP(uint32_t, u, ==); } diff --git a/src/vm.h b/src/vm.h index 2b0470d..d9a4caa 100644 --- a/src/vm.h +++ b/src/vm.h @@ -1,5 +1,5 @@ -#ifndef ZRL_VM_H -#define ZRL_VM_H +#ifndef ZRE_VM_H +#define ZRE_VM_H #include "opcodes.h" diff --git a/test/add.lisp b/test/add.asm similarity index 100% rename from test/add.lisp rename to test/add.asm diff --git a/test/fib.lisp b/test/fib.asm similarity index 100% rename from test/fib.lisp rename to test/fib.asm diff --git a/test/hello.lisp b/test/hello.asm similarity index 100% rename from test/hello.lisp rename to test/hello.asm diff --git a/test/hello.ul b/test/hello.ul index dd150bd..7016193 100644 --- a/test/hello.ul +++ b/test/hello.ul @@ -1 +1,8 @@ -print("nuqneH 'u'?"); +function main(int argc, str[] argv) { + str name = "World"; + if argc > 1 { + name = argv[1]; + } + print("Hello, {name}!"); + exits("Done"); +} diff --git a/test/loop.lisp b/test/loop.asm similarity index 100% rename from test/loop.lisp rename to test/loop.asm diff --git a/test/run.sh b/test/run.sh index 4211f20..2fc7994 100755 --- a/test/run.sh +++ b/test/run.sh @@ -37,5 +37,5 @@ print_section "zlc ($FILENAME.zl)" echo "test input" | time zlc "$FILENAME.zl" # ZRE Implementation -print_section "zre ($FILENAME.zrl)" - echo "test input" | time ../src/zre -t "$FILENAME.zrl" +print_section "zre ($FILENAME.ul)" + echo "test input" | time ../src/zre -t "$FILENAME.ul" diff --git a/test/simple.lisp b/test/simple.asm similarity index 100% rename from test/simple.lisp rename to test/simple.asm