summaryrefslogtreecommitdiff
path: root/archive/cgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'archive/cgen.c')
-rw-r--r--archive/cgen.c463
1 files changed, 0 insertions, 463 deletions
diff --git a/archive/cgen.c b/archive/cgen.c
deleted file mode 100644
index 7ff2308..0000000
--- a/archive/cgen.c
+++ /dev/null
@@ -1,463 +0,0 @@
-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;
-}