diff options
-rw-r--r-- | base_cgen.c | 26 | ||||
-rw-r--r-- | cgen.c | 164 | ||||
-rw-r--r-- | decls_cgen.c | 8 | ||||
-rw-r--r-- | main.c | 3 | ||||
-rw-r--r-- | out.c | 19 | ||||
-rw-r--r-- | out.h | 3 | ||||
-rw-r--r-- | parse.c | 1 | ||||
-rw-r--r-- | test.toc | 13 | ||||
-rw-r--r-- | types.c | 11 |
9 files changed, 191 insertions, 57 deletions
diff --git a/base_cgen.c b/base_cgen.c index b8da495..1f0b09c 100644 --- a/base_cgen.c +++ b/base_cgen.c @@ -48,7 +48,7 @@ static void cgen_write(CGenerator *g, const char *fmt, ...) { } /* Used to write an UNNECESSARY space */ -static void cgen_write_space(CGenerator *g) { +static void cgen_space(CGenerator *g) { cgen_write(g, " "); } @@ -134,6 +134,15 @@ static bool cgen_fn_uses_out_param(Type *fn_ret_type) { } } + +static void cgen_anon_var(CGenerator *g, unsigned long v) { + cgen_write(g, "av___%lu", v); +} + +static void cgen_anon_fn(CGenerator *g, unsigned long f) { + cgen_write(g, "af___%lu", f); +} + static void cgen_type_pre(CGenerator *g, Type *t) { switch (t->kind) { case TYPE_VOID: @@ -174,7 +183,7 @@ static void cgen_fn_params(CGenerator *g, Type *param_types, Param *params, size for (size_t i = 0; i < nparams; i++) { if (i) { cgen_write(g, ","); - cgen_write_space(g); + cgen_space(g); } if (param_types) { cgen_type_pre(g, ¶m_types[i]); @@ -193,7 +202,7 @@ static void cgen_fn_params(CGenerator *g, Type *param_types, Param *params, size if (uses_out_param) { if (nparams) { cgen_write(g, ","); - cgen_write_space(g); + cgen_space(g); } /* write out param */ cgen_type_pre(g, ret_type); @@ -221,7 +230,7 @@ static void cgen_type_post(CGenerator *g, Type *t) { if (!uses_out_param) { cgen_type_post(g, ret_type); } - cgen_write_space(g); + cgen_space(g); } break; case TYPE_TUPLE: assert(0); @@ -238,18 +247,17 @@ static void cgen_type_post(CGenerator *g, Type *t) { static bool cgen_fn_name(CGenerator *g, FnExpr *f, Location *where) { if (f->name) { + /* TODO: check block */ if (f->name == g->main_ident) { cgen_write(g, "main__"); + return true; } else { return cgen_ident(g, f->name, where); } } else { - cgen_write(g, "a___"); + cgen_anon_fn(g, f->id); + return true; } - - if (f->id != 0) - cgen_write(g, "%lu", f->id); - return true; } static bool cgen_fn_header(CGenerator *g, FnExpr *f) { @@ -10,7 +10,8 @@ static void cgen_create(CGenerator *g, Identifiers *ids, FILE *c_out, FILE *h_ou g->writing_to = CGEN_WRITING_TO_H; cgen_write(g, "#include <stddef.h>\n" - "#include <stdint.h>\n"); + "#include <stdint.h>\n" + "#include <string.h>\n"); g->writing_to = CGEN_WRITING_TO_C; cgen_write(g, "#include \"%s\"\n", h_filename); @@ -38,6 +39,59 @@ static bool cgen_direct(CGenerator *g, DirectExpr *direct, Location where) { return true; } + +/* generates C statements which must go before an expression. */ +static bool cgen_expr_pre(CGenerator *g, Expression *e) { + switch (e->kind) { + case EXPR_BINARY_OP: + if (!cgen_expr_pre(g, e->binary.lhs)) return false; + if (!cgen_expr_pre(g, e->binary.rhs)) return false; + /* TODO(eventually): Short-circuiting operators will need some work */ + break; + case EXPR_UNARY_OP: + if (!cgen_expr_pre(g, e->unary.of)) return false; + break; + case EXPR_CALL: { + if (!cgen_expr_pre(g, e->call.fn)) return false; + arr_foreach(&e->call.args, Expression, arg) + if (!cgen_expr_pre(g, arg)) + return false; + Type *fn_types = e->call.fn->type.fn.types.data; + Type *ret_type = &fn_types[0]; + if (cgen_fn_uses_out_param(ret_type)) { + /* generate out call */ + e->call.out_var = g->anon_var_count++; + + /* declaration of out variable */ + cgen_type_pre(g, ret_type); + cgen_anon_var(g, e->call.out_var); + cgen_type_post(g, ret_type); + cgen_writeln(g, ";"); + + cgen_expr(g, e->call.fn); + + cgen_write(g, "("); + arr_foreach(&e->call.args, Expression, arg) { + if (arg != e->call.args.data) { + cgen_write(g, ","); + cgen_space(g); + } + if (!cgen_expr(g, arg)) return false; + } + if (e->call.args.len) { + cgen_write(g, ","); + cgen_space(g); + } + cgen_write(g, "&"); + cgen_anon_var(g, e->call.out_var); + cgen_writeln(g, ");"); + } + } break; + default: break; + } + return true; +} + static bool cgen_expr(CGenerator *g, Expression *e) { switch (e->kind) { case EXPR_INT_LITERAL: @@ -98,18 +152,24 @@ static bool cgen_expr(CGenerator *g, Expression *e) { case EXPR_FN: if (!cgen_fn_name(g, &e->fn, &e->where)) return false; break; - case EXPR_CALL: - if (!cgen_expr(g, e->call.fn)) return false; - cgen_write(g, "("); - arr_foreach(&e->call.args, Expression, arg) { - if (arg != e->call.args.data) { - cgen_write(g, ","); - cgen_write_space(g); + case EXPR_CALL: { + Type *fn_types = e->call.fn->type.fn.types.data; + Type *ret_type = &fn_types[0]; + if (cgen_fn_uses_out_param(ret_type)) { /* if there's an out parameter, */ + cgen_anon_var(g, e->call.out_var); /* just use the variable we made earlier */ + } else { + if (!cgen_expr(g, e->call.fn)) return false; + cgen_write(g, "("); + arr_foreach(&e->call.args, Expression, arg) { + if (arg != e->call.args.data) { + cgen_write(g, ","); + cgen_space(g); + } + if (!cgen_expr(g, arg)) return false; } - if (!cgen_expr(g, arg)) return false; + cgen_write(g, ")"); } - cgen_write(g, ")"); - break; + } break; case EXPR_DIRECT: if (!cgen_direct(g, &e->direct, e->where)) return false; break; @@ -150,7 +210,10 @@ static void cgen_zero_value(CGenerator *g, Type *t) { static bool cgen_decl(CGenerator *g, Declaration *d) { size_t i = d->idents.len; - Expression *expr = &d->expr; + if (d->flags & DECL_FLAG_HAS_EXPR) { + if (!cgen_expr_pre(g, &d->expr)) + return false; + } /* because , is left-associative, we want to go backwards */ arr_foreach_reverse(&d->idents, Identifier, ident) { Type *type; @@ -165,19 +228,53 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { return false; } } + if (type->kind == TYPE_ARR) { + /* if you do a : [3]int; translates into int64_t av___23[3] = {0}; int64_t *a = av___23; */ + int has_expr = d->flags & DECL_FLAG_HAS_EXPR; + unsigned long var; + if (!has_expr) { + /* int64_t av___23[3] = {0}; */ + var = g->anon_var_count++; + cgen_type_pre(g, type); + cgen_anon_var(g, var); + cgen_type_post(g, type); + cgen_space(g); + cgen_write(g, "="); + cgen_space(g); + cgen_zero_value(g, type); + cgen_writeln(g, ";"); + } + /* int64_t *a = av___23; */ + cgen_type_pre(g, type->arr.of); + cgen_write(g, "(*"); + cgen_ident(g, *ident, NULL); + cgen_write(g, ")"); + cgen_type_post(g, type->arr.of); + cgen_space(g); + cgen_write(g, "="); + cgen_space(g); + if (has_expr) { + if (!cgen_expr(g, &d->expr)) return false; + } else { + cgen_anon_var(g, var); + } + cgen_writeln(g, ";"); + return true; + } + cgen_type_pre(g, type); - if (d->flags & DECL_FLAG_CONST) { /* TODO: remove this */ - cgen_write_space(g); + if (d->flags & DECL_FLAG_CONST) { /* TODO: remove this (never actually produce constants) */ + cgen_space(g); cgen_write(g, "const"); - cgen_write_space(g); + cgen_space(g); } cgen_ident(g, *ident, NULL); cgen_type_post(g, type); - cgen_write_space(g); + cgen_space(g); cgen_write(g, "="); + cgen_space(g); if (d->flags & DECL_FLAG_HAS_EXPR) { - cgen_write_space(g); - + Expression *expr = &d->expr; if (d->idents.len > 1) { if (expr->kind == EXPR_BINARY_OP && expr->binary.op == BINARY_COMMA) { if (!cgen_expr(g, expr->binary.rhs)) return false; @@ -191,7 +288,6 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { if (!cgen_expr(g, expr)) return false; } } else { - cgen_write_space(g); cgen_zero_value(g, type); } cgen_write(g, "; "); @@ -238,16 +334,32 @@ static bool cgen_block(CGenerator *g, Block *b, BlockExitKind *exit_kind) { } if (exit_kind->is_return) { /* generate return from function */ - if (b->ret_expr && cgen_fn_uses_out_param(&b->ret_expr->type)) { - cgen_write(g, "*out__ = "); - cgen_expr(g, b->ret_expr); - cgen_writeln(g, ";"); - cgen_writeln(g, "return;"); + Expression *ret = b->ret_expr; + if (ret && cgen_fn_uses_out_param(&ret->type)) { + if (ret->type.kind == TYPE_ARR) { + /* returning possibly multi-dimensional arrays */ + size_t total_size = 1; /* product of all dimensions */ + Type *type; + for (type = &ret->type; type->kind == TYPE_ARR; type = type->arr.of) + total_size *= type->arr.n; + /* type is now the base type of the array, e.g. [3][3][3]fn() => fn() */ + cgen_write(g, "memcpy(*out__, "); + if (!cgen_expr(g, b->ret_expr)) return false; + cgen_write(g, ", %lu * sizeof(", total_size); + cgen_type_pre(g, type); + cgen_type_post(g, type); + cgen_writeln(g, ")); return;"); + } else { + cgen_write(g, "*out__ = "); + if (!cgen_expr(g, b->ret_expr)) return false; + cgen_writeln(g, ";"); + cgen_writeln(g, "return;"); + } } else { cgen_write(g, "return"); if (b->ret_expr) { cgen_write(g, " "); - cgen_expr(g, b->ret_expr); + if (!cgen_expr(g, b->ret_expr)) return false; } cgen_writeln(g, ";"); } @@ -267,7 +379,7 @@ static bool cgen_fn(CGenerator *g, FnExpr *f) { if (!cgen_fn_header(g, f)) return false; Block *prev_block = g->block; cgen_block_enter(g, &f->body); - cgen_write_space(g); + cgen_space(g); BlockExitKind e_kind; e_kind.is_return = 1; if (!cgen_block(g, &f->body, &e_kind)) return false; diff --git a/decls_cgen.c b/decls_cgen.c index b05c767..a596f53 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -61,7 +61,7 @@ static bool cgen_decls_stmt(CGenerator *g, Statement *s) { Declaration *d = &s->decl; bool is_const_fn = (d->flags & DECL_FLAG_HAS_EXPR) && (d->flags & DECL_FLAG_CONST) && d->expr.kind == EXPR_FN; - + if (is_const_fn) { /* e.g. foo @= fn() {}; (we want to set the function's name to "foo") */ d->expr.fn.name = *(Identifier*)d->idents.data; @@ -79,14 +79,14 @@ static bool cgen_decls_stmt(CGenerator *g, Statement *s) { cgen_ident(g, *i, NULL); cgen_type_post(g, &d->type); if (d->flags & DECL_FLAG_HAS_EXPR) { /* TODO: check if expr is const */ - cgen_write_space(g); + cgen_space(g); cgen_write(g, "="); - cgen_write_space(g); + cgen_space(g); if (!cgen_expr(g, &d->expr)) return false; } cgen_write(g, ";"); - cgen_write_space(g); + cgen_space(g); } cgen_writeln(g, ""); } @@ -1,5 +1,6 @@ +/* TODO: multi-dimensional arrays are flattened in types.c */ +/* TODO: remove all cgen errors */ /* TODO: don't eval consts in C */ -/* TODO: array assignment (x : [3]int = y;) */ /* TODO: Functions returning fixed-length arrays */ /* TODO: improve error for declaring a keyword, e.g. i8: int = 8123; */ #include "toc.c" @@ -2,14 +2,21 @@ /* toc */ #include <stdio.h> -void foo(int64_t (*out__)[3]) { - int64_t x[3] = {0}; - *out__ = x; - return; +void foo(int64_t (*out__)[3][3]) { + int64_t av___0[3][3] = {{0}}; + int64_t (*x)[3] = av___0; + memcpy(*out__, x, 9 * sizeof(int64_t )); return; } void main__(void) { - int64_t x[3] = foo(); - printf("Foo: %ld\n", (long)x); + int64_t av___1[3][3]; + foo(&av___1); + int64_t (*x)[3] = av___1; + +for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + printf("%ld", x[i][j]); +puts(""); + ; return; } @@ -1,4 +1,5 @@ #include <stddef.h> #include <stdint.h> -void foo(int64_t (*out__)[3]); +#include <string.h> +void foo(int64_t (*out__)[3][3]); void main__(void); @@ -112,6 +112,7 @@ typedef struct Expression { struct { struct Expression *fn; Array args; /* of Expression */ + unsigned long out_var; /* which out variable is used for this call (used by cgen) */ } call; DirectExpr direct; Identifier ident; @@ -1,9 +1,14 @@ #C("#include <stdio.h>\n"); -foo @= fn() [3]int { - x : [3]int; +foo @= fn() [3][3]int { + x : [3][3]int; x }; main @= fn() { - x := foo(); - #C("printf(\"Foo: %ld\\n\", (long)x)"); + x : [3][3]int = foo(); + #C(" +for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + printf(\"%ld\", x[i][j]); +puts(\"\"); + "); }; @@ -254,20 +254,19 @@ static bool type_of_expr(Expression *e, Type *t) { } break; case EXPR_CALL: { Expression *f = e->call.fn; - Type fn_type; if (f->kind == EXPR_IDENT) { /* allow calling a function before declaring it */ - if (!type_of_ident(f->where, f->ident, &fn_type, true)) return false; + if (!type_of_ident(f->where, f->ident, &f->type, true)) return false; } else { - if (!type_of_expr(f, &fn_type)) return false; + if (!type_of_expr(f, &f->type)) return false; } - if (fn_type.kind != TYPE_FN) { - char *type = type_to_str(&fn_type); + if (f->type.kind != TYPE_FN) { + char *type = type_to_str(&f->type); err_print(e->where, "Calling non-function (type %s).", type); return false; } /* TODO: Make sure args match fn type */ - *t = *(Type*)fn_type.fn.types.data; + *t = *(Type*)f->type.fn.types.data; break; } case EXPR_DIRECT: |