diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-05-09 02:56:07 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-06-21 01:15:38 +0200 |
| commit | b25ff71bb198c227b3202ee32a8067cda413bc16 (patch) | |
| tree | 41d665a87d948c10b17a853220cbcdbaeebf3672 /type.c | |
| download | prc-master.tar.gz | |
Diffstat (limited to 'type.c')
| -rw-r--r-- | type.c | 459 |
1 files changed, 459 insertions, 0 deletions
@@ -0,0 +1,459 @@ +#include "type.h" +#include "errloc.h" +#include "fn.h" +#include "lex.h" +#include "parse.h" +#include "prv.h" +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +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; +} |
