#include "type.h" #include "errloc.h" #include "fn.h" #include "lex.h" #include "parse.h" #include "prv.h" #include "triplet.h" #include #include #include #include static int aetc(const struct lex *l, struct prv *p); static int aid(const struct lex *l, struct prv *p); static int anum(const struct lex *l, struct prv *p); static int p(const struct lex *l, struct prv *p); static int t(const struct lex *l, struct prv *p); static const struct seq seqs[] = { {(struct step[]){{ID, "array"}, {ID, "of"}, {ID, "etc"}, {0}}, .fn = aetc}, {(struct step[]){{ID, "array"}, {ID, "of"}, {NUM}, {0}}, .fn = anum}, {(struct step[]){{ID, "array"}, {ID, "of"}, {ID}, {0}}, .fn = aid}, {(struct step[]){{ID, "pointer"}, {ID, "to"}, {0}}, .fn = p}, {(struct step[]){{ID, "void"}, {0}}, .fn = t}, {(struct step[]){{ID, "char"}, {0}}, .fn = t}, {(struct step[]){{ID, "schar"}, {0}}, .fn = t}, {(struct step[]){{ID, "short"}, {0}}, .fn = t}, {(struct step[]){{ID, "int"}, {0}}, .fn = t}, {(struct step[]){{ID, "long"}, {0}}, .fn = t}, {(struct step[]){{ID, "longlong"}, {0}}, .fn = t}, {(struct step[]){{ID, "uchar"}, {0}}, .fn = t}, {(struct step[]){{ID, "ushort"}, {0}}, .fn = t}, {(struct step[]){{ID, "uint"}, {0}}, .fn = t}, {(struct step[]){{ID, "ulong"}, {0}}, .fn = t}, {(struct step[]){{ID, "ulonglong"}, {0}}, .fn = t}, {(struct step[]){{ID}, {0}}, .fn = t}, {0} }; void type_free(struct type *t) { switch (t->type) { case U: { struct u *u = &t->u.u; storage_free(u->storage); } break; case S: { struct s *s = &t->u.s; storage_free(s->storage); } break; case C: break; case P: { struct p *p = &t->u.p; fn_free(p->fn); free(p->fn); } break; case T: case ARY: case PTR: case BUILTIN: break; } } void type_lfree(struct type *t) { if (t) { if (t->child) type_lfree(t->child); type_free(t); } free(t); } static int append(const char *s, char **out) { size_t n = *out ? strlen(*out) : 0; char *ns = realloc(*out, strlen(s) + n + 1); if (!ns) { perror("realloc(3)"); return -1; } strcpy(ns + n, s); *out = ns; return 0; } char *type_name(const struct type *t) { char *ret = NULL; while (t) { int n = -1; switch (t->type) { case BUILTIN: n = append(t->u.b.name, &ret); break; case ARY: { const struct ary *ary = &t->u.ary; char s[sizeof "18446744073709551615 "]; if (ary->etc) snprintf(s, sizeof s, "etc "); else snprintf(s, sizeof s, "%llu ", t->u.ary.n); n = append("array of ", &ret) || append(s, &ret); break; } case PTR: n = append("pointer to ", &ret); break; case U: case S: case C: case P: case T: n = append(t->tk->s, &ret); break; } if (n) { free(ret); return NULL; } t = t->child; } return ret; } const struct type *type_ufind(const struct fn *fn, const char *tr, const char *s) { const struct td *td = fn->td; const struct type *t; if (fn->parent && (t = type_find(fn->parent, tr, s))) return t; else if ((t = triplet_type(tr, s))) return t; else if (td) for (const struct type *t = td->types; t; t = t->next) if (!strcmp(t->tk->s, s)) return t; for (size_t i = 0; i < fn->nimps; i++) if ((t = type_ufind(fn->imps[i].ast.fns, tr, s))) return t; return NULL; } const struct type *type_find(const struct fn *fn, const char *tr, const char *s) { const struct type *t = type_ufind(fn, tr, s); if (t && t->type == T) return t->u.t.alias; return t; } static void queue(struct prv *p, struct type *t) { struct type *tt; if (!(tt = p->t)) p->t = t; else { while (tt->child) tt = tt->child; tt->child = t; } p->stk = p->tk; reset(p); } static int aetc(const struct lex *l, struct prv *p) { struct type *t; const struct type *tt = p->t; while (tt) { if (tt->type == ARY && tt->u.ary.etc) { errloc(p->stk, "multi-dimensional arrays " "with unknown size are not allowed"); return -1; } tt = tt->next; } if (!(t = malloc(sizeof *t))) { perror("malloc(3)"); return -1; } *t = (struct type){.type = ARY, .u.ary.etc = 1}; queue(p, t); return 0; } static int aid(const struct lex *l, struct prv *p) { const struct tk *qty = p->stk + 2; const struct type *ct = type_find(fn_cur(p), triplet(p), qty->s); struct type *t; unsigned long long v; if (!ct) { errloc(qty, "undefined reference to type \"%s\"", qty->s); return -1; } else if (ct->type != C) { errloc(qty, "type \"%s\" not a constant", qty->s); return -1; } else if (ct->sign) { errloc(qty, "type \"%s\" defines a negative constant (%lld)", qty->s, ct->u.c.v); return -1; } else if (!(v = ct->u.c.uv)) { errloc(qty, "constant \"%s\" equals zero and cannot be used " "for array sizes", qty->s); return -1; } else if (!(t = malloc(sizeof *t))) { perror("malloc(3)"); return -1; } *t = (struct type){.type = ARY, .u.ary.n = v}; queue(p, t); return 0; } static int anum(const struct lex *l, struct prv *p) { const struct tk *qty = p->stk + 2; unsigned long long n = strtoull(qty->s, NULL, 0); struct type *t; if (*qty->s == '-' || errno) { errloc(qty, "invalid negative size for array"); return -1; } else if (!n) { errloc(qty, "array size cannot be zero"); return -1; } else if (!(t = malloc(sizeof *t))) { perror("malloc(3)"); return -1; } *t = (struct type){.type = ARY, .u.ary.n = n}; queue(p, t); return 0; } static int p(const struct lex *l, struct prv *p) { struct type *t = malloc(sizeof *t), *tt; if (!t) { perror("malloc(3)"); return -1; } *t = (struct type) { .type = PTR, /* TODO: ask target for sizeof (void *) */ .sz = sizeof (void *), .align = sizeof (void *) }; if ((tt = p->t) && tt->type == ARY) { /* TODO: ask target for sizeof (void *) */ tt->sz = tt->u.ary.n * sizeof (void *); tt->align = sizeof (void *); } queue(p, t); return 0; } static int aryeq(const struct type *a, const struct type *b) { const struct ary *aa = &a->u.ary, *ab = &b->u.ary; return !memcmp(aa, ab, sizeof *aa); } static int eq(const struct type *a, const struct type *b) { for (; a && b; a = a->child, b = b->child) if (a->type != b->type) return 0; else if (a->type == ARY && !aryeq(a, b)) return 0; return !a && !b; } const struct type *type_insert(struct prv *p, struct type *a) { struct ast *ast = p->ast; struct type *tt = ast->types; for (const struct type *b = ast->types; b; b = b->next) if (eq(a, b)) { type_lfree(a); return b; } if (!ast->types) ast->types = a; else { while (tt->next) tt = tt->next; tt->next = a; } return a; } static int t(const struct lex *l, struct prv *p) { const struct fn *fn = fn_cur(p); const struct tk *tk = p->stk; const struct type *t = type_find(fn, triplet(p), tk->s); struct type *tt = p->t; if (!t) { errloc(tk, "undefined reference to type \"%s\"", tk->s); return -1; } else if (tt) { struct type *nt = malloc(sizeof *nt); if (!nt) { perror("malloc(3)"); return -1; } *nt = *t; while (tt->child) tt = tt->child; tt->child = nt; tt = p->t; /* array size still undecided */ if (tt->type == ARY && !tt->sz) { tt->sz = tt->u.ary.n * nt->sz; tt->align = t->align; } if (!(t = type_insert(p, p->t))) return -1; } else p->t = (struct type *)t; if (pop(l, p)) return -1; p->stk = p->tk; p->t = NULL; return p->type(l, p, t); } static int endtype(const struct lex *l, struct prv *p) { if (!p->t) { errloc(p->stk - 1, "expected type"); return -1; } return 0; } int type(const struct lex *l, struct prv *p, int (*fn)(const struct lex *, struct prv *, const struct type *)) { struct pos init = { .name = __func__, .seq = seqs, .end = endtype }; p->stk = p->tk; p->type = fn; return push(&init, p); }