aboutsummaryrefslogtreecommitdiff
path: root/eval.c
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-02-11 18:43:18 -0800
committerMichael Forney <mforney@mforney.org>2019-02-12 01:55:14 -0800
commiteddc4693e49f70cd214b7645cb9fce54a89fbb6c (patch)
treefa1b640f49cde25e323aa0629aed64c064da930e /eval.c
Initial import
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/eval.c b/eval.c
new file mode 100644
index 0000000..80e9578
--- /dev/null
+++ b/eval.c
@@ -0,0 +1,134 @@
+#include <stddef.h>
+#include <stdint.h>
+#include "util.h"
+#include "decl.h"
+#include "emit.h"
+#include "eval.h"
+#include "expr.h"
+#include "token.h"
+#include "type.h"
+
+struct expression *
+eval(struct expression *expr)
+{
+ struct expression *l, *r, *c;
+ int op;
+
+ switch (expr->kind) {
+ case EXPRIDENT:
+ if (expr->ident.decl->kind != DECLCONST)
+ break;
+ expr->kind = EXPRCONST;
+ expr->constant.i = intconstvalue(expr->ident.decl->value);
+ break;
+ case EXPRUNARY:
+ l = eval(expr->unary.base);
+ if (expr->unary.op != TBAND)
+ break;
+ switch (l->kind) {
+ case EXPRUNARY:
+ if (l->unary.op == TMUL)
+ expr = eval(l->unary.base);
+ break;
+ case EXPRSTRING:
+ l->ident.decl = stringdecl(l);
+ l->kind = EXPRIDENT;
+ expr->unary.base = l;
+ break;
+ }
+ break;
+ case EXPRCAST:
+ l = eval(expr->cast.e);
+ if (l->kind == EXPRCONST) {
+ expr->kind = EXPRCONST;
+ if (typeprop(l->type) & PROPINT && typeprop(expr->type) & PROPFLOAT)
+ expr->constant.i = l->constant.f;
+ else if (typeprop(l->type) & PROPFLOAT && typeprop(expr->type) & PROPINT)
+ expr->constant.f = l->constant.i;
+ else
+ expr->constant = l->constant;
+ } else if (l->type->kind == TYPEPOINTER && expr->type->kind == TYPEPOINTER) {
+ expr = l;
+ }
+ break;
+ case EXPRBINARY:
+ l = eval(expr->binary.l);
+ r = eval(expr->binary.r);
+ expr->binary.l = l;
+ expr->binary.r = r;
+ if (l->kind != EXPRCONST)
+ break;
+ if (expr->binary.op == TLOR)
+ return !l->constant.i ? r : l;
+ if (expr->binary.op == TLAND)
+ return l->constant.i ? r : l;
+ if (r->kind != EXPRCONST)
+ break;
+ expr->kind = EXPRCONST;
+ op = expr->binary.op;
+#define F (1<<8)
+#define S (2<<8)
+ if (typeprop(l->type) & PROPFLOAT)
+ op |= F;
+ else if (l->type->basic.issigned)
+ op |= S;
+ switch (op) {
+ case TMUL:
+ case TMUL|S: expr->constant.i = l->constant.i * r->constant.i; break;
+ case TMUL|F: expr->constant.f = l->constant.f * r->constant.f; break;
+ case TDIV: expr->constant.i = l->constant.i / r->constant.i; break;
+ case TDIV|S: expr->constant.i = (int64_t)l->constant.i / (int64_t)r->constant.i; break;
+ case TDIV|F: expr->constant.f = l->constant.f / r->constant.f; break;
+ case TMOD: expr->constant.i = l->constant.i % r->constant.i; break;
+ case TMOD|S: expr->constant.i = (int64_t)l->constant.i % (int64_t)r->constant.i; break;
+ case TADD:
+ case TADD|S: expr->constant.i = l->constant.i + r->constant.i; break;
+ case TADD|F: expr->constant.f = l->constant.f + r->constant.f; break;
+ case TSUB:
+ case TSUB|S: expr->constant.i = l->constant.i - r->constant.i; break;
+ case TSUB|F: expr->constant.f = l->constant.f - r->constant.f; break;
+ case TSHL:
+ case TSHL|S: expr->constant.i = l->constant.i << r->constant.i; break;
+ case TSHR: expr->constant.i = l->constant.i >> r->constant.i; break;
+ case TSHR|S: expr->constant.i = (int64_t)l->constant.i >> r->constant.i; break;
+ case TBAND:
+ case TBAND|S: expr->constant.i = l->constant.i & r->constant.i; break;
+ case TBOR:
+ case TBOR|S: expr->constant.i = l->constant.i | r->constant.i; break;
+ case TXOR:
+ case TXOR|S: expr->constant.i = l->constant.i ^ r->constant.i; break;
+ case TLESS: expr->constant.i = l->constant.i < r->constant.i; break;
+ case TLESS|S: expr->constant.i = (int64_t)l->constant.i < (int64_t)r->constant.i; break;
+ case TLESS|F: expr->constant.i = l->constant.f < r->constant.f; break;
+ case TGREATER: expr->constant.i = l->constant.i > r->constant.i; break;
+ case TGREATER|S: expr->constant.i = (int64_t)l->constant.i > (int64_t)r->constant.i; break;
+ case TGREATER|F: expr->constant.i = l->constant.f > r->constant.f; break;
+ case TLEQ: expr->constant.i = l->constant.i <= r->constant.i; break;
+ case TLEQ|S: expr->constant.i = (int64_t)l->constant.i <= (int64_t)r->constant.i; break;
+ case TLEQ|F: expr->constant.i = l->constant.f <= r->constant.f; break;
+ case TGEQ: expr->constant.i = l->constant.i >= r->constant.i; break;
+ case TGEQ|S: expr->constant.i = (int64_t)l->constant.i >= (int64_t)r->constant.i; break;
+ case TGEQ|F: expr->constant.i = l->constant.f >= r->constant.f; break;
+ case TEQL:
+ case TEQL|S: expr->constant.i = l->constant.i == r->constant.i; break;
+ case TEQL|F: expr->constant.i = l->constant.f == r->constant.f; break;
+ case TNEQ:
+ case TNEQ|S: expr->constant.i = l->constant.i != r->constant.i; break;
+ case TNEQ|F: expr->constant.i = l->constant.f != r->constant.f; break;
+ default:
+ fatal("internal error; unknown binary expression");
+ }
+#undef F
+#undef S
+ break;
+ case EXPRCOND:
+ l = expr->cond.t;
+ r = expr->cond.f;
+ c = eval(expr->cond.e);
+ if (c->kind != EXPRCONST)
+ break;
+ return eval(c->constant.i ? l : r);
+ }
+
+ return expr;
+}