diff options
Diffstat (limited to 'fptr_ast/fptr.c')
-rw-r--r-- | fptr_ast/fptr.c | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/fptr_ast/fptr.c b/fptr_ast/fptr.c new file mode 100644 index 0000000..7959735 --- /dev/null +++ b/fptr_ast/fptr.c @@ -0,0 +1,387 @@ +#include <stdarg.h> +#include <stdint.h> + +#include "common.h" + +typedef struct var { + char *name; + intptr_t v; +} var; + +#define VEC_NAME vars +#define VEC_TYPE var +#include <conts/vec.h> +typedef struct vars vars; + +typedef struct proc { + vars vars; +} proc; + +static proc *gen_proc(int header, ...) +{ + (void)header; + + proc *proc = calloc(1, sizeof(struct proc)); + if (!proc) + return NULL; + + proc->vars = vars_create(0); + + va_list args; + va_start(args, header); + while (1) { + char *name = va_arg(args, char *); + + /* NULL sentinel */ + if (!name) + break; + + var var = { + .name = name, + .v = 0 + }; + vars_append(&proc->vars, var); + } + va_end(args); + + return proc; +} + +#define gen_proc(...) gen_proc(0, __VA_ARGS__, NULL) + +static void proc_set(proc *proc, char *name, intptr_t v) +{ + foreach(vars, var, &proc->vars) { + if (strcmp(var->name, name) != 0) + continue; + + var->v = v; + return; + } + + /* abort? */ +} + +typedef struct node node; + +typedef intptr_t (*node_run_t)(struct node *); + +typedef struct node { + node_run_t run; +} node; + +static intptr_t run(node *n) +{ + assert(n); + return n->run(n); +} + +typedef struct load { + node node; + node *addr; +} load; + +static intptr_t run_load(load *l) +{ + return *(intptr_t *)run(l->addr); +} + +static node *gen_load(node *addr) +{ + load *l = calloc(1, sizeof(load)); + if (!l) + return NULL; + + l->node.run = (node_run_t)run_load; + l->addr = addr; + return &l->node; +} + +typedef struct store { + node node; + node *addr; + node *val; +} store; + +static intptr_t run_store(store *s) +{ + intptr_t *dst = (intptr_t *)run(s->addr); + intptr_t val = run(s->val); + *dst = val; + return 0; +} + +static node *gen_store(node *addr, node *val) +{ + store *s = calloc(1, sizeof(store)); + if (!s) + return NULL; + + s->node.run = (node_run_t)run_store; + s->addr = addr; + s->val = val; + return &s->node; +} + +typedef struct add { + node node; + node *l; + node *r; +} add; + +static intptr_t run_add(add *a) +{ + intptr_t l = run(a->l); + intptr_t r = run(a->r); + return l + r; +} + +static node *gen_add(node *l, node *r) +{ + add *a = calloc(1, sizeof(add)); + if (!a) + return NULL; + + a->node.run = (node_run_t)run_add; + a->l = l; + a->r = r; + return &a->node; +} + +typedef struct mul { + node node; + node *l; + node *r; +} mul; + +static intptr_t run_mul(mul *m) +{ + intptr_t l = run(m->l); + intptr_t r = run(m->r); + return l * r; +} + +static node *gen_mul(node *l, node *r) +{ + mul *m = calloc(1, sizeof(mul)); + if (!m) + return NULL; + + m->node.run = (node_run_t)run_mul; + m->l = l; + m->r = r; + return &m->node; +} + +typedef struct var_n { + node node; + intptr_t *varref; +} var_n; + +static intptr_t run_var(var_n *v) +{ + return *v->varref; +} + +static node *gen_var(proc *proc, char *name) +{ + assert(proc && name); + + var_n *v = calloc(1, sizeof(var_n)); + if (!v) + return NULL; + + v->node.run = (node_run_t)run_var; + foreach(vars, var, &proc->vars) { + if (strcmp(var->name, name) != 0) + continue; + + v->varref = &var->v; + return &v->node; + } + + free(v); + return NULL; +} + +typedef struct varref { + node node; + intptr_t *varref; +} varref; + +static intptr_t run_varref(varref *v) +{ + return (intptr_t)v->varref; +} + +static node *gen_varref(proc *proc, char *name) +{ + assert(proc && name); + + /* technically speaking we could use the same trick here as in struct.c + * since var and varref are the same shape, but feels a bit dirty. */ + + varref *v = calloc(1, sizeof(varref)); + if (!v) + return NULL; + + v->node.run = (node_run_t)run_varref; + foreach(vars, var, &proc->vars) { + if (strcmp(var->name, name) != 0) + continue; + + v->varref = &var->v; + return &v->node; + } + + free(v); + return NULL; +} + +typedef struct const_n { + node node; + intptr_t v; +} const_n; + +static intptr_t run_const_n(const_n *c) +{ + return c->v; +} + +static node *gen_const(intptr_t v) +{ + const_n *c = calloc(1, sizeof(const_n)); + if (!c) + return NULL; + + c->node.run = (node_run_t)run_const_n; + c->v = v; + return &c->node; +} + +typedef struct assign { + node node; + node *dst; + node *src; +} assign; + +static intptr_t run_assign(assign *a) +{ + intptr_t *dst = (intptr_t *)run(a->dst); + intptr_t src = run(a->src); + *dst = src; + return 0; +} + +static node *gen_assign(node *dst, node *src) +{ + assign *a = calloc(1, sizeof(assign)); + if (!a) + return NULL; + + a->node.run = (node_run_t)run_assign; + a->dst = dst; + a->src = src; + return &a->node; +} + +typedef struct for_n { + node node; + node *init; + node *cond; + node *post; + node *body; +} for_n; + +static intptr_t run_for(for_n *f) +{ + for (run(f->init); run(f->cond); run(f->post)) + run(f->body); + + return 0; +} + +static node *gen_for(node *init, node *cond, node *post, node *body) +{ + for_n *f = calloc(1, sizeof(for_n)); + if (!f) + return NULL; + + f->node.run = (node_run_t)run_for; + f->init = init; + f->cond = cond; + f->post = post; + f->body = body; + return &f->node; +} + +typedef struct lt { + node node; + node *l; + node *r; +} lt; + +static intptr_t run_lt(lt *c) +{ + intptr_t l = run(c->l); + intptr_t r = run(c->r); + return l < r; +} + +static node *gen_lt(node *l, node *r) +{ + lt *c = calloc(1, sizeof(lt)); + if (!c) + return NULL; + + c->node.run = (node_run_t)run_lt; + c->l = l; + c->r = r; + return &c->node; +} + +#define VEC_NAME nodes +#define VEC_TYPE node * +#include <conts/vec.h> +typedef struct nodes nodes; + +typedef struct body { + node node; + nodes list; +} body; + +static intptr_t run_body(body *b) +{ + foreach(nodes, node, &b->list) { + run(*node); + } + + return 0; +} + +static node *gen_body(int header, ...) +{ + (void)header; + body *b = calloc(1, sizeof(body)); + if (!b) + return NULL; + + b->node.run = (node_run_t)run_body; + b->list = nodes_create(0); + + va_list args; + va_start(args, header); + while (1) { + node *n = va_arg(args, node *); + if (!n) + break; + + nodes_append(&b->list, n); + } + + va_end(args); + + return &b->node; +} + +#define gen_body(...) gen_body(0, __VA_ARGS__, NULL) |