Files
scc/libs/ast2ir/src/scc_ast2ir.c
T
zzy 28f65f8775 fix(argparse): 修复参数解析错误处理逻辑
当解析过程中出现错误时,应该继续循环而不是直接跳出,
确保完整的错误处理流程能够执行。

fix(ast2ir): 修复函数调用表达式中的类型检查

在每次迭代中重新获取指针以避免向量重分配问题,
并添加类型引用断言确保参数类型有效性。

fix(lexer): 添加词法分析器资源释放

在main函数中正确释放tok_ring资源,防止内存泄漏。

test: 更新测试用例输出字符串格式

将测试用例中的输出字符串从全小写更新为首字母大写,
保持代码风格一致性。
2026-05-25 00:46:42 +08:00

1721 lines
71 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <scc_ast2ir.h>
#include <scc_ast_def.h>
#include <scc_ast_utils.h>
#include <scc_hir_builder.h>
#include <scc_hir_def.h>
// 判断 AST 参数是否为 ... 生成的假 VA_LIST 参数
static cbool is_variadic_marker(const scc_ast_decl_t *decl_param) {
return decl_param->name == nullptr &&
decl_param->param.type->base.type == SCC_AST_TYPE_BUILTIN &&
scc_ast_canon_type(decl_param->param.type)->builtin.type ==
SCC_AST_BUILTIN_TYPE_VA_LIST;
}
// 计算函数类型中的固定参数个数(去掉尾部的 ... 标记)
static int fixed_param_count(const scc_ast_canon_type_t *canon) {
int n = (int)scc_vec_size(canon->function.params);
if (n > 0) {
const scc_ast_decl_t *last =
scc_vec_at(canon->function.params, (usize)(n - 1));
if (is_variadic_marker(last))
return n - 1;
}
return n;
}
static scc_hir_type_ref_t parse_base_type(scc_ast2ir_ctx_t *ctx,
const scc_ast_qual_type_t *ast_type) {
scc_abi_type_layout_t layout;
// 映射内置类型
ctx->abi->compute_type_layout(ctx->abi, (void *)ast_type, &layout);
switch (layout.size) {
case 0:
return scc_hir_builder_type_void(&ctx->builder);
case 1:
return scc_hir_builder_type_i8(&ctx->builder);
case 2:
return scc_hir_builder_type_i16(&ctx->builder);
case 4:
return scc_hir_builder_type_i32(&ctx->builder);
case 8:
return scc_hir_builder_type_i64(&ctx->builder);
break;
default:
break;
}
return SCC_HIR_REF_nullptr;
}
static inline bool scc_hir_type_is_signed(scc_hir_type_tag_t tag) {
switch (tag) {
case SCC_HIR_TYPE_i8:
case SCC_HIR_TYPE_i16:
case SCC_HIR_TYPE_i32:
case SCC_HIR_TYPE_i64:
case SCC_HIR_TYPE_i128:
return true;
case SCC_HIR_TYPE_u8:
case SCC_HIR_TYPE_u16:
case SCC_HIR_TYPE_u32:
case SCC_HIR_TYPE_u64:
case SCC_HIR_TYPE_u128:
return false;
default:
// 指针可以视作无符号整数
return false;
}
}
// 判断是否为算术类型(整数或浮点)
static cbool is_arithmetic_type(const scc_hir_type_t *type) {
switch (type->tag) {
case SCC_HIR_TYPE_i8:
case SCC_HIR_TYPE_i16:
case SCC_HIR_TYPE_i32:
case SCC_HIR_TYPE_i64:
case SCC_HIR_TYPE_i128:
case SCC_HIR_TYPE_u8:
case SCC_HIR_TYPE_u16:
case SCC_HIR_TYPE_u32:
case SCC_HIR_TYPE_u64:
case SCC_HIR_TYPE_u128:
case SCC_HIR_TYPE_f16:
case SCC_HIR_TYPE_f32:
case SCC_HIR_TYPE_f64:
case SCC_HIR_TYPE_f128:
return true;
default:
return false;
}
}
// 辅助函数:生成数组初始化代码
static void emit_array_initialization(scc_ast2ir_ctx_t *ctx,
scc_hir_value_ref_t array_ptr,
const scc_hir_type_t *array_type,
const scc_ast_expr_t *init_expr) {
Assert(array_type->tag == SCC_HIR_TYPE_ARRAY);
scc_hir_type_ref_t elem_type_ref = array_type->data.array.base;
const scc_hir_type_t *elem_type =
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx), elem_type_ref);
usize array_len = array_type->data.array.len;
// 字符串字面量初始化:直接 memcpy
if (init_expr->base.type == SCC_AST_EXPR_STRING_LITERAL) {
scc_hir_value_ref_t str_val = scc_ast2ir_expr(ctx, init_expr, false);
scc_ap_t len_ap;
scc_ap_set_int(&len_ap, array_len);
scc_hir_value_ref_t len_ref = scc_hir_builder_integer(
&ctx->builder, scc_hir_builder_type_u64(&ctx->builder), &len_ap);
scc_hir_builder_builtin_memcpy(&ctx->builder, array_ptr, str_val,
len_ref);
return;
}
// 复合初始化:逐个元素 store
if (init_expr->base.type != SCC_AST_EXPR_COMPOUND) {
Panic("unsupported initializer for array");
}
// 遍历初始化列表
usize idx = 0;
scc_vec_foreach(init_expr->compound.rhs_exprs, i) {
scc_ast_expr_t *elem_expr =
scc_vec_at(init_expr->compound.rhs_exprs, i);
Assert(elem_expr != nullptr);
if (idx >= array_len)
break; // 防止溢出
// 生成元素地址:array_ptr + idx * elem_size
scc_ap_t offset_ap;
scc_ap_set_int(&offset_ap, idx);
scc_hir_value_ref_t idx_val = scc_hir_builder_integer(
&ctx->builder, scc_hir_builder_type_u64(&ctx->builder), &offset_ap);
scc_hir_value_ref_t elem_ptr =
scc_hir_builder_get_elem_ptr(&ctx->builder, array_ptr, idx_val);
// 递归处理:如果元素本身是数组且初始化表达式是复合初始化,需要嵌套处理
if (elem_type->tag == SCC_HIR_TYPE_ARRAY &&
elem_expr->base.type == SCC_AST_EXPR_COMPOUND) {
// 递归调用自身,但注意 elem_ptr 已经是子数组的首地址
emit_array_initialization(ctx, elem_ptr, elem_type, elem_expr);
} else {
// 标量元素:计算右值并 store
scc_hir_value_ref_t val = scc_ast2ir_expr(ctx, elem_expr, false);
scc_hir_builder_store(&ctx->builder, elem_ptr, val);
}
idx++;
}
// 如果初始化列表元素少于数组长度,剩余元素默认零初始化(C 标准要求)
// 这里简单忽略,实际可生成 memset 循环,但为简化暂不处理
}
static void emit_aggregate_initialization(scc_ast2ir_ctx_t *ctx,
scc_hir_value_ref_t base_ptr,
const scc_hir_type_t *type,
const scc_ast_expr_t *init_expr) {
Assert(type->tag == SCC_HIR_TYPE_STRUCT || type->tag == SCC_HIR_TYPE_UNION);
if (init_expr->base.type != SCC_AST_EXPR_COMPOUND) {
Panic("expected compound initializer");
}
usize idx = 0;
scc_vec_foreach(init_expr->compound.rhs_exprs, i) {
if (idx >= type->data.aggregate.fields.size)
break;
scc_ast_expr_t *field_init =
scc_vec_at(init_expr->compound.rhs_exprs, i);
scc_hir_type_ref_t field_type_ref =
scc_vec_at(type->data.aggregate.fields, idx);
const scc_hir_type_t *field_type =
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx), field_type_ref);
scc_ap_t idx_ap;
scc_ap_set_int(&idx_ap, idx);
scc_hir_value_ref_t idx_val = scc_hir_builder_integer(
&ctx->builder, scc_hir_builder_type_u64(&ctx->builder), &idx_ap);
scc_hir_value_ref_t field_ptr =
scc_hir_builder_get_elem_ptr(&ctx->builder, base_ptr, idx_val);
if (field_type->tag == SCC_HIR_TYPE_ARRAY) {
emit_array_initialization(ctx, field_ptr, field_type, field_init);
} else if (field_type->tag == SCC_HIR_TYPE_STRUCT ||
field_type->tag == SCC_HIR_TYPE_UNION) {
emit_aggregate_initialization(ctx, field_ptr, field_type,
field_init);
} else {
scc_hir_value_ref_t val = scc_ast2ir_expr(ctx, field_init, false);
scc_hir_builder_store(&ctx->builder, field_ptr, val);
}
idx++;
}
}
// static inline void parse_struct_union_layout(scc_ast_qual_type_t *type) {}
// 辅助函数:计算数组实际长度(如果原长度为0)
static void resolve_array_length(scc_ast2ir_ctx_t *ctx,
const scc_hir_type_t *orig_array_type,
scc_hir_type_t *resolved_array_type,
const scc_ast_expr_t *init_expr) {
*resolved_array_type = *orig_array_type; // 拷贝
Assert(orig_array_type->tag == SCC_HIR_TYPE_ARRAY);
if (orig_array_type->data.array.len != 0)
return; // 长度已知,无需推断
usize new_len = 0;
switch (init_expr->base.type) {
case SCC_AST_EXPR_STRING_LITERAL:
// 字符串字面量:长度 = 字符串字符数 + 1('\0')
// TODO: L"" \n \r 计算 暂不支持
new_len = scc_strlen(init_expr->literal.lexme) + 1;
break;
case SCC_AST_EXPR_COMPOUND: {
// 复合初始化:元素个数 = 初始化列表长度
scc_vec_foreach(init_expr->compound.lhs_exprs, i) {
scc_ast_expr_t *elem = scc_vec_at(init_expr->compound.lhs_exprs, i);
// TODO: 支持嵌套的多维数组初始化(递归)
// 这里简化:只统计顶层元素个数,假设是一维数组
new_len++;
}
break;
}
default:
Panic("unsupported initializer for zero-length array");
}
resolved_array_type->data.array.len = new_len;
}
scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
const scc_ast_qual_type_t *ast_type) {
if (ctx == nullptr || ast_type == nullptr) {
LOG_ERROR("args is nullptr");
return 0;
}
scc_hir_type_t ir_type;
switch (ast_type->base.type) {
case SCC_AST_TYPE_BUILTIN: {
return parse_base_type(ctx, ast_type);
}
case SCC_AST_TYPE_POINTER: {
scc_hir_type_init(&ir_type, SCC_HIR_TYPE_PTR);
scc_hir_type_ref_t pointee_type =
scc_ast2ir_type(ctx, scc_ast_canon_type(ast_type)->pointer.pointee);
ir_type.data.pointer.base = pointee_type;
break;
}
case SCC_AST_TYPE_ARRAY: {
scc_hir_type_init(&ir_type, SCC_HIR_TYPE_ARRAY);
scc_hir_type_ref_t element_type =
scc_ast2ir_type(ctx, scc_ast_canon_type(ast_type)->array.element);
ir_type.data.array.base = element_type;
ir_type.data.array.len = 0;
if (scc_ast_canon_type(ast_type)->array.size) {
// TODO constant expression
if (scc_ast_canon_type(ast_type)->array.size->base.type !=
SCC_AST_EXPR_INT_LITERAL) {
Panic("TODO: array size expression");
}
scc_ap_t value;
scc_ap_from_cstr(
&value, scc_ast_canon_type(ast_type)->array.size->literal.lexme,
10);
// FIXME hack
ir_type.data.array.len = value.data.digit;
}
} break;
case SCC_AST_TYPE_FUNCTION: {
scc_hir_type_init(&ir_type, SCC_HIR_TYPE_FUNC);
// 处理返回类型
scc_hir_type_ref_t ret_type = scc_ast2ir_type(
ctx, scc_ast_canon_type(ast_type)->function.return_type);
// 将返回类型添加到程序的类型容器中
ir_type.data.function.ret_type = ret_type;
// 转换参数类型(跳过尾部的 ... 假参数)
scc_hir_type_ref_vec_t params;
scc_vec_init(params);
int n_fixed = fixed_param_count(scc_ast_canon_type(ast_type));
scc_ast_decl_vec_t *ast_params =
&scc_ast_canon_type(ast_type)->function.params;
for (int i = 0; i < n_fixed; i++) {
scc_ast_decl_t *decl_param = scc_vec_at(*ast_params, i);
Assert(decl_param->base.type == SCC_AST_DECL_PARAM);
scc_hir_type_ref_t tmp_type =
scc_ast2ir_type(ctx, decl_param->param.type);
scc_vec_push(params, tmp_type);
}
ir_type.data.function.params = params;
} break;
case SCC_AST_TYPE_STRUCT:
case SCC_AST_TYPE_UNION: {
const scc_ast_canon_type_t *canon = scc_ast_canon_type(ast_type);
// === 1. 查缓存,如果已存在则直接返回(递归时一定会命中) ===
scc_hir_type_ref_t cached =
(scc_hir_type_ref_t)(usize)scc_hashtable_get(&ctx->type_cache,
canon);
if (cached != 0) {
return cached;
}
// === 2. 创建占位类型(字段为空) ===
scc_hir_type_t placeholder;
scc_hir_type_init(&placeholder,
ast_type->base.type == SCC_AST_TYPE_STRUCT
? SCC_HIR_TYPE_STRUCT
: SCC_HIR_TYPE_UNION);
// 可以给占位符一个调试名
if (canon->record.name) {
placeholder.name = canon->record.name;
}
// === 3. 直接添加到模块,不经过 builder 的 uniquing ===
// 因为此时我们不需要类型去重,只需要一个确定不移的引用
scc_hir_type_ref_t place_ref =
scc_hir_module_add_type(scc_ast2ir_mir_module(ctx), &placeholder);
// === 4. 将映射写入缓存(关键!必须在递归前) ===
scc_hashtable_set(&ctx->type_cache, canon, (void *)(usize)place_ref);
// === 5. 递归解析所有字段 ===
// 此时若字段类型指回本结构体,将直接通过缓存返回 place_ref
scc_hir_type_ref_vec_t fields;
scc_vec_init(fields);
scc_ast_decl_t *decl = canon->record.decl;
if (decl == nullptr) {
Panic("struct/union declaration is missing");
}
scc_vec_foreach(decl->record.fields, i) {
scc_ast_decl_t *field_decl = scc_vec_at(decl->record.fields, i);
Assert(field_decl->base.type == SCC_AST_DECL_VAR);
scc_hir_type_ref_t field_ir_type =
scc_ast2ir_type(ctx, field_decl->var.type);
scc_vec_push(fields, field_ir_type);
}
// === 6. 将字段填入占位类型 ===
scc_hir_type_t *place_type =
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx), place_ref);
// 注意:scc_hir_type_init 已经为 struct/union 初始化了 fields 空向量
// 这里直接 push 即可(也可以先 scc_vec_free 再 init,看需要)
scc_vec_foreach(fields, i) {
scc_vec_push(place_type->data.aggregate.fields,
scc_vec_at(fields, i));
}
scc_vec_free(fields); // 释放临时向量
// === 7. 返回占位符的引用(现在已经变成完整类型) ===
return place_ref;
} break;
case SCC_AST_TYPE_ENUM:
scc_ast_canon_type_t *int_canon_type = scc_ast_ctx_get_builtin_type(
ctx->ast_ctx, SCC_AST_BUILTIN_TYPE_INT);
scc_ast_qual_type_t int_type = {
.base.type = SCC_AST_TYPE_BUILTIN,
.type = int_canon_type,
};
return parse_base_type(ctx, &int_type);
case SCC_AST_TYPE_TYPEDEF:
// TODO maybe using cache
return scc_ast2ir_type(
ctx,
scc_ast_canon_type(ast_type)->typedef_type.decl->typedef_decl.type);
default:
LOG_FATAL("Unsupported AST type: %d", ast_type->base.type);
return 0;
}
return scc_hir_builder_type(&ctx->builder, &ir_type);
}
scc_hir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
const scc_ast_expr_t *expr) {
// scc_hir_bblock_ref_t start_block =
// scc_hir_builder_current_bblock(&ctx->builder);
scc_hir_value_ref_t right_block =
scc_hir_builder_create_bblock(&ctx->builder, "logic_right");
scc_hir_value_ref_t end_block =
scc_hir_builder_create_bblock(&ctx->builder, "logic_end");
// 为结果创建临时存储空间
scc_hir_type_ref_t int32_type = scc_hir_builder_type_i32(&ctx->builder);
scc_hir_value_ref_t result_var =
scc_hir_builder_alloca(&ctx->builder, int32_type, "logic_result");
// 计算左操作数
scc_hir_value_ref_t left_val =
scc_ast2ir_expr(ctx, expr->binary.lhs, false);
scc_ap_t zero_ap;
scc_ap_set_int(&zero_ap, 0);
scc_ap_t one_ap;
scc_ap_set_int(&one_ap, 1);
scc_hir_value_ref_t zero_val =
scc_hir_builder_integer(&ctx->builder, int32_type, &zero_ap);
scc_hir_value_ref_t one_val =
scc_hir_builder_integer(&ctx->builder, int32_type, &one_ap);
if (expr->binary.op == SCC_AST_OP_LOGICAL_AND) {
// a && b
scc_hir_value_ref_t false_block =
scc_hir_builder_create_bblock(&ctx->builder, "and_false");
// 如果左操作数为0,结果为0(短路)
scc_hir_value_ref_t is_left_zero = scc_hir_builder_binop(
&ctx->builder, SCC_HIR_OP_EQ, left_val, zero_val);
scc_hir_builder_branch(&ctx->builder, is_left_zero, false_block,
right_block);
// false_block: 左边为0,结果为0
scc_hir_builder_append_bblock(&ctx->builder, false_block);
scc_hir_builder_set_current_bblock(&ctx->builder, false_block);
scc_hir_builder_store(&ctx->builder, result_var, zero_val);
scc_hir_builder_jump(&ctx->builder, end_block);
// right_block: 左边非0,计算右边
scc_hir_builder_append_bblock(&ctx->builder, right_block);
scc_hir_builder_set_current_bblock(&ctx->builder, right_block);
scc_hir_value_ref_t right_val =
scc_ast2ir_expr(ctx, expr->binary.rhs, false);
scc_hir_value_ref_t is_right_zero = scc_hir_builder_binop(
&ctx->builder, SCC_HIR_OP_EQ, right_val, zero_val);
scc_hir_value_ref_t result =
scc_hir_builder_binop(&ctx->builder, SCC_HIR_OP_XOR, is_right_zero,
one_val); // !right == 0 ? 1 : 0
scc_hir_builder_store(&ctx->builder, result_var, result);
scc_hir_builder_jump(&ctx->builder, end_block);
} else { // SCC_AST_OP_LOGICAL_OR
// a || b
scc_hir_value_ref_t true_block =
scc_hir_builder_create_bblock(&ctx->builder, "or_true");
// 如果左操作数非0,结果为1(短路)
scc_hir_value_ref_t is_left_nonzero = scc_hir_builder_binop(
&ctx->builder, SCC_HIR_OP_NEQ, left_val, zero_val);
scc_hir_builder_branch(&ctx->builder, is_left_nonzero, true_block,
right_block);
// true_block: 左边非0,结果为1
scc_hir_builder_append_bblock(&ctx->builder, true_block);
scc_hir_builder_set_current_bblock(&ctx->builder, true_block);
scc_hir_builder_store(&ctx->builder, result_var, one_val);
scc_hir_builder_jump(&ctx->builder, end_block);
// right_block: 左边为0,计算右边
scc_hir_builder_append_bblock(&ctx->builder, right_block);
scc_hir_builder_set_current_bblock(&ctx->builder, right_block);
scc_hir_value_ref_t right_val =
scc_ast2ir_expr(ctx, expr->binary.rhs, false);
scc_hir_value_ref_t is_right_zero = scc_hir_builder_binop(
&ctx->builder, SCC_HIR_OP_EQ, right_val, zero_val);
scc_hir_value_ref_t result =
scc_hir_builder_binop(&ctx->builder, SCC_HIR_OP_XOR, is_right_zero,
one_val); // !right == 0 ? 1 : 0
scc_hir_builder_store(&ctx->builder, result_var, result);
scc_hir_builder_jump(&ctx->builder, end_block);
}
// 设置结束块为当前块,并返回结果
scc_hir_builder_append_bblock(&ctx->builder, end_block);
scc_hir_builder_set_current_bblock(&ctx->builder, end_block);
return scc_hir_builder_load(&ctx->builder, result_var);
}
/**
* @brief
*
* @param ctx
* @param expr
* @return scc_hir_value_ref_t
*/
scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
const scc_ast_expr_t *expr,
cbool is_lvalue) {
if (ctx == nullptr || expr == nullptr) {
LOG_ERROR("args is nullptr");
return 0;
}
cbool is_assign = true;
switch (expr->base.type) {
case SCC_AST_EXPR_BINARY: {
scc_ast_expr_t tmp_expr;
scc_hir_value_ref_t lhs = SCC_HIR_REF_nullptr,
rhs = SCC_HIR_REF_nullptr;
switch (expr->binary.op) {
case SCC_AST_OP_ASSIGN: // =
rhs = scc_ast2ir_expr(ctx, expr->binary.rhs, false);
break;
case SCC_AST_OP_ASSIGN_ADD: // +=
scc_ast_expr_binary_init(&tmp_expr, SCC_AST_OP_ADD,
expr->binary.lhs, expr->binary.rhs,
expr->base.loc);
rhs = scc_ast2ir_expr(ctx, &tmp_expr, false);
break;
case SCC_AST_OP_ASSIGN_SUB: // -=
scc_ast_expr_binary_init(&tmp_expr, SCC_AST_OP_SUB,
expr->binary.lhs, expr->binary.rhs,
expr->base.loc);
rhs = scc_ast2ir_expr(ctx, &tmp_expr, false);
break;
case SCC_AST_OP_ASSIGN_MUL: // *=
scc_ast_expr_binary_init(&tmp_expr, SCC_AST_OP_MUL,
expr->binary.lhs, expr->binary.rhs,
expr->base.loc);
rhs = scc_ast2ir_expr(ctx, &tmp_expr, false);
break;
case SCC_AST_OP_ASSIGN_DIV: // /=
scc_ast_expr_binary_init(&tmp_expr, SCC_AST_OP_DIV,
expr->binary.lhs, expr->binary.rhs,
expr->base.loc);
rhs = scc_ast2ir_expr(ctx, &tmp_expr, false);
break;
case SCC_AST_OP_ASSIGN_MOD: // %=
scc_ast_expr_binary_init(&tmp_expr, SCC_AST_OP_MOD,
expr->binary.lhs, expr->binary.rhs,
expr->base.loc);
rhs = scc_ast2ir_expr(ctx, &tmp_expr, false);
break;
case SCC_AST_OP_ASSIGN_AND: // &=
scc_ast_expr_binary_init(&tmp_expr, SCC_AST_OP_BITWISE_AND,
expr->binary.lhs, expr->binary.rhs,
expr->base.loc);
rhs = scc_ast2ir_expr(ctx, &tmp_expr, false);
break;
case SCC_AST_OP_ASSIGN_XOR: // ^=
scc_ast_expr_binary_init(&tmp_expr, SCC_AST_OP_BITWISE_XOR,
expr->binary.lhs, expr->binary.rhs,
expr->base.loc);
rhs = scc_ast2ir_expr(ctx, &tmp_expr, false);
break;
case SCC_AST_OP_ASSIGN_OR: // |=
scc_ast_expr_binary_init(&tmp_expr, SCC_AST_OP_BITWISE_OR,
expr->binary.lhs, expr->binary.rhs,
expr->base.loc);
rhs = scc_ast2ir_expr(ctx, &tmp_expr, false);
break;
case SCC_AST_OP_ASSIGN_LSHIFT: // <<=
scc_ast_expr_binary_init(&tmp_expr, SCC_AST_OP_LEFT_SHIFT,
expr->binary.lhs, expr->binary.rhs,
expr->base.loc);
rhs = scc_ast2ir_expr(ctx, &tmp_expr, false);
break;
case SCC_AST_OP_ASSIGN_RSHIFT: // >>=
scc_ast_expr_binary_init(&tmp_expr, SCC_AST_OP_RIGHT_SHIFT,
expr->binary.lhs, expr->binary.rhs,
expr->base.loc);
rhs = scc_ast2ir_expr(ctx, &tmp_expr, false);
break;
default:
is_assign = false;
break;
}
if (is_assign) {
Assert(rhs != SCC_HIR_REF_nullptr);
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, true);
// 将 RHS 转换为 LHS 指向的类型(C11 6.5.16.1 简单赋值)
scc_hir_type_t *lhs_ptr_type = scc_hir_module_get_type_by_value(
scc_ast2ir_mir_module(ctx), lhs);
if (lhs_ptr_type->tag == SCC_HIR_TYPE_PTR &&
is_arithmetic_type(
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx),
lhs_ptr_type->data.pointer.base))) {
rhs = scc_ast2ir_emit_conversion(
ctx, rhs, lhs_ptr_type->data.pointer.base);
}
return scc_hir_builder_store(&ctx->builder, lhs, rhs);
}
if (expr->binary.op == SCC_AST_OP_LOGICAL_AND ||
expr->binary.op == SCC_AST_OP_LOGICAL_OR) {
// TODO 类型提升
return scc_ast2ir_logical_expr(ctx, expr);
}
rhs = scc_ast2ir_expr(ctx, expr->binary.rhs, false);
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, false);
// 类型提升:对算术类型二元操作应用寻常算术转换(C11 6.3.1.8)
// 移位操作符不适用(仅对每个操作数单独整数提升)
cbool is_shift = (expr->binary.op == SCC_AST_OP_LEFT_SHIFT ||
expr->binary.op == SCC_AST_OP_RIGHT_SHIFT);
if (!is_shift && expr->binary.op != SCC_AST_OP_COMMA) {
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
scc_hir_type_ref_t lhs_type_ref =
scc_hir_module_get_value(module, lhs)->type;
scc_hir_type_ref_t rhs_type_ref =
scc_hir_module_get_value(module, rhs)->type;
scc_hir_type_t *lhs_type =
scc_hir_module_get_type(module, lhs_type_ref);
scc_hir_type_t *rhs_type =
scc_hir_module_get_type(module, rhs_type_ref);
if (is_arithmetic_type(lhs_type) && is_arithmetic_type(rhs_type)) {
scc_hir_type_ref_t common =
scc_ast2ir_usual_arithmetic_conversion(ctx, lhs_type_ref,
rhs_type_ref);
if (common != 0) {
lhs = scc_ast2ir_emit_conversion(ctx, lhs, common);
rhs = scc_ast2ir_emit_conversion(ctx, rhs, common);
}
}
} else if (is_shift) {
// 移位操作符:只进行整数提升(C11 6.5.7)
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
scc_hir_type_ref_t lhs_type_ref =
scc_hir_module_get_value(module, lhs)->type;
scc_hir_type_ref_t promoted =
scc_ast2ir_integer_promotion(ctx, lhs_type_ref);
if (promoted != 0)
lhs = scc_ast2ir_emit_conversion(ctx, lhs, promoted);
}
// 映射操作符
scc_hir_op_type_t op;
switch (expr->binary.op) {
/* clang-format off */
case SCC_AST_OP_ADD: op = SCC_HIR_OP_ADD; break;
case SCC_AST_OP_SUB: op = SCC_HIR_OP_SUB; break;
case SCC_AST_OP_MUL: op = SCC_HIR_OP_MUL; break;
case SCC_AST_OP_DIV: op = SCC_HIR_OP_DIV; break;
case SCC_AST_OP_MOD: op = SCC_HIR_OP_MOD; break;
case SCC_AST_OP_BITWISE_AND: op = SCC_HIR_OP_AND; break;
case SCC_AST_OP_BITWISE_OR: op = SCC_HIR_OP_OR; break;
case SCC_AST_OP_BITWISE_XOR: op = SCC_HIR_OP_XOR; break;
case SCC_AST_OP_LEFT_SHIFT: op = SCC_HIR_OP_SHL; break;
case SCC_AST_OP_RIGHT_SHIFT: {
op = SCC_HIR_OP_SHR;
// FIXME op = SCC_HIR_OP_SAR;
break;
}
case SCC_AST_OP_EQUAL: op = SCC_HIR_OP_EQ; break;
case SCC_AST_OP_NOT_EQUAL: op = SCC_HIR_OP_NEQ; break;
case SCC_AST_OP_LESS: op = SCC_HIR_OP_LT; break;
case SCC_AST_OP_LESS_EQUAL: op = SCC_HIR_OP_LE; break;
case SCC_AST_OP_GREATER: op = SCC_HIR_OP_GT; break;
case SCC_AST_OP_GREATER_EQUAL: op = SCC_HIR_OP_GE; break;
case SCC_AST_OP_COMMA: {
// 逗号运算符:计算左表达式,丢弃结果,返回右表达式
return rhs;
}
/* 逻辑操作符 */
case SCC_AST_OP_LOGICAL_OR: // ||
case SCC_AST_OP_LOGICAL_AND: // &&
UNREACHABLE();
return 0;
/* clang-format on */
default:
LOG_FATAL("Unsupported binary operator: %d", expr->binary.op);
return 0;
}
// 创建操作节点
return scc_hir_builder_binop(&ctx->builder, op, lhs, rhs);
} break;
case SCC_AST_EXPR_UNARY: {
if (expr->unary.op == SCC_AST_OP_ADDRESS_OF) {
return scc_ast2ir_expr(ctx, expr->unary.operand, true);
} else if (expr->unary.op == SCC_AST_OP_INDIRECTION) {
// 从地址取值
scc_hir_value_ref_t ptr =
scc_ast2ir_expr(ctx, expr->unary.operand, false);
if (is_lvalue) {
// 作为左值使用(如 *ptr = ...),直接返回指针值(地址)
return ptr;
} else {
// 作为右值使用(如 x = *ptr),加载指针指向的值
return scc_hir_builder_load(&ctx->builder, ptr);
}
}
scc_hir_value_ref_t operand =
scc_ast2ir_expr(ctx, expr->unary.operand, is_lvalue);
switch (expr->unary.op) {
case SCC_AST_OP_UNARY_PLUS:
/* just pass */
return operand;
case SCC_AST_OP_UNARY_MINUS: {
// 负号
// 实现为0 - operand
scc_hir_type_ref_t type_ref =
scc_hir_builder_type_i32(&ctx->builder);
scc_ap_t value;
scc_ap_set_int(&value, 0);
scc_hir_value_ref_t zero_ref =
scc_hir_builder_integer(&ctx->builder, type_ref, &value);
return scc_hir_builder_binop(&ctx->builder, SCC_HIR_OP_SUB,
zero_ref, operand);
}
case SCC_AST_OP_ADDRESS_OF:
case SCC_AST_OP_INDIRECTION:
UNREACHABLE();
break;
case SCC_AST_OP_BITWISE_NOT:
// 按位取反
return scc_hir_builder_binop(&ctx->builder, SCC_HIR_OP_NOT, operand,
0);
case SCC_AST_OP_LOGICAL_NOT: {
// 逻辑非
// 实现为与0比较
scc_hir_type_ref_t type_ref =
scc_hir_builder_type_i32(&ctx->builder);
scc_ap_t value;
scc_ap_set_int(&value, 0);
scc_hir_value_ref_t zero_ref =
scc_hir_builder_integer(&ctx->builder, type_ref, &value);
return scc_hir_builder_binop(&ctx->builder, SCC_HIR_OP_EQ, zero_ref,
operand);
}
case SCC_AST_OP_PREFIX_INCREMENT:
case SCC_AST_OP_PREFIX_DECREMENT: {
// 获取左值地址
scc_hir_value_ref_t addr =
scc_ast2ir_expr(ctx, expr->unary.operand, true);
scc_hir_value_ref_t old_val =
scc_hir_builder_load(&ctx->builder, addr);
scc_hir_type_ref_t old_type =
scc_hir_module_get_value(
scc_hir_builder_get_module(&ctx->builder), old_val)
->type;
// 整数提升:C11 6.3.1.1,对 short/char 等类型提升为 int
scc_hir_type_ref_t promoted_type_ref =
scc_ast2ir_integer_promotion(ctx, old_type);
scc_hir_value_ref_t promoted = old_val;
if (promoted_type_ref != 0) {
promoted =
scc_ast2ir_emit_conversion(ctx, old_val, promoted_type_ref);
} else {
promoted_type_ref = old_type;
}
scc_hir_value_ref_t one = scc_hir_builder_integer(
&ctx->builder, promoted_type_ref,
&(scc_ap_t){.data.digit = 1, .capacity = -1});
scc_hir_op_type_t op =
(expr->unary.op == SCC_AST_OP_PREFIX_INCREMENT)
? SCC_HIR_OP_ADD
: SCC_HIR_OP_SUB;
scc_hir_value_ref_t new_val =
scc_hir_builder_binop(&ctx->builder, op, promoted, one);
// 如果原类型不是提升后的类型,需要截断回原类型再存储
scc_hir_value_ref_t stored_val = new_val;
if (promoted_type_ref != old_type) {
stored_val = scc_ast2ir_emit_conversion(ctx, new_val, old_type);
}
scc_hir_builder_store(&ctx->builder, addr, stored_val);
Assert(new_val != SCC_HIR_REF_nullptr);
return new_val; // 表达式的值是提升后的新值(符合 C 标准)
} break;
case SCC_AST_OP_POSTFIX_INCREMENT:
case SCC_AST_OP_POSTFIX_DECREMENT: {
// 获取左值地址
scc_hir_value_ref_t addr =
scc_ast2ir_expr(ctx, expr->unary.operand, true);
scc_hir_value_ref_t old_val =
scc_hir_builder_load(&ctx->builder, addr);
scc_hir_type_ref_t old_type =
scc_hir_module_get_value(
scc_hir_builder_get_module(&ctx->builder), old_val)
->type;
// 整数提升(C11 6.3.1.1)
scc_hir_type_ref_t promoted_type_ref =
scc_ast2ir_integer_promotion(ctx, old_type);
scc_hir_value_ref_t promoted = old_val;
if (promoted_type_ref != 0) {
promoted =
scc_ast2ir_emit_conversion(ctx, old_val, promoted_type_ref);
} else {
promoted_type_ref = old_type;
}
scc_hir_value_ref_t one = scc_hir_builder_integer(
&ctx->builder, promoted_type_ref,
&(scc_ap_t){.data.digit = 1, .capacity = -1});
scc_hir_op_type_t op =
(expr->unary.op == SCC_AST_OP_POSTFIX_INCREMENT)
? SCC_HIR_OP_ADD
: SCC_HIR_OP_SUB;
scc_hir_value_ref_t new_val =
scc_hir_builder_binop(&ctx->builder, op, promoted, one);
scc_hir_value_ref_t stored_val = new_val;
if (promoted_type_ref != old_type) {
stored_val = scc_ast2ir_emit_conversion(ctx, new_val, old_type);
}
scc_hir_builder_store(&ctx->builder, addr, stored_val);
// 后缀返回旧值的提升后版本(C11 6.5.2.4)
return promoted;
} break;
default:
LOG_FATAL("Unsupported unary operator: %d", expr->unary.op);
return 0;
}
UNREACHABLE();
} break;
case SCC_AST_EXPR_COND: {
scc_hir_type_ref_t true_type = SCC_HIR_REF_nullptr;
scc_hir_type_ref_t false_type = SCC_HIR_REF_nullptr;
scc_hir_value_ref_t true_block =
scc_hir_builder_bblock(&ctx->builder, "cond_true");
scc_hir_value_ref_t false_block =
scc_hir_builder_bblock(&ctx->builder, "cond_false");
scc_hir_value_ref_t merge_block =
scc_hir_builder_bblock(&ctx->builder, "cond_merge");
scc_hir_value_ref_t cond_node =
scc_ast2ir_expr(ctx, expr->cond.cond, false);
scc_hir_builder_branch(&ctx->builder, cond_node, true_block,
false_block);
// 生成true分支
scc_hir_builder_set_current_bblock(&ctx->builder, true_block);
scc_hir_value_ref_t true_val =
scc_ast2ir_expr(ctx, expr->cond.then_expr, false);
true_type = scc_hir_module_get_value(
scc_hir_builder_get_module(&ctx->builder), true_val)
->type;
Assert(true_type != SCC_HIR_REF_nullptr);
scc_hir_value_ref_t result_slot =
scc_hir_builder_alloca(&ctx->builder, true_type, "cond_result");
scc_hir_builder_store(&ctx->builder, result_slot, true_val);
scc_hir_builder_jump(&ctx->builder, merge_block);
// 生成false分支
scc_hir_builder_set_current_bblock(&ctx->builder, false_block);
scc_hir_value_ref_t false_val =
scc_ast2ir_expr(ctx, expr->cond.else_expr, false);
false_type = scc_hir_module_get_value(
scc_hir_builder_get_module(&ctx->builder), false_val)
->type;
Assert(false_type != SCC_HIR_REF_nullptr);
scc_hir_builder_store(&ctx->builder, result_slot, false_val);
scc_hir_builder_jump(&ctx->builder, merge_block);
// 合并并返回
scc_hir_builder_set_current_bblock(&ctx->builder, merge_block);
if (true_type != false_type) {
LOG_ERROR("Type mismatch in conditional expression");
// FIXME need panic
}
return scc_hir_builder_load(&ctx->builder, result_slot);
} break;
case SCC_AST_EXPR_CALL: {
// 转换参数
scc_hir_value_ref_vec_t args;
scc_vec_init(args);
// 获取函数类型信息用于参数转换。注意:不能长期持有指向 types 向量
// 内部的指针(如 ft->data.function.params),因为递归的
// scc_ast2ir_expr 可能触发 scc_hir_module_add_type 导致 realloc。
// 改为通过 func_type_ref(稳定的索引)每次需要时重新获取指针。
scc_hir_func_ref_t callee_func =
(scc_hir_func_ref_t)(usize)scc_hashtable_get(
&ctx->symtab, expr->call.callee->identifier._target->name);
scc_hir_type_ref_t func_type_ref = SCC_HIR_REF_nullptr;
cbool is_variadic = false;
int fixed_count = 0;
if (callee_func != SCC_HIR_REF_nullptr) {
scc_hir_func_t *hir_func = scc_hir_module_get_func(
scc_ast2ir_mir_module(ctx), callee_func);
scc_hir_func_meta_t *meta = SCC_HIR_FUNC_META(hir_func);
is_variadic = meta->is_variadic;
func_type_ref = meta->type;
if (func_type_ref != SCC_HIR_REF_nullptr) {
const scc_hir_type_t *ft = scc_hir_module_get_type(
scc_ast2ir_mir_module(ctx), func_type_ref);
if (ft != nullptr && ft->tag == SCC_HIR_TYPE_FUNC)
fixed_count = (int)ft->data.function.params.size;
}
}
scc_vec_foreach(expr->call.args, i) {
scc_ast_expr_t *arg_expr = scc_vec_at(expr->call.args, i);
scc_hir_value_ref_t arg_node;
arg_node = scc_ast2ir_expr(ctx, arg_expr, false);
if ((int)i < fixed_count) {
// 固定参数:转换为形参类型
// 每次迭代重新获取指针(scc_ast2ir_expr 可能触发 types 向量
// realloc)
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
const scc_hir_type_t *ft =
scc_hir_module_get_type(module, func_type_ref);
scc_hir_type_ref_t param_type =
scc_vec_at(ft->data.function.params, i);
arg_node =
scc_ast2ir_emit_conversion(ctx, arg_node, param_type);
} else if (is_variadic) {
// 可变参数:只应用默认参数提升(C11 6.5.2.2)
// 整数提升:char/short → int
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
scc_hir_type_ref_t arg_type_ref =
scc_hir_module_get_value(module, arg_node)->type;
Assert(arg_type_ref != 0);
scc_hir_type_tag_t arg_tag =
scc_hir_module_get_type(module, arg_type_ref)->tag;
scc_hir_type_ref_t promoted =
scc_ast2ir_integer_promotion(ctx, arg_type_ref);
if (promoted != 0) {
arg_node =
scc_ast2ir_emit_conversion(ctx, arg_node, promoted);
} else if (arg_tag == SCC_HIR_TYPE_f32) {
// float → double(默认参数提升)
scc_hir_type_t f64_desc;
scc_hir_type_init(&f64_desc, SCC_HIR_TYPE_f64);
scc_hir_type_ref_t f64_ref =
scc_hir_builder_type(&ctx->builder, &f64_desc);
arg_node =
scc_ast2ir_emit_conversion(ctx, arg_node, f64_ref);
}
// 指针、i32/i64 等保持不变
}
scc_vec_push(args, arg_node);
}
// 创建调用节点(需要查找函数定义)
if (!callee_func) {
LOG_ERROR("Function %s not found",
expr->call.callee->identifier._target->name);
}
scc_hir_value_ref_t node = scc_hir_builder_call(
&ctx->builder, callee_func, args.data, args.size);
scc_vec_free(args);
return node;
}
case SCC_AST_EXPR_ARRAY_SUBSCRIPT: {
// 1. 计算数组/指针基址(右值,得到地址)
scc_hir_value_ref_t base_ptr =
scc_ast2ir_expr(ctx, expr->subscript.array, true);
// 2. 计算下标值
scc_hir_value_ref_t index =
scc_ast2ir_expr(ctx, expr->subscript.index, false);
// 保证 index 至少 64 位,防止后端寄存器分配时宽度错误
scc_hir_type_t *idx_type =
scc_hir_module_get_type_by_value(scc_ast2ir_mir_module(ctx), index);
if (idx_type != nullptr &&
scc_hir_module_type_size(scc_ast2ir_mir_module(ctx), idx_type) <
sizeof(void *)) {
scc_hir_type_t ptrw_desc;
scc_hir_type_init(&ptrw_desc, SCC_HIR_TYPE_u64);
scc_hir_type_ref_t ptrw_ref =
scc_hir_builder_type(&ctx->builder, &ptrw_desc);
index = scc_ast2ir_emit_conversion(ctx, index, ptrw_ref);
}
// 3. 生成 getptr(GEP)
scc_hir_value_ref_t elem_ptr =
scc_hir_builder_get_elem_ptr(&ctx->builder, base_ptr, index);
// 4. 根据左值/右值返回
if (is_lvalue) {
return elem_ptr; // 作为左值:返回地址
} else {
return scc_hir_builder_load(&ctx->builder,
elem_ptr); // 作为右值:加载值
}
}
case SCC_AST_EXPR_MEMBER: {
// 1. 获取基对象的左值(地址)
scc_hir_value_ref_t base_ptr =
scc_ast2ir_expr(ctx, expr->member.base, true);
// 2. 通过偏移生成字段地址
// 需要基对象类型来计算索引:假设 sema 填好了 _target_idx
usize field_idx = expr->member._target_idx;
scc_ap_t idx_ap;
scc_ap_set_int(&idx_ap, field_idx);
scc_hir_value_ref_t idx_val = scc_hir_builder_integer(
&ctx->builder, scc_hir_builder_type_u64(&ctx->builder), &idx_ap);
scc_hir_value_ref_t field_ptr =
scc_hir_builder_get_elem_ptr(&ctx->builder, base_ptr, idx_val);
if (is_lvalue)
return field_ptr;
else
return scc_hir_builder_load(&ctx->builder, field_ptr);
}
case SCC_AST_EXPR_PTR_MEMBER: {
// 1. 计算指针值(obj->field 等价于 (*obj).field)
scc_hir_value_ref_t obj_ptr =
scc_ast2ir_expr(ctx, expr->member.base, false);
// 2. 解引用得到对象地址,再访问成员
// 但更简单:先 load 出对象值?不对:obj
// 是指向结构体的指针,我们需要指针的地址? 实际上,obj->field 相当于
// (*(obj)).field,所以可以直接用 obj 作为基地址进行 get_elem_ptr
// 因为 get_elem_ptr 接收一个指针,obj 本身就是指向结构体的指针。
usize field_idx = expr->member._target_idx;
scc_ap_t idx_ap;
scc_ap_set_int(&idx_ap, field_idx);
scc_hir_value_ref_t idx_val = scc_hir_builder_integer(
&ctx->builder, scc_hir_builder_type_u64(&ctx->builder), &idx_ap);
scc_hir_value_ref_t field_ptr =
scc_hir_builder_get_elem_ptr(&ctx->builder, obj_ptr, idx_val);
if (is_lvalue)
return field_ptr;
else
return scc_hir_builder_load(&ctx->builder, field_ptr);
}
case SCC_AST_EXPR_CAST: {
// 1. 转换操作数(右值)
scc_hir_value_ref_t operand =
scc_ast2ir_expr(ctx, expr->cast.expr, false);
// 2. 转换目标类型为 IR 类型
scc_hir_type_ref_t target_type = scc_ast2ir_type(ctx, expr->cast.type);
// 3. 确定转换模式(SEXT / ZEXT / TRUNC)
// 这里用简单的启发式:根据大小变化决定
scc_hir_type_t *src_type = scc_hir_module_get_type_by_value(
scc_ast2ir_mir_module(ctx), operand);
scc_hir_type_t *dst_type =
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx), target_type);
usize src_size = scc_hir_module_type_size(
scc_ast2ir_mir_module(ctx),
src_type); // 你可能有这个函数,否则自行计算
usize dst_size =
scc_hir_module_type_size(scc_ast2ir_mir_module(ctx), dst_type);
int conv_kind;
if (dst_size > src_size) {
// 目标更大,需要扩展。根据源类型有无符号决定符号扩展还是零扩展
conv_kind = scc_hir_type_is_signed(src_type->tag)
? SCC_HIR_CONV_SEXT
: SCC_HIR_CONV_ZEXT;
} else if (dst_size < src_size) {
conv_kind = SCC_HIR_CONV_TRUNC;
} else {
// 同大小,可以视为 NOP 转换,或者直接返回操作数
return operand; // 或创建一个 CONV_SEXT 也没问题
}
// 4. 构造转换节点
scc_hir_value_t conv_node = {
.tag = SCC_HIR_VALUE_TAG_CONV,
.type = target_type,
.data.conv.operand = operand,
.data.conv.target_type = target_type,
.data.conv.conv_type = conv_kind,
};
return scc_hir_module_add_value(scc_ast2ir_mir_module(ctx), &conv_node);
}
case SCC_AST_EXPR_SIZE_OF: {
// 1. 将 sizeof 的操作数(类型或表达式)转换为 IR 类型
scc_hir_type_ref_t hir_type;
if (expr->attr_of.type) {
// sizeof(type)
hir_type = scc_ast2ir_type(ctx, expr->attr_of.type);
} else if (expr->attr_of.expr) {
// sizeof expression:计算表达式类型
// 注意:sizeof
// 不对表达式求值,只需类型,这里假设语义分析已经标注了类型
scc_hir_value_ref_t dummy =
scc_ast2ir_expr(ctx, expr->attr_of.expr, false);
hir_type =
scc_hir_module_get_value(scc_ast2ir_mir_module(ctx), dummy)
->type;
} else {
scc_ap_t val;
val.data.digit = 0;
LOG_ERROR("[ast2ir] unsupported");
return scc_hir_builder_integer(
&ctx->builder, scc_hir_builder_type_u64(&ctx->builder), &val);
}
// 2. 计算大小
const scc_hir_type_t *type =
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx), hir_type);
usize dst_size =
scc_hir_module_type_size(scc_ast2ir_mir_module(ctx), type);
scc_ap_t val;
val.data.digit = dst_size;
return scc_hir_builder_integer(
&ctx->builder, scc_hir_builder_type_u64(&ctx->builder), &val);
}
case SCC_AST_EXPR_ALIGN_OF: {
TODO();
// return scc_hir_builder_integer(
// &ctx->builder, scc_hir_builder_type_u64(&ctx->builder), val);
}
case SCC_AST_EXPR_COMPOUND: {
// 1. 从 base 子节点取得类型(base 一定是 SCC_AST_EXPR_LVALUE)
Assert(expr->compound.base != nullptr);
Assert(expr->compound.base->base.type == SCC_AST_EXPR_LVALUE);
scc_ast_qual_type_t *ast_type = expr->compound.base->lvalue.type;
scc_hir_type_ref_t type_ref = scc_ast2ir_type(ctx, ast_type);
const scc_hir_type_t *type =
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx), type_ref);
// 2. 分配栈上临时存储
scc_hir_value_ref_t storage =
scc_hir_builder_alloca(&ctx->builder, type_ref, "compound_literal");
// 3. 根据类型调用对应的初始化函数
if (type->tag == SCC_HIR_TYPE_ARRAY) {
emit_array_initialization(ctx, storage, type, expr);
} else if (type->tag == SCC_HIR_TYPE_STRUCT ||
type->tag == SCC_HIR_TYPE_UNION) {
emit_aggregate_initialization(ctx, storage, type, expr);
} else {
// 标量:取初始化列表的第一个值
Assert(expr->compound.rhs_exprs.size > 0);
scc_ast_expr_t *init_expr = scc_vec_at(expr->compound.rhs_exprs, 0);
scc_hir_value_ref_t val = scc_ast2ir_expr(ctx, init_expr, false);
scc_hir_builder_store(&ctx->builder, storage, val);
}
// 4. 根据左值 / 右值返回
if (is_lvalue) {
return storage; // 左值
} else {
// 右值:数组退化为首元素指针,结构体暂时返回地址
if (type->tag == SCC_HIR_TYPE_ARRAY) {
return scc_hir_builder_get_elem_ptr(&ctx->builder, storage,
SCC_HIR_REF_nullptr);
} else if (type->tag == SCC_HIR_TYPE_STRUCT ||
type->tag == SCC_HIR_TYPE_UNION) {
return storage; // 调用者会 memcpy
} else {
return scc_hir_builder_load(&ctx->builder, storage);
}
}
} break;
case SCC_AST_EXPR_LVALUE: {
UNREACHABLE(); // should only appear as compound.base
} break;
case SCC_AST_EXPR_BUILTIN: {
TODO();
} break;
case SCC_AST_EXPR_INT_LITERAL: {
// FIXME maybe using some array to int;
scc_hir_type_ref_t type_ref = scc_hir_builder_type_i32(&ctx->builder);
scc_ap_t value;
scc_ap_from_cstr(&value, expr->literal.lexme, 10);
return scc_hir_builder_integer(&ctx->builder, type_ref, &value);
}
// SCC_AST_EXPR_FLOAT_LITERAL, // 浮点字面量
case SCC_AST_EXPR_CHAR_LITERAL: {
// FIXME just 'a' '\n'
const char *lexme = expr->literal.lexme;
Assert(lexme[0] == '\'');
i8 int_lit = 0;
if (lexme[1] == '\\') {
switch (lexme[2]) {
case 'a':
int_lit = '\a';
break;
case 'b':
int_lit = '\b';
break;
case 'f':
int_lit = '\f';
break;
case 'n':
int_lit = '\n';
break;
case 'r':
int_lit = '\r';
}
} else {
int_lit = lexme[1];
}
scc_ap_t value;
// FIXME i32 maybe false, we need i8 or u8
scc_hir_type_ref_t type_ref = scc_hir_builder_type_i32(&ctx->builder);
scc_ap_set_int(&value, int_lit);
return scc_hir_builder_integer(&ctx->builder, type_ref, &value);
}
case SCC_AST_EXPR_STRING_LITERAL: {
// FIXME
scc_hir_value_ref_t value =
scc_hir_builder_const_string(&ctx->builder, expr->literal.lexme,
scc_strlen(expr->literal.lexme));
if (is_lvalue)
TODO();
return value;
}
case SCC_AST_EXPR_IDENTIFIER: {
if (expr->identifier._target == nullptr) {
LOG_ERROR("unknown identifier %s", expr->identifier.name);
}
// FIXME hack hashtable
scc_hir_value_ref_t in = (scc_hir_value_ref_t)(usize)scc_hashtable_get(
&ctx->ast2ir_cache, expr->identifier._target);
Assert(in != 0);
if (is_lvalue) {
return in;
} else {
// 右值:如果是数组类型,退化为指针(返回地址)
scc_hir_type_t *ir_type = scc_hir_module_get_type_by_value(
scc_ast2ir_mir_module(ctx), in);
if (ir_type->tag == SCC_HIR_TYPE_PTR) {
scc_hir_type_t *target_type = scc_hir_module_get_type(
scc_ast2ir_mir_module(ctx), ir_type->data.pointer.base);
if (target_type->tag == SCC_HIR_TYPE_ARRAY) {
// 生成 getptr 获取数组首地址
return scc_hir_builder_get_elem_ptr(&ctx->builder, in,
SCC_HIR_REF_nullptr);
} else {
// 标量类型:加载值
return scc_hir_builder_load(&ctx->builder, in);
}
} else {
return in;
}
}
}
default:
LOG_FATAL("Unsupported expression type: %d", expr->base.type);
return 0;
}
UNREACHABLE();
}
/**
* @brief
*
* @param ctx
* @param stmt
*/
void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
if (stmt == nullptr) {
return;
}
switch (stmt->base.type) {
case SCC_AST_STMT_COMPOUND: {
scc_vec_foreach(stmt->compound.block_items, i) {
scc_ast_node_t *child_stmt =
scc_vec_at(stmt->compound.block_items, i);
if (SCC_AST_IS_A(scc_ast_stmt_t, child_stmt)) {
scc_ast2ir_stmt(ctx,
SCC_AST_CAST_TO(scc_ast_stmt_t, child_stmt));
} else if (SCC_AST_IS_A(scc_ast_decl_t, child_stmt)) {
scc_ast2ir_decl(
ctx, SCC_AST_CAST_TO(scc_ast_decl_t, child_stmt), false);
} else {
UNREACHABLE();
}
}
break;
}
case SCC_AST_STMT_EXPR: {
scc_ast2ir_expr(ctx, stmt->expr.expr, false);
break;
}
case SCC_AST_STMT_IF: {
/*
branch cond
/ \
true_block false_block
\ /
merge_block
*/
scc_hir_value_ref_t true_block =
scc_hir_builder_create_bblock(&ctx->builder, "if_true");
scc_hir_value_ref_t false_block =
scc_hir_builder_create_bblock(&ctx->builder, "if_false");
scc_hir_value_ref_t merge_block =
scc_hir_builder_create_bblock(&ctx->builder, "if_merge");
scc_hir_value_ref_t cond_node =
scc_ast2ir_expr(ctx, stmt->if_stmt.cond, false);
scc_hir_builder_branch(&ctx->builder, cond_node, true_block,
stmt->if_stmt.opt_else_stmt ? false_block
: merge_block);
// 生成true分支
scc_hir_builder_append_bblock(&ctx->builder, true_block);
scc_hir_builder_set_current_bblock(&ctx->builder, true_block);
scc_ast2ir_stmt(ctx, stmt->if_stmt.then_stmt);
scc_hir_builder_jump(&ctx->builder, merge_block);
// 生成false分支
if (stmt->if_stmt.opt_else_stmt) {
scc_hir_builder_append_bblock(&ctx->builder, false_block);
scc_hir_builder_set_current_bblock(&ctx->builder, false_block);
scc_ast2ir_stmt(ctx, stmt->if_stmt.opt_else_stmt);
scc_hir_builder_jump(&ctx->builder, merge_block);
}
scc_hir_builder_append_bblock(&ctx->builder, merge_block);
scc_hir_builder_set_current_bblock(&ctx->builder, merge_block);
break;
}
case SCC_AST_STMT_WHILE: {
scc_hir_value_ref_t cond_block =
scc_hir_builder_create_bblock(&ctx->builder, "while_cond");
scc_hir_value_ref_t body_block =
scc_hir_builder_create_bblock(&ctx->builder, "while_body");
scc_hir_value_ref_t exit_block =
scc_hir_builder_create_bblock(&ctx->builder, "while_exit");
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)cond_block);
scc_hir_builder_jump(&ctx->builder, cond_block);
scc_hir_builder_append_bblock(&ctx->builder, cond_block);
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
scc_hir_value_ref_t cond_node =
scc_ast2ir_expr(ctx, stmt->while_stmt.cond, false);
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
exit_block);
scc_hir_builder_append_bblock(&ctx->builder, body_block);
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
scc_hir_builder_jump(&ctx->builder, cond_block);
scc_hir_builder_append_bblock(&ctx->builder, exit_block);
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
break;
}
case SCC_AST_STMT_DO_WHILE: {
scc_hir_value_ref_t cond_block =
scc_hir_builder_create_bblock(&ctx->builder, "do_while_cond");
scc_hir_value_ref_t body_block =
scc_hir_builder_create_bblock(&ctx->builder, "do_while_body");
scc_hir_value_ref_t exit_block =
scc_hir_builder_create_bblock(&ctx->builder, "do_while_exit");
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)cond_block);
scc_hir_builder_jump(&ctx->builder, body_block);
scc_hir_builder_append_bblock(&ctx->builder, body_block);
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
scc_hir_builder_jump(&ctx->builder, cond_block);
scc_hir_builder_append_bblock(&ctx->builder, cond_block);
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
scc_hir_value_ref_t cond_node =
scc_ast2ir_expr(ctx, stmt->while_stmt.cond, false);
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
exit_block);
scc_hir_builder_append_bblock(&ctx->builder, exit_block);
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
break;
}
case SCC_AST_STMT_FOR: {
scc_hir_value_ref_t cond_block =
scc_hir_builder_create_bblock(&ctx->builder, "for_cond");
scc_hir_value_ref_t body_block =
scc_hir_builder_create_bblock(&ctx->builder, "for_body");
scc_hir_value_ref_t incr_block =
scc_hir_builder_create_bblock(&ctx->builder, "for_incr");
scc_hir_value_ref_t exit_block =
scc_hir_builder_create_bblock(&ctx->builder, "for_exit");
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)incr_block);
if (stmt->for_stmt.init) {
if (SCC_AST_IS_A(scc_ast_decl_t, stmt->for_stmt.init)) {
scc_ast2ir_decl(
ctx, SCC_AST_CAST_TO(scc_ast_decl_t, stmt->for_stmt.init),
false);
} else if (SCC_AST_IS_A(scc_ast_expr_t, stmt->for_stmt.init)) {
scc_ast2ir_expr(
ctx, SCC_AST_CAST_TO(scc_ast_expr_t, stmt->for_stmt.init),
false);
} else {
LOG_FATAL("invalid for init statement");
}
}
scc_hir_builder_jump(&ctx->builder, cond_block);
scc_hir_builder_append_bblock(&ctx->builder, cond_block);
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
if (stmt->for_stmt.cond) {
scc_hir_value_ref_t cond_node =
scc_ast2ir_expr(ctx, stmt->for_stmt.cond, false);
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
exit_block);
} else {
scc_hir_builder_jump(&ctx->builder, body_block);
}
scc_hir_builder_append_bblock(&ctx->builder, body_block);
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
scc_ast2ir_stmt(ctx, stmt->for_stmt.body);
scc_hir_builder_jump(&ctx->builder, incr_block);
scc_hir_builder_append_bblock(&ctx->builder, incr_block);
scc_hir_builder_set_current_bblock(&ctx->builder, incr_block);
if (stmt->for_stmt.incr) {
scc_ast2ir_expr(ctx, stmt->for_stmt.incr, false);
}
scc_hir_builder_jump(&ctx->builder, cond_block);
scc_hir_builder_append_bblock(&ctx->builder, exit_block);
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
break;
}
case SCC_AST_STMT_SWITCH: {
scc_hir_value_ref_t exit_block =
scc_hir_builder_bblock(&ctx->builder, "switch_exit");
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
// TODO:
} break;
case SCC_AST_STMT_CASE:
case SCC_AST_STMT_DEFAULT:
UNREACHABLE();
break;
case SCC_AST_STMT_BREAK: {
scc_hir_bblock_ref_t target =
(usize)scc_hashtable_get(&ctx->break_cache, stmt->jump._target);
Assert(target != SCC_HIR_REF_nullptr);
scc_hir_builder_jump(&ctx->builder, target);
} break;
case SCC_AST_STMT_CONTINUE: {
scc_hir_bblock_ref_t target =
(usize)scc_hashtable_get(&ctx->continue_cache, stmt->jump._target);
Assert(target != SCC_HIR_REF_nullptr);
scc_hir_builder_jump(&ctx->builder, target);
} break;
case SCC_AST_STMT_RETURN: {
if (stmt->return_stmt.expr) {
scc_hir_value_ref_t ret_val_node =
scc_ast2ir_expr(ctx, stmt->return_stmt.expr, false);
// 将返回值转换为函数返回值类型
scc_hir_func_ref_t func = ctx->builder.current_func;
if (func != SCC_HIR_REF_nullptr) {
scc_hir_func_t *hir_func =
scc_hir_module_get_func(scc_ast2ir_mir_module(ctx), func);
scc_hir_func_meta_t *meta = SCC_HIR_FUNC_META(hir_func);
if (meta->type != SCC_HIR_REF_nullptr) {
const scc_hir_type_t *func_type = scc_hir_module_get_type(
scc_ast2ir_mir_module(ctx), meta->type);
if (func_type != nullptr &&
func_type->tag == SCC_HIR_TYPE_FUNC) {
ret_val_node = scc_ast2ir_emit_conversion(
ctx, ret_val_node,
func_type->data.function.ret_type);
}
}
}
scc_hir_builder_ret(&ctx->builder, ret_val_node);
} else {
scc_hir_builder_ret_void(&ctx->builder);
}
break;
}
case SCC_AST_STMT_GOTO: {
// scc_hir_bblock_ref_t target = (usize)scc_hashtable_get(
// &ctx->ast2ir_cache, (void *)stmt->goto_stmt._target);
// Assert(target != SCC_HIR_REF_nullptr);
// scc_hir_builder_jump(&ctx->builder, target);
} break;
case SCC_AST_STMT_LABEL: {
scc_hir_value_ref_t label_block =
scc_hir_builder_bblock(&ctx->builder, stmt->label_stmt.label);
scc_hir_builder_set_current_bblock(&ctx->builder, label_block);
scc_hashtable_set(&ctx->ast2ir_cache, stmt, (void *)label_block);
scc_ast2ir_stmt(ctx, stmt->label_stmt.stmt);
} break;
default:
LOG_FATAL("Unsupported statement type: %d", stmt->base.type);
break;
}
}
/**
* @brief
*
* @param ctx
* @param decl
*/
void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
cbool is_global) {
if (ctx == nullptr || decl == nullptr) {
LOG_ERROR("Invalid argument");
return;
}
switch (decl->base.type) {
case SCC_AST_DECL_VAR: {
// 1. 获取原始类型(可能数组长度为0)
scc_hir_type_ref_t orig_type_ref = scc_ast2ir_type(ctx, decl->var.type);
// 借用指针并拷贝类型(避免悬空)
const scc_hir_type_t *orig_type;
SCC_HIR_BUILDER_BEGIN_BORROW(
&ctx->builder, orig_type,
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx), orig_type_ref));
scc_hir_type_t final_type_desc = *orig_type;
SCC_HIR_BUILDER_END_BORROW(&ctx->builder);
// 2. 如果是未知长度数组且有初始化,解析实际长度
scc_hir_type_ref_t final_type_ref = orig_type_ref;
if (decl->var.init && final_type_desc.tag == SCC_HIR_TYPE_ARRAY &&
final_type_desc.data.array.len == 0) {
scc_hir_type_t tmp_type_desc;
resolve_array_length(ctx, &final_type_desc, &tmp_type_desc,
decl->var.init);
final_type_desc = tmp_type_desc;
final_type_ref =
scc_hir_builder_type(&ctx->builder, &final_type_desc);
// 此时 final_type_desc 中的长度已经确定
}
// 3. 分配变量(栈或全局)
scc_hir_value_ref_t alloc_val_node;
if (is_global) {
// 全局变量:需要生成全局分配,当前代码暂未实现,保留 TODO
// alloc_val_node = scc_hir_builder_global_alloca(&ctx->builder,
// final_type_ref, decl->name);
// scc_vec_push(builder->cprog->global_vals, alloc_val_node);
// 这里先返回,后续补充
return;
} else {
alloc_val_node = scc_hir_builder_alloca(&ctx->builder,
final_type_ref, decl->name);
}
scc_hashtable_set(&ctx->ast2ir_cache, decl,
(void *)(usize)alloc_val_node);
// 4. 处理初始化
if (decl->var.init) {
// 再次借用 final_type 以判断是否为数组
const scc_hir_type_t *final_type;
SCC_HIR_BUILDER_BEGIN_BORROW(
&ctx->builder, final_type,
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx),
final_type_ref));
scc_hir_type_t type = *final_type;
SCC_HIR_BUILDER_END_BORROW(&ctx->builder);
if (type.tag == SCC_HIR_TYPE_ARRAY) {
emit_array_initialization(ctx, alloc_val_node, &type,
decl->var.init);
} else if (type.tag == SCC_HIR_TYPE_STRUCT ||
type.tag == SCC_HIR_TYPE_UNION) {
emit_aggregate_initialization(ctx, alloc_val_node, &type,
decl->var.init);
} else {
// 标量类型
scc_hir_value_ref_t init_val =
scc_ast2ir_expr(ctx, decl->var.init, false);
scc_hir_builder_store(&ctx->builder, alloc_val_node, init_val);
}
}
break;
}
case SCC_AST_DECL_FUNC: {
scc_hir_type_ref_t func_type_ref =
scc_ast2ir_type(ctx, decl->func.type);
scc_hir_func_ref_t func_ref =
(usize)scc_hashtable_get(&ctx->symtab, decl->name);
if (func_ref == SCC_HIR_REF_nullptr) {
func_ref =
scc_hir_builder_func(&ctx->builder, func_type_ref, decl->name);
// TODO: add func to cache because function pointer is needed
scc_hashtable_set(&ctx->symtab, decl->name,
(void *)(usize)func_ref);
}
// 检测是否是可变参数函数(无论是否有函数体)
scc_hir_func_t *hir_func =
scc_hir_module_get_func(&ctx->builder.cprog->module, func_ref);
int n_fixed = fixed_param_count(scc_ast_canon_type(decl->func.type));
int n_total = (int)scc_vec_size(
scc_ast_canon_type(decl->func.type)->function.params);
if (n_total > n_fixed) {
SCC_HIR_FUNC_META(hir_func)->is_variadic = true;
}
if (decl->func.body == nullptr) {
// function decl
break;
}
// TODO this is double check defined
Assert(SCC_HIR_FUNC_META(hir_func)->defined == false);
SCC_HIR_FUNC_META(hir_func)->defined = true;
scc_hir_builder_begin_func(&ctx->builder, func_ref);
scc_hir_builder_begin_bblock(&ctx->builder, "entry");
// 只处理固定参数,跳过尾部的 ... 假参数
scc_ast_decl_vec_t *ast_params =
&scc_ast_canon_type(decl->func.type)->function.params;
for (int i = 0; i < n_fixed; i++) {
scc_ast_decl_t *param = scc_vec_at(*ast_params, i);
scc_ast2ir_decl(ctx, param, false);
}
scc_ast2ir_stmt(ctx, decl->func.body);
// FIXME need ret for none return or other default ret
scc_hir_builder_ret_void(&ctx->builder);
scc_hir_builder_end_bblock(&ctx->builder);
scc_hir_builder_end_func(&ctx->builder);
break;
}
case SCC_AST_DECL_LIST: {
scc_vec_foreach(decl->list.vars, i) {
scc_ast_decl_t *sub_decl = scc_vec_at(decl->list.vars, i);
scc_ast2ir_decl(ctx, sub_decl, is_global);
}
break;
}
case SCC_AST_DECL_PARAM: {
// 跳过 void 参数和 ... 假参数(无名 VA_LIST)
if (decl->param.type->base.type == SCC_AST_TYPE_BUILTIN &&
scc_ast_canon_type(decl->param.type)->builtin.type ==
SCC_AST_BUILTIN_TYPE_VOID) {
break;
}
if (is_variadic_marker(decl)) {
break;
}
scc_hir_type_ref_t parma_type_ref =
scc_ast2ir_type(ctx, decl->param.type);
scc_hir_value_ref_t param_ref = scc_hir_builder_func_arg_ref(
&ctx->builder, parma_type_ref, decl->name, decl->param.param_idx);
if (!ctx->hint_using_value) {
scc_hir_value_ref_t val_ref = scc_hir_builder_alloca(
&ctx->builder, parma_type_ref, decl->name);
scc_hir_builder_store(&ctx->builder, val_ref, param_ref);
scc_hashtable_set(&ctx->ast2ir_cache, decl, (void *)(usize)val_ref);
} else {
Panic("using value is not supported");
}
break;
}
case SCC_AST_DECL_STRUCT:
case SCC_AST_DECL_UNION: {
scc_ast_canon_type_t canon_type = {
.record.decl = decl,
.record.name = decl->name,
};
scc_ast_qual_type_t type = {
.base.type =
SCC_AST_DECL_STRUCT ? SCC_AST_TYPE_STRUCT : SCC_AST_TYPE_UNION,
.type = &canon_type,
};
scc_hir_type_ref_t type_ref = scc_ast2ir_type(ctx, &type);
// scc_hir_builder_global_alloca(&ctx->builder, type_ref,
// SCC_HIR_REF_nullptr);
} break;
case SCC_AST_DECL_ENUM: {
scc_ap_t val;
int idx = 0;
scc_ap_set_int(&val, idx);
scc_vec_foreach(decl->record.fields, i) {
scc_ast_decl_t *item = scc_vec_at(decl->record.fields, i);
Assert(item->base.type == SCC_AST_DECL_VAR);
if (item->var.init) {
Assert(item->var.init->base.type == SCC_AST_EXPR_INT_LITERAL);
scc_ap_from_cstr(&val, item->var.init->literal.lexme, 10);
}
scc_hir_value_ref_t item_val_ref = scc_hir_builder_integer(
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder), &val);
scc_hashtable_set(&ctx->ast2ir_cache, item,
(void *)(usize)item_val_ref);
// FIXME hack ap
idx = val.data.digit;
idx += 1;
// scc_ap_add 1 ();
scc_ap_set_int(&val, idx);
}
} break;
case SCC_AST_DECL_TYPEDEF:
break;
default:
LOG_FATAL("Unsupported declaration type: %d", decl->base.type);
break;
}
}
void scc_ast2ir_run(scc_ast2ir_ctx_t *ctx,
const scc_ast_translation_unit_t *tu) {
Assert(ctx != nullptr && tu != nullptr);
scc_vec_foreach(tu->declarations, i) {
scc_ast_decl_t *decl = scc_vec_at(tu->declarations, i);
scc_ast2ir_decl(ctx, decl, true);
}
}
void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_abi_type_calc_t *abi,
scc_ast_ctx_t *ast_ctx, scc_hir_cprog_t *cprog) {
Assert(ctx != nullptr);
Assert(abi != nullptr);
Assert(ast_ctx != nullptr);
Assert(cprog != nullptr);
ctx->abi = abi;
ctx->ast_ctx = ast_ctx;
scc_hir_builder_init(&ctx->builder, cprog);
scc_hashtable_usize_init(&ctx->ast2ir_cache);
scc_hashtable_usize_init(&ctx->break_cache);
scc_hashtable_usize_init(&ctx->continue_cache);
scc_hashtable_cstr_init(&ctx->symtab);
scc_hashtable_usize_init(&ctx->type_cache);
ctx->hint_using_value = false;
}
void scc_ast2ir_ctx_drop(scc_ast2ir_ctx_t *ctx) {
scc_hir_builder_drop(&ctx->builder);
scc_hashtable_drop(&ctx->ast2ir_cache);
scc_hashtable_drop(&ctx->break_cache);
scc_hashtable_drop(&ctx->continue_cache);
scc_hashtable_drop(&ctx->type_cache);
scc_hashtable_drop(&ctx->symtab);
}