58#ifndef COMPILER_BACKEND_C_H
59#define COMPILER_BACKEND_C_H
109namespace Compiler_Backend_C_Detail {
113 result.reserve(text.size() + 8);
114 for (
const unsigned char ch : text)
116 if (std::isalnum(
ch))
117 result.push_back(
static_cast<char>(std::tolower(
ch)));
119 result.push_back(
'_');
122 while (
not result.empty()
and result.front() ==
'_')
123 result.erase(result.begin());
124 while (
not result.empty()
and result.back() ==
'_')
126 while (result.find(
"__") != std::string::npos)
127 result.replace(result.find(
"__"), 2,
"_");
131 if (std::isdigit(
static_cast<unsigned char>(result.front())))
132 result.insert(result.begin(),
'_');
139 for (
char &
ch : result)
140 ch =
static_cast<char>(std::toupper(
static_cast<unsigned char>(
ch)));
147 result.reserve(text.size() + 2);
148 result.push_back(
'"');
149 for (
const char ch : text)
168 result.push_back(
ch);
170 result.push_back(
'"');
176 while (text.find(
"*/") != std::string::npos)
177 text.replace(text.find(
"*/"), 2,
"* /");
187 value = std::strtoll(text.c_str(), &end, 10);
188 return end !=
nullptr and *end ==
'\0';
194 for (
size_t i = 0; i < function.local_slots.size(); ++i)
207 return "v" + std::to_string(
id);
212 return "s" + std::to_string(
id);
217 return "g" + std::to_string(
id);
222 return "B" + std::to_string(
id);
227 return std::string(
count,
' ');
294 if (
types_ ==
nullptr or type_id == 0)
303 ? std::string(
"module")
349 const std::string symbol =
names_.
prefix +
"_f" + std::to_string(i) +
"_"
360 for (
size_t i = 0; i < errors.size(); ++i)
361 fail(errors.access(i));
362 for (
size_t i = 0; i < warnings.size(); ++i)
363 warn(warnings.access(i));
367 fail(
"C backend requires dense zero-based function ids; function '"
369 + std::to_string(
module_->
functions.access(i)->id) +
" but its module index is "
370 + std::to_string(i));
385 std::string &
error)
const
387 if (
inst.text ==
"unit")
393 if (
inst.text ==
"true" or inst.text ==
"false")
396 + std::string(
inst.text ==
"true" ?
"true" :
"false") +
")";
400 long long integer_value = 0;
419 error =
"C backend does not know how to emit constant literal '" +
inst.text +
"'";
425 out <<
"#include <stdbool.h>\n"
426 <<
"#include <stddef.h>\n"
427 <<
"#include <stdio.h>\n"
428 <<
"#include <stdlib.h>\n"
429 <<
"#include <string.h>\n\n"
450 <<
" bool boolean;\n"
451 <<
" long long integer;\n"
452 <<
" const char * string;\n"
453 <<
" char character;\n"
465 <<
" size_t arity;\n"
466 <<
" const char * name;\n"
468 <<
"static const char *\n"
481 <<
" return \"Unknown\";\n"
486 <<
" fprintf(stderr, \"[" <<
names_.
prefix <<
"] %s\\n\", message);\n"
494 <<
" value.as.integer = 0;\n"
495 <<
" return value;\n"
502 <<
" value.as.integer = 0;\n"
503 <<
" return value;\n"
510 <<
" value.as.boolean = value_in;\n"
511 <<
" return value;\n"
518 <<
" value.as.integer = value_in;\n"
519 <<
" return value;\n"
526 <<
" value.as.string = value_in;\n"
527 <<
" return value;\n"
534 <<
" value.as.character = value_in;\n"
535 <<
" return value;\n"
542 <<
" value.as.function = function;\n"
543 <<
" return value;\n"
552 <<
"] %s uses an uninitialized value\\n\", context);\n"
555 <<
" return value;\n"
557 <<
"static long long\n"
565 <<
"] %s expects Int but received %s\\n\",\n"
570 <<
" return value.as.integer;\n"
580 <<
"] %s expects Bool but received %s\\n\",\n"
585 <<
" return value.as.boolean;\n"
595 <<
"] %s expects Function but received %s\\n\",\n"
600 <<
" return value.as.function;\n"
608 <<
" if (lhs.tag != rhs.tag)\n"
609 <<
" return false;\n"
610 <<
" switch (lhs.tag)\n"
616 <<
" return lhs.as.boolean == rhs.as.boolean;\n"
618 <<
" return lhs.as.integer == rhs.as.integer;\n"
620 <<
" return strcmp(lhs.as.string, rhs.as.string) == 0;\n"
622 <<
" return lhs.as.character == rhs.as.character;\n"
624 <<
" return lhs.as.function == rhs.as.function;\n"
626 <<
" return false;\n"
637 <<
" if (function->arity != argc)\n"
640 <<
"] function %s expects %zu arguments but received %zu\\n\",\n"
646 <<
" return function->pointer(module, args, argc);\n"
653 <<
" switch (value.tag)\n"
656 <<
" fputs(\"Invalid\", out);\n"
659 <<
" fputs(\"Unit\", out);\n"
662 <<
" fputs(value.as.boolean ? \"Bool(true)\" : \"Bool(false)\", out);\n"
665 <<
" fprintf(out, \"Int(%lld)\", value.as.integer);\n"
668 <<
" fprintf(out, \"String(\\\"%s\\\")\", value.as.string);\n"
671 <<
" fprintf(out, \"Char('%c')\", value.as.character);\n"
674 <<
" fprintf(out, \"Function(%s)\", value.as.function->name);\n"
691 <<
"_GLOBAL_COUNT];\n";
694 out <<
"static void\n"
698 out <<
" (void) module;\n";
704 out <<
"static void\n"
709 <<
" fputs(\"Globals\\n\", out);\n";
711 out <<
" fputs(\" <none>\\n\", out);\n";
716 out <<
" fputs(\" g" <<
slot.id <<
" "
719 <<
" fputc('\\n', out);\n";
741 <<
"size_t argc);\n\n";
755 for (
size_t i = 0; i < function.
local_slots.size(); ++i)
766 if (
not type_text.empty())
776 for (
size_t value_id = 1; value_id <= function.
next_value_id; ++value_id)
785 out <<
" if (argc != " <<
arity <<
"u)\n"
787 <<
" fprintf(stderr, \"[" <<
names_.
prefix <<
"] function "
789 <<
" expects %zu arguments but received %zu\\n\",\n"
790 <<
" (size_t) " <<
arity <<
"u,\n"
796 for (
size_t i = 0; i < function.
local_slots.size(); ++i)
814 if (
inst.result_id != 0)
823 out <<
"(f" <<
inst.function_id <<
')';
862 <<
"(module->globals[" <<
inst.global_slot_id <<
"], "
875 if (
inst.operands.is_empty())
877 fail(
"C backend cannot emit Store without one operand");
882 out <<
" module->globals[" <<
inst.global_slot_id
890 <<
"(" <<
value(
inst.operands.access(0)) <<
", "
897 if (
inst.operands.is_empty())
899 fail(
"C backend cannot emit Unary without one operand");
924 fail(
"C backend does not support unary operator '"
931 if (
inst.operands.size() < 2)
933 fail(
"C backend cannot emit Binary without two operands");
954 <<
value(
inst.operands.access(0)) <<
", "
959 <<
value(
inst.operands.access(1)) <<
", "
964 <<
"(lhs_value " <<
op_text <<
" rhs_value);\n"
977 <<
value(
inst.operands.access(0)) <<
", "
982 <<
value(
inst.operands.access(1)) <<
", "
986 <<
" if (rhs_value == 0LL)\n"
990 <<
"(lhs_value " <<
op_text <<
" rhs_value);\n"
1006 <<
value(
inst.operands.access(0)) <<
", "
1011 <<
value(
inst.operands.access(1)) <<
", "
1016 <<
"(lhs_value " <<
op_text <<
" rhs_value);\n"
1027 <<
value(
inst.operands.access(0)) <<
", "
1032 <<
value(
inst.operands.access(1)) <<
", "
1037 <<
"(lhs_value " <<
op_text <<
" rhs_value);\n"
1051 fail(
"C backend does not support binary operator '"
1058 if (
inst.operands.is_empty())
1060 fail(
"C backend cannot emit Call without a callee operand");
1065 if (
inst.operands.size() == 1)
1067 <<
value(
inst.operands.access(0)) <<
", NULL, 0u);\n";
1072 for (
size_t i = 1; i <
inst.operands.size(); ++i)
1074 <<
value(
inst.operands.access(i)) <<
", "
1076 + std::to_string(i - 1))
1077 <<
")" << (i + 1 <
inst.operands.size() ?
"," :
"") <<
'\n';
1080 <<
value(
inst.operands.access(0)) <<
", call_args, " << (
inst.operands.size() - 1)
1134 "entered unreachable block in function " + function.
name)
1140 fail(
"C backend cannot emit unterminated block "
1148 const std::string &symbol)
1154 if (
not type_text.empty())
1161 <<
" (void) module;\n";
1168 for (
size_t i = 0; i < function.
blocks.size(); ++i)
1170 const auto &block = function.
blocks.access(i);
1216 warn(
"C backend was asked to emit main(), but the IR module has no top-level body");
1226 <<
"(&module, NULL, 0u);\n"
1227 <<
" fputs(\"Result = \", stdout);\n"
1229 <<
" fputc('\\n', stdout);\n"
1252 std::ostringstream
out;
1254 out <<
"/* Generated by Compiler_Backend_C.H from explicit IR. */\n\n";
1290 if (module ==
nullptr)
1293 emission.errors.append(
"Compiler_C_Backend::emit_module(): null IR module");
Reusable explicit-value IR model, validation, and deterministic dumps.
Exception handling system with formatted messages for Aleph-w.
size_t size_t int32_t value
size_t size_t int32_t * out
Emitter(const Compiler_C_Backend_Options &options_in, const Compiler_IR_Module &module_in, const Compiler_Type_Context *types_in)
Builds an emitter over one module and one option set.
const Compiler_IR_Module * module_
void emit_instruction(std::ostream &out, const Compiler_IR_Instruction &inst, const Compiler_IR_Function &function)
void emit_module_layout(std::ostream &out) const
void emit_function(const size_t index, std::ostream &out)
Compiler_C_Backend_Emission emission_
void emit_value_declarations(std::ostream &out, const Compiler_IR_Function &function) const
void emit_top_level(std::ostream &out)
bool emit_constant_expression(const Compiler_IR_Instruction &inst, std::string &expression, std::string &error) const
const Compiler_C_Backend_Options * options_
void initialize_symbols()
void warn(const std::string &message)
std::string function_symbol(const size_t index) const
void emit_parameter_bindings(std::ostream &out, const Compiler_IR_Function &function) const
std::string type_comment(const Compiler_Type_Id type_id) const
const Compiler_Type_Context * types_
void emit_prototypes(std::ostream &out) const
std::string function_descriptor_symbol(const size_t index) const
void emit_function_descriptors(std::ostream &out) const
void emit_main(std::ostream &out)
void emit_slot_declarations(std::ostream &out, const Compiler_IR_Function &function) const
void emit_function_body(std::ostream &out, const Compiler_IR_Function &function, const std::string &symbol)
void emit_function_signature(std::ostream &out, const std::string &symbol) const
void emit_runtime_prelude(std::ostream &out) const
Compiler_C_Backend_Emission run()
Emits the full C translation unit.
void emit_terminator(std::ostream &out, const Compiler_IR_Block &block, const Compiler_IR_Function &function)
void emit_instruction_comment(std::ostream &out, const Compiler_IR_Instruction &inst) const
void fail(const std::string &message)
Emits portable C from one validated Compiler_IR_Module.
Compiler_C_Backend_Emission emit_module(const Compiler_IR_Module *module, const Compiler_Type_Context *types=nullptr) const
Emits one validated IR module as portable C.
Compiler_C_Backend_Options options
Compiler_C_Backend(Compiler_C_Backend_Options options_in={})
Builds one reusable C backend with options_in.
Context owning all compiler type nodes.
std::string to_string(const Compiler_Type_Id id) const
Renders one type to a deterministic human-readable string.
T & access(const size_t i) const noexcept
Fast access without checking allocation and bound_min_clock checking.
T & append()
Allocate a new entry to the end of array.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
std::string global_name(const Compiler_IR_Global_Slot_Id id)
size_t count_parameters(const Compiler_IR_Function &function) noexcept
std::string token_name(const Compiler_Operator_Kind kind) noexcept
bool parse_integer_literal(const std::string &text, long long &value) noexcept
std::string indent(const size_t count)
std::string value_name(const Compiler_IR_Value_Id id)
std::string upper_identifier(std::string_view text)
std::string block_label(const size_t id)
std::string sanitize_identifier(std::string_view text)
std::string local_name(const Compiler_IR_Local_Slot_Id id)
std::string c_string_literal(std::string_view text)
std::string safe_comment_text(std::string text)
Main namespace for Aleph-w library functions.
const char * compiler_ir_terminator_kind_name(const Compiler_IR_Terminator_Kind kind) noexcept
Stable debug name for one terminator kind.
void message(const char *file, int line, const char *format,...)
Print an informational message with file and line info.
size_t size(Node *root) noexcept
const char * compiler_operator_name(const Compiler_Operator_Kind kind) noexcept
Returns a stable debug name for one operator kind.
Compiler_IR_Validation_Report validate_ir_module(const Compiler_IR_Module &module)
Validates all functions in one lowered IR module.
and
Check uniqueness with explicit hash + equality functors.
size_t Compiler_IR_Value_Id
constexpr size_t compiler_ir_invalid_id() noexcept
Returns the sentinel invalid IR id.
const char * compiler_ir_slot_kind_name(const Compiler_IR_Slot_Kind kind) noexcept
Stable debug name for one slot kind.
void error(const char *file, int line, const char *format,...)
Print an error message with file and line info.
size_t Compiler_IR_Global_Slot_Id
const char * compiler_ir_instruction_kind_name(const Compiler_IR_Instruction_Kind kind) noexcept
Stable debug name for one instruction kind.
Compiler_C_Backend_Emission compiler_emit_c_module(const Compiler_IR_Module *module, const Compiler_C_Backend_Options &options={}, const Compiler_Type_Context *types=nullptr)
Convenience wrapper that emits one IR module to portable C.
Compiler_Operator_Kind
Stable operator kinds shared by reusable compiler layers.
size_t Compiler_IR_Local_Slot_Id
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
static struct argp_option options[]
std::string value_type_name
std::string top_level_symbol
std::string make_function_symbol
std::string require_int_symbol
std::string function_type_name
std::string module_struct_name
std::string require_bool_symbol
std::string tag_function_name
std::string make_bool_symbol
std::string require_function_symbol
std::string function_pointer_type_name
std::string tag_name_symbol
std::string tag_enum_name
std::string make_string_symbol
std::string tag_invalid_name
std::string tag_char_name
std::string tag_bool_name
std::string make_int_symbol
std::string make_unit_symbol
std::string module_init_symbol
std::string require_assigned_symbol
std::string print_value_symbol
std::string make_invalid_symbol
std::string dump_globals_symbol
std::string make_char_symbol
std::string tag_string_name
std::string tag_unit_name
Result of one C backend emission request.
DynArray< std::string > errors
Hard emission failures.
bool valid
Whether emission completed successfully.
DynArray< std::string > warnings
Non-fatal findings.
std::string value_type_name
Generated C typedef name for runtime values.
std::string print_value_symbol
Generated C symbol that prints one runtime value.
std::string module_struct_name
Generated C struct name for module state.
std::string c_prefix
Shared prefix used for runtime helpers and generated symbols.
DynArray< std::string > function_descriptor_symbols
Generated callable descriptor symbols aligned with module.functions.
std::string dump_globals_symbol
Generated C symbol that prints current global state.
std::string module_init_symbol
Generated C symbol that initializes module globals.
bool ok() const noexcept
Returns whether emission finished without hard errors.
std::string top_level_symbol
Generated C symbol for the lowered top-level body, if any.
DynArray< std::string > function_symbols
Generated C function symbols aligned with module.functions.
std::string source
Final generated C translation unit.
Options that control one C backend emission request.
bool emit_comments
Whether to annotate the generated C with readable IR-derived comments.
bool emit_main
Whether to emit a standalone main() when the IR has a top-level body.
std::string module_name
Prefix used to derive stable C identifiers.
One basic block of IR instructions.
Lowered IR for one function or top-level body.
Compiler_IR_Value_Id next_value_id
Next value id to allocate while lowering.
DynArray< Compiler_IR_Block > blocks
Basic blocks in deterministic id order.
std::string name
Debug or source-level name.
Compiler_Type_Id type_id
Full function type, when known.
Compiler_IR_Block_Id entry_block
Canonical entry block.
DynArray< Compiler_IR_Slot > local_slots
Parameter/local slots in stable order.
One instruction producing an optional explicit result value.
Lowered IR module with shared global slots and functions.
DynArray< Compiler_IR_Slot > global_slots
Module-wide global slots.
DynArray< Compiler_IR_Function * > functions
Lowered non-top-level functions.
Compiler_IR_Function * top_level
Optional top-level body lowered as a function.
Compiler_SSA_Block_Id id
Dense SSA block id.
DynArray< Compiler_SSA_Instruction > instructions
Linear SSA instruction list.
std::string label
Deterministic debug label.
Compiler_SSA_Terminator terminator
Explicit block terminator.
Compiler_SSA_Value_Id return_value
Return value, when relevant.
DynArray< Compiler_SSA_Block_Id > successors
Successors in deterministic order.
Compiler_IR_Terminator_Kind kind
Terminator category.
Compiler_SSA_Value_Id condition_value
Branch condition, when relevant.
Lazy and scalable dynamic array implementation.