diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-10-09 11:16:07 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-10-09 11:16:07 -0400 |
commit | a2f5cd5069df70436228c8f6cb6ed82edcdcaae8 (patch) | |
tree | 85a3aa174a9b30d562a2dab9860e141719261de0 | |
parent | 621359c153dbe378264d9ce96caf467b52a29f0c (diff) |
started cgen
-rw-r--r-- | archive/base_cgen.c (renamed from base_cgen.c) | 0 | ||||
-rw-r--r-- | archive/cgen.c | 463 | ||||
-rw-r--r-- | archive/decls_cgen.c | 106 | ||||
-rw-r--r-- | cast.toc | 3 | ||||
-rw-r--r-- | cgen.c | 470 | ||||
-rw-r--r-- | decls_cgen.c | 109 | ||||
-rw-r--r-- | main.c | 15 | ||||
-rw-r--r-- | out.c | 2 | ||||
-rw-r--r-- | prev.toc | 14 | ||||
-rw-r--r-- | test.toc | 13 | ||||
-rw-r--r-- | toc.c | 2 | ||||
-rw-r--r-- | types.c | 8 | ||||
-rw-r--r-- | types.h | 1 |
13 files changed, 633 insertions, 573 deletions
diff --git a/base_cgen.c b/archive/base_cgen.c index d773ba9..d773ba9 100644 --- a/base_cgen.c +++ b/archive/base_cgen.c diff --git a/archive/cgen.c b/archive/cgen.c new file mode 100644 index 0000000..7ff2308 --- /dev/null +++ b/archive/cgen.c @@ -0,0 +1,463 @@ +static void cgen_create(CGenerator *g, Identifiers *ids, FILE *c_out, FILE *h_out, const char *h_filename) { + g->c_out = c_out; + g->h_out = h_out; + g->anon_fn_count = 0; + g->anon_var_count = 0; + g->indent_level = 0; + g->block = NULL; + g->indent_next = true; + g->main_ident = ident_get(ids, "main"); + + g->writing_to = CGEN_WRITING_TO_H; + cgen_write(g, "#include <stddef.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); + cgen_writeln(g, ""); /* extra newline between includes and code */ +} + +static bool cgen_direct(CGenerator *g, DirectExpr *direct, Location where) { + switch (direct->which) { + case DIRECT_C: { + Expression *args = direct->args.data; + size_t nargs = direct->args.len; + if (nargs != 1) { + err_print(where, "Expected 1 argument to #C directive, but got %lu.", nargs); + } + /* TODO: compile-time constants */ + if (args[0].kind != EXPR_STR_LITERAL) { + err_print(args[0].where, "Argument to #C directive must be a string literal."); + } + cgen_write(g, "%s", args[0].strl.str); + } break; + case DIRECT_COUNT: + assert(0); + return false; + } + 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: + cgen_write(g, "%lld", e->intl); + break; + case EXPR_FLOAT_LITERAL: + /* TODO: more precision */ + cgen_write(g, "%f", (double)e->floatl); + break; + case EXPR_STR_LITERAL: + cgen_write(g, "\""); + /* OPTIM: Maybe don't use i? this will probably be optimized by the compiler though... */ + for (size_t i = 0; i < e->strl.len; i++) { + /* TODO: Print ordinary characters nicely */ + cgen_write(g, "\\x%02x", e->strl.str[i]); + } + cgen_write(g, "\""); + break; + case EXPR_IDENT: + if (!cgen_ident(g, e->ident, &e->where)) return false; + break; + case EXPR_BINARY_OP: + cgen_write(g, "("); + if (!cgen_expr(g, e->binary.lhs)) return false; + switch (e->binary.op) { + case BINARY_PLUS: + cgen_write(g, "+"); + break; + case BINARY_MINUS: + cgen_write(g, "-"); + break; + case BINARY_SET: + cgen_write(g, "="); + break; + case BINARY_AT_INDEX: + cgen_write(g, "["); + break; + case BINARY_COMMA: + assert(0); + return false; + } + if (!cgen_expr(g, e->binary.rhs)) return false; + if (e->binary.op == BINARY_AT_INDEX) { + cgen_write(g, "]"); + } + cgen_write(g, ")"); + break; + case EXPR_UNARY_OP: + cgen_write(g, "("); + switch (e->unary.op) { + case UNARY_MINUS: + cgen_write(g, "-"); + break; + } + if (!cgen_expr(g, e->unary.of)) return false; + cgen_write(g, ")"); + break; + case EXPR_FN: + if (!cgen_fn_name(g, &e->fn, &e->where)) return false; + break; + 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; + } + cgen_write(g, ")"); + } + } break; + case EXPR_DIRECT: + if (!cgen_direct(g, &e->direct, e->where)) return false; + break; + } + return true; +} + +static bool cgen_stmt(CGenerator *g, Statement *s); + +static void cgen_zero_value(CGenerator *g, Type *t) { + switch (t->kind) { + case TYPE_VOID: /* we should never need this */ + assert(0); + break; + case TYPE_FN: + cgen_write(g, "NULL"); + break; + case TYPE_ARR: + cgen_write(g, "{"); + cgen_zero_value(g, t->arr.of); + cgen_write(g, "}"); + break; + case TYPE_TUPLE: + assert(0); + break; + case TYPE_BUILTIN: + if (type_builtin_is_numerical(t->builtin)) { + cgen_write(g, "0"); + } else { + assert(0); + } + break; + case TYPE_UNKNOWN: + assert(0); + break; + } +} + +static bool cgen_decl(CGenerator *g, Declaration *d) { + size_t i = d->idents.len; + 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; + if (d->idents.len > 1) { + /* it's a tuple! */ + type = &(((Type*)d->type.tuple.data)[--i]); + } else { + type = &d->type; + if (type->kind == TYPE_TUPLE) { + /* TODO */ + err_print(d->where, "Direct declaration of tuples is not supported yet."); + 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 (never actually produce constants) */ + cgen_space(g); + cgen_write(g, "const"); + cgen_space(g); + } + cgen_ident(g, *ident, NULL); + cgen_type_post(g, type); + cgen_space(g); + cgen_write(g, "="); + cgen_space(g); + if (d->flags & DECL_FLAG_HAS_EXPR) { + 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; + expr = expr->binary.lhs; /* ((3,4),5),6 => (3,4),5 */ + } else { + /* last iteration */ + if (!cgen_expr(g, expr)) return false; + } + + } else { + if (!cgen_expr(g, expr)) return false; + } + } else { + cgen_zero_value(g, type); + } + cgen_write(g, "; "); + } + cgen_writeln(g, ""); + return true; +} + +static bool cgen_stmt(CGenerator *g, Statement *s) { + switch (s->kind) { + case STMT_EXPR: + if (!cgen_expr(g, &s->expr)) + return false; + cgen_writeln(g, ";"); + break; + case STMT_DECL: { + Declaration *d = &s->decl; + if ((d->flags & DECL_FLAG_HAS_EXPR) && (d->flags & DECL_FLAG_CONST)) + if (d->expr.kind == EXPR_FN) + return true; /* already dealt with below */ + + return cgen_decl(g, &s->decl); + } + } + return true; +} + +static bool cgen_fns_in_stmt(CGenerator *g, Statement *s); + +typedef struct { + bool is_return; /* true => this is a function return */ + unsigned long var_no; /* if is_return = false, set the anonymous variable with this number to the return value. */ + const char *exit_with; /* how to exit this block in C, e.g. "break" (not needed if is_return = true). */ +} BlockExitKind; + +/* generates a block but not the functions, etc. inside it */ +static bool cgen_block(CGenerator *g, Block *b, BlockExitKind *exit_kind) { + bool success = true; + cgen_writeln(g, "{"); + g->indent_level++; + arr_foreach(&b->stmts, Statement, s) { + if (!cgen_stmt(g, s)) + success = false; + } + if (exit_kind->is_return) { + /* generate return from function */ + 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, " "); + if (!cgen_expr(g, b->ret_expr)) return false; + } + cgen_writeln(g, ";"); + } + } else { + err_print(b->ret_expr->where, "TODO"); + return false; + } + if (success) { + g->indent_level--; + cgen_writeln(g, "}"); + } + return success; +} + +/* Generates function definition, and the definitions of all functions inside this */ +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_space(g); + BlockExitKind e_kind; + e_kind.is_return = 1; + if (!cgen_block(g, &f->body, &e_kind)) return false; + + bool ret = true; + arr_foreach(&f->body.stmts, Statement, stmt) { + if (!cgen_fns_in_stmt(g, stmt)) ret = false; + } + cgen_block_exit(g, prev_block); + return ret; +} + +static bool cgen_fns_in_expr(CGenerator *g, Expression *e) { + switch (e->kind) { + case EXPR_FN: + return cgen_fn(g, &e->fn); + case EXPR_CALL: + return cgen_fns_in_expr(g, e->call.fn); + default: return true; + } +} + +static bool cgen_fns_in_stmt(CGenerator *g, Statement *s) { + switch (s->kind) { + case STMT_EXPR: + if (s->expr.kind == EXPR_FN) { + warn_print(s->where, "Statement of function has no effect (try assigning the function to a variable)."); + } else { + return cgen_fns_in_expr(g, &s->expr); + } + break; + case STMT_DECL: { + Declaration *d = &s->decl; + if (d->flags & DECL_FLAG_HAS_EXPR) + return cgen_fns_in_expr(g, &d->expr); + } break; + } + return true; +} + +/* generate a statement at top level, including any functions in it. */ +static bool cgen_stmt_top(CGenerator *g, Statement *s) { + if (!cgen_fns_in_stmt(g, s)) return false; + switch (s->kind) { + case STMT_EXPR: { + Expression *e = &s->expr; + bool ignored = true; + switch (e->kind) { + case EXPR_DIRECT: + switch (e->direct.which) { + case DIRECT_C: + ignored = false; + cgen_direct(g, &e->direct, e->where); + break; + case DIRECT_COUNT: assert(0); break; + } + default: break; + } + if (ignored) + warn_print(e->where, "Expression at top level currently ignored."); /* TODO */ + } break; + case STMT_DECL: break; + } + return true; +} + +static bool cgen_file(CGenerator *g, ParsedFile *f) { + cgen_write_line_comment(g, "toc"); + bool ret = true; + if (!cgen_decls_file(g, f)) return false; + arr_foreach(&f->stmts, Statement, s) { + if (!cgen_stmt_top(g, s)) return false; + } + g->writing_to = CGEN_WRITING_TO_C; + /* write actual main function */ + cgen_write(g, "\nint main(void) {\n" + "\tmain__();\n" + "\treturn 0;\n" + "}\n"); + return ret; +} diff --git a/archive/decls_cgen.c b/archive/decls_cgen.c new file mode 100644 index 0000000..a596f53 --- /dev/null +++ b/archive/decls_cgen.c @@ -0,0 +1,106 @@ +/* C declarations of functions and global variables. e must be a function expression */ +static bool cgen_decl_fn(CGenerator *g, FnExpr *f) { + /* assign an ID to the function */ + if (f->name && g->block == NULL) { + f->id = f->name->c_fn_reps++; + } else { + f->id = g->anon_fn_count++; + } + + if (!cgen_fn_header(g, f)) return false; + cgen_writeln(g, ";"); + return true; +} + +static bool cgen_decls_stmt(CGenerator *g, Statement *s); + +static bool cgen_decls_expr(CGenerator *g, Expression *e) { + switch (e->kind) { + case EXPR_FN: { + FnExpr *f = &e->fn; + if (f->name && g->block == NULL) { /* write named function prototypes in global scope to header file */ + g->writing_to = CGEN_WRITING_TO_H; + } else { + g->writing_to = CGEN_WRITING_TO_C; + } + if (!cgen_decl_fn(g, f)) + return false; + g->writing_to = CGEN_WRITING_TO_C; + + + bool ret = true; + Block *prev_block = g->block; + cgen_block_enter(g, &f->body); + arr_foreach(&f->body.stmts, Statement, s) { + if (!cgen_decls_stmt(g, s)) + ret = false; + } + cgen_block_exit(g, prev_block); + return ret; + } + case EXPR_CALL: + if (!cgen_decls_expr(g, e->call.fn)) + return false; + arr_foreach(&e->call.args, Expression, arg) { + if (!cgen_decls_expr(g, arg)) + return false; + } + break; + default: break; + } + return true; +} + + +static bool cgen_expr(CGenerator *g, Expression *e); +static bool cgen_decls_stmt(CGenerator *g, Statement *s) { + switch (s->kind) { + case STMT_EXPR: + return cgen_decls_expr(g, &s->expr); + case STMT_DECL: { + 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; + } + + if (d->flags & DECL_FLAG_HAS_EXPR) { + cgen_decls_expr(g, &d->expr); + } + + if (!is_const_fn) { + if (g->block == NULL) { + /* declare this/these global variable(s) */ + arr_foreach(&d->idents, Identifier, i) { + cgen_type_pre(g, &d->type); + 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_space(g); + cgen_write(g, "="); + cgen_space(g); + if (!cgen_expr(g, &d->expr)) + return false; + } + cgen_write(g, ";"); + cgen_space(g); + } + cgen_writeln(g, ""); + } + } + + } break; + } + return true; +} + +static bool cgen_decls_file(CGenerator *g, ParsedFile *f) { + arr_foreach(&f->stmts, Statement, s) { + if (!cgen_decls_stmt(g, s)) + return false; + } + return true; +} diff --git a/cast.toc b/cast.toc new file mode 100644 index 0000000..d8c6381 --- /dev/null +++ b/cast.toc @@ -0,0 +1,3 @@ +main @= fn() { + +};
\ No newline at end of file @@ -1,463 +1,27 @@ -static void cgen_create(CGenerator *g, Identifiers *ids, FILE *c_out, FILE *h_out, const char *h_filename) { - g->c_out = c_out; - g->h_out = h_out; - g->anon_fn_count = 0; - g->anon_var_count = 0; - g->indent_level = 0; - g->block = NULL; - g->indent_next = true; - g->main_ident = ident_get(ids, "main"); - - g->writing_to = CGEN_WRITING_TO_H; - cgen_write(g, "#include <stddef.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); - cgen_writeln(g, ""); /* extra newline between includes and code */ -} - -static bool cgen_direct(CGenerator *g, DirectExpr *direct, Location where) { - switch (direct->which) { - case DIRECT_C: { - Expression *args = direct->args.data; - size_t nargs = direct->args.len; - if (nargs != 1) { - err_print(where, "Expected 1 argument to #C directive, but got %lu.", nargs); - } - /* TODO: compile-time constants */ - if (args[0].kind != EXPR_STR_LITERAL) { - err_print(args[0].where, "Argument to #C directive must be a string literal."); - } - cgen_write(g, "%s", args[0].strl.str); - } break; - case DIRECT_COUNT: - assert(0); - return false; - } - 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: - cgen_write(g, "%lld", e->intl); - break; - case EXPR_FLOAT_LITERAL: - /* TODO: more precision */ - cgen_write(g, "%f", (double)e->floatl); - break; - case EXPR_STR_LITERAL: - cgen_write(g, "\""); - /* OPTIM: Maybe don't use i? this will probably be optimized by the compiler though... */ - for (size_t i = 0; i < e->strl.len; i++) { - /* TODO: Print ordinary characters nicely */ - cgen_write(g, "\\x%02x", e->strl.str[i]); - } - cgen_write(g, "\""); - break; - case EXPR_IDENT: - if (!cgen_ident(g, e->ident, &e->where)) return false; - break; - case EXPR_BINARY_OP: - cgen_write(g, "("); - if (!cgen_expr(g, e->binary.lhs)) return false; - switch (e->binary.op) { - case BINARY_PLUS: - cgen_write(g, "+"); - break; - case BINARY_MINUS: - cgen_write(g, "-"); - break; - case BINARY_SET: - cgen_write(g, "="); - break; - case BINARY_AT_INDEX: - cgen_write(g, "["); - break; - case BINARY_COMMA: - assert(0); - return false; - } - if (!cgen_expr(g, e->binary.rhs)) return false; - if (e->binary.op == BINARY_AT_INDEX) { - cgen_write(g, "]"); - } - cgen_write(g, ")"); - break; - case EXPR_UNARY_OP: - cgen_write(g, "("); - switch (e->unary.op) { - case UNARY_MINUS: - cgen_write(g, "-"); - break; - } - if (!cgen_expr(g, e->unary.of)) return false; - cgen_write(g, ")"); - break; - case EXPR_FN: - if (!cgen_fn_name(g, &e->fn, &e->where)) return false; - break; - 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; - } - cgen_write(g, ")"); - } - } break; - case EXPR_DIRECT: - if (!cgen_direct(g, &e->direct, e->where)) return false; - break; - } - return true; -} - -static bool cgen_stmt(CGenerator *g, Statement *s); - -static void cgen_zero_value(CGenerator *g, Type *t) { - switch (t->kind) { - case TYPE_VOID: /* we should never need this */ - assert(0); - break; - case TYPE_FN: - cgen_write(g, "NULL"); - break; - case TYPE_ARR: - cgen_write(g, "{"); - cgen_zero_value(g, t->arr.of); - cgen_write(g, "}"); - break; - case TYPE_TUPLE: - assert(0); - break; - case TYPE_BUILTIN: - if (type_builtin_is_numerical(t->builtin)) { - cgen_write(g, "0"); - } else { - assert(0); - } - break; - case TYPE_UNKNOWN: - assert(0); - break; - } -} - -static bool cgen_decl(CGenerator *g, Declaration *d) { - size_t i = d->idents.len; - 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; - if (d->idents.len > 1) { - /* it's a tuple! */ - type = &(((Type*)d->type.tuple.data)[--i]); - } else { - type = &d->type; - if (type->kind == TYPE_TUPLE) { - /* TODO */ - err_print(d->where, "Direct declaration of tuples is not supported yet."); - 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 (never actually produce constants) */ - cgen_space(g); - cgen_write(g, "const"); - cgen_space(g); - } - cgen_ident(g, *ident, NULL); - cgen_type_post(g, type); - cgen_space(g); - cgen_write(g, "="); - cgen_space(g); - if (d->flags & DECL_FLAG_HAS_EXPR) { - 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; - expr = expr->binary.lhs; /* ((3,4),5),6 => (3,4),5 */ - } else { - /* last iteration */ - if (!cgen_expr(g, expr)) return false; - } - - } else { - if (!cgen_expr(g, expr)) return false; - } - } else { - cgen_zero_value(g, type); - } - cgen_write(g, "; "); - } - cgen_writeln(g, ""); - return true; -} - -static bool cgen_stmt(CGenerator *g, Statement *s) { - switch (s->kind) { - case STMT_EXPR: - if (!cgen_expr(g, &s->expr)) - return false; - cgen_writeln(g, ";"); - break; - case STMT_DECL: { - Declaration *d = &s->decl; - if ((d->flags & DECL_FLAG_HAS_EXPR) && (d->flags & DECL_FLAG_CONST)) - if (d->expr.kind == EXPR_FN) - return true; /* already dealt with below */ - - return cgen_decl(g, &s->decl); - } - } - return true; -} - -static bool cgen_fns_in_stmt(CGenerator *g, Statement *s); - typedef struct { - bool is_return; /* true => this is a function return */ - unsigned long var_no; /* if is_return = false, set the anonymous variable with this number to the return value. */ - const char *exit_with; /* how to exit this block in C, e.g. "break" (not needed if is_return = true). */ -} BlockExitKind; - -/* generates a block but not the functions, etc. inside it */ -static bool cgen_block(CGenerator *g, Block *b, BlockExitKind *exit_kind) { - bool success = true; - cgen_writeln(g, "{"); - g->indent_level++; - arr_foreach(&b->stmts, Statement, s) { - if (!cgen_stmt(g, s)) - success = false; - } - if (exit_kind->is_return) { - /* generate return from function */ - 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, " "); - if (!cgen_expr(g, b->ret_expr)) return false; - } - cgen_writeln(g, ";"); - } - } else { - err_print(b->ret_expr->where, "TODO"); - return false; - } - if (success) { - g->indent_level--; - cgen_writeln(g, "}"); - } - return success; -} - -/* Generates function definition, and the definitions of all functions inside this */ -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_space(g); - BlockExitKind e_kind; - e_kind.is_return = 1; - if (!cgen_block(g, &f->body, &e_kind)) return false; + FILE *outc; + long ident_counter; +} CGenerator; - bool ret = true; - arr_foreach(&f->body.stmts, Statement, stmt) { - if (!cgen_fns_in_stmt(g, stmt)) ret = false; - } - cgen_block_exit(g, prev_block); - return ret; +static void cgen_create(CGenerator *g, FILE *out) { + g->outc = out; + g->ident_counter = 0; } -static bool cgen_fns_in_expr(CGenerator *g, Expression *e) { - switch (e->kind) { - case EXPR_FN: - return cgen_fn(g, &e->fn); - case EXPR_CALL: - return cgen_fns_in_expr(g, e->call.fn); - default: return true; - } +static inline FILE *cgen_writing_to(CGenerator *g) { + return g->outc; /* for now */ } -static bool cgen_fns_in_stmt(CGenerator *g, Statement *s) { - switch (s->kind) { - case STMT_EXPR: - if (s->expr.kind == EXPR_FN) { - warn_print(s->where, "Statement of function has no effect (try assigning the function to a variable)."); - } else { - return cgen_fns_in_expr(g, &s->expr); - } - break; - case STMT_DECL: { - Declaration *d = &s->decl; - if (d->flags & DECL_FLAG_HAS_EXPR) - return cgen_fns_in_expr(g, &d->expr); - } break; - } - return true; +static void cgen_write(CGenerator *g, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vfprintf(cgen_writing_to(g), fmt, args); + va_end(args); } -/* generate a statement at top level, including any functions in it. */ -static bool cgen_stmt_top(CGenerator *g, Statement *s) { - if (!cgen_fns_in_stmt(g, s)) return false; - switch (s->kind) { - case STMT_EXPR: { - Expression *e = &s->expr; - bool ignored = true; - switch (e->kind) { - case EXPR_DIRECT: - switch (e->direct.which) { - case DIRECT_C: - ignored = false; - cgen_direct(g, &e->direct, e->where); - break; - case DIRECT_COUNT: assert(0); break; - } - default: break; - } - if (ignored) - warn_print(e->where, "Expression at top level currently ignored."); /* TODO */ - } break; - case STMT_DECL: break; - } - return true; -} +static void cgen_decls_file(CGenerator *g, ParsedFile *f); -static bool cgen_file(CGenerator *g, ParsedFile *f) { - cgen_write_line_comment(g, "toc"); - bool ret = true; - if (!cgen_decls_file(g, f)) return false; - arr_foreach(&f->stmts, Statement, s) { - if (!cgen_stmt_top(g, s)) return false; - } - g->writing_to = CGEN_WRITING_TO_C; - /* write actual main function */ - cgen_write(g, "\nint main(void) {\n" - "\tmain__();\n" - "\treturn 0;\n" - "}\n"); - return ret; +static void cgen_file(CGenerator *g, ParsedFile *f) { + cgen_decls_file(g, f); + cgen_write(g, "/* code */\n"); } diff --git a/decls_cgen.c b/decls_cgen.c index a596f53..bce26c7 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -1,106 +1,17 @@ -/* C declarations of functions and global variables. e must be a function expression */ -static bool cgen_decl_fn(CGenerator *g, FnExpr *f) { - /* assign an ID to the function */ - if (f->name && g->block == NULL) { - f->id = f->name->c_fn_reps++; - } else { - f->id = g->anon_fn_count++; - } - - if (!cgen_fn_header(g, f)) return false; - cgen_writeln(g, ";"); - return true; -} - -static bool cgen_decls_stmt(CGenerator *g, Statement *s); - -static bool cgen_decls_expr(CGenerator *g, Expression *e) { - switch (e->kind) { - case EXPR_FN: { - FnExpr *f = &e->fn; - if (f->name && g->block == NULL) { /* write named function prototypes in global scope to header file */ - g->writing_to = CGEN_WRITING_TO_H; - } else { - g->writing_to = CGEN_WRITING_TO_C; - } - if (!cgen_decl_fn(g, f)) - return false; - g->writing_to = CGEN_WRITING_TO_C; - - - bool ret = true; - Block *prev_block = g->block; - cgen_block_enter(g, &f->body); - arr_foreach(&f->body.stmts, Statement, s) { - if (!cgen_decls_stmt(g, s)) - ret = false; - } - cgen_block_exit(g, prev_block); - return ret; - } - case EXPR_CALL: - if (!cgen_decls_expr(g, e->call.fn)) - return false; - arr_foreach(&e->call.args, Expression, arg) { - if (!cgen_decls_expr(g, arg)) - return false; - } - break; - default: break; - } - return true; -} - - -static bool cgen_expr(CGenerator *g, Expression *e); -static bool cgen_decls_stmt(CGenerator *g, Statement *s) { +static void cgen_decls_stmt(CGenerator *g, Statement *s) { switch (s->kind) { + case STMT_DECL: + break; case STMT_EXPR: - return cgen_decls_expr(g, &s->expr); - case STMT_DECL: { - 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; - } - - if (d->flags & DECL_FLAG_HAS_EXPR) { - cgen_decls_expr(g, &d->expr); - } - - if (!is_const_fn) { - if (g->block == NULL) { - /* declare this/these global variable(s) */ - arr_foreach(&d->idents, Identifier, i) { - cgen_type_pre(g, &d->type); - 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_space(g); - cgen_write(g, "="); - cgen_space(g); - if (!cgen_expr(g, &d->expr)) - return false; - } - cgen_write(g, ";"); - cgen_space(g); - } - cgen_writeln(g, ""); - } - } - - } break; + break; + case STMT_RET: + break; } - return true; } -static bool cgen_decls_file(CGenerator *g, ParsedFile *f) { - arr_foreach(&f->stmts, Statement, s) { - if (!cgen_decls_stmt(g, s)) - return false; +static void cgen_decls_file(CGenerator *g, ParsedFile *f) { + cgen_write(g, "/* declarations */\n"); + arr_foreach(f->stmts, Statement, s) { + cgen_decls_stmt(g, s); } - return true; } @@ -1,7 +1,5 @@ /* TODO: -improve casting: do you really need "as"? -fix void fn type re-do cgen any odd number of "s for a string */ @@ -67,7 +65,6 @@ int main(int argc, char **argv) { printf("\n\n-----\n\n"); - block_enter(NULL, f.stmts); /* enter global scope */ Typer tr; Evaluator ev; evalr_create(&ev); @@ -78,7 +75,15 @@ int main(int argc, char **argv) { } parse_printing_after_types = true; fprint_parsed_file(stdout, &f); - block_exit(NULL, f.stmts); /* exit global scope */ + + FILE *out = fopen("out.c", "w"); + if (!out) { + err_fprint(TEXT_IMPORTANT("Could not open output file (out.c).\n")); + return EXIT_FAILURE; + } + CGenerator g; + cgen_create(&g, out); + cgen_file(&g, &f); tokr_free(&t); @@ -87,7 +92,7 @@ int main(int argc, char **argv) { parser_free(&p); typer_free(&tr); evalr_free(&ev); - /* fclose(c_out); */ + fclose(out); /* fclose(h_out); */ idents_free(&file_idents); } @@ -0,0 +1,2 @@ +/* declarations */ +/* code */ diff --git a/prev.toc b/prev.toc new file mode 100644 index 0000000..83f01d3 --- /dev/null +++ b/prev.toc @@ -0,0 +1,14 @@ +main @= fn() { + add3 @= fn(x : int, y : int, z : int) int { + x + y + z + }; + add2 @= fn(x : int, y : int) int { + x + y + }; + id @= fn(x : int) int { x }; + + a1 : [id(7)]int; + a2 : [add2(53, 3)]int; + a3 : [add3(3,1,2)]f32; + GHJK : [{x := 5; x}]f32; +};
\ No newline at end of file @@ -1,14 +1,3 @@ main @= fn() { - add3 @= fn(x : int, y : int, z : int) int { - x + y + z - }; - add2 @= fn(x : int, y : int) int { - x + y - }; - id @= fn(x : int) int { x }; - - a1 : [id(7)]int; - a2 : [add2(53, 3)]int; - a3 : [add3(3,1,2)]f32; - GHJK : [{x := 5; x}]f32; + x := 5; };
\ No newline at end of file @@ -24,5 +24,7 @@ #include "scope.c" #include "eval.c" #include "types.c" +#include "cgen.c" +#include "decls_cgen.c" #include "tests.c" @@ -352,7 +352,7 @@ static Status type_cast_status(Type *from, Type *to) { case TYPE_BUILTIN: return STATUS_NONE; case TYPE_ARR: return STATUS_ERR; case TYPE_PTR: return STATUS_WARN; - case TYPE_FN: return STATUS_WARN; + case TYPE_FN: return STATUS_ERR; case TYPE_TUPLE: return STATUS_ERR; } break; @@ -372,8 +372,6 @@ static Status type_cast_status(Type *from, Type *to) { break; case TYPE_TUPLE: return STATUS_ERR; case TYPE_FN: - if (to->kind == TYPE_BUILTIN && type_builtin_is_int(to->builtin)) - return STATUS_WARN; if (to->kind == TYPE_PTR || to->kind == TYPE_FN) return STATUS_WARN; return STATUS_ERR; @@ -1068,11 +1066,13 @@ static void typer_create(Typer *tr, Evaluator *ev) { static bool types_file(Typer *tr, ParsedFile *f) { bool ret = true; + block_enter(NULL, f->stmts); /* enter global scope */ arr_foreach(f->stmts, Statement, s) { if (!types_stmt(tr, s)) { ret = false; } - } + } + block_exit(NULL, f->stmts); /* exit global scope */ return ret; } @@ -94,6 +94,7 @@ root.children[low part of 1st char].children[high part of 1st char] typedef struct IdentTree { /* zero value is an empty trie */ uint16_t depth; + uint16_t flags; unsigned char index_in_parent; /* index of this in .parent.children */ struct IdentTree *parent; struct IdentTree *children[TREE_NCHILDREN]; |