From f0be8a1bd5bdd3b76862a8de50d2b2805d378de2 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Sun, 3 Aug 2025 01:03:39 +0200 Subject: [PATCH] More progress on the assembler --- Makefile | 2 +- src/assemble.c | 155 +++++++++++++++++++++++++++++++++++++++++-------- src/assemble.h | 3 +- src/basic.h | 3 + src/file.c | 2 +- src/main.c | 4 +- src/parse.c | 2 +- 7 files changed, 140 insertions(+), 31 deletions(-) diff --git a/Makefile b/Makefile index 79501fb..8e6b94a 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,2 @@ all: - gcc src/basic.c src/file.c src/parse.c src/main.c -o wl -Wall -Wextra -O0 -g3 \ No newline at end of file + gcc src/basic.c src/file.c src/parse.c src/assemble.c src/main.c -o wl -Wall -Wextra -O0 -g3 \ No newline at end of file diff --git a/src/assemble.c b/src/assemble.c index 51c2f2f..f034ab7 100644 --- a/src/assemble.c +++ b/src/assemble.c @@ -1,3 +1,8 @@ +#include +#include +#include +#include + #include "parse.h" #include "assemble.h" @@ -54,15 +59,42 @@ typedef struct { int strings_cap; char *strings; + char *errbuf; + int errmax; + int errlen; + } Assembler; +void assembler_report(Assembler *a, char *fmt, ...) +{ + if (a->errmax == 0 || a->errlen > 0) + return; + + int len = snprintf(a->errbuf, a->errmax, "Error: "); + if (len < 0) { + // TODO + } + + va_list args; + va_start(args, fmt); + int ret = vsnprintf(a->errbuf + len, a->errmax - len, fmt, args); + va_end(args); + if (ret < 0) { + // TODO + } + len += ret; + + a->errlen = len; +} + int add_string_literal(Assembler *a, String str) { if (a->strings_cap - a->strings_len < str.len) { int c = MAX(2 * a->strings_cap, a->strings_len + str.len); char *p = malloc(c); if (p == NULL) { - // TODO + assembler_report(a, "Out of memory"); + return -1; } if (a->strings_cap) { memcpy(p, a->strings, a->strings_len); @@ -129,6 +161,13 @@ int append_u32(OutputBuffer *out, uint32_t x) return off; } +int append_u64(OutputBuffer *out, uint64_t x) +{ + int off = out->len; + append_mem(out, &x, (int) sizeof(x)); + return off; +} + int append_f64(OutputBuffer *out, double x) { int off = out->len; @@ -142,6 +181,11 @@ void patch_with_current_offset(OutputBuffer *out, int off) patch_mem(out, off, &x, (int) sizeof(x)); } +int current_offset(OutputBuffer *out) +{ + return out->len; +} + int count_nodes(Node *head) { int n = 0; @@ -153,16 +197,36 @@ int count_nodes(Node *head) return n; } -int declare_var(Assembler *a, String name) +int find_variable(Assembler *a, String name) { - if (a->num_vars == MAX_VARS) - return -1; - // TODO: check if the variable exists already - int idx = a->num_vars++; - a->vars[idx] = (Variable) { name }; - return idx - a->scopes[a->num_scopes-1].var_base; + Scope *scope = &a->scopes[a->num_scopes-1]; + for (int i = scope->var_base; i < a->num_vars; i++) + if (streq(name, a->vars[i].name)) + return i; + assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr); + return -1; } +int declare_var(Assembler *a, String name) +{ + if (a->num_vars == MAX_VARS) { + assembler_report(a, "Variable limit reached"); + return -1; + } + + Scope *scope = &a->scopes[a->num_scopes-1]; + for (int i = scope->var_base; i < a->num_vars; i++) + if (streq(name, a->vars[i].name)) { + assembler_report(a, "Variable '%.*s' declared twice", name.len, name.ptr); + return -1; + } + + int idx = a->num_vars++; + a->vars[idx] = (Variable) { name }; + return idx - scope->var_base; +} + +/* void assemble_html_node_inner(Assembler *a, Node *node, OutputBuffer *tmp) { append_u8(tmp, '<'); @@ -197,6 +261,41 @@ void assemble_html_node(Assembler *a, Node *node) OutputBuffer tmp; assemble_html_node_inner(a, node, &tmp); } +*/ + +b32 is_expr(Node *node) +{ + switch (node->type) { + + default: + break; + + case NODE_SELECT: + case NODE_FUNC_CALL: + case NODE_OPER_POS: + case NODE_OPER_NEG: + case NODE_OPER_ASS: + case NODE_OPER_EQL: + case NODE_OPER_NQL: + case NODE_OPER_LSS: + case NODE_OPER_GRT: + case NODE_OPER_ADD: + case NODE_OPER_SUB: + case NODE_OPER_MUL: + case NODE_OPER_DIV: + case NODE_OPER_MOD: + case NODE_VALUE_INT: + case NODE_VALUE_FLOAT: + case NODE_VALUE_STR: + case NODE_VALUE_VAR: + case NODE_VALUE_HTML: + case NODE_VALUE_ARRAY: + case NODE_VALUE_MAP: + return true; + } + + return false; +} void assemble_node(Assembler *a, Node *node) { @@ -213,14 +312,15 @@ void assemble_node(Assembler *a, Node *node) Node *args[32]; if (arg_count > COUNT(args)) { - // TODO + assembler_report(a, "Argument limit reached"); + return; } for (int i = arg_count-1; i >= 0; i--) { + int idx = declare_var(a, args[i]->sval); - if (idx < 0) { - // TODO - } + if (idx < 0) return; + append_u8(&a->out, OPCODE_SETV); append_u8(&a->out, idx); } @@ -256,7 +356,8 @@ void assemble_node(Assembler *a, Node *node) FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall)); if (call == NULL) { - // TODO + assembler_report(a, "Out of memory"); + return; } call->name = func->sval; call->off = p; @@ -278,9 +379,7 @@ void assemble_node(Assembler *a, Node *node) case NODE_VAR_DECL: { int idx = declare_var(a, node->var_name); - if (idx < 0) { - // TODO - } + if (idx < 0) return; if (node->var_value) { assemble_node(a, node->var_value); @@ -375,7 +474,7 @@ void assemble_node(Assembler *a, Node *node) assemble_node(a, node->left); append_u8(&a->out, OPCODE_JUMP); - opcode_u32(&a->out, start); + append_u32(&a->out, start); patch_with_current_offset(&a->out, p); } @@ -476,7 +575,8 @@ void assemble_node(Assembler *a, Node *node) break; case NODE_VALUE_HTML: - assemble_html_node(a, node); + // TODO + //assemble_html_node(a, node); break; case NODE_VALUE_ARRAY: @@ -526,10 +626,8 @@ void assemble_node(Assembler *a, Node *node) if (dst->type == NODE_VALUE_VAR) { - int idx = find_variable(dst->sval); - if (idx < 0) { - // TODO - } + int idx = find_variable(a, dst->sval); + if (idx < 0) return; assemble_node(a, src); append_u8(&a->out, OPCODE_SETV); @@ -544,18 +642,25 @@ void assemble_node(Assembler *a, Node *node) } else { - // TODO ERROR + assembler_report(a, "Assignment left side can't be assigned to"); + return; } } break; + + default: + break; } } -AssembleResult assemble(Node *root) +AssembleResult assemble(Node *root, char *errbuf, int errmax) { - Assembler a = {0}; + Assembler a = {0, .errbuf=errbuf, .errmax=errmax, .errlen=0}; assemble_node(&a, root); append_u8(&a.out, OPCODE_NOPE); + Program p; // TODO + + return (AssembleResult) { p, a.errlen }; } diff --git a/src/assemble.h b/src/assemble.h index 452cebc..04b7551 100644 --- a/src/assemble.h +++ b/src/assemble.h @@ -41,8 +41,9 @@ typedef struct { typedef struct { Program program; + int errlen; } AssembleResult; -AssembleResult assemble(Node *root); +AssembleResult assemble(Node *root, char *errbuf, int errmax); #endif // WL_ASSEMBLE_INCLUDED \ No newline at end of file diff --git a/src/basic.h b/src/basic.h index 7601c7d..1c88178 100644 --- a/src/basic.h +++ b/src/basic.h @@ -25,6 +25,9 @@ typedef struct { #define S(X) (String) { (X), (int) sizeof(X)-1 } #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) + +#define COUNT(X) (int) (sizeof(X) / sizeof((X)[0])) b32 is_space(char c); b32 is_digit(char c); diff --git a/src/file.c b/src/file.c index 3aa5400..9901fe5 100644 --- a/src/file.c +++ b/src/file.c @@ -14,7 +14,7 @@ int file_open(String path, File *handle, int *size) { char zt[1<<10]; - if (path.len >= (int) sizeof(zt)) + if (path.len >= COUNT(zt)) return -1; memcpy(zt, path.ptr, path.len); zt[path.len] = '\0'; diff --git a/src/main.c b/src/main.c index e5f9877..43a40c3 100644 --- a/src/main.c +++ b/src/main.c @@ -15,9 +15,9 @@ int main(void) char err[1<<9]; char mem[1<<14]; - Arena a = { mem, (int) sizeof(mem), 0 }; + Arena a = { mem, COUNT(mem), 0 }; - ParseResult result = parse(src, &a, err, (int) sizeof(err)); + ParseResult result = parse(src, &a, err, COUNT(err)); if (result.node == NULL) { printf("%.*s\n", result.errlen, err); return -1; diff --git a/src/parse.c b/src/parse.c index a103127..15c1509 100644 --- a/src/parse.c +++ b/src/parse.c @@ -837,7 +837,7 @@ Node *parse_atom(Parser *p) default: { char buf[1<<8]; - String str = tok2str(t, buf, (int) sizeof(buf)); + String str = tok2str(t, buf, COUNT(buf)); report(p, "Invalid token \'%.*s\' inside expression", str.len, str.ptr); } return NULL;