aboutsummaryrefslogtreecommitdiffhomepage
path: root/eval.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-10-19 08:09:09 +0200
committerlemon <lsof@mailbox.org>2025-10-19 08:09:09 +0200
commitdea8fd171acb54b6d9685422d5e391fb55074008 (patch)
tree2c149892f35c5183c9b2a1da4ab437228dc432ef /eval.c
parent3437945692f2b87883a4f066473c9deed50f25f5 (diff)
Organize source files into directories
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c316
1 files changed, 0 insertions, 316 deletions
diff --git a/eval.c b/eval.c
deleted file mode 100644
index d32cd6e..0000000
--- a/eval.c
+++ /dev/null
@@ -1,316 +0,0 @@
-#include "c.h"
-
-static int
-targ2hosttype(enum typetag t)
-{
- if (t == TYPTR) t = targ_64bit ? TYUVLONG : TYUINT;
- if (isintt(t)) {
- int siz = targ_primsizes[t];
- int sgn = issignedt(t);
-#define U(Ty,Tag) if (!sgn & (siz == sizeof(unsigned Ty))) return Tag;
-#define S(Ty,Tag) if ( sgn & (siz == sizeof(signed Ty))) return Tag;
- U(char, TYUCHAR)
- S(char, TYSCHAR)
- U(short, TYUSHORT)
- S(short, TYSHORT)
- U(int, TYUINT)
- S(int, TYINT)
- U(long long, TYUVLONG)
- S(long long, TYVLONG)
-#undef U
-#undef S
- } else if (isfltt(t)) return t;
- return 0;
-}
-
-static bool
-numcast(union type ty, struct expr *dst, const struct expr *src)
-{
- struct expr tmp;
- enum typetag td = targ2hosttype(ty.t);
- enum typetag ts = targ2hosttype(src->ty.t == TYENUM ? src->ty.backing : src->ty.t);
- if (src == dst) tmp = *src, src = &tmp;
-
- assert(src->t == ENUMLIT);
-#define TT(d,s) (td == d && ts == s)
-#define TF(d) (td == d && isfltt(ts))
- if (!ts || !td) return 0;
- else if (TT(TYFLOAT, TYFLOAT)) dst->f = (float) src->f;
- else if (TT(TYFLOAT, TYDOUBLE)) dst->f = (float) src->f;
- else if (TT(TYDOUBLE, TYFLOAT)) dst->f = src->f;
- else if (TT(TYDOUBLE, TYDOUBLE)) dst->f = src->f;
- else if (TT(TYFLOAT, TYUVLONG)) dst->f = (float) src->u;
- else if (TT(TYDOUBLE, TYUVLONG)) dst->f = (double) src->u;
- else if (td == TYFLOAT) dst->f = (float) src->i;
- else if (td == TYDOUBLE) dst->f = (double) src->i;
- else if (TF(TYUVLONG)) dst->u = src->f;
- else if (TF(TYBOOL)) dst->i = (bool) src->f;
- else if (isfltt(ts)) { dst->i = src->f; goto Narrow; }
- else {
- Narrow:
- switch (td) {
-#define I(Ty, Tag) case Tag: dst->i = (Ty) src->i; break;
- I(bool, TYBOOL)
- I(signed char, TYSCHAR)
- I(unsigned char, TYUCHAR)
- I(signed short, TYSHORT)
- I(unsigned short, TYUSHORT)
- I(signed int, TYINT)
- I(unsigned int, TYUINT)
- I(signed long long, TYVLONG)
- I(unsigned long long, TYUVLONG)
-#undef I
- case TYFLOAT: dst->f = (float) src->f; break;
- case TYDOUBLE: dst->f = src->f; break;
- default: assert(0 && "bad cast?");
- }
- }
-#undef TT
-#undef TF
-
- dst->t = ENUMLIT;
- dst->ty = ty;
- return 1;
-}
-
-static bool
-unop(struct expr *ex, enum evalmode mode)
-{
- struct expr *sub = ex->sub;
-
- if (mode >= EVSTATICINI && ex->t == EDEREF) {
- uvlong off;
- struct bytes s;
- if (sub->t == ESTRLIT) {
- /* *"s" */
- off = 0;
- s = sub->s;
- } else if (sub->t == EADD && sub->sub[0].t == ESTRLIT && eval(&sub->sub[1], EVINTCONST)) {
- /* "s"[0] */
- assert(sub->sub[1].t == ENUMLIT && isint(sub->sub[1].ty));
- off = sub->sub[1].u;
- s = sub->sub[0].s;
- } else if (sub->t == EADD && sub->sub[1].t == ESTRLIT && eval(&sub->sub[0], EVINTCONST)) {
- /* 0["s"] */
- assert(sub->sub[0].t == ENUMLIT && isint(sub->sub[0].ty));
- off = sub->sub[0].u;
- s = sub->sub[1].s;
- } else return 0;
- if (off > s.n) return 0;
- ex->t = ENUMLIT;
- ex->ty = mktype(TYINT);
- ex->u = off == s.n ? 0 : s.p[off];
- return 1;
- }
- if (ex->t == EADDROF) {
- assert(ex->ty.t == TYPTR);
- /* oh boy */
- /* match &(*(T *)12345).fld */
- if (sub->t == EGETF && sub->sub->t == EDEREF && eval(sub->sub->sub, EVFOLD) && sub->sub->sub->t == ENUMLIT) {
- ex->t = ENUMLIT;
- ex->u = sub->sub->sub->u + sub->fld.off;
- return 1;
- }
- }
- if (sub->t != ENUMLIT && !eval(sub, mode)) return 0;
- if (sub->t != ENUMLIT) return 0;
- switch (ex->t) {
- case ECAST:
- if (ex->ty.t == TYPTR) {
- ex->t = ENUMLIT;
- ex->u = sub->u;
- return 1;
- }
- break;
- case EPLUS:
- break;
- case ENEG:
- if (isint(sub->ty)) sub->u = -sub->u;
- else assert(isflt(sub->ty)), sub->f = -sub->f;
- break;
- case ECOMPL:
- if (!isint(sub->ty)) return 0;
- sub->u = ~sub->u;
- break;
- case ELOGNOT:
- if (isint(sub->ty) || isptrcvt(sub->ty)) sub->u = !sub->u;
- else assert(isflt(sub->ty)), sub->u = !sub->f;
- break;
- default:
- return 0;
- }
- if (!numcast(ex->ty, ex, sub)) return 0;
- return 1;
-}
-
-/* link time constants */
-static bool
-isglobsym(const struct expr *ex)
-{
- return ex->t == ESTRLIT || (ex->t == ESYM && ex->sym && (ex->sym->scls & (SCSTATIC | SCEXTERN)));
-}
-
-static bool
-isaddrconst(struct expr *ex)
-{
- if (ex->t == ECAST)
- return isaddrconst(ex->sub) || (eval(ex->sub, EVSTATICINI) && ex->sub->t == ENUMLIT);
- if (ex->t == EADDROF && (isglobsym(ex->sub) || (ex->sub->t == EGETF && isglobsym(ex->sub->sub))))
- return 1;
- if (isglobsym(ex) && in_range(ex->ty.t, TYARRAY, TYFUNC))
- return 1;
- if (ex->t == ESUB)
- return isglobsym(&ex->sub[0]) && isint(ex->sub[1].ty) && eval(&ex->sub[1], EVSTATICINI);
- if (ex->t == EADD) {
- for (int swp = 0; swp < 2; ++swp)
- if (isglobsym(&ex->sub[swp]) && isint(ex->sub[swp^1].ty) && eval(&ex->sub[swp^1], EVSTATICINI))
- return 1;
- }
- return 0;
-}
-
-static bool
-binop(struct expr *ex, enum evalmode mode)
-{
- union type oty;
- bool flt;
- bool sgn;
- int t;
- struct expr *lhs = &ex->sub[0], *rhs = &ex->sub[1];
-
- if (ex->ty.t == TYPTR) mode = EVFOLD;
- if (!eval(lhs, mode)) return 0;
- if (!eval(rhs, mode)) return 0;
- if (in_range(ex->t, EADD, ESHR))
- oty = ex->ty;
- else
- oty = cvtarith(lhs->ty, rhs->ty);
- if (!numcast(oty, lhs, lhs)) return 0;
- if (!numcast(oty, rhs, rhs)) return 0;
- flt = isflt(oty);
- sgn = issigned(oty);
- switch (ex->t) {
-#define ef else if
- case EADD: if (flt) lhs->f += rhs->f;
- else lhs->u += rhs->u;
- break;
- case ESUB: if (oty.t == TYPTR) {
- assert(lhs->t == ENUMLIT && rhs->t == ENUMLIT);
- assert(!isincomplete(typechild(ex->ty)));
- lhs->u = (lhs->u - rhs->u) / typesize(typechild(ex->ty));
- }
- ef (flt) lhs->f -= rhs->f;
- else lhs->u -= rhs->u;
- break;
- case EMUL: if (flt) lhs->f *= rhs->f;
- ef (sgn) lhs->i *= rhs->i;
- else lhs->u *= rhs->u;
- break;
- case EDIV: if (!flt && !rhs->i) return 0;
- ef (flt) lhs->f /= rhs->f;
- ef (sgn) lhs->i /= rhs->i;
- else lhs->u /= rhs->u;
- break;
- case EREM: if (!rhs->i) return 0;
- ef (sgn) lhs->i %= rhs->i;
- else lhs->u %= rhs->u;
- break;
- case EBAND: lhs->u &= rhs->u;
- break;
- case EBIOR: lhs->u |= rhs->u;
- break;
- case EXOR: lhs->u ^= rhs->u;
- break;
- case ESHL: if (sgn && lhs->i < 0) return 0;
- ef (rhs->i >= 8*targ_primsizes[oty.t]) return 0;
- lhs->u <<= rhs->u;
- break;
- case ESHR: if (rhs->i >= 8*targ_primsizes[oty.t]) return 0;
- ef (sgn) lhs->i >>= rhs->i;
- else lhs->u >>= rhs->u;
- break;
- case ELOGAND: if (flt) t = lhs->f && rhs->f;
- else t = lhs->u && rhs->u;
- lhs->u = t;
- break;
- case ELOGIOR: if (flt) t = lhs->f || rhs->f;
- else t = lhs->u || rhs->u;
- lhs->u = t;
- break;
- case EEQU: if (flt) t = lhs->f == rhs->f;
- else t = lhs->u == rhs->u;
- lhs->u = t;
- break;
- case ENEQ: if (flt) t = lhs->f != rhs->f;
- else t = lhs->u != rhs->u;
- lhs->u = t;
- break;
- case ELTH: if (flt) t = lhs->f < rhs->f;
- ef (sgn) t = lhs->i < rhs->i;
- else t = lhs->u < rhs->u;
- lhs->u = t;
- break;
- case EGTH: if (flt) t = lhs->f > rhs->f;
- ef (sgn) t = lhs->i > rhs->i;
- else t = lhs->u > rhs->u;
- lhs->u = t;
- break;
- case ELTE: if (flt) t = lhs->f <= rhs->f;
- ef (sgn) t = lhs->i <= rhs->i;
- else t = lhs->u <= rhs->u;
- lhs->u = t;
- break;
- case EGTE: if (flt) t = lhs->f >= rhs->f;
- ef (sgn) t = lhs->i >= rhs->i;
- else t = lhs->u >= rhs->u;
- lhs->u = t;
- break;
- default: return 0;
-#undef ef
- }
-
- return numcast(ex->ty, ex, lhs);
-}
-
-bool
-eval(struct expr *ex, enum evalmode mode)
-{
- if (ex->t == ENUMLIT) {
- if (mode <= EVINTCONST) return isint(ex->ty);
- return 1;
- }
- if (ex->t == ESTRLIT && mode > EVINTCONST) return 1;
- if (mode == EVSTATICINI && isaddrconst(ex)) {
- struct expr *e = ex;
- while (e->t == ECAST) e = e->sub;
- if (e != ex) {
- e->ty = ex->ty;
- *ex = *e;
- }
- return 1;
- }
- mode += mode == EVINTCONST;
- if (isunop(ex->t)) return unop(ex, mode) && eval(ex, mode);
- if (isbinop(ex->t)) return binop(ex, mode) && eval(ex, mode);
- if (ex->t == ESEQ) {
- if (!eval(&ex->sub[0], mode)) return 0;
- *ex = ex->sub[1];
- return eval(ex, mode);
- }
- if (ex->t == ECOND) {
- if (!eval(&ex->sub[0], mode) || ex->sub[0].t != ENUMLIT) return 0;
- if (!eval(&ex->sub[1], mode)) return 0;
- if (!eval(&ex->sub[2], mode)) return 0;
- *ex = ex->sub[!ex->sub[0].u + 1];
- return eval(ex, mode);
- }
- if (ex->t == EINIT) {
- for (struct initval *v = ex->init->vals; v; v = v->next) {
- if (!eval(&v->ex, mode)) return 0;
- }
- return 1;
- }
- return 0;
-}
-
-/* vim:set ts=3 sw=3 expandtab: */