267 lines
8.1 KiB
Plaintext
267 lines
8.1 KiB
Plaintext
// c_backend.bux — C transpiler backend (ported from c_backend.nim)
|
|
// Generates C code from the HIR.
|
|
module CBackend {
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Type → C type name
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func CBackend_TypeToC(kind: int) -> String {
|
|
if kind == tkVoid { return "void"; }
|
|
if kind == tkBool { return "bool"; }
|
|
if kind == tkBool8 { return "bool"; }
|
|
if kind == tkBool16 { return "bool"; }
|
|
if kind == tkBool32 { return "bool"; }
|
|
if kind == tkChar8 { return "char"; }
|
|
if kind == tkChar16 { return "uint16_t"; }
|
|
if kind == tkChar32 { return "uint32_t"; }
|
|
if kind == tkStr { return "const char*"; }
|
|
if kind == tkInt8 { return "int8_t"; }
|
|
if kind == tkInt16 { return "int16_t"; }
|
|
if kind == tkInt32 { return "int32_t"; }
|
|
if kind == tkInt64 { return "int64_t"; }
|
|
if kind == tkInt { return "int"; }
|
|
if kind == tkUInt8 { return "uint8_t"; }
|
|
if kind == tkUInt16 { return "uint16_t"; }
|
|
if kind == tkUInt32 { return "uint32_t"; }
|
|
if kind == tkUInt64 { return "uint64_t"; }
|
|
if kind == tkUInt { return "unsigned int"; }
|
|
if kind == tkFloat32 { return "float"; }
|
|
if kind == tkFloat64 { return "double"; }
|
|
if kind == tkPointer { return "void*"; }
|
|
if kind == tkNamed { return "void*"; }
|
|
return "int";
|
|
}
|
|
|
|
func CBackend_OpToC(op: int) -> String {
|
|
if op == tkPlus { return "+"; }
|
|
if op == tkMinus { return "-"; }
|
|
if op == tkStar { return "*"; }
|
|
if op == tkSlash { return "/"; }
|
|
if op == tkPercent { return "%"; }
|
|
if op == tkEq { return "=="; }
|
|
if op == tkNe { return "!="; }
|
|
if op == tkLt { return "<"; }
|
|
if op == tkLe { return "<="; }
|
|
if op == tkGt { return ">"; }
|
|
if op == tkGe { return ">="; }
|
|
if op == tkAmpAmp { return "&&"; }
|
|
if op == tkPipePipe { return "||"; }
|
|
if op == tkBang { return "!"; }
|
|
if op == tkAmp { return "&"; }
|
|
if op == tkPipe { return "|"; }
|
|
if op == tkCaret { return "^"; }
|
|
if op == tkShl { return "<<"; }
|
|
if op == tkShr { return ">>"; }
|
|
if op == tkAssign { return "="; }
|
|
return "?";
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// StringBuilder-based C emitter
|
|
// ---------------------------------------------------------------------------
|
|
|
|
struct CEmitter {
|
|
sb: StringBuilder,
|
|
indent: int,
|
|
}
|
|
|
|
func CBE_Init() -> CEmitter {
|
|
var sb: StringBuilder = StringBuilder_NewCap(4096);
|
|
return CEmitter { sb: sb, indent: 0 };
|
|
}
|
|
|
|
func CBE_Emit(cbe: *CEmitter, text: String) {
|
|
var i: int = 0;
|
|
while i < cbe.indent {
|
|
StringBuilder_Append(&cbe.sb, " ");
|
|
i = i + 1;
|
|
}
|
|
StringBuilder_Append(&cbe.sb, text);
|
|
}
|
|
|
|
func CBE_EmitLine(cbe: *CEmitter, text: String) {
|
|
CBE_Emit(cbe, text);
|
|
StringBuilder_Append(&cbe.sb, "\n");
|
|
}
|
|
|
|
func CBE_Build(cbe: *CEmitter) -> String {
|
|
return StringBuilder_Build(&cbe.sb);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Emit HIR node
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) {
|
|
if node == null as *HirNode { return; }
|
|
let kind: int = node.kind;
|
|
|
|
// Literal
|
|
if kind == hLit {
|
|
StringBuilder_Append(&cbe.sb, node.strValue);
|
|
return;
|
|
}
|
|
|
|
// Variable
|
|
if kind == hVar {
|
|
StringBuilder_Append(&cbe.sb, node.strValue);
|
|
return;
|
|
}
|
|
|
|
// Binary
|
|
if kind == hBinary {
|
|
CBE_EmitExpr(cbe, node.child1);
|
|
StringBuilder_Append(&cbe.sb, " ");
|
|
StringBuilder_Append(&cbe.sb, CBackend_OpToC(node.intValue));
|
|
StringBuilder_Append(&cbe.sb, " ");
|
|
CBE_EmitExpr(cbe, node.child2);
|
|
return;
|
|
}
|
|
|
|
// Unary
|
|
if kind == hUnary {
|
|
StringBuilder_Append(&cbe.sb, CBackend_OpToC(node.intValue));
|
|
CBE_EmitExpr(cbe, node.child1);
|
|
return;
|
|
}
|
|
|
|
// Call
|
|
if kind == hCall {
|
|
StringBuilder_Append(&cbe.sb, node.strValue);
|
|
StringBuilder_Append(&cbe.sb, "(");
|
|
if node.child1 != null as *HirNode {
|
|
CBE_EmitExpr(cbe, node.child1);
|
|
}
|
|
if node.child2 != null as *HirNode {
|
|
StringBuilder_Append(&cbe.sb, ", ");
|
|
CBE_EmitExpr(cbe, node.child2);
|
|
}
|
|
StringBuilder_Append(&cbe.sb, ")");
|
|
return;
|
|
}
|
|
|
|
// Return
|
|
if kind == hReturn {
|
|
StringBuilder_Append(&cbe.sb, "return");
|
|
if node.child1 != null as *HirNode {
|
|
StringBuilder_Append(&cbe.sb, " ");
|
|
CBE_EmitExpr(cbe, node.child1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Alloca
|
|
if kind == hAlloca {
|
|
StringBuilder_Append(&cbe.sb, CBackend_TypeToC(tkInt)); // simplified type
|
|
StringBuilder_Append(&cbe.sb, " ");
|
|
StringBuilder_Append(&cbe.sb, node.strValue);
|
|
StringBuilder_Append(&cbe.sb, ";\n");
|
|
return;
|
|
}
|
|
|
|
// Store
|
|
if kind == hStore {
|
|
CBE_EmitExpr(cbe, node.child1);
|
|
StringBuilder_Append(&cbe.sb, " = ");
|
|
CBE_EmitExpr(cbe, node.child2);
|
|
return;
|
|
}
|
|
|
|
// Cast
|
|
if kind == hCast {
|
|
StringBuilder_Append(&cbe.sb, "((");
|
|
StringBuilder_Append(&cbe.sb, CBackend_TypeToC(tkPointer));
|
|
StringBuilder_Append(&cbe.sb, ")");
|
|
CBE_EmitExpr(cbe, node.child1);
|
|
StringBuilder_Append(&cbe.sb, ")");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Emit function declaration
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func CBE_EmitFuncDecl(cbe: *CEmitter, f: *HirFunc) {
|
|
// Return type
|
|
if String_Eq(f.retTypeName, "") || String_Eq(f.retTypeName, "void") {
|
|
StringBuilder_Append(&cbe.sb, "void ");
|
|
} else {
|
|
StringBuilder_Append(&cbe.sb, "int "); // simplified
|
|
}
|
|
|
|
StringBuilder_Append(&cbe.sb, f.name);
|
|
StringBuilder_Append(&cbe.sb, "(");
|
|
|
|
// Parameters
|
|
var i: int = 0;
|
|
while i < f.paramCount {
|
|
if i > 0 {
|
|
StringBuilder_Append(&cbe.sb, ", ");
|
|
}
|
|
StringBuilder_Append(&cbe.sb, "int "); // simplified param type
|
|
var pname: String = "";
|
|
if i == 0 { pname = f.param0.name; }
|
|
else if i == 1 { pname = f.param1.name; }
|
|
else if i == 2 { pname = f.param2.name; }
|
|
else if i == 3 { pname = f.param3.name; }
|
|
else if i == 4 { pname = f.param4.name; }
|
|
else if i == 5 { pname = f.param5.name; }
|
|
StringBuilder_Append(&cbe.sb, pname);
|
|
i = i + 1;
|
|
}
|
|
|
|
StringBuilder_Append(&cbe.sb, ")");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Generate complete C module
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func CBackend_Generate(mod: *HirModule) -> String {
|
|
let cbe: *CEmitter = bux_alloc(sizeof(CEmitter)) as *CEmitter;
|
|
cbe.sb = StringBuilder_NewCap(8192);
|
|
cbe.indent = 0;
|
|
|
|
// Header
|
|
StringBuilder_Append(&cbe.sb, "// Generated by Bux C Backend\n");
|
|
StringBuilder_Append(&cbe.sb, "#include <stdint.h>\n");
|
|
StringBuilder_Append(&cbe.sb, "#include <stdbool.h>\n");
|
|
StringBuilder_Append(&cbe.sb, "#include <string.h>\n");
|
|
StringBuilder_Append(&cbe.sb, "#include <stdio.h>\n");
|
|
StringBuilder_Append(&cbe.sb, "#include <stdlib.h>\n\n");
|
|
|
|
// Extern declarations
|
|
var i: int = 0;
|
|
while i < mod.externCount {
|
|
CBE_EmitFuncDecl(cbe, &mod.externFuncs[i]);
|
|
StringBuilder_Append(&cbe.sb, ";\n");
|
|
i = i + 1;
|
|
}
|
|
StringBuilder_Append(&cbe.sb, "\n");
|
|
|
|
// Function definitions
|
|
i = 0;
|
|
while i < mod.funcCount {
|
|
CBE_EmitFuncDecl(cbe, &mod.funcs[i]);
|
|
StringBuilder_Append(&cbe.sb, " {\n");
|
|
// Body (simplified)
|
|
if mod.funcs[i].body != null as *HirNode {
|
|
StringBuilder_Append(&cbe.sb, " ");
|
|
CBE_EmitExpr(cbe, mod.funcs[i].body);
|
|
StringBuilder_Append(&cbe.sb, ";\n");
|
|
}
|
|
StringBuilder_Append(&cbe.sb, " return 0;\n}\n\n");
|
|
i = i + 1;
|
|
}
|
|
|
|
return StringBuilder_Build(&cbe.sb);
|
|
}
|
|
|
|
func CBackend_Free(cbe: *CEmitter) {
|
|
StringBuilder_Free(&cbe.sb);
|
|
bux_free(cbe as *void);
|
|
}
|
|
}
|