diff options
| author | David Moc <personal@cdatgoose.org> | 2026-03-05 23:38:49 +0100 |
|---|---|---|
| committer | David Moc <personal@cdatgoose.org> | 2026-03-05 23:38:49 +0100 |
| commit | 0385817bb1301a778bb33f8405a435293b9f8905 (patch) | |
| tree | 53f4b6f13e393bd368c37ba4363826b46940dfd3 /src/ast.h | |
| parent | 262abf9b552a168ef3ae91f91af97683f16420a7 (diff) | |
Pushing to repo for safety.
Diffstat (limited to 'src/ast.h')
| -rw-r--r-- | src/ast.h | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/src/ast.h b/src/ast.h new file mode 100644 index 0000000..6c326cc --- /dev/null +++ b/src/ast.h @@ -0,0 +1,410 @@ +#ifndef INCLUDE_ast +#define INCLUDE_ast + +#include "token.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + + +typedef enum { EX_NUMBER, EX_VAR, EX_BINOP, EX_CALL, EX_ADDR, EX_DEREF, EX_STRING, EX_INDEX } _EK; + +typedef struct _EX { + _EK kind; + union { + int value; // for number + char *name; // for var + struct { + struct _EX *l; + _TK op; + struct _EX *r; + } binop; + struct { + char *func_name; + struct _EX **args; + int argc; + } call; + struct { + struct _EX *expr; // &expr + } addr; + struct { + struct _EX *expr; // *expr + } deref; + char *string; // for string literal + struct { + struct _EX *array; // array expression + struct _EX *index; // index expression + } index; + }; +} _EX; + + +typedef enum { STK_RETURN, STK_VAR_DECL, STK_ASSIGN, STK_EXPR, STK_BLOCK, STK_IF, STK_WHILE, STK_FOR } _STK; + +typedef struct _STN { + _STK kind; + union { + struct { + char *name; + _EX *init; + _TY type; + } var_decl; + struct { + _EX *lhs; // var or *expr + _EX *expr; + } assign; + _EX *expr; // STK_EXPR + _EX *return_expr; // STK_RETURN + struct _STN *body; // STK_BLOCK + struct { // STK_IF + _EX *cond; + struct _STN *thenb; + struct _STN *elseb; // may be NULL + } ifs; + struct { // STK_WHILE + _EX *cond; + struct _STN *body; + } whl; + struct { // STK_FOR + struct _STN *init; // may be NULL (a stmt like decl/assign) + _EX *cond; // may be NULL + struct _STN *step; // may be NULL (an expr stmt) + struct _STN *body; + } fr; + }; + struct _STN *n; // linked list +} _STN; + + + +typedef struct _FN { + char *name; + char **params; + _TY *param_types; + int pac; + _STN *body; + struct _FN *n; +} _FN; + +typedef struct NameEntry { + char *name; + struct NameEntry *next; +} NameEntry; + +#define HASH_SIZE 128 + +static unsigned long hash_str(const char *s) { + unsigned long h = 5381; + int c; + while ((c = *s++)) + h = ((h << 5) + h) + (unsigned long)c; + return h; +} + +static int name_seen(NameEntry **table, const char *name) { + unsigned long h = hash_str(name) % HASH_SIZE; + for (NameEntry *e = table[h]; e; e = e->next) { + if (strcmp(e->name, name) == 0) + return 1; + } + NameEntry *ne = malloc(sizeof(*ne)); + if (!ne) { + fprintf(stderr, "Error: malloc failed\n"); + exit(1); + } + ne->name = strdup(name); + ne->next = table[h]; + table[h] = ne; + return 0; +} + +static void free_hash_table(NameEntry **table) { + for (int i = 0; i < HASH_SIZE; i++) { + NameEntry *e = table[i]; + while (e) { + NameEntry *next = e->next; + free(e->name); + free(e); + e = next; + } + table[i] = NULL; + } +} + +_FN *fnlist_prepare(_FN *head) { + if (!head) return NULL; + + NameEntry *table[HASH_SIZE] = {0}; + + _FN *main_node = NULL; + _FN *main_prev = NULL; + _FN *prev = NULL; + + for (_FN *cur = head; cur; cur = cur->n) { + if (!cur->name) { + fprintf(stderr, "[fnlist prepare] error: function with NULL name\n"); + free_hash_table(table); + exit(1); + } + + if (name_seen(table, cur->name)) { + fprintf(stderr, "[fnlist prepare] error: duplicate function name '%s'\n", cur->name); + free_hash_table(table); + exit(1); + } + + if (strcmp(cur->name, "main") == 0) { + if (main_node) { + fprintf(stderr, "[fnlist prepare] error: multiple 'main' functions found\n"); + free_hash_table(table); + exit(1); + } + main_node = cur; + main_prev = prev; + } + + prev = cur; + } + + free_hash_table(table); + + if (!main_node) return head; + if (!main_prev) return head; + + main_prev->n = main_node->n; + main_node->n = head; + return main_node; +} + + + + + +/* Generic alloc macros */ +#define NEW_EX(k) \ + _EX *e = (_EX *)calloc(1, sizeof(_EX)); \ + e->kind = k +#define NEW_ST(k) \ + _STN *s = (_STN *)calloc(1, sizeof(_STN)); \ + s->kind = k +#define NEW_FN() _FN *f = (_FN *)calloc(1, sizeof(_FN)) + +/* Constructor declaration macros */ +#define DEFINE_EX_CONSTRUCTOR(name, kind, ...) \ + static inline _EX *ex_##name(__VA_ARGS__) + +#define DEFINE_ST_CONSTRUCTOR(name, kind, ...) \ + static inline _STN *st_##name(__VA_ARGS__) + +#define DEFINE_FN_CONSTRUCTOR(name, ...) \ + static inline _FN *fn_##name(__VA_ARGS__) + + + +DEFINE_EX_CONSTRUCTOR(number, EX_NUMBER, int value) { + NEW_EX(EX_NUMBER); + e->value = value; + return e; +} + +DEFINE_EX_CONSTRUCTOR(var, EX_VAR, char *name) { + NEW_EX(EX_VAR); + e->name = name; + return e; +} + +DEFINE_EX_CONSTRUCTOR(binop, EX_BINOP, _EX *l, _TK op, _EX *r) { + NEW_EX(EX_BINOP); + e->binop.l = l; + e->binop.r = r; + e->binop.op = op; + return e; +} + +DEFINE_EX_CONSTRUCTOR(call, EX_CALL, char *func_name, _EX **args, int argc) { + NEW_EX(EX_CALL); + e->call.func_name = func_name; + e->call.args = args; + e->call.argc = argc; + return e; +} + +DEFINE_EX_CONSTRUCTOR(string, EX_STRING, char *str) { + NEW_EX(EX_STRING); + e->string = str; + return e; +} + +DEFINE_EX_CONSTRUCTOR(index, EX_INDEX, _EX *array, _EX *idx) { + NEW_EX(EX_INDEX); + e->index.array = array; + e->index.index = idx; + return e; +} + + +DEFINE_ST_CONSTRUCTOR(return, STK_RETURN, _EX *expr) { + NEW_ST(STK_RETURN); + s->return_expr = expr; + return s; +} + +DEFINE_ST_CONSTRUCTOR(var_decl, STK_VAR_DECL, char *name, _EX *init) { + NEW_ST(STK_VAR_DECL); + s->var_decl.name = name; + s->var_decl.init = init; + return s; +} + +DEFINE_ST_CONSTRUCTOR(assign, STK_ASSIGN, _EX *lhs, _EX *expr) { + NEW_ST(STK_ASSIGN); + s->assign.lhs = lhs; + s->assign.expr = expr; + return s; +} + +DEFINE_ST_CONSTRUCTOR(expr, STK_EXPR, _EX *expr) { + NEW_ST(STK_EXPR); + s->expr = expr; + return s; +} + +DEFINE_ST_CONSTRUCTOR(block, STK_BLOCK, _STN *body) { + NEW_ST(STK_BLOCK); + s->body = body; + return s; +} + +DEFINE_ST_CONSTRUCTOR(if, STK_IF, _EX *cond, _STN *thenb, _STN *elseb) { + NEW_ST(STK_IF); + s->ifs.cond = cond; + s->ifs.thenb = thenb; + s->ifs.elseb = elseb; + return s; +} + +DEFINE_ST_CONSTRUCTOR(while, STK_WHILE, _EX *cond, _STN *body) { + NEW_ST(STK_WHILE); + s->whl.cond = cond; + s->whl.body = body; + return s; +} + +DEFINE_ST_CONSTRUCTOR(for, STK_FOR, _STN *init, _EX *cond, _STN *step, _STN *body) { + NEW_ST(STK_FOR); + s->fr.init = init; + s->fr.cond = cond; + s->fr.step = step; + s->fr.body = body; + return s; +} + + + +DEFINE_FN_CONSTRUCTOR(new, char *name, char **params, _TY* params_types, int pac, _STN *body) { + NEW_FN(); + f->name = name; + f->params = params; + f->param_types = params_types; + f->pac = pac; + f->body = body; + return f; +} + + +static inline void ex_free(_EX *e) { + if (!e) + return; + switch (e->kind) { + case EX_NUMBER: + break; + case EX_VAR: + free(e->name); + break; + case EX_BINOP: + ex_free(e->binop.l); + ex_free(e->binop.r); + break; + case EX_CALL: + for (int i = 0; i < e->call.argc; i++) + ex_free(e->call.args[i]); + free(e->call.args); + free(e->call.func_name); + break; + case EX_ADDR: + ex_free(e->addr.expr); + break; + case EX_DEREF: + ex_free(e->deref.expr); + break; + case EX_STRING: + free(e->string); + break; + case EX_INDEX: + ex_free(e->index.array); + ex_free(e->index.index); + break; + } + free(e); +} + +static inline void st_free(_STN *s) { + if (!s) + return; + switch (s->kind) { + case STK_RETURN: + ex_free(s->return_expr); + break; + case STK_VAR_DECL: + ex_free(s->var_decl.init); + free(s->var_decl.name); + break; + case STK_ASSIGN: + ex_free(s->assign.expr); + break; + case STK_EXPR: + ex_free(s->expr); + break; + case STK_BLOCK: + st_free(s->body); + break; + case STK_IF: + ex_free(s->ifs.cond); + st_free(s->ifs.thenb); + st_free(s->ifs.elseb); + break; + case STK_WHILE: + ex_free(s->whl.cond); + st_free(s->whl.body); + break; + case STK_FOR: + st_free(s->fr.init); + ex_free(s->fr.cond); + st_free(s->fr.step); + st_free(s->fr.body); + break; + } + _STN *next = s->n; + free(s); + st_free(next); +} + +static inline void fn_free(_FN *f) { + while (f) { + _FN *next = f->n; + if (f->name) + free(f->name); + if (f->params) { + for (int i = 0; i < f->pac; i++) { + free(f->params[i]); + } + free(f->params); + } + free(f->param_types); + st_free(f->body); + free(f); + f = next; + } +} + +#endif |
