#include #include #include "common.h" typedef struct var { char *name; intptr_t v; } var; #define VEC_NAME vars #define VEC_TYPE var #include 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 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)