summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base_cgen.c26
-rw-r--r--cgen.c164
-rw-r--r--decls_cgen.c8
-rw-r--r--main.c3
-rw-r--r--out.c19
-rw-r--r--out.h3
-rw-r--r--parse.c1
-rw-r--r--test.toc13
-rw-r--r--types.c11
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, &param_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) {
diff --git a/cgen.c b/cgen.c
index b694039..7ff2308 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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, "");
}
diff --git a/main.c b/main.c
index c875f4b..120ebe8 100644
--- a/main.c
+++ b/main.c
@@ -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"
diff --git a/out.c b/out.c
index 720322c..cd8f28b 100644
--- a/out.c
+++ b/out.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;
}
diff --git a/out.h b/out.h
index 32435db..a8d55c8 100644
--- a/out.h
+++ b/out.h
@@ -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);
diff --git a/parse.c b/parse.c
index 6e062c6..49668fd 100644
--- a/parse.c
+++ b/parse.c
@@ -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;
diff --git a/test.toc b/test.toc
index 6c9ff18..5c5b9fc 100644
--- a/test.toc
+++ b/test.toc
@@ -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(\"\");
+ ");
};
diff --git a/types.c b/types.c
index 80f46ec..da55937 100644
--- a/types.c
+++ b/types.c
@@ -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: