diff options
Diffstat (limited to 'storage.c')
| -rw-r--r-- | storage.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/storage.c b/storage.c new file mode 100644 index 0000000..4b49fc2 --- /dev/null +++ b/storage.c @@ -0,0 +1,201 @@ +#include "storage.h" +#include "errloc.h" +#include "fn.h" +#include "lex.h" +#include "prv.h" +#include "type.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +static int vab(const struct lex *l, struct prv *p); +static int vac(const struct lex *l, struct prv *p); +static int vb(const struct lex *l, struct prv *p); +static int vc(const struct lex *l, struct prv *p); + +#define VAB(x) \ + {(const struct step[]){{ID}, {ID, "array"}, {ID, x}, {NUM}, {0}}, .fn = vab} + +#define VB(x) {(const struct step[]){{ID}, {ID, x}, {0}}, .fn = vb} + +static const struct seq seqs[] = +{ + /* array with built-in type */ + VAB("void"), + VAB("byte"), + VAB("halfword"), + VAB("word"), + VAB("long"), + VAB("ubyte"), + VAB("uhalfword"), + VAB("uword"), + VAB("ulong"), + + /* array with custom type */ + {(const struct step[]){{ID}, {ID, "array"}, {ID}, {0}}, .fn = vac}, + + /* var with built-in type */ + VB("void"), + VB("byte"), + VB("halfword"), + VB("word"), + VB("long"), + VB("ubyte"), + VB("uhalfword"), + VB("uword"), + VB("ulong"), + + /* var with custom type */ + {(const struct step[]){{ID}, {ID}, {0}}, .fn = vc}, + {0} +}; + +static int stpush(const struct lex *l, struct prv *p, const struct tk *tk, + const struct tk *type) +{ + const struct ast *ast = p->ast; + struct pos *pos = &p->pos[p->i]; + struct stentry *entries; + struct storage *st = p->st; + size_t n = st->nentries + 1; + const struct type *t = type_find(&ast->fns[ast->nfns - 1], type->s); + const struct loc *loc = &tk->loc; + + if (!t) + { + errloc(type, "undefined reference to type \"%s\"", type->s); + return -1; + } + else if (!t->sz) + { + errloc(type, "type \"%s\" has null size", type->s); + return -1; + } + else if (!(entries = realloc(st->entries, n * sizeof *entries))) + { + perror("realloc(3)"); + return -1; + } + + /* todo: type*/ + entries[st->nentries++] = (struct stentry){.t = t, .tk = tk}; + st->entries = entries; + p->stk = p->tk; + pos->seq = seqs; + pos->step = seqs->steps; + fprintf(stderr, "\tadding %s (%d:%d) to %s, type %s\n", tk->s, + loc->line, loc->col, st->name, type->s); + return 1; +} + +static int vb(const struct lex *l, struct prv *p) +{ + const struct tk *name = p->stk, *type = p->tk - 1; + const struct fn *fn = fn_cur(p); + const struct storage *st = p->st; + const struct stentry *e; + + if (st->check && (e = fn_var(fn, name))) + { + const struct loc *loc = &e->tk->loc; + + errloc(name, "variable \"%s\" already defined at %s:%d:%d", + name->s, loc->f, loc->line, loc->col); + return -1; + } + + /* find var in currently known symbols */ + for (size_t i = 0; i < st->nentries; i++) + { + const struct stentry *e = &st->entries[i]; + const struct tk *tk = e->tk; + + if (!strcmp(tk->s, name->s)) + { + const struct loc *loc = &tk->loc; + + errloc(name, "variable \"%s\" already defined at %s:%d:%d", + name->s, loc->f, loc->line, loc->col); + return -1; + } + } + + return stpush(l, p, name, type); +} + +static int vc(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} + +static int vab(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} + +static int vac(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} + +void storage_free(struct storage *s) +{ + if (s) + free(s->entries); + + free(s); +} + +const struct stentry *storage_find(const char *name, const struct storage *s) +{ + for (size_t i = 0; i < s->nentries; i++) + { + const struct stentry *e = &s->entries[i]; + + if (!strcmp(name, e->tk->s)) + return e; + } + + return NULL; +} + +int storage(const struct lex *l, struct prv *p, const char *name, int check, + struct storage **out) +{ + struct storage *st = NULL; + const struct tk *tk = p->tk - 1; + struct pos init = + { + .seq = seqs, + .stseq = seqs, + .step = seqs->steps + }; + + if (*out) + { + const struct loc *loc = &(*out)->tk->loc; + + errloc(tk, "%s already defined at %s:%d:%d", name, loc->f, loc->line, + loc->col); + goto failure; + } + else if (!(st = malloc(sizeof *st))) + { + perror("malloc(3)"); + goto failure; + } + else if (push(&init, p)) + goto failure; + + *st = (struct storage){.name = name, .tk = tk, .check = check}; + *out = p->st = st; + p->stk = p->tk; + return 1; + +failure: + free(st); + return -1; +} |
