commit acce85b011f7c1153e1ddd80f31338577d0f452f
parent c00a13d5662dd512e9505d18a37bb331332f7575
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 22 Dec 2020 09:43:31 -0500
check, gen: bindings
Diffstat:
8 files changed, 153 insertions(+), 20 deletions(-)
diff --git a/include/expr.h b/include/expr.h
@@ -37,6 +37,12 @@ struct expression_access {
const struct scope_object *object;
};
+struct expression_binding {
+ const struct scope_object *object;
+ struct expression *initializer;
+ struct expression_binding *next;
+};
+
// TODO: Stretchy constants
union expression_constant {
bool bval;
@@ -71,6 +77,7 @@ struct expression {
bool terminates;
union {
struct expression_access access;
+ struct expression_binding binding;
union expression_constant constant;
struct expression_list list;
struct expression_return _return;
diff --git a/include/gen.h b/include/gen.h
@@ -10,12 +10,19 @@ struct unit;
void gen(const struct unit *unit, struct qbe_program *out);
+struct gen_binding {
+ const struct scope_object *object;
+ char *name;
+ struct gen_binding *next;
+};
+
struct gen_context {
struct qbe_program *out;
struct identifier *ns;
struct qbe_func *current;
const struct qbe_value *end_label;
const struct qbe_value *return_value;
+ struct gen_binding *bindings;
uint64_t id;
};
diff --git a/include/qbe.h b/include/qbe.h
@@ -205,7 +205,7 @@ void geni(struct qbe_statement *stmt, const struct qbe_value *out, enum qbe_inst
const char *genl(struct qbe_statement *stmt, uint64_t *id, const char *fmt);
void pushi(struct qbe_func *func, const struct qbe_value *out, enum qbe_instr instr, ...);
const char *pushl(struct qbe_func *func, uint64_t *id, const char *fmt);
-void pushc(struct qbe_func *func, const char *text);
+void pushc(struct qbe_func *func, const char *fmt, ...);
void push(struct qbe_func *func, struct qbe_statement *stmt);
void constw(struct qbe_value *val, uint32_t l);
diff --git a/include/scope.h b/include/scope.h
@@ -7,7 +7,6 @@
struct scope_object {
struct identifier ident;
const struct type *type;
- char *alias; // Used during gen
struct scope_object *next;
};
@@ -28,7 +27,7 @@ struct scope *scope_pop(struct scope **stack, enum trace_sys sys);
void scope_free(struct scope *scope);
void scope_free_all(struct scopes *scopes);
-void scope_insert(struct scope *scope,
+const struct scope_object *scope_insert(struct scope *scope,
const struct identifier *ident, const struct type *type);
const struct scope_object *scope_lookup(struct scope *scope,
const struct identifier *ident);
diff --git a/src/check.c b/src/check.c
@@ -53,6 +53,50 @@ check_expr_access(struct context *ctx,
}
static void
+check_expr_binding(struct context *ctx,
+ const struct ast_expression *aexpr,
+ struct expression *expr)
+{
+ trace(TR_CHECK, "binding");
+ expr->type = EXPR_BINDING;
+ expr->result = &builtin_type_void;
+
+ struct expression_binding *binding = &expr->binding;
+ struct expression_binding **next = &expr->binding.next;
+
+ const struct ast_expression_binding *abinding = &aexpr->binding;
+ while (abinding) {
+ struct identifier ident = {
+ .name = abinding->name,
+ };
+ struct expression *initializer =
+ calloc(1, sizeof(struct expression));
+ check_expression(ctx, abinding->initializer, initializer);
+
+ const struct type *type;
+ if (abinding->type) {
+ type = type_store_lookup_atype(
+ &ctx->store, abinding->type);
+ // TODO: Check assignability of initializer
+ } else {
+ type = initializer->result;
+ }
+
+ struct scope_object *obj = scope_insert(ctx->scope, &ident, type);
+ binding->object = obj;
+ binding->initializer = initializer;
+
+ if (abinding->next) {
+ binding = *next =
+ calloc(1, sizeof(struct expression_binding));
+ next = &binding->next;
+ }
+
+ abinding = abinding->next;
+ }
+}
+
+static void
check_expr_constant(struct context *ctx,
const struct ast_expression *aexpr,
struct expression *expr)
@@ -164,7 +208,10 @@ check_expression(struct context *ctx,
case EXPR_ASSERT:
case EXPR_ASSIGN:
case EXPR_BINARITHM:
+ assert(0); // TODO
case EXPR_BINDING:
+ check_expr_binding(ctx, aexpr, expr);
+ break;
case EXPR_BREAK:
case EXPR_CALL:
case EXPR_CAST:
diff --git a/src/gen.c b/src/gen.c
@@ -32,18 +32,8 @@ ident_to_sym(const struct identifier *ident)
}
static void
-qval_for_object(struct gen_context *ctx,
- struct qbe_value *val,
- const struct scope_object *obj)
-{
- val->kind = QV_TEMPORARY; // XXX: Is this always the case?
- val->type = qtype_for_type(ctx, obj->type, false);
- val->name = obj->alias ? obj->alias : ident_to_sym(&obj->ident);
-}
-
-static void
gen_temp(struct gen_context *ctx, struct qbe_value *val,
- const struct qbe_type *type, char *fmt)
+ const struct qbe_type *type, const char *fmt)
{
val->kind = QV_TEMPORARY;
val->type = type;
@@ -58,7 +48,7 @@ gen_temp(struct gen_context *ctx, struct qbe_value *val,
static void
alloc_temp(struct gen_context *ctx, struct qbe_value *val,
- const struct type *type, char *fmt)
+ const struct type *type, const char *fmt)
{
gen_temp(ctx, val, &qbe_long, fmt); // XXX: Architecture dependent
@@ -67,6 +57,45 @@ alloc_temp(struct gen_context *ctx, struct qbe_value *val,
pushi(ctx->current, val, alloc_for_align(type->align), &size, NULL);
}
+static struct gen_binding *
+binding_alloc(struct gen_context *ctx, const struct scope_object *obj,
+ struct qbe_value *val, const char *fmt)
+{
+ alloc_temp(ctx, val, obj->type, fmt);
+
+ struct gen_binding *binding = calloc(1, sizeof(struct gen_binding));
+ binding->name = strdup(val->name);
+ binding->object = obj;
+ binding->next = ctx->bindings;
+ ctx->bindings = binding;
+
+ return binding;
+}
+
+static const struct gen_binding *
+binding_lookup(const struct gen_context *ctx, const struct scope_object *obj)
+{
+ struct gen_binding *binding = ctx->bindings;
+ while (binding) {
+ if (binding->object == obj) {
+ return binding;
+ }
+ binding = binding->next;
+ }
+ return NULL;
+}
+
+static void
+qval_for_object(struct gen_context *ctx,
+ struct qbe_value *val,
+ const struct scope_object *obj)
+{
+ const struct gen_binding *binding = binding_lookup(ctx, obj);
+ val->kind = QV_TEMPORARY; // XXX: Is this always the case?
+ val->type = qtype_for_type(ctx, obj->type, false);
+ val->name = binding ? strdup(binding->name) : ident_to_sym(&obj->ident);
+}
+
// Given value src of type A, and value dest of type pointer to A, store src in
// dest.
static void
@@ -109,6 +138,26 @@ static void gen_expression(struct gen_context *ctx,
const struct expression *expr, const struct qbe_value *out);
static void
+gen_binding(struct gen_context *ctx,
+ const struct expression *expr,
+ const struct qbe_value *out)
+{
+ assert(out == NULL);
+
+ const struct expression_binding *binding = &expr->binding;
+ while (binding) {
+ const struct type *type = binding->object->type;
+ assert(!type_is_aggregate(type)); // TODO
+
+ struct qbe_value temp;
+ binding_alloc(ctx, binding->object, &temp, "binding.%d");
+ gen_expression(ctx, binding->initializer, &temp);
+
+ binding = binding->next;
+ }
+}
+
+static void
gen_access(struct gen_context *ctx,
const struct expression *expr,
const struct qbe_value *out)
@@ -203,7 +252,10 @@ gen_expression(struct gen_context *ctx,
case EXPR_ASSERT:
case EXPR_ASSIGN:
case EXPR_BINARITHM:
+ assert(0); // TODO
case EXPR_BINDING:
+ gen_binding(ctx, expr, out);
+ break;
case EXPR_BREAK:
case EXPR_CALL:
case EXPR_CAST:
@@ -264,7 +316,7 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
assert(0); // TODO
} else {
struct qbe_value val;
- alloc_temp(ctx, &val, obj->type, "copy.%d");
+ binding_alloc(ctx, obj, &val, "param.%d");
struct qbe_value src = {
.kind = QV_TEMPORARY,
.type = param->type,
@@ -272,7 +324,6 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
};
gen_store(ctx, &val, &src);
free(obj->ident.name);
- obj->alias = strdup(val.name);
}
obj = obj->next;
@@ -300,6 +351,16 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
type_is_signed(fntype->func.result));
pushi(&qdef->func, NULL, Q_RET, &load, NULL);
+ // Free bindings
+ struct gen_binding *binding = ctx->bindings;
+ while (binding) {
+ struct gen_binding *next = binding->next;
+ free(binding->name);
+ free(binding);
+ binding = next;
+ }
+ ctx->bindings = NULL;
+
qbe_append_def(ctx->out, qdef);
ctx->current = NULL;
}
diff --git a/src/qbe.c b/src/qbe.c
@@ -241,10 +241,21 @@ pushl(struct qbe_func *func, uint64_t *id, const char *fmt)
}
void
-pushc(struct qbe_func *func, const char *text)
+pushc(struct qbe_func *func, const char *fmt, ...)
{
struct qbe_statement stmt = {0};
- stmt.comment = strdup(text);
+
+ va_list ap;
+ va_start(ap, fmt);
+ int n = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+
+ char *str = calloc(1, n + 1);
+ va_start(ap, fmt);
+ vsnprintf(str, n + 1, fmt, ap);
+ va_end(ap);
+
+ stmt.comment = str;
push(func, &stmt);
}
diff --git a/src/scope.c b/src/scope.c
@@ -59,7 +59,7 @@ scope_free_all(struct scopes *scopes)
}
}
-void
+const struct scope_object *
scope_insert(struct scope *scope,
const struct identifier *ident,
const struct type *type)
@@ -69,6 +69,7 @@ scope_insert(struct scope *scope,
o->type = type;
*scope->next = o;
scope->next = &o->next;
+ return o;
}
const struct scope_object *