function void gen_decl(Decl *node); function void gen_cdecl(Typespec *type, String str); function void gen_stmt_list(Stmt *stmt); global String_List *glist; global Arena *gscratch; global Parser *genp; #define strf(...) string_listf(gscratch, glist, __VA_ARGS__) //----------------------------------------------------------------------------- // String replacing util //----------------------------------------------------------------------------- typedef struct String_Map String_Map; struct String_Map{ String replace; String with; }; function void string_mapped_print(String string, String_Map *map, SizeU count){ Tokens tokens = lex_stream(string, lit("string_mapped_print")); for(Token *t = tokens.tokens; t != tokens.tokens + tokens.len; t++){ String string = t->string; for(SizeU i = 0; i < count; i++){ if(string_compare(string, map[i].replace)){ string = map[i].with; break; } } if(t->kind == TK_At) continue; if(string_compare(t->string,keyword_function.s)) strf("\n"); strf("%.*s", (int)string.len, string.str); if(string_compare(t->string,keyword_function.s)) strf("\n"); if(t->kind == TK_OpenBrace) strf("\n"); if(t->kind == TK_CloseBrace && t[1].kind != TK_Semicolon) strf("\n"); if(t->kind == TK_Semicolon) strf("\n"); if(t->kind == TK_Identifier && (t[1].kind == TK_Keyword || t[1].kind == TK_Identifier)) strf(" "); if(t->kind == TK_Keyword) strf(" "); if(t->kind == TK_Comma) strf(" "); } free(tokens.tokens); } #define STR(X) lit(#X) //----------------------------------------------------------------------------- // Codegen //----------------------------------------------------------------------------- function void token_strf(Token *token){ strf("%.*s", (S32)token->len, token->str); } function void gen_expr(Expr *expr){ switch(expr->kind) { case EK_Atom: { token_strf(expr->token); } break; case EK_Sizeof:{ strf("sizeof("); if(expr->size_of.kind == SIZEOF_Expr){ gen_expr(expr->size_of.expr); } else{ assert(expr->size_of.kind == SIZEOF_Type); gen_cdecl(expr->size_of.type, string_empty); } strf(")"); }break; case EK_Binary:{ strf("("); gen_expr(expr->binary.left); token_strf(expr->token); gen_expr(expr->binary.right); strf(")"); } break; case EK_Unary:{ strf("("); token_strf(expr->token); gen_expr(expr->unary.expr); strf(")"); } break; case EK_Ternary:{ strf("("); gen_expr(expr->ternary.cond); strf("?"); gen_expr(expr->ternary.on_true); strf(":"); gen_expr(expr->ternary.on_false); strf(")"); } break; case EK_List:{ strf("("); for(Expr *n = expr->list.first; n; n=n->next){ gen_expr(n); if(n!=expr->list.last) strf(","); } strf(")"); }break; case EK_Cast:{ strf("("); strf("("); gen_cdecl(expr->cast.type, string_empty); strf(")"); gen_expr(expr->cast.expr); strf(")"); } break; case EK_Index:{ gen_expr(expr->index.atom); strf("["); gen_expr(expr->index.index); strf("]"); }break; case EK_Call:{ gen_expr(expr->call.atom); strf("("); gen_expr(expr->call.list); strf(")"); }break; default: {invalid_codepath;} break; } } function String gen_cdecl_paren(String str, String original){ if(string_is_empty(original) || original.str[0] == '['){ return str; } else{ String result = string_fmt(gscratch, "(%.*s)", (int)str.len, str.str); return result; } } function String gen__cdecl(Typespec *type, String str){ switch(type->kind) { case TS_Name: { String space = string_is_empty(str) ? lit(""):lit(" "); String result = string_fmt(gscratch, "%s%s%.*s", type->name.s.str, space.str, (int)str.len, str.str); return result; } break; case TS_Pointer: { String pointer = string_fmt(gscratch, "*%.*s", (int)str.len, str.str); String add_paren = gen_cdecl_paren(pointer, str); String result = gen__cdecl(type->base, add_paren); return result; } break; case TS_Array: { String left = string_fmt(gscratch, "%s[", str.str); String_List *save = glist; String_List list = {0}; glist = &list; gen_expr(type->array_spec.size); String expr_string = string_list_flatten(gscratch, glist); glist = save; String right = string_fmt(gscratch, "%s%s]", left.str, expr_string.str); String paren = gen_cdecl_paren(right, str); String result = gen__cdecl(type->array_spec.base, paren); return result; } break; case TS_Function: { String result = string_fmt(gscratch, "(*%s)(", str.str); if (type->function_spec.first == 0) { result= string_fmt(gscratch, "%svoid", result.str); } else { for(Typespec *n = type->function_spec.first; n; n=n->next){ String arg = gen__cdecl(n, string_empty); result = string_fmt(gscratch, "%s%s", result.str, arg.str); if(n != type->function_spec.last) result = string_fmt(gscratch, "%s, ", result.str); } } result = string_fmt(gscratch, "%s)", result.str); result = gen__cdecl(type->function_spec.ret, result); return result; } break; default: {invalid_codepath;} break; } return string_empty; } function void gen_cdecl(Typespec *type, String str){ String string = gen__cdecl(type, str); strf("%.*s", (int)string.len, string.str); } function void gen_assign_expr(Expr *expr){ if(expr){ strf(" = "); gen_expr(expr); } } function void gen_function_decl(Decl *node){ strf("function "); gen_cdecl(node->function_decl.ret, string_empty); strf(" %s(", node->name.s.str); for(Decl_Function_Arg *arg = node->function_decl.first; arg; arg=arg->next){ gen_cdecl(arg->typespec, arg->name.s); if(arg!=node->function_decl.last) strf(", "); } strf(")"); } typedef struct Macro{ Intern_String name; Note *param_type; Note *param_expr; Decl *decl; }Macro; global Macro macros[32]; global S32 macros_i; function void gen_forward_decl(Decl *node){ U8 *name = node->name.s.str; switch(node->kind) { case DECL_List: { for(Decl *n = node->list.first; n; n=n->next){ gen_forward_decl(n); } } break; case DECL_Variable:{ } break; case DECL_Typedef:{ } break; case DECL_Function:{ gen_function_decl(node); strf(";\n"); }break; case DECL_Struct: case DECL_Union :{ Note *note = decl_find_note(node, lit("register")); if(note){ Note *param_expr = decl_find_note(node, lit("param_expr")); Note *param_type = decl_find_note(node, lit("param_type")); macros[macros_i++] = (Macro){ .name=node->name, .param_type=param_type, .param_expr=param_expr, .decl=node }; } else{ U8 *struct_name = node->kind==DECL_Struct ? (U8*)"struct" : (U8*)"union"; if(node->struct_decl.kind == STRUCT_Base) strf("typedef %s %s %s;\n", struct_name, name, name); } } break; case DECL_Enum:{ } break; default: {invalid_codepath;} break; } } function void gen_decl(Decl *node){ U8 *name = node->name.s.str; switch(node->kind) { case DECL_List: { for(Decl *n = node->list.first; n; n=n->next){ gen_decl(n); strf("\n"); } } break; case DECL_Variable:{ gen_cdecl(node->variable_decl.type, node->name.s); gen_assign_expr(node->variable_decl.expr); strf(";"); } break; case DECL_Typedef:{ strf("typedef "); gen_cdecl(node->typedef_decl.type, node->name.s); strf(";"); } break; case DECL_Struct: case DECL_Union :{ Note *note = decl_find_note(node, lit("register")); if(note){ Arena_Checkpoint checkpoint = arena_checkpoint(gscratch); Pointer_Array array = gather(checkpoint.arena, node, GATHER_Decl|GATHER_Typespec, TRAVERS_All); Intern_String based = intern_string(genp, lit("Based_Type_Represent")); Intern_String type = intern_string(genp, lit("Type")); for(Pointer it = pointer_array_iter_begin(&array); it.typespec; it = pointer_array_iter_next(&array)){ if(it.kind == PK_Typespec){ Typespec *typespec = it.typespec; assert(typespec->kind == TS_Name || typespec->kind == TS_Pointer || typespec->kind == TS_Array || typespec->kind == TS_Function); if(typespec->kind == TS_Name){ if(intern_compare(typespec->name, type)){ typespec->name = based; } } } else if(it.kind == PK_Decl){ Decl *decl = it.decl; if(decl->kind == DECL_Struct || decl->kind == DECL_Function){ if(intern_compare(decl->name, type)){ decl->name = based; } } } } arena_restore(checkpoint); } U8 *struct_name = node->kind==DECL_Struct ? (U8*)"struct" : (U8*)"union"; strf("%s", struct_name); if(node->struct_decl.kind == STRUCT_Base) strf(" %s", node->name.s.str); strf("{\n"); for(Decl *n = node->struct_decl.first; n; n=n->next){ gen_decl(n); strf("\n"); } strf("}"); if(node->struct_decl.kind == STRUCT_Nested) strf("%.*s", (int)node->name.s.len, node->name.s.str); strf(";"); if(node->struct_decl.kind == STRUCT_Base) strf("\n"); } break; case DECL_Enum:{ strf("typedef enum %s", name); if(!intern_compare(node->enum_decl.typespec->name, intern_s64)){ strf(" : "); strf("%s", node->enum_decl.typespec->name.s.str); } strf("{\n"); String prefix = decl_find_string_note(node, lit("prefix"), string_empty); for(Decl_Enum_Child *n = node->enum_decl.first; n; n=n->next){ strf("%.*s%s", (int)prefix.len, prefix.str, n->name.s.str); gen_assign_expr(n->expr); strf(",\n"); } strf("}%s;\n", name); } break; case DECL_Function:{ gen_function_decl(node); gen_stmt_list(node->function_decl.body); } break; default: {invalid_codepath;} break; } } function void gen_stmt_list(Stmt *stmt){ strf("{\n"); for(Stmt *s = stmt->list.first; s; s=s->next){ gen_stmt(s); strf("\n"); } strf("}"); } function void gen_stmt(Stmt *stmt){ switch(stmt->kind) { case STMT_List: { gen_stmt_list(stmt); } break; case STMT_Return:{ strf("return "); gen_expr(stmt->ret.expr); strf(";"); } break; case STMT_If:{ strf("if "); gen_expr(stmt->stmt_if.cond); gen_stmt_list(stmt->stmt_if.body); for(Stmt_If *s = stmt->stmt_if.next; s; s=s->next){ if(s->next){ strf("else if "); gen_expr(s->cond); gen_stmt_list(s->body); } else{ strf("else"); gen_stmt_list(s->body); } } } break; case STMT_Expr: { gen_expr(stmt->expr); strf(";"); } break; case STMT_Decl: { gen_decl(stmt->decl); } break; default: {invalid_codepath;} break; } } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- global Decl *gen_parent; function void gen_code(Decl *node){ U8 *name = node->name.s.str; switch(node->kind) { case DECL_List: { for(Decl *n = node->list.first; n; n=n->next){ gen_code(n); } } break; case DECL_Variable:{ } break; case DECL_Typedef:{ } break; case DECL_Struct: case DECL_Union :{ gen_parent = node; for(Decl *n = node->struct_decl.first; n; n=n->next){ gen_code(n); } } break; case DECL_Enum:{ } break; default: {invalid_codepath;} break; } } String_List list; function void gen_begin(Arena *scratch, Parser *p){ list = (String_List){0}; gscratch = scratch; glist = &list; genp = p; } function void gen_end(){ String result = string_list_flatten(gscratch, glist); lex_print("%s", result.str); }