/* * C code generator. Does not actually call the compiler, * that's done by the Makefile. The other `out*.c` files handle * specific parts of C code generation. * * Copyright © 2020-2025 Samuel Lidén Borell * * SPDX-License-Identifier: EUPL-1.2+ */ #include #include #include "compiler.h" #include "out.h" static void emit_header(void) { outf( "/* Generated code from bootstrap compiler */\n" "#include \"rtl.h\"\n" "\n"); } static void emit_footer(void) { } void emit_ident(struct Ident *ident) { outf("%.*s", ident->node.length, ident->node.name); } /* FIXME arrays, optional types, generics... */ void emit_typeref_prefix(struct TypeRef *tr) { /* TODO output parantheses for nested types e.g. array of pointer etc. */ switch (tr->kind) { case TR_UNKNOWN: ast_error("TR_UNKNOWN encountered at codegen time"); case TR_BOOL: outf("bool "); break; case TR_INT: /* TODO unsigned and uint64 */ outf("int "); break; case TR_STRING: case TR_CLASS: emit_type(tr->u.class_); outc(' '); outc('*'); } } void emit_typeref_suffix(struct TypeRef *tr) { /* TODO arrays? */ (void)tr; } /*static void emit_decl(struct Type *type, struct Ident *ident) { emit_type_prefix(type); if (ident) { emit_ident(ident); } emit_type_suffix(type); }*/ /*static void emit_vardecl(struct Var *var) { } */ void emit_type(struct Type *type) { /* FIXME this leads to a name conflict. */ /* FIXME currently, there's no check that nested/inner types start with `_` */ outf("struct "); if (type->outer) { emit_ident(&type->outer->ident); } emit_ident(&type->ident); } static void emit_module(struct Module *mod) { struct Type *type, *inner; emit_string_constants(); if (mod->types_list) { outc('\n'); /* Pre-declare types */ for (type = mod->types_list; type; type = type->next) { predeclare_type(type); for (inner = type->inner_types_list; inner; inner = inner->next) { assert(inner->inner_types_list == NULL); predeclare_type(inner); } } /* Emit types */ /* XXX this is tricky if structs are allowed to be embedded without a pointer. Then it has to be done in the correct order */ for (type = mod->types_list; type; type = type->next) { define_type(type); for (inner = type->inner_types_list; inner; inner = inner->next) { define_type(inner); } } } outc('\n'); /* Pre-declare functions */ predeclare_funcs(mod->funcs_list); for (type = mod->types_list; type; type = type->next) { predeclare_funcs(type->funcs_list); for (inner = type->inner_types_list; inner; inner = inner->next) { predeclare_funcs(inner->funcs_list); } } /* Emit function bodies */ define_funcs(mod->funcs_list); for (type = mod->types_list; type; type = type->next) { define_funcs(type->funcs_list); for (inner = type->inner_types_list; inner; inner = inner->next) { define_funcs(inner->funcs_list); } } } static void emit_code(void) { struct Module *mod; for (mod = modules; mod; mod = mod->next) { emit_module(mod); } /* TODO test code. replace this. maybe the stdlib should be in a separate object file? (which could contain `main()`) */ beginf("int main(void) {\n"); indentf("printf(\"Test\\n\");\n"); indentf("return EXIT_SUCCESS;\n"); endf("}\n"); } void emit_c_code(const char *filename) { outfile_path = filename; outfile = fopen(filename, "wb"); if (!outfile) { io_error(); } emit_header(); emit_code(); emit_footer(); if (fclose(outfile) < 0) { io_error(); } }