summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base_cgen.c218
-rw-r--r--cgen.c294
-rw-r--r--main.c13
-rw-r--r--out.c19
-rw-r--r--out.h2
-rw-r--r--parse.c13
-rw-r--r--test.toc19
-rw-r--r--toc.c2
-rw-r--r--tokenizer.c6
-rw-r--r--types_cgen.c74
-rw-r--r--util/arr.c30
11 files changed, 415 insertions, 275 deletions
diff --git a/base_cgen.c b/base_cgen.c
new file mode 100644
index 0000000..52cd3d6
--- /dev/null
+++ b/base_cgen.c
@@ -0,0 +1,218 @@
+/* figures out types and writes function prototypes */
+/* TODO: check ferror */
+typedef enum {
+ CGEN_WRITING_TO_H,
+ CGEN_WRITING_TO_C
+} CGenWritingTo;
+typedef struct {
+ FILE *c_out;
+ FILE *h_out;
+ unsigned long anon_fn_count;
+ Block *block;
+ int indent_level;
+ bool indent_next; /* should the next thing written be indented? */
+ CGenWritingTo writing_to;
+} CGenerator;
+
+static FILE *cgen_writing_to(CGenerator *g) {
+ switch (g->writing_to) {
+ case CGEN_WRITING_TO_H:
+ return g->h_out;
+ case CGEN_WRITING_TO_C:
+ return g->c_out;
+ }
+ assert(0);
+ return NULL;
+}
+
+static void cgen_vwrite(CGenerator *g, const char *fmt, va_list args) {
+ if (g->indent_next) {
+ for (int i = 0; i < g->indent_level; i++)
+ fprintf(cgen_writing_to(g), "\t");
+ g->indent_next = false;
+ }
+ vfprintf(cgen_writing_to(g), fmt, args);
+}
+
+static void cgen_write(CGenerator *g, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ cgen_vwrite(g, fmt, args);
+ va_end(args);
+}
+
+/* Used to write an UNNECESSARY space */
+static void cgen_write_space(CGenerator *g) {
+ cgen_write(g, " ");
+}
+
+/* Used to write something followed by an UNNECESSARY newline */
+static void cgen_writeln(CGenerator *g, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ cgen_vwrite(g, fmt, args);
+ va_end(args);
+ cgen_write(g, "\n");
+ g->indent_next = true;
+}
+
+static void cgen_write_comment(CGenerator *g, const char *fmt, ...) {
+ cgen_write(g, "/* ");
+ va_list args;
+ va_start(args, fmt);
+ cgen_vwrite(g, fmt, args);
+ va_end(args);
+ cgen_write(g, " */");
+}
+
+static void cgen_write_line_comment(CGenerator *g, const char *fmt, ...) {
+ /* could switch to // for c99 */
+ cgen_write(g, "/* ");
+ va_list args;
+ va_start(args, fmt);
+ cgen_vwrite(g, fmt, args);
+ va_end(args);
+ cgen_write(g, " */\n");
+}
+
+static void cgen_create(CGenerator *g, 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->indent_level = 0;
+ g->block = NULL;
+ g->writing_to = CGEN_WRITING_TO_C;
+ g->indent_next = true;
+
+ cgen_write(g, "#include \"%s\"\n", h_filename);
+ cgen_write(g, "#include <stdint.h>\n");
+ cgen_writeln(g, ""); /* extra newline between includes and code */
+}
+
+static void cgen_ident(CGenerator *g, Identifier i) {
+ fprint_ident(cgen_writing_to(g), i);
+}
+
+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_DOUBLE: return "double";
+ case BUILTIN_TYPE_COUNT: break;
+ }
+ assert(0);
+ return NULL;
+}
+
+/* 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 void cgen_fn_name(CGenerator *g, FnExpr *f) {
+ if (f->name)
+ cgen_ident(g, f->name);
+ else
+ cgen_write(g, "a___");
+
+ if (f->id != 0)
+ cgen_write(g, "%lu", f->id);
+}
+
+static bool cgen_fn_header(CGenerator *g, FnExpr *f) {
+ CGenWritingTo writing_to_before = g->writing_to;
+ if (!f->name || g->block != NULL) {
+ cgen_write(g, "static "); /* anonymous functions only exist in this translation unit */
+ }
+ if (!cgen_type(g, &f->ret_type)) return false;
+ cgen_write(g, " ");
+ cgen_fn_name(g, f);
+ cgen_write(g, "(");
+ arr_foreach(&f->params, Param, p) {
+ if (p != f->params.data) {
+ cgen_write(g, ",");
+ cgen_write_space(g);
+ }
+ if (!cgen_type(g, &p->type))
+ return false;
+ cgen_write(g, " ");
+ cgen_ident(g, p->name);
+ }
+ cgen_write(g, ")");
+ g->writing_to = writing_to_before;
+ return true;
+}
+
+static bool cgen_block_enter(CGenerator *g, Block *b) {
+ bool ret = true;
+ g->block = b;
+ arr_foreach(&b->stmts, Statement, stmt) {
+ if (stmt->kind == STMT_DECL) {
+ Declaration *decl = &stmt->decl;
+ arr_foreach(&decl->idents, Identifier, ident) {
+ Array *decls = &(*ident)->decls;
+ if (decls->len) {
+ /* 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;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+static bool cgen_block_exit(CGenerator *g, Block *into) {
+ /* OPTIM: figure out some way of not re-iterating over everything */
+ bool ret = true;
+ Block *b = g->block;
+ g->block = into;
+ arr_foreach(&b->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;
+}
+
diff --git a/cgen.c b/cgen.c
index a204493..1c13039 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1,92 +1,3 @@
-/* the generation of C code */
-/* TODO: check ferror */
-typedef struct {
- FILE *out;
- unsigned long anon_fn_count;
-} CGenerator;
-
-
-static void cgen_vwrite(CGenerator *g, const char *fmt, va_list args) {
- vfprintf(g->out, fmt, args);
-}
-
-static void cgen_write(CGenerator *g, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- cgen_vwrite(g, fmt, args);
- va_end(args);
-}
-
-static void cgen_writeln(CGenerator *g, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- cgen_vwrite(g, fmt, args);
- va_end(args);
- cgen_write(g, "\n");
-}
-
-static void cgen_write_comment(CGenerator *g, const char *fmt, ...) {
- cgen_write(g, "/* ");
- va_list args;
- va_start(args, fmt);
- cgen_vwrite(g, fmt, args);
- va_end(args);
- cgen_write(g, " */");
-}
-
-static void cgen_write_line_comment(CGenerator *g, const char *fmt, ...) {
- /* could switch to // for c99 */
- cgen_write(g, "/* ");
- va_list args;
- va_start(args, fmt);
- cgen_vwrite(g, fmt, args);
- va_end(args);
- cgen_write(g, " */\n");
-}
-
-static void cgen_create(CGenerator *g, FILE *out) {
- g->out = out;
- g->anon_fn_count = 0;
-}
-
-static void cgen_ident(CGenerator *g, Identifier i) {
- fprint_ident(g->out, i);
-}
-
-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;
-}
-
-/* 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:
@@ -134,71 +45,57 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
cgen_write(g, ")");
break;
case EXPR_FN:
- err_print(e->where, "Function expression not part of declaration or call.");
- return false;
- }
- return true;
-}
-
-/* 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 */
+ cgen_fn_name(g, &e->fn);
+ break;
+ case EXPR_CALL:
+ 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_write_space(g);
}
+ cgen_expr(g, arg);
}
+ cgen_write(g, ")");
+ break;
}
- return ret;
+ return true;
}
-static bool cgen_block_exit(Array stmts, Block *b) {
- /* OPTIM: figure out some way of not re-iterating over everything */
+static bool cgen_stmt(CGenerator *g, Statement *s);
+
+/* Generates the definition of a function, not just the identifier */
+static bool cgen_fn(CGenerator *g, FnExpr *f) {
+ if (!cgen_fn_header(g, f)) return false;
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 */
-
- }
- }
+ cgen_write_space(g);
+ cgen_writeln(g, "{");
+ g->indent_level++;
+ Block *prev_block = g->block;
+ cgen_block_enter(g, &f->body);
+ arr_foreach(&f->body.stmts, Statement, s) {
+ if (!cgen_stmt(g, s))
+ ret = false;
}
+ cgen_block_exit(g, prev_block);
+ g->indent_level--;
+ cgen_writeln(g, "}");
return ret;
}
static bool cgen_decl(CGenerator *g, Declaration *d) {
- /* TODO */
+ arr_foreach(&d->idents, Identifier, ident) {
+ cgen_type(g, &d->type);
+ cgen_write(g, " ");
+ cgen_ident(g, *ident);
+ cgen_write_space(g);
+ cgen_write(g, "=");
+ cgen_write_space(g);
+ cgen_expr(g, &d->expr);
+ cgen_write(g, "; ");
+ }
+ cgen_writeln(g, "");
return true;
}
@@ -209,95 +106,48 @@ static bool cgen_stmt(CGenerator *g, Statement *s) {
return false;
cgen_writeln(g, ";");
break;
- case STMT_DECL:
+ 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;
}
-/*
-
-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_in_stmt(CGenerator *g, Statement *s);
-static bool cgen_fns_expr(CGenerator *g, Expression *e, Identifier fn_name, bool def) {
+static bool cgen_fns_in_expr(CGenerator *g, Expression *e) {
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;
+ case EXPR_FN:
+ cgen_fn(g, &e->fn);
+ arr_foreach(&e->fn.body.stmts, Statement, stmt) {
+ cgen_fns_in_stmt(g, stmt);
}
- return ret;
- }
+ return true;
case EXPR_CALL:
- cgen_fns_expr(g, e->call.fn, NULL, def);
- break;
- default: break;
+ return cgen_fns_in_expr(g, e->call.fn);
+ default: return true;
}
- return true;
}
-static bool cgen_fns_stmt(CGenerator *g, Statement *s, bool def) {
+static bool cgen_fns_in_stmt(CGenerator *g, Statement *s) {
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;
+ 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;
-
- }
- return true;
-}
-
-static bool cgen_fns(ParsedFile *f, CGenerator *g, bool def) {
- arr_foreach(&f->stmts, Statement, s) {
- cgen_fns_stmt(g, s, def);
+ case STMT_DECL: {
+ Declaration *d = &s->decl;
+ if (d->flags & DECL_FLAG_HAS_EXPR)
+ cgen_fns_in_expr(g, &d->expr);
+ } break;
}
return true;
}
@@ -305,15 +155,9 @@ static bool cgen_fns(ParsedFile *f, CGenerator *g, bool def) {
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 (!cgen_stmt(g, stmt))
- ret = false;
+ if (!cgen_types(g, f)) return false;
+ arr_foreach(&f->stmts, Statement, s) {
+ if (!cgen_fns_in_stmt(g, s)) return false;
}
return ret;
}
diff --git a/main.c b/main.c
index 8213db4..118f8a6 100644
--- a/main.c
+++ b/main.c
@@ -29,6 +29,7 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error reading input file: %s.\n", argv[1]);
return EXIT_FAILURE;
}
+ fclose(in);
err_filename = in_filename;
Tokenizer t;
@@ -55,11 +56,12 @@ int main(int argc, char **argv) {
tokr_free(&t);
- const char *out_filename = "out.c";
-
- FILE *out = fopen(out_filename, "w");
+ const char *c_out_filename = "out.c";
+ const char *h_out_filename = "out.h";
+ FILE *c_out = fopen(c_out_filename, "w");
+ FILE *h_out = fopen(h_out_filename, "w");
CGenerator cgen;
- cgen_create(&cgen, out);
+ cgen_create(&cgen, c_out, h_out, h_out_filename);
if (!cgen_file(&cgen, &f)) {
err_fprint(TEXT_IMPORTANT("Errors occured while generating C code.\n"));
return EXIT_FAILURE;
@@ -67,6 +69,7 @@ int main(int argc, char **argv) {
free(contents);
- fclose(in);
+ fclose(c_out);
+ fclose(h_out);
idents_free();
}
diff --git a/out.c b/out.c
index ee35fb9..7d51729 100644
--- a/out.c
+++ b/out.c
@@ -1,15 +1,12 @@
+#include "out.h"
+#include <stdint.h>
+
/* toc */
-void xasfd();
-void a__();
-void a__1(int64_t y);
-double foo(int64_t x, int64_t y, uint64_t z);
-void xasfd() {
+static void bar();
+void main() {
+ int64_t x = ((12+(-(-3)))+3);
}
-void a__() {
+int8_t foo(int64_t x, float y, double z) {
}
-void a__1(int64_t y) {
-}
-double foo(int64_t x, int64_t y, uint64_t z) {
-(3+5);
-(5+6);
+void bar() {
}
diff --git a/out.h b/out.h
new file mode 100644
index 0000000..20f1ebe
--- /dev/null
+++ b/out.h
@@ -0,0 +1,2 @@
+void main();
+static int8_t foo(int64_t x, float y, double z);
diff --git a/parse.c b/parse.c
index 0ec84b0..e9d049e 100644
--- a/parse.c
+++ b/parse.c
@@ -15,8 +15,7 @@ typedef enum {
BUILTIN_U32,
BUILTIN_U64,
BUILTIN_FLOAT,
- BUILTIN_F32,
- BUILTIN_F64,
+ BUILTIN_DOUBLE,
BUILTIN_TYPE_COUNT
} BuiltinType;
@@ -42,6 +41,7 @@ typedef struct {
Array params;
Type ret_type;
Block body;
+ Identifier name; /* NULL if the function is anonymous (set to NULL by parse.c, set to actual value by types_cgen.c) */
unsigned long id; /* this is used to keep track of local vs global/other local functions (there might be multiple functions called "foo") */
} FnExpr; /* an expression such as fn(x: int) int {return 2 * x;} */
@@ -152,8 +152,7 @@ static BuiltinType kw_to_builtin_type(Keyword kw) {
case KW_U32: return BUILTIN_U32;
case KW_U64: return BUILTIN_U64;
case KW_FLOAT: return BUILTIN_FLOAT;
- case KW_F32: return BUILTIN_F32;
- case KW_F64: return BUILTIN_F64;
+ case KW_DOUBLE: return BUILTIN_DOUBLE;
default: return BUILTIN_TYPE_COUNT;
}
}
@@ -170,8 +169,7 @@ static Keyword builtin_type_to_kw(BuiltinType t) {
case BUILTIN_U32: return KW_U32;
case BUILTIN_U64: return KW_U64;
case BUILTIN_FLOAT: return KW_FLOAT;
- case BUILTIN_F32: return KW_F32;
- case BUILTIN_F64: return KW_F64;
+ case BUILTIN_DOUBLE: return KW_DOUBLE;
case BUILTIN_TYPE_COUNT: break;
}
assert(0);
@@ -255,6 +253,7 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
Tokenizer *t = p->tokr;
/* only called when token is fn */
assert(token_is_kw(t->token, KW_FN));
+ f->name = NULL;
t->token++;
if (!token_is_kw(t->token, KW_LPAREN)) {
tokr_err(t, "Expected '(' after 'fn'.");
@@ -658,7 +657,7 @@ static bool decl_parse(Declaration *d, Parser *p) {
*ident = t->token->ident;
/*
only keep track of file scoped declarations---
- blocks.c will handle the rest
+ block enter/exit code will handle the rest
*/
if (p->block == NULL) {
if ((*ident)->decls.len) {
diff --git a/test.toc b/test.toc
index cec1a43..c43db3a 100644
--- a/test.toc
+++ b/test.toc
@@ -1,11 +1,8 @@
-xasfd @ int = fn () {
- x @= (fn( ) {
- x @= (fn(y: int) {
- })(3);
- })();
-};
-
-foo @= fn (x: int, y: int, z: u64) f64 {
- 3+5;
- 5+6;
-};
+main @= fn() {
+ foo @= fn(x: int, y: float, z: double) i8 {
+ };
+ bar @= fn() {
+
+ };
+ x : int = 12 + --3 + 3;
+}; \ No newline at end of file
diff --git a/toc.c b/toc.c
index a767e4a..c452ddb 100644
--- a/toc.c
+++ b/toc.c
@@ -15,4 +15,6 @@
#include "tokenizer.c"
#include "parse.c"
#include "infer.c"
+#include "base_cgen.c"
+#include "types_cgen.c"
#include "cgen.c"
diff --git a/tokenizer.c b/tokenizer.c
index 7bede8c..7333db8 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -34,15 +34,13 @@ typedef enum {
KW_U32,
KW_U64,
KW_FLOAT,
- KW_F32,
- KW_F64,
+ KW_DOUBLE,
KW_COUNT
} Keyword;
static const char *keywords[KW_COUNT] =
{";", "=", ":", "@", ",", "(", ")", "{", "}", "==", "<", "<=", "-", "+", "fn",
- "int", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "float", "f32",
- "f64"};
+ "int", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "float", "double"};
/* Returns KW_COUNT if it's not a keyword */
/* OPTIM: don't use strncmp so much */
diff --git a/types_cgen.c b/types_cgen.c
new file mode 100644
index 0000000..fb1e690
--- /dev/null
+++ b/types_cgen.c
@@ -0,0 +1,74 @@
+static bool cgen_types_stmt(CGenerator *g, Statement *s);
+static bool cgen_types_fn(CGenerator *g, FnExpr *f) {
+ bool ret = true;
+ /* assign an ID to the function */
+ if (f->name) {
+ 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, ";");
+ Block *prev_block = g->block;
+ cgen_block_enter(g, &f->body);
+ arr_foreach(&f->body.stmts, Statement, s) {
+ if (!cgen_types_stmt(g, s))
+ ret = false;
+ }
+ cgen_block_exit(g, prev_block);
+ return ret;
+}
+
+
+static bool cgen_types_expr(CGenerator *g, Expression *e) {
+ switch (e->kind) {
+ case EXPR_FN: {
+ if (e->fn.name && g->block == NULL) { /* write named function prototypes in global scope to header file */
+ g->writing_to = CGEN_WRITING_TO_H;
+ }
+ if (!cgen_types_fn(g, &e->fn))
+ return false;
+ g->writing_to = CGEN_WRITING_TO_C;
+ } break;
+ case EXPR_CALL:
+ if (!cgen_types_expr(g, e->call.fn))
+ return false;
+ arr_foreach(&e->call.args, Expression, arg) {
+ if (!cgen_types_expr(g, arg))
+ return false;
+ }
+ break;
+ default: /* TODO */ break;
+ }
+ return true;
+}
+
+
+static bool cgen_types_stmt(CGenerator *g, Statement *s) {
+ switch (s->kind) {
+ case STMT_EXPR:
+ if (!cgen_types_expr(g, &s->expr))
+ return false;
+ break;
+ case STMT_DECL: {
+ Declaration *d = &s->decl;
+ if ((d->flags & DECL_FLAG_HAS_EXPR) && (d->flags & DECL_FLAG_CONST)) {
+ /* e.g. foo @= fn() {}; (we want to set the function's name to "foo") */
+ if (d->expr.kind == EXPR_FN) {
+ d->expr.fn.name = *(Identifier*)d->idents.data;
+ }
+ }
+ cgen_types_expr(g, &d->expr);
+ } break;
+
+ }
+ return true;
+}
+
+static bool cgen_types(CGenerator *g, ParsedFile *f) {
+ arr_foreach(&f->stmts, Statement, s) {
+ cgen_types_stmt(g, s);
+ }
+ return true;
+}
diff --git a/util/arr.c b/util/arr.c
index 6cbf9eb..f8da701 100644
--- a/util/arr.c
+++ b/util/arr.c
@@ -6,20 +6,20 @@ typedef struct {
size_t item_sz;
} Array;
-void arr_create(Array *arr, size_t item_sz) {
+static void arr_create(Array *arr, size_t item_sz) {
arr->len = arr->cap = 0;
arr->item_sz = item_sz;
arr->data = NULL;
arr->last = NULL;
}
-void arr_reserve(Array *arr, size_t n) {
+static void arr_reserve(Array *arr, size_t n) {
arr->cap = n;
arr->data = realloc(arr->data, arr->item_sz * arr->cap);
arr->last = (void*)((char*)arr->data + arr->item_sz * (arr->len - 1));
}
-void *arr_add(Array *arr) {
+static void *arr_add(Array *arr) {
if (arr->len >= arr->cap) {
arr_reserve(arr, (arr->cap + 2) * 2);
}
@@ -29,20 +29,26 @@ void *arr_add(Array *arr) {
return item;
}
-void arr_remove_last(Array *arr) {
- arr->len--;
- /* OPTIM (memory): Shorten array. */
+static void arr_clear(Array *arr) {
+ free(arr->data);
+ arr->len = arr->cap = 0;
+ arr->data = NULL;
+ arr->last = NULL;
}
-void arr_free(Array *arr) {
- free(arr->data);
+static void arr_remove_last(Array *arr) {
+ /* OPTIM (memory): Shorten array. */
+ arr->len--;
+ if (arr->len) {
+ arr->last = (char*)arr->last - arr->item_sz;
+ } else {
+ arr_clear(arr);
+ }
+
}
-void arr_clear(Array *arr) {
+static void arr_free(Array *arr) {
free(arr->data);
- arr->len = arr->cap = 0;
- arr->data = NULL;
- arr->last = NULL;
}
#define arr_foreach(arr, type, var) for (type *var = (arr)->data; var; var == (arr)->last ? var = NULL : var++)