#include "type.h" #include "errloc.h" #include "fn.h" #include "lex.h" #include "parse.h" #include "prv.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, "byte"}, {0}}, .fn = t}, {(struct step[]){{ID, "halfword"}, {0}}, .fn = t}, {(struct step[]){{ID, "word"}, {0}}, .fn = t}, {(struct step[]){{ID, "long"}, {0}}, .fn = t}, {(struct step[]){{ID, "ubyte"}, {0}}, .fn = t}, {(struct step[]){{ID, "uhalfword"}, {0}}, .fn = t}, {(struct step[]){{ID, "uword"}, {0}}, .fn = t}, {(struct step[]){{ID, "ulong"}, {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->child) type_lfree(t->child); 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 *s) { static const struct type builtins[] = { {.type = BUILTIN, .u.b.name = "void"}, {.type = BUILTIN, .u.b.name = "byte", .sz = 1, .sign = 1, .align = 1}, {.type = BUILTIN, .u.b.name = "halfword", .sz = 2, .sign = 1, .align = 2}, {.type = BUILTIN, .u.b.name = "word", .sz = 4, .sign = 1, .align = 4}, {.type = BUILTIN, .u.b.name = "long", .sz = 8, .sign = 1, .align = 8}, {.type = BUILTIN, .u.b.name = "ubyte", .sz = 1, .align = 1}, {.type = BUILTIN, .u.b.name = "uhalfword", .sz = 2, .align = 2}, {.type = BUILTIN, .u.b.name = "uword", .sz = 4, .align = 4}, {.type = BUILTIN, .u.b.name = "ulong", .sz = 8, .align = 8} }; const struct td *td = fn->td; if (fn->parent) { const struct type *t = type_find(fn->parent, s); if (t) return t; } for (size_t i = 0; i < sizeof builtins / sizeof *builtins; i++) { const struct type *t = &builtins[i]; if (!strcmp(t->u.b.name, s)) return t; } if (td) for (size_t i = 0; i < td->ntypes; i++) { const struct type *t = &td->types[i]; if (!strcmp(t->tk->s, s)) return t; } for (size_t i = 0; i < fn->nimps; i++) { const struct type *t = type_ufind(fn->imps[i].ast.fns, s); if (t) return t; } return NULL; } const struct type *type_find(const struct fn *fn, const char *s) { const struct type *t = type_ufind(fn, s); if (t && t->type == T) return t->u.t.alias; return t; } static int queue(struct prv *p, struct type *t) { struct type *tt; struct pos *pos = &p->pos[p->i]; if (!(tt = p->t)) p->t = t; else { while (tt->child) tt = tt->child; tt->child = t; } pos->seq = pos->stseq; pos->step = pos->seq->steps; p->stk = p->tk; return 1; } 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"); return -1; } *t = (struct type){.type = ARY, .u.ary.etc = 1}; return queue(p, t); } 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), 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"); return -1; } *t = (struct type){.type = ARY, .u.ary.n = v}; return queue(p, t); } 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"); return -1; } *t = (struct type){.type = ARY, .u.ary.n = n}; return queue(p, t); } static int p(const struct lex *l, struct prv *p) { struct type *t = malloc(sizeof *t), *tt; if (!t) { perror("malloc"); return -1; } *t = (struct type) { .type = PTR, .sz = sizeof (void *), .align = sizeof (void *) }; if ((tt = p->t) && tt->type == ARY) { tt->sz = tt->u.ary.n * sizeof (void *); tt->align = sizeof (void *); } return queue(p, t); } 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; } static const struct type *insert(struct prv *p) { struct ast *ast = p->ast; struct type *a = p->t, *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, 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 = insert(p))) return -1; p->t = NULL; } return p->type(l, p, t); } int type(const struct lex *l, struct prv *p, int (*fn)(const struct lex *, struct prv *, const struct type *)) { struct pos init = { .seq = seqs, .stseq = seqs, .step = seqs->steps }; p->stk = p->tk; p->type = fn; return push(&init, p) ? -1 : 1; }