harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit acce85b011f7c1153e1ddd80f31338577d0f452f
parent c00a13d5662dd512e9505d18a37bb331332f7575
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue, 22 Dec 2020 09:43:31 -0500

check, gen: bindings

Diffstat:
Minclude/expr.h | 7+++++++
Minclude/gen.h | 7+++++++
Minclude/qbe.h | 2+-
Minclude/scope.h | 3+--
Msrc/check.c | 47+++++++++++++++++++++++++++++++++++++++++++++++
Msrc/gen.c | 89++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/qbe.c | 15+++++++++++++--
Msrc/scope.c | 3++-
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 *