commit f6d3b449c97b42579fa47f409db4ca20ac2ef45c
parent 6f822c4aeb48683f63c58afcc654e717d20ca7a8
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 4 Aug 2021 13:49:07 +0200
gen: implement if expressions
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
3 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -532,6 +532,48 @@ gen_expr_const(struct gen_context *ctx, const struct expression *expr)
}
static struct gen_value
+gen_expr_if_with(struct gen_context *ctx,
+ const struct expression *expr,
+ struct gen_value *out)
+{
+ struct gen_value gvout = gv_void;
+ struct qbe_value qvout;
+ if (!out) {
+ gvout = mktemp(ctx, expr->result, ".%d");
+ qvout = mkqval(ctx, &gvout);
+ }
+
+ struct qbe_statement ltrue, lfalse, lend;
+ struct qbe_value btrue = mklabel(ctx, <rue, "true.%d");
+ struct qbe_value bfalse = mklabel(ctx, &lfalse, "false.%d");
+ struct qbe_value bend = mklabel(ctx, &lend, ".%d");
+ struct gen_value cond = gen_expr(ctx, expr->_if.cond);
+ struct qbe_value qcond = mkqval(ctx, &cond);
+ pushi(ctx->current, NULL, Q_JNZ, &qcond, &btrue, &bfalse, NULL);
+
+ push(&ctx->current->body, <rue);
+ struct gen_value vtrue = gen_expr_with(ctx, expr->_if.true_branch, out);
+ if (!out) {
+ struct qbe_value qvtrue = mkqval(ctx, &vtrue);
+ pushi(ctx->current, &qvout, Q_COPY, &qvtrue, NULL);
+ }
+ pushi(ctx->current, NULL, Q_JMP, &bend, NULL);
+
+ push(&ctx->current->body, &lfalse);
+ if (expr->_if.false_branch) {
+ struct gen_value vfalse = gen_expr_with(
+ ctx, expr->_if.false_branch, out);
+ if (!out) {
+ struct qbe_value qvfalse = mkqval(ctx, &vfalse);
+ pushi(ctx->current, &qvout, Q_COPY, &qvfalse, NULL);
+ }
+ }
+
+ push(&ctx->current->body, &lend);
+ return gvout;
+}
+
+static struct gen_value
gen_expr_list_with(struct gen_context *ctx,
const struct expression *expr,
struct gen_value *out)
@@ -668,7 +710,9 @@ gen_expr(struct gen_context *ctx, const struct expression *expr)
case EXPR_DELETE:
case EXPR_FOR:
case EXPR_FREE:
+ assert(0); // TODO
case EXPR_IF:
+ return gen_expr_if_with(ctx, expr, NULL);
case EXPR_INSERT:
assert(0); // TODO
case EXPR_LIST:
@@ -710,6 +754,9 @@ gen_expr_at(struct gen_context *ctx,
case EXPR_CONSTANT:
gen_expr_const_at(ctx, expr, out);
return;
+ case EXPR_IF:
+ gen_expr_if_with(ctx, expr, &out);
+ return;
case EXPR_LIST:
gen_expr_list_with(ctx, expr, &out);
return;
@@ -723,7 +770,10 @@ gen_expr_at(struct gen_context *ctx,
break; // Prefers non-at style
}
- gen_store(ctx, out, gen_expr(ctx, expr));
+ struct gen_value result = gen_expr(ctx, expr);
+ if (!expr->terminates) {
+ gen_store(ctx, out, result);
+ }
}
static struct gen_value
diff --git a/src/genutil.c b/src/genutil.c
@@ -89,6 +89,6 @@ mklabel(struct gen_context *ctx, struct qbe_statement *stmt, const char *fmt)
{
struct qbe_value val;
val.kind = QV_LABEL;
- val.name = strdup(genl(stmt, &ctx->id, "failed.%d"));
+ val.name = strdup(genl(stmt, &ctx->id, fmt));
return val;
}
diff --git a/tests/configure b/tests/configure
@@ -9,7 +9,8 @@ tests() {
902-arithm \
903-postfix \
904-copy \
- 905-assign
+ 905-assign \
+ 906-if
do
cat <<EOF
tests/$t: harec tests/$t.ha tests/rt.o