commit 16f55e41373fcd71ccf26dad2e6a7f0238861ee6
parent 1350398abc63b71b0b4cd2c7c070d1e3950c304a
Author: Eyal Sawady <ecs@d2evs.net>
Date: Tue, 12 Jan 2021 18:35:34 -0500
gen: implement break/continue
Diffstat:
2 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/include/gen.h b/include/gen.h
@@ -17,6 +17,13 @@ struct gen_binding {
struct gen_binding *next;
};
+struct gen_loop_context {
+ const char *label;
+ struct qbe_value *after;
+ struct qbe_value *end;
+ struct gen_loop_context *parent;
+};
+
struct gen_context {
struct qbe_program *out;
struct identifier *ns;
@@ -24,6 +31,7 @@ struct gen_context {
const struct qbe_value *end_label;
const struct qbe_value *return_value;
struct gen_binding *bindings;
+ struct gen_loop_context *loop;
uint64_t id;
};
diff --git a/src/gen.c b/src/gen.c
@@ -900,6 +900,27 @@ gen_expr_constant(struct gen_context *ctx,
}
static void
+gen_expr_control(struct gen_context *ctx,
+ const struct expression *expr,
+ const struct qbe_value *out)
+{
+ assert(out == NULL); // Invariant
+ struct gen_loop_context *loop = ctx->loop;
+ while (expr->control.label != NULL && loop != NULL) {
+ if (loop->label && strcmp(expr->control.label, loop->label) == 0) {
+ break;
+ }
+ loop = loop->parent;
+ }
+ assert(loop != NULL);
+ if (expr->type == EXPR_BREAK) {
+ pushi(ctx->current, NULL, Q_JMP, loop->end, NULL);
+ } else {
+ pushi(ctx->current, NULL, Q_JMP, loop->after, NULL);
+ }
+}
+
+static void
gen_expr_for(struct gen_context *ctx,
const struct expression *expr,
const struct qbe_value *out)
@@ -922,6 +943,14 @@ gen_expr_for(struct gen_context *ctx,
push(&ctx->current->body, &loopl);
+ struct gen_loop_context *loop_ctx =
+ xcalloc(sizeof(struct gen_loop_context), 1);
+ loop_ctx->after = &after;
+ loop_ctx->end = &end;
+ loop_ctx->label = expr->_for.label;
+ loop_ctx->parent = ctx->loop;
+ ctx->loop = loop_ctx;
+
struct qbe_value cond = {0};
gen_temp(ctx, &cond, &qbe_word, "cond.%d");
gen_expression(ctx, expr->_for.cond, &cond);
@@ -935,7 +964,9 @@ gen_expr_for(struct gen_context *ctx,
if (expr->_for.afterthought) {
gen_expression(ctx, expr->_for.afterthought, NULL);
}
- (void)after; // TODO: continue
+
+ ctx->loop = ctx->loop->parent;
+ free(loop_ctx);
pushi(ctx->current, NULL, Q_JMP, &loop, NULL);
@@ -1152,7 +1183,9 @@ gen_expression(struct gen_context *ctx,
gen_expr_binding(ctx, expr, out);
break;
case EXPR_BREAK:
- assert(0); // TODO
+ case EXPR_CONTINUE:
+ gen_expr_control(ctx, expr, out);
+ break;
case EXPR_CALL:
gen_expr_call(ctx, expr, out);
break;
@@ -1162,8 +1195,6 @@ gen_expression(struct gen_context *ctx,
case EXPR_CONSTANT:
gen_expr_constant(ctx, expr, out);
break;
- case EXPR_CONTINUE:
- assert(0); // TODO
case EXPR_FOR:
gen_expr_for(ctx, expr, out);
break;