commit dfe1a0078939de5a486a7730ef423061594fa03d
parent b83bbfd0855cc65db0b7b8fd8f03a1a85e4b8a07
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 24 Dec 2020 12:26:46 -0500
Implement prototypes
Diffstat:
4 files changed, 39 insertions(+), 15 deletions(-)
diff --git a/include/check.h b/include/check.h
@@ -38,7 +38,7 @@ struct declaration {
};
struct declarations {
- struct declaration decl;
+ struct declaration *decl;
struct declarations *next;
};
diff --git a/src/check.c b/src/check.c
@@ -421,11 +421,14 @@ check_expression(struct context *ctx,
trleave(TR_CHECK, NULL);
}
-static void
+static struct declaration *
check_function(struct context *ctx,
- const struct ast_decl *adecl,
- struct declaration *decl)
+ const struct ast_decl *adecl)
{
+ if (!adecl->function.body) {
+ return NULL; // Prototype
+ }
+
const struct ast_function_decl *afndecl = &adecl->function;
trenter(TR_CHECK, "function");
assert(!afndecl->symbol); // TODO
@@ -438,6 +441,8 @@ check_function(struct context *ctx,
const struct type *fntype = type_store_lookup_atype(
&ctx->store, &fn_atype);
assert(fntype); // Invariant
+
+ struct declaration *decl = calloc(1, sizeof(struct declaration));
decl->type = DECL_FUNC;
decl->func.type = fntype;
// TODO: Rewrite ident to be a member of the unit's namespace
@@ -473,10 +478,10 @@ check_function(struct context *ctx,
"%s function cannot be exported", flags);
}
- // TODO: Add declaration to unit scope
-
+ scope_insert(ctx->unit, &decl->ident, decl->func.type);
scope_pop(&ctx->scope, TR_CHECK);
trleave(TR_CHECK, NULL);
+ return decl;
}
static void
@@ -486,14 +491,11 @@ check_declarations(struct context *ctx,
{
trenter(TR_CHECK, "declarations");
while (adecls) {
- struct declarations *decls = *next =
- calloc(1, sizeof(struct declarations));
- struct declaration *decl = &decls->decl;
+ struct declaration *decl;
const struct ast_decl *adecl = &adecls->decl;
- decl->exported = adecl->exported;
switch (adecl->decl_type) {
case AST_DECL_FUNC:
- check_function(ctx, adecl, decl);
+ decl = check_function(ctx, adecl);
break;
case AST_DECL_TYPE:
assert(0); // TODO
@@ -502,8 +504,16 @@ check_declarations(struct context *ctx,
case AST_DECL_CONST:
assert(0); // TODO
}
+
+ if (decl) {
+ struct declarations *decls = *next =
+ calloc(1, sizeof(struct declarations));
+ decl->exported = adecl->exported;
+ decls->decl = decl;
+ next = &decls->next;
+ }
+
adecls = adecls->next;
- next = &decls->next;
}
trleave(TR_CHECK, NULL);
}
@@ -524,6 +534,10 @@ scan_function(struct context *ctx, const struct ast_function_decl *decl)
char buf[1024];
identifier_unparse_static(&decl->ident, buf, sizeof(buf));
trleave(TR_SCAN, "func %s", buf);
+
+ if (!decl->body) {
+ scope_insert(ctx->unit, &decl->ident, fntype);
+ }
}
static void
diff --git a/src/gen.c b/src/gen.c
@@ -574,7 +574,7 @@ gen(const struct unit *unit, struct qbe_program *out)
assert(decls); // At least one is required
trenter(TR_GEN, "gen");
while (decls) {
- gen_decl(&ctx, &decls->decl);
+ gen_decl(&ctx, decls->decl);
decls = decls->next;
}
trleave(TR_GEN, NULL);
diff --git a/src/parse.c b/src/parse.c
@@ -1175,8 +1175,18 @@ parse_fn_decl(struct parser *par, struct ast_function_decl *decl)
want(par, T_FN, NULL);
parse_identifier(par, &decl->ident);
parse_prototype(par, &decl->prototype);
- want(par, T_EQUAL, NULL);
- decl->body = parse_compound_expression(par);
+
+ switch (lex(par->lex, &tok)) {
+ case T_EQUAL:
+ decl->body = parse_compound_expression(par);
+ break;
+ case T_SEMICOLON:
+ unlex(par->lex, &tok);
+ decl->body = NULL; // Prototype
+ break;
+ default:
+ synassert(false, &tok, T_EQUAL, T_SEMICOLON, T_EOF);
+ }
char symbol[1024], buf[1024];
if (decl->symbol) {