#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 #include 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 char *tr = triplet(p); const struct type *byte = type_find(fn, tr, "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 char *tr = triplet(p); const struct type *t; if (!e && !(t = type_ufind(fn, tr, 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); }