summaryrefslogtreecommitdiff
path: root/cgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'cgen.c')
-rw-r--r--cgen.c220
1 files changed, 206 insertions, 14 deletions
diff --git a/cgen.c b/cgen.c
index 831a22e..03113b5 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1,7 +1,8 @@
/* the generation of C code */
-
+/* TODO: check ferror */
typedef struct {
FILE *out;
+ unsigned long anon_fn_count;
} CGenerator;
@@ -43,15 +44,50 @@ static void cgen_write_line_comment(CGenerator *g, const char *fmt, ...) {
cgen_write(g, " */\n");
}
-static void cgen_write_ident(CGenerator *g, Identifier i) {
+static void cgen_create(CGenerator *g, FILE *out) {
+ g->out = out;
+ g->anon_fn_count = 0;
+}
+
+static void cgen_ident(CGenerator *g, Identifier i) {
ident_fprint(g->out, i);
}
-static void cgen_create(CGenerator *g, FILE *out) {
- g->out = out;
+static const char *builtin_type_to_str(BuiltinType b) {
+ /* TODO: make this return int/long/etc. if stdint.h is not available */
+ switch (b) {
+ case BUILTIN_INT: return "int64_t";
+ case BUILTIN_I8: return "int8_t";
+ case BUILTIN_I16: return "int16_t";
+ case BUILTIN_I32: return "int32_t";
+ case BUILTIN_I64: return "int64_t";
+ case BUILTIN_U8: return "uint8_t";
+ case BUILTIN_U16: return "uint16_t";
+ case BUILTIN_U32: return "uint32_t";
+ case BUILTIN_U64: return "uint64_t";
+ case BUILTIN_FLOAT: return "float";
+ case BUILTIN_F32: return "float";
+ case BUILTIN_F64: return "double";
+ case BUILTIN_TYPE_COUNT: break;
+ }
+ assert(0);
+ return NULL;
}
-static bool expr_cgen(Expression *e, CGenerator *g) {
+/* NOTE: this will eventually be split into two functions when functions/arrays are added */
+static bool cgen_type(CGenerator *g, Type *t) {
+ switch (t->kind) {
+ case TYPE_VOID:
+ cgen_write(g, "void");
+ break;
+ case TYPE_BUILTIN:
+ cgen_write(g, "%s", builtin_type_to_str(t->builtin));
+ break;
+ }
+ return true;
+}
+
+static bool cgen_expr(CGenerator *g, Expression *e) {
switch (e->kind) {
case EXPR_INT_LITERAL:
cgen_write(g, "%lld", e->intl);
@@ -71,11 +107,11 @@ static bool expr_cgen(Expression *e, CGenerator *g) {
break;
case EXPR_IDENT:
/* TODO: check if declared */
- cgen_write_ident(g, e->ident);
+ cgen_ident(g, e->ident);
break;
case EXPR_BINARY_OP:
cgen_write(g, "(");
- expr_cgen(e->binary.lhs, g);
+ cgen_expr(g, e->binary.lhs);
switch (e->binary.op) {
case BINARY_PLUS:
cgen_write(g, "+");
@@ -84,7 +120,7 @@ static bool expr_cgen(Expression *e, CGenerator *g) {
cgen_write(g, "-");
break;
}
- expr_cgen(e->binary.rhs, g);
+ cgen_expr(g, e->binary.rhs);
cgen_write(g, ")");
break;
case EXPR_UNARY_OP:
@@ -94,33 +130,189 @@ static bool expr_cgen(Expression *e, CGenerator *g) {
cgen_write(g, "-");
break;
}
- expr_cgen(e->unary.of, g);
+ cgen_expr(g, e->unary.of);
cgen_write(g, ")");
break;
+ case EXPR_FN:
+ err_print(e->where, "Function expression not part of declaration or call.");
+ return false;
}
return true;
}
-static bool stmt_cgen(Statement *s, CGenerator *g) {
+/* b = NULL => file */
+static bool cgen_block_enter(Array stmts, Block *b) {
+ bool ret = true;
+
+ arr_foreach(&stmts, Statement, stmt) {
+ if (stmt->kind == STMT_DECL) {
+ Declaration *decl = &stmt->decl;
+ arr_foreach(&decl->idents, Identifier, ident) {
+ Array *decls = &(*ident)->decls;
+ if (decls->item_sz) {
+ /* check that it hasn't been declared in this block */
+ IdentDecl *prev = decls->last;
+ if (prev->scope == b) {
+ err_print(decl->where, "Re-declaration of identifier in the same block.");
+ info_print(prev->decl->where, "Previous declaration was here.");
+ ret = false;
+ continue;
+ }
+ } else {
+ /* array not initialized yet */
+ arr_create(&(*ident)->decls, sizeof(IdentDecl));
+ }
+ if (infer_decl(decl)) {
+ IdentDecl *ident_decl = arr_add(decls);
+ ident_decl->decl = decl;
+ ident_decl->scope = b;
+ } else {
+ ret = false;
+ }
+ }
+ if (decl->expr.kind == EXPR_FN) {
+ /* TODO */
+ }
+ }
+ }
+ return ret;
+}
+
+static bool cgen_block_exit(Array stmts, Block *b) {
+ /* OPTIM: figure out some way of not re-iterating over everything */
+ bool ret = true;
+ arr_foreach(&stmts, Statement, stmt) {
+ if (stmt->kind == STMT_DECL) {
+ Declaration *decl = &stmt->decl;
+ arr_foreach(&decl->idents, Identifier, ident) {
+ Array *decls = &(*ident)->decls;
+ assert(decls->item_sz);
+ IdentDecl *last_decl = decls->last;
+ if (last_decl->scope == b)
+ arr_remove_last(decls); /* remove that declaration */
+
+ }
+ }
+ }
+ return ret;
+}
+
+static bool cgen_decl(CGenerator *g, Declaration *d) {
+ /* TODO */
+ return true;
+}
+
+static bool cgen_stmt(CGenerator *g, Statement *s) {
switch (s->kind) {
case STMT_EXPR:
- if (!expr_cgen(&s->expr, g))
+ if (!cgen_expr(g, &s->expr))
return false;
- cgen_write(g, ";\n");
+ cgen_writeln(g, ";");
+ break;
+ case STMT_DECL:
+ return cgen_decl(g, &s->decl);
+ }
+ return true;
+}
+
+/*
+
+because functions can have circular dependencies, we need two passes:
+one declares the functions, and one defines them.
+
+*/
+
+static bool cgen_fns_stmt(CGenerator *g, Statement *s, bool def);
+
+static bool cgen_fns_expr(CGenerator *g, Expression *e, Identifier fn_name, bool def) {
+ switch (e->kind) {
+ case EXPR_FN: {
+ bool ret = true;
+ FnExpr *f = &e->fn;
+ cgen_type(g, &f->ret_type);
+ if (!def) {
+ /* get id for function */
+ if (fn_name) {
+ f->id = fn_name->c_fn_reps++;
+ } else {
+ f->id = g->anon_fn_count++;
+ }
+ }
+ cgen_write(g, " ");
+ if (fn_name) {
+ cgen_ident(g, fn_name);
+ } else {
+ cgen_write(g, "a__");
+ }
+ if (f->id != 0)
+ cgen_write(g, "%lu", f->id);
+ cgen_write(g, "(");
+ arr_foreach(&f->params, Param, p) {
+ if (p != f->params.data)
+ cgen_write(g, ", ");
+ cgen_type(g, &p->type);
+ cgen_write(g, " ");
+ cgen_ident(g, p->name);
+ }
+ cgen_write(g, ")");
+ if (def) {
+ cgen_writeln(g, " {");
+ arr_foreach(&f->body.stmts, Statement, s) {
+ if (!cgen_stmt(g, s)) ret = false;
+ }
+ cgen_writeln(g, "}");
+ } else {
+ cgen_writeln(g, ";");
+ }
+
+ arr_foreach(&f->body.stmts, Statement, s) {
+ if (!cgen_fns_stmt(g, s, def))
+ ret = false;
+ }
+ return ret;
+ }
+ case EXPR_CALL:
+ cgen_fns_expr(g, e->call.fn, NULL, def);
break;
+ default: break;
+ }
+ return true;
+}
+
+static bool cgen_fns_stmt(CGenerator *g, Statement *s, bool def) {
+ switch (s->kind) {
+ case STMT_EXPR:
+ if (!cgen_fns_expr(g, &s->expr, NULL, def)) return false;
+ break;
+ case STMT_DECL:
+ if (s->decl.flags & DECL_FLAG_HAS_EXPR) {
+ if (!cgen_fns_expr(g, &s->decl.expr, *(Identifier*)s->decl.idents.data, def))
+ return false;
+ }
+ break;
+
+ }
+ return true;
+}
+
+static bool cgen_fns(ParsedFile *f, CGenerator *g, bool def) {
+ arr_foreach(&f->stmts, Statement, s) {
+ cgen_fns_stmt(g, s, def);
}
return true;
}
-static bool file_cgen(ParsedFile *f, CGenerator *g) {
+static bool cgen_file(CGenerator *g, ParsedFile *f) {
cgen_write_line_comment(g, "toc");
bool ret = true;
+ if (!cgen_fns(f, g, false)) return false;
+ if (!cgen_fns(f, g, true)) return false;
arr_foreach(&f->stmts, Statement, stmt) {
if (stmt->kind == STMT_EXPR) {
/* TODO: eventually make this an error / compile-time statement */
warn_print(stmt->where, "Expression statement at top level.");
}
- if (!stmt_cgen(stmt, g))
+ if (!cgen_stmt(g, stmt))
ret = false;
}
return ret;