diff --git a/Makefile b/Makefile index a803ee3..ccb5783 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ BASE_CFLAGS := -I$(SRC_DIR) -Wall -Wextra -Werror -pedantic CORE_CFLAGS := $(BASE_CFLAGS) -std=c89 -ffreestanding -nostdlib -fno-builtin # --- PLATFORM-SPECIFIC FLAGS --- -PLATFORM_CFLAGS := $(BASE_CFLAGS) +PLATFORM_CFLAGS := $(BASE_CFLAGS) -std=c99 # --- MODE & PLATFORM SPECIFIC FLAGS --- ifeq ($(BUILD_MODE), deploy) @@ -51,8 +51,8 @@ ifeq ($(PLATFORM), emscripten) # For deploy: optimize, strip debug, minimize size ifeq ($(BUILD_MODE), deploy) - PLATFORM_CFLAGS += -O3 - LDFLAGS += -O3 --closure 1 + PLATFORM_CFLAGS += -O2 + LDFLAGS += -O2 --closure 1 else # For debug: preserve names, generate source maps PLATFORM_CFLAGS += -gsource-map @@ -68,23 +68,28 @@ ifndef TARGET TARGET = $(BUILD_DIR)/zre-$(PLATFORM)$(TARGET_SUFFIX) endif -# --- CORE SOURCES (flat in src/) --- -CORE_SOURCES := \ - $(SRC_DIR)/str.c \ - $(SRC_DIR)/vm.c \ - $(SRC_DIR)/device.c \ - $(SRC_DIR)/test.c +# --- VM CORE SOURCES --- +VM_SOURCES := \ + $(SRC_DIR)/vm/vm.c \ + $(SRC_DIR)/vm/device.c \ + $(SRC_DIR)/vm/str.c -# --- PLATFORM SOURCE --- -PLATFORM_SOURCE := $(ARCH_DIR)/main.c \ - $(ARCH_DIR)/devices.c +ifeq ($(BUILD_MODE), deploy) + PLATFORM_SOURCE := $(ARCH_DIR)/main.c \ + $(ARCH_DIR)/devices.c +else + PLATFORM_SOURCE := $(ARCH_DIR)/main.c \ + $(ARCH_DIR)/devices.c \ + $(SRC_DIR)/tools/test.c \ + $(SRC_DIR)/tools/parser.c +endif # --- OBJECT FILES --- -CORE_OBJS := $(CORE_SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) +VM_OBJS := $(VM_SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) PLATFORM_OBJ := $(PLATFORM_SOURCE:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) # --- DEPENDENCIES --- -DEPS := $(CORE_OBJS:.o=.d) $(PLATFORM_OBJ:.o=.d) +DEPS := $(VM_OBJS:.o=.d) $(PLATFORM_OBJ:.o=.d) .PHONY: all debug deploy clean clean-all help @@ -99,8 +104,23 @@ debug: $(TARGET) deploy: BUILD_MODE = deploy deploy: $(TARGET) +# --- COMPILE VM CORE (freestanding) --- +$(BUILD_DIR)/vm/%.o: $(SRC_DIR)/vm/%.c + @mkdir -p $(dir $@) + $(CC) $(CORE_CFLAGS) -MMD -MP -c $< -o $@ + +# --- COMPILE TOOLS (debug only, uses PLATFORM_CFLAGS) --- +$(BUILD_DIR)/tools/%.o: $(SRC_DIR)/tools/%.c + @mkdir -p $(dir $@) + $(CC) $(PLATFORM_CFLAGS) -MMD -MP -c $< -o $@ + +# --- COMPILE PLATFORM --- +$(BUILD_DIR)/arch/$(PLATFORM)/%.o: $(ARCH_DIR)/%.c + @mkdir -p $(dir $@) + $(CC) $(PLATFORM_CFLAGS) -MMD -MP -c $< -o $@ + # Main build rule -$(TARGET): $(CORE_OBJS) $(PLATFORM_OBJ) +$(TARGET): $(VM_OBJS) $(PLATFORM_OBJ) @mkdir -p $(dir $@) $(CC) $(PLATFORM_CFLAGS) $(LDFLAGS) -o $@ $^ @echo "Built: $@" @@ -108,16 +128,6 @@ $(TARGET): $(CORE_OBJS) $(PLATFORM_OBJ) echo "Open in browser: file://$(shell pwd)/$@"; \ fi -# --- COMPILE CORE (freestanding) --- -$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c - @mkdir -p $(dir $@) - $(CC) $(CORE_CFLAGS) -MMD -MP -c $< -o $@ - -# --- COMPILE PLATFORM --- -$(BUILD_DIR)/arch/$(PLATFORM)/%.o: $(ARCH_DIR)/%.c - @mkdir -p $(dir $@) - $(CC) $(PLATFORM_CFLAGS) -MMD -MP -c $< -o $@ - # --- AUTO-DEPENDENCIES --- -include $(DEPS) diff --git a/src/arch/linux/devices.h b/src/arch/linux/devices.h index 845e6c0..376324a 100644 --- a/src/arch/linux/devices.h +++ b/src/arch/linux/devices.h @@ -1,5 +1,5 @@ -#include "../../device.h" -#include "../../vm.h" +#include "../../vm/device.h" +#include "../../vm/vm.h" #include /* Screen device data */ diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index 97f87bf..c5dc305 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -1,5 +1,6 @@ -#include "../../test.h" -#include "../../vm.h" +#include "../../tools/test.h" +#include "../../tools/parser.h" +#include "../../vm/vm.h" #include "devices.h" #include @@ -12,19 +13,19 @@ static DeviceOps screen_ops = {.open = screen_open, .read = screen_read, .write = screen_write, .close = screen_close, - .ioctl = NULL}; + .ioctl = nil}; static DeviceOps mouse_ops = {.open = mouse_open, .read = mouse_read, .write = mouse_write, .close = mouse_close, - .ioctl = NULL}; + .ioctl = nil}; static DeviceOps keyboard_ops = {.open = keyboard_open, .read = keyboard_read, .write = keyboard_write, .close = keyboard_close, - .ioctl = NULL}; + .ioctl = nil}; static DeviceOps console_device_ops = { .open = console_open, @@ -62,6 +63,28 @@ void compileFile(const char *path, VM *vm) { } void repl(VM *vm) { + USED(vm); + + const char *source = "(fn main ()\n" + " (print (ftos (addf 1.0 2.0))))\n" + "\n" + "(device Terminal \"/dev/term/0\"\n" + " (write buffer size)\n" + " (read buffer size))"; + + printf("Parsing:\n%s\n\n", source); + + ExprNode *ast = expr_parse(source, strlen(source)); + if (!ast) { + printf("Parse failed.\n"); + exit(1); + } + + printf("AST:\n"); + expr_print(ast, 0); + + expr_free(ast); + char line[1024]; for (;;) { printf("> "); @@ -70,25 +93,26 @@ void repl(VM *vm) { printf("\n"); break; } - /* reset the code counter to 0 */ - vm->cp = 0; - vm->sp = 0; - vm->pc = 0; - vm->mp = 0; - /* assemble(line, vm); */ - while (step_vm(vm)) - ; + ExprNode *ast = expr_parse(source, strlen(line)); + if (!ast) { + printf("Parse failed.\n"); + continue; + } + + printf("AST:\n"); + expr_print(ast, 0); + + expr_free(ast); } exit(0); } enum FlagType { FLAG_NONE = 0, - FLAG_DEV_MODE = 1, - FLAG_TEST_MODE = 2, - FLAG_DUMP_ROM = 4, - FLAG_GUI_MODE = 8, + FLAG_TEST_MODE = 1, + FLAG_DUMP_ROM = 2, + FLAG_GUI_MODE = 4, }; #define MAX_INPUT_FILES 16 /* Adjust based on your system's constraints */ @@ -114,9 +138,7 @@ i32 parse_arguments(i32 argc, char *argv[], struct CompilerConfig *config) { for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { /* Long and short flag handling */ - if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--dev") == 0) { - config->flags |= FLAG_DEV_MODE; - } else if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gui") == 0) { + 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; diff --git a/src/gen/build.sh b/src/gen/build.sh index bdf5a10..b758b83 100644 --- a/src/gen/build.sh +++ b/src/gen/build.sh @@ -1,2 +1,2 @@ gcc math_gen.c -o math_gen -lm -./math_gen > ../math.h \ No newline at end of file +./math_gen > ./math.h \ No newline at end of file diff --git a/src/tools/parser.c b/src/tools/parser.c new file mode 100644 index 0000000..12508c8 --- /dev/null +++ b/src/tools/parser.c @@ -0,0 +1,194 @@ +#include "parser.h" +#include +#include +#include +#include + +// Helper function to allocate memory and handle errors +static void *safe_malloc(size_t size) { + void *ptr = malloc(size); + if (!ptr) { + fprintf(stderr, "Memory allocation failed\n"); + exit(1); + } + return ptr; +} + +// Helper function to create a new node +static ExprNode *expr_node_create(const char *token, int line) { + ExprNode *node = (ExprNode *)safe_malloc(sizeof(ExprNode)); + node->token = strdup(token ? token : ""); + node->children = NULL; + node->child_count = 0; + node->line = line; + return node; +} + +// Forward declaration +static ExprNode *parse_expression(const char **ptr, int line); + +// Skip whitespace characters +static const char *skip_whitespace(const char *ptr) { + while (*ptr && isspace(*ptr)) { + ptr++; + } + return ptr; +} + +// Parse a token (atom) +static char *parse_token(const char **ptr) { + const char *start = *ptr; + + // Skip leading whitespace + start = skip_whitespace(start); + if (!*start) return NULL; + + const char *end = start; + + // Handle parentheses specially + if (*end == '(' || *end == ')') { + end++; + } else { + // Read until whitespace or parentheses + while (*end && !isspace(*end) && *end != '(' && *end != ')') { + end++; + } + } + + if (end == start) return NULL; + + size_t len = end - start; + char *token = (char *)safe_malloc(len + 1); + memcpy(token, start, len); + token[len] = '\0'; + + *ptr = end; + return token; +} + +// Parse a list (expression starting with '(') +static ExprNode *parse_list(const char **ptr, int line) { + // Skip the opening parenthesis + (*ptr)++; + + // Parse the operator (first token) + *ptr = skip_whitespace(*ptr); + if (**ptr == ')') { + // Empty list + (*ptr)++; + return expr_node_create("nil", line); + } + + // Parse the operator/first element + char *op_token = parse_token(ptr); + if (!op_token) { + fprintf(stderr, "Error: Expected operator at line %d\n", line); + return NULL; + } + + ExprNode *node = expr_node_create(op_token, line); + free(op_token); + + // Parse children + while (**ptr && **ptr != ')') { + *ptr = skip_whitespace(*ptr); + if (**ptr == ')') break; + + ExprNode *child = parse_expression(ptr, line); + if (child) { + // Resize children array properly + ExprNode **new_children = (ExprNode **)safe_malloc(sizeof(ExprNode *) * (node->child_count + 1)); + + // Copy existing children + for (size_t i = 0; i < node->child_count; i++) { + new_children[i] = node->children[i]; + } + + // Add new child + new_children[node->child_count] = child; + + // Free old array and update + free(node->children); + node->children = new_children; + node->child_count++; + } + + *ptr = skip_whitespace(*ptr); + } + + if (**ptr == ')') { + (*ptr)++; // Skip closing parenthesis + } else { + fprintf(stderr, "Error: Missing closing parenthesis at line %d\n", line); + } + + return node; +} + +// Parse an expression (either atom or list) +static ExprNode *parse_expression(const char **ptr, int line) { + *ptr = skip_whitespace(*ptr); + + if (!**ptr) return NULL; + + if (**ptr == '(') { + return parse_list(ptr, line); + } else { + // Parse atom + char *token = parse_token(ptr); + if (token) { + ExprNode *node = expr_node_create(token, line); + free(token); + return node; + } + return NULL; + } +} + +// Main parsing function +ExprNode *expr_parse(const char *source, size_t source_len) { + if (!source || source_len == 0) return NULL; + + const char *ptr = source; + int line = 1; + + ptr = skip_whitespace(ptr); + if (!*ptr) return NULL; + + return parse_expression(&ptr, line); +} + +// Free an Expr AST (and all children) +void expr_free(ExprNode *node) { + if (!node) return; + + free(node->token); + + for (size_t i = 0; i < node->child_count; i++) { + expr_free(node->children[i]); + } + free(node->children); + free(node); +} + +// Debug: print AST (for dev) +void expr_print(ExprNode *node, int indent) { + if (!node) return; + + for (int i = 0; i < indent; i++) { + printf(" "); + } + + if (node->child_count == 0) { + // Atom + printf("Atom: '%s' (line %d)\n", node->token, node->line); + } else { + // List + printf("List: '%s' (line %d) [%zu children]\n", + node->token, node->line, node->child_count); + + for (size_t i = 0; i < node->child_count; i++) { + expr_print(node->children[i], indent + 1); + } + } +} \ No newline at end of file diff --git a/src/tools/parser.h b/src/tools/parser.h new file mode 100644 index 0000000..a58bd1c --- /dev/null +++ b/src/tools/parser.h @@ -0,0 +1,27 @@ +#ifndef PARSER_H +#define PARSER_H + +#include // for size_t + +// Forward declare +typedef struct ExprNode ExprNode; + +// Node type: atom or list +struct ExprNode { + char *token; // For atoms: the value ("123", "$0", "add") + // For lists: the operator (first token) + ExprNode **children; // Array of child nodes (NULL if atom) + size_t child_count; // 0 if atom + int line; // Source line number (for errors) +}; + +// Parse a string into an Expr AST +ExprNode *expr_parse(const char *source, size_t source_len); + +// Free an Expr AST (and all children) +void expr_free(ExprNode *node); + +// Debug: print AST (for dev) +void expr_print(ExprNode *node, int indent); + +#endif \ No newline at end of file diff --git a/src/test.c b/src/tools/test.c similarity index 93% rename from src/test.c rename to src/tools/test.c index cd312ca..05fcf81 100644 --- a/src/test.c +++ b/src/tools/test.c @@ -1,7 +1,7 @@ #include "test.h" -#include "opcodes.h" -#include "str.h" -#include "vm.h" +#include "../vm/opcodes.h" +#include "../vm/vm.h" +#include "string.h" #include u32 real_alloc(VM *vm, float v) { @@ -39,7 +39,7 @@ struct TestMapping internal_tests[] = { bool compile_internal_test(const char *filename, VM *vm) { i32 i; for (i = 0; internal_tests[i].filename != NULL; i++) { - if (streq(internal_tests[i].filename, filename)) { + if (strcmp(internal_tests[i].filename, filename) == 0) { return internal_tests[i].test_func(vm); } } diff --git a/src/test.h b/src/tools/test.h similarity index 95% rename from src/test.h rename to src/tools/test.h index 7cf5d2c..f3e33bf 100644 --- a/src/test.h +++ b/src/tools/test.h @@ -1,7 +1,7 @@ #ifndef ZRE_TEST_H #define ZRE_TEST_H -#include "opcodes.h" +#include "../vm/opcodes.h" #define AS_FIXED(v) ((float)(i32)(v) / 65536.0f) #define TO_FIXED(f) ((u32)((i32)( \ diff --git a/src/common.h b/src/vm/common.h similarity index 100% rename from src/common.h rename to src/vm/common.h diff --git a/src/device.c b/src/vm/device.c similarity index 100% rename from src/device.c rename to src/vm/device.c diff --git a/src/device.h b/src/vm/device.h similarity index 100% rename from src/device.h rename to src/vm/device.h diff --git a/src/opcodes.h b/src/vm/opcodes.h similarity index 100% rename from src/opcodes.h rename to src/vm/opcodes.h diff --git a/src/str.c b/src/vm/str.c similarity index 97% rename from src/str.c rename to src/vm/str.c index 19ed6d8..c0b805f 100644 --- a/src/str.c +++ b/src/vm/str.c @@ -25,7 +25,7 @@ bool streq(const char *s1, const char *s2) { } -u32 strlen(const char *str) { +u32 strlength(const char *str) { u32 i; if (str == nil) {return 0;} for (i = 0; str[i] != '\0'; i++) { @@ -34,7 +34,7 @@ u32 strlen(const char *str) { return i; } -u32 strnlen(const char *str, u32 max_len) { +u32 strnlength(const char *str, u32 max_len) { u32 i; if (str == nil) {return 0;} for (i = 0; i < max_len && str[i] != '\0'; i++) { diff --git a/src/str.h b/src/vm/str.h similarity index 67% rename from src/str.h rename to src/vm/str.h index 460abee..684756c 100644 --- a/src/str.h +++ b/src/vm/str.h @@ -3,10 +3,11 @@ #include "common.h" -i32 strcopy(char* to, const char *from, u32 length); -u32 strlen(const char* str); bool streq(const char *s1, const char *s2); -char *write_digits_backwards(u32 value, char *buf_end, char *buf_start); +i32 strcopy(char* to, const char *from, u32 length); +u32 strlength(const char *str); +u32 strnlength(const char *str, u32 max_len); +void uint_to_string(u32 value, char *buffer); void int_to_string(i32 value, char *buffer); void fixed_to_string(i32 value, char *buffer); diff --git a/src/vm.c b/src/vm/vm.c similarity index 98% rename from src/vm.c rename to src/vm/vm.c index 187b293..177d7bd 100644 --- a/src/vm.c +++ b/src/vm/vm.c @@ -434,7 +434,7 @@ bool step_vm(VM *vm) { src1 = read_u8(vm, code, vm->pc); vm->pc++; int_to_string(AS_INT(frame.registers[src1]), buffer); - ptr = str_alloc(vm, &frame, buffer, strlen(buffer)); + ptr = str_alloc(vm, &frame, buffer, strlength(buffer)); frame.registers[dest] = ptr; return true; } @@ -445,7 +445,7 @@ bool step_vm(VM *vm) { src1 = read_u8(vm, code, vm->pc); vm->pc++; uint_to_string(frame.registers[src1], buffer); - ptr = str_alloc(vm, &frame, buffer, strlen(buffer)); + ptr = str_alloc(vm, &frame, buffer, strlength(buffer)); frame.registers[dest] = ptr; return true; } @@ -457,7 +457,7 @@ bool step_vm(VM *vm) { vm->pc++; fixed_to_string(AS_INT(frame.registers[src1]), buffer); ptr = - str_alloc(vm, &frame, buffer, strlen(buffer)); /* copy buffer to dest */ + str_alloc(vm, &frame, buffer, strlength(buffer)); /* copy buffer to dest */ frame.registers[dest] = ptr; return true; } diff --git a/src/vm.h b/src/vm/vm.h similarity index 100% rename from src/vm.h rename to src/vm/vm.h