#include "storage.h" #include "errloc.h" #include "fn.h" #include "lex.h" #include "prv.h" #include "type.h" #include #include #include static int id(const struct lex *l, struct prv *p); static const struct seq seqs[] = { {(struct step[]){{ID}, {0}}, .fn = id}, {0} }; static int compat(const struct fn *fn, const struct prv *p, const struct tk *name, const struct type *t, const struct type **ot) { const struct stentry *oe; const struct fn *top = fn_cur(p); /* allow global entries if already found on linkage section * and vice versa, as long as the types are compatible. */ if (p->st == top->gl) { for (size_t i = 0; i < fn->nimps; i++) { const struct im *im = &fn->imps[i]; if (compat(im->ast.fns, p, name, t, ot)) return 1; } if (fn->lk && (oe = storage_find(name->s, fn->lk))) { if (t == oe->t) return 1; *ot = oe->t; return -1; } } else if (p->st == top->lk) { if (fn->gl && (oe = storage_find(name->s, fn->gl))) { if (t == oe->t) return 1; *ot = oe->t; return -1; } } return 0; } static int stpush(const struct lex *l, struct prv *p, const struct tk *name, const struct type *t) { int ret = -1; struct stentry *entries; struct storage *st = p->st; size_t n = st->nentries + 1; const struct fn *fn = fn_cur(p); const struct loc *loc = &name->loc; const struct stentry *e; char *tname = type_name(t); if (!t->sz && p->st != fn->lk) { errloc(name + 1, "type \"%s\" has null size", tname); goto end; } else if (st->check && (e = fn_var(fn, name))) { const struct loc *loc = &e->tk->loc; const struct type *ot; int ret = compat(fn, p, name, t, &ot); if (ret < 0) { errloc(name, "variable \"%s\" (\"%s\") already defined at " "%s:%d:%d with incompatible type (\"%s\")", name->s, type_name(t), loc->f, loc->line, loc->col, type_name(ot)); goto end; } else if (!ret) { errloc(name, "variable \"%s\" already defined at %s:%d:%d", name->s, loc->f, loc->line, loc->col); goto end; } } /* 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(name->s, tk->s)) { const struct loc *loc = &tk->loc; errloc(tk, "variable \"%s\" already defined at %s:%d:%d", tk->s, loc->f, loc->line, loc->col); goto end; } } if (pop(l, p)) goto end; else if (!(entries = realloc(st->entries, n * sizeof *entries))) { perror("realloc(3)"); goto end; } if (t->sz) st->offset += st->offset % t->sz; entries[st->nentries++] = (struct stentry) { .t = t, .tk = name, .offset = st->offset }; st->entries = entries; st->offset += t->sz; p->stk = p->tk; if (p->proto) fputc('\t', stderr); fprintf(stderr, "\tadding %s (%d:%d) to %s, type %s, offset %zu, " "size %zu\n", name->s, loc->line, loc->col, st->name, tname, entries[st->nentries - 1].offset, t->sz); ret = 1; end: free(tname); return ret; } static int v(const struct lex *l, struct prv *p, const struct type *t) { return stpush(l, p, p->id, t); } static int id(const struct lex *l, struct prv *p) { p->id = p->stk; return type(l, p, v); } 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; struct pos init = { .seq = seqs, .stseq = seqs, .step = seqs->steps }; if (*out) { const struct loc *loc = &(*out)->tk->loc; errloc(p->stk, "%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 = p->stk, .check = check}; *out = p->st = st; p->stk = p->tk; return 1; failure: free(st); return -1; }