diff options
Diffstat (limited to 'src/prc1/sym.c')
| -rw-r--r-- | src/prc1/sym.c | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/src/prc1/sym.c b/src/prc1/sym.c new file mode 100644 index 0000000..fb67f14 --- /dev/null +++ b/src/prc1/sym.c @@ -0,0 +1,478 @@ +#include "sym.h" +#include "errloc.h" +#include "fn.h" +#include "lex.h" +#include "parse.h" +#include "prv.h" +#include "storage.h" +#include "type.h" +#include <stdio.h> +#include <stdlib.h> + +static int addr(const struct lex *, struct prv *); +static int cnt(const struct lex *, struct prv *); +static int off(const struct lex *, struct prv *); +static int szof(const struct lex *, struct prv *); +static int idof(const struct lex *, struct prv *); +static int numof(const struct lex *, struct prv *); +static int cast(const struct lex *, struct prv *); +static int to(const struct lex *, struct prv *); +static int lit(const struct lex *, struct prv *); +static int num(const struct lex *, struct prv *); +static int id(const struct lex *, struct prv *); +static int push_to(struct prv *); + +static const struct seq seqs[] = +{ + {(struct step[]){{ID, "address"}, {ID, "of"}, {0}}, .fn = addr}, + {(struct step[]){{ID, "contents"}, {ID, "of"}, {0}}, .fn = cnt}, + {(struct step[]){{ID, "offset"}, {ID, "of"}, {0}}, .fn = off}, + {(struct step[]){{ID, "size"}, {ID, "of"}, {0}}, .fn = szof}, + {(struct step[]){{ID, "cast"}, {0}}, .fn = cast}, + {(struct step[]){{ID}, {ID, "of"}, {0}}, .fn = idof}, + {(struct step[]){{NUM}, {ID, "of"}, {0}}, .fn = numof}, + {(struct step[]){{LIT}, {0}}, .fn = lit}, + {(struct step[]){{NUM}, {0}}, .fn = num}, + {(struct step[]){{ID}, {0}}, .fn = id}, + {0} +}; + +static const struct seq cast_seqs[] = +{ + {(struct step[]){{ID, "to"}, {0}}, .fn = to}, + {0} +}; + +static void queue(struct prv *p, struct sym *s) +{ + struct sym *ss = p->s; + + if (!ss) + p->s = s; + else + { + while (ss->child) + ss = ss->child; + + ss->child = s; + s->parent = ss; + } + + reset(p); +} + +static int pushsym(struct prv *p, enum symtype t) +{ + struct sym *s = malloc(sizeof *s); + + if (!s) + { + perror("malloc(3)"); + return -1; + } + + *s = (struct sym){.type = t, .tk = p->stk}; + queue(p, s); + return 0; +} + +static int addr(const struct lex *l, struct prv *p) +{ + return pushsym(p, SYM_ADDR); +} + +static int cnt(const struct lex *l, struct prv *p) +{ + return pushsym(p, SYM_CNT); +} + +static int off(const struct lex *l, struct prv *p) +{ + return pushsym(p, SYM_OFF); +} + +static int szof(const struct lex *l, struct prv *p) +{ + return pushsym(p, SYM_SZ); +} + +static void insert(struct fn *fn, struct sym *s) +{ + struct sym *ss = fn->syms; + + while (ss && ss->next) + ss = ss->next; + + if (!ss) + fn->syms = s; + else + ss->next = s; +} + +static int symbol(const struct sym *s) +{ + switch (s->type) + { + case SYM_ID: + case SYM_TMP: + case SYM_LIT: + case SYM_NUM: + return 1; + + case SYM_CAST: + case SYM_ADDR: + case SYM_SZ: + case SYM_CNT: + case SYM_OFF: + break; + } + + return 0; +} + +static struct sym *getsym(struct sym *s) +{ + for (struct sym *ss = s; ss; ss = ss->child) + if (symbol(ss)) + return ss; + + return NULL; +} + +static int idof(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + reset(p); + return -1; +} + +static int numof(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + reset(p); + return -1; +} + +static struct sym *inner(struct sym *s) +{ + struct sym *ret = NULL; + + for (; s; s = s->child) + if (s->type == SYM_CAST && !s->u.t) + ret = s; + + return ret; +} + +static struct sym *resolve(const struct sym *s) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return NULL; +} + +static int run(const struct lex *l, struct prv *p) +{ + struct fn *fn = fn_cur(p); + struct sym *s = p->s; + + insert(fn, s); + p->s = NULL; + + if (getsym(s)) + return p->sym(l, p, s); + + errloc(p->stk - 1, "expected identifier, literal or number"); + return -1; +} + +static int totype(const struct lex *l, struct prv *p, const struct type *t) +{ + struct sym *s = inner(p->s); + + if (!s || s->u.t) + { + errloc(p->tk - 1, "incomplete cast"); + return -1; + } + + s->u.t = t; + + if (pop(l, p)) + return -1; + + return !inner(p->s) && getsym(p->s) ? run(l, p) : 0; +} + +static int to(const struct lex *l, struct prv *p) +{ + return type(l, p, totype); +} + +static int endcast(const struct lex *l, struct prv *p) +{ + struct sym *s = inner(p->s); + + if (!p->cast--) + { + errloc(p->tk - 1, "incomplete cast"); + return -1; + } + else if (s) + { + if (lex_eof(l, p->tk)) + { + errloc(p->tk - 1, "incomplete cast"); + return -1; + } + + return push_to(p); + } + + return 0; +} + +static int cast(const struct lex *l, struct prv *p) +{ + p->cast++; + return pushsym(p, SYM_CAST); +} + +static int push_to(struct prv *p) +{ + struct pos init = + { + .name = __func__, + .seq = cast_seqs, + .end = endcast + }; + + return push(&init, p); +} + +static int lit(const struct lex *l, struct prv *p) +{ + struct sym *cs = inner(p->s); + + if (pushsym(p, SYM_LIT)) + return -1; + + return cs ? push_to(p) : run(l, p); +} + +static int num(const struct lex *l, struct prv *p) +{ + fprintf(stderr, "%s: TODO\n", __func__); + reset(p); + return -1; +} + +static int id(const struct lex *l, struct prv *p) +{ + struct sym *cs = inner(p->s); + + if (pushsym(p, SYM_ID)) + return -1; + else if (cs) + return push_to(p); + + p->stk = p->tk; + return run(l, p); +} + +void sym_free(struct sym *s) +{ + struct sym *ss = s; + + while (ss) + { + struct sym *child = ss->child; + + free(ss); + ss = child; + } +} + +int sym_lval(const struct sym *s) +{ + int ret = 1; + + while (s) + { + switch (s->type) + { + case SYM_OFF: + case SYM_SZ: + case SYM_LIT: + case SYM_NUM: + case SYM_TMP: + ret = 0; + break; + + case SYM_ADDR: + if (!s->parent || s->parent->type != SYM_CNT) + ret = 0; + case SYM_ID: + case SYM_CNT: + case SYM_CAST: + break; + } + + s = s->child; + } + + return ret; +} + +static int endsym(const struct lex *l, struct prv *p) +{ + return p->s ? run(l, p) : 0; +} + +static int invalid(const struct tk *tk, const struct type *a, + const struct type *b) +{ + static int t[BUILTIN + 1][BUILTIN + 1] = + { + /* U S C P T PTR ARY BUILTIN */ + /* U */ {1, 0, 0, 0, 0, 0, 0, 0}, + /* S */ {0, 1, 0, 0, 0, 0, 0, 0}, + /* C */ {0, 0, 1, 0, 0, 0, 0, 0}, + /* P */ {0, 0, 0, 1, 0, 1, 0, 0}, + /* T */ {0, 0, 0, 0, 1, 0, 0, 0}, + /* PTR */ {0, 0, 0, 0, 0, 1, 1, 0}, + /* ARY */ {0, 0, 0, 0, 0, 0, 1, 0}, + /* BUILTIN */ {0, 0, 0, 0, 0, 0, 0, 1} + }; + + int valid = t[a->type][b->type]; + + if (!valid) + { + char *s1 = type_name(b), *s2 = type_name(a); + + if (s1 && s2) + errloc(tk, "cannot convert \"%s\" to \"%s\"", s1, s2); + + free(s1); + free(s2); + } + + return !valid; +} + +static const struct type *genlittype(struct prv *p) +{ + const struct fn *fn = fn_cur(p); + const struct type *byte = type_find(fn, "char"); + struct type *bytedup = NULL, *t = NULL; + + if (!byte) + return NULL; + else if (!(bytedup = malloc(sizeof *bytedup)) + || !(t = malloc(sizeof *t))) + { + perror("malloc(3)"); + goto failure; + } + + *bytedup = *byte; + *t = (struct type) + { + .type = ARY, + .u.ary.etc = 1, + .child = bytedup + }; + + return p->ast->littype = type_insert(p, t); + +failure: + free(t); + free(bytedup); + return NULL; +} + +static const struct type *littype(struct prv *p) +{ + const struct type *t = p->ast->littype; + + return t ? t : genlittype(p); +} + +const struct type *sym_type(struct prv *p, const struct sym *s) +{ + const struct fn *fn = fn_cur(p); + const struct type *ret = NULL; + + for (; s; s = s->child) + { + const struct tk *tk = s->tk; + + switch (s->type) + { + case SYM_CAST: + if (!ret) + ret = s->u.t; + else if (invalid(tk, ret, s->u.t)) + return NULL; + + break; + + case SYM_ID: + { + const struct stentry *e = fn_var(fn, tk); + const struct type *t; + + if (!e && !(t = type_ufind(fn, tk->s))) + return NULL; + else if (e) + t = e->t; + + if (!ret) + ret = t; + else if (invalid(tk, ret, t)) + return NULL; + } + break; + + case SYM_LIT: + { + const struct type *lt = littype(p); + + if (!ret) + ret = lt; + else if (invalid(tk, ret, lt)) + return NULL; + } + break; + + case SYM_ADDR: + case SYM_TMP: + case SYM_NUM: + case SYM_SZ: + case SYM_CNT: + case SYM_OFF: + break; + } + } + + return ret; +} + +int sym_rval(const struct sym *s) +{ + return !sym_lval(s); +} + +int sym(struct prv *p, sym_fn fn) +{ + struct pos init = + { + .name = __func__, + .seq = seqs, + .end = endsym + }; + + p->stk = p->tk; + p->sym = fn; + return push(&init, p); +} |
