Files
scc/libs/ast2ir/src/scc_ast2ir.c
T
zzy b06c4fe3cc feat(ast2ir): 添加AST上下文支持并修复类型转换逻辑
- 在scc_ast2ir_ctx_t中添加ast_ctx字段用于访问AST上下文
- 修改scc_ast2ir_ctx_init函数签名以接收ast_ctx参数
- 修复enum类型的处理逻辑,使用正确的内置类型获取方式
- 修正for循环控制流中错误的跳转目标
- 移除未使用的parse_struct_union_layout函数

refactor(cfg): 优化模块接口的const正确性

- 将scc_cfg_module_unsafe_get_*系列函数的module参数标记为const
- 提高接口的安全性和一致性

refactor(lir): 简化寄存器定义宏

- 移除未使用的SCC_LIR_PREG宏定义
- 简化头文件中的冗余声明

fix(hir2lir): 修复空指针常量的表示方式

- 修正NULL值的AP整数表示,正确初始化ap结构体字段
- 确保空指针在低级IR中被正确表示

refactor(mir): 重构函数元数据结构

- 为MIR函数元数据添加栈槽位和寄存器分配相关字段
- 定义新的栈槽位数据结构scc_mir_stack_slot_t
- 添加函数元数据初始化函数scc_mir_func_meta_init

refactor(x86): 改进后端代码生成

- 修正ret指令生成,使用近返回指令RET_NEAR
- 修复伪alloca指令的形式转换问题
- 改进选择函数的const正确性
- 正确初始化函数元数据结构

style(config): 添加MIR阶段配置选项

- 为MIR各个处理阶段添加配置标志
- 包括寄存器分配、栈布局和前言后记生成的输出选项

fix(parser): 改进错误处理机制

- 修正语义分析上下文变量命名
- 添加解析错误码检查,及时返回错误状态
2026-05-01 22:51:31 +08:00

1145 lines
46 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>
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 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;
}
// 辅助函数:生成数组初始化代码
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(&ctx->builder.cprog->module, 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 循环,但为简化暂不处理
}
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);
scc_vec_foreach(scc_ast_canon_type(ast_type)->function.params, i) {
scc_ast_decl_t *decl_param =
scc_vec_at(scc_ast_canon_type(ast_type)->function.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: {
scc_hir_type_init(&ir_type, ast_type->base.type == SCC_AST_TYPE_STRUCT
? SCC_HIR_TYPE_STRUCT
: SCC_HIR_TYPE_UNION);
if (scc_ast_canon_type(ast_type)->record.decl == nullptr) {
Panic("%s record fields is nullptr",
scc_ast_canon_type(ast_type)->record.name);
}
scc_vec_foreach(
scc_ast_canon_type(ast_type)->record.decl->record.fields, i) {
scc_ast_decl_t *decl_field = scc_vec_at(
scc_ast_canon_type(ast_type)->record.decl->record.fields, i);
Assert(decl_field->base.type == SCC_AST_DECL_VAR);
scc_hir_type_ref_t field_type =
scc_ast2ir_type(ctx, decl_field->var.type);
scc_vec_push(ir_type.data.aggregate.fields, field_type);
}
} 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_value_ref_t lhs,
scc_hir_value_ref_t rhs) {
// scc_hir_bblock_ref_t start_block =
// scc_hir_builder_current_bblock(&ctx->builder);
scc_hir_value_ref_t right_block =
scc_hir_builder_bblock(&ctx->builder, "logic_right");
scc_hir_value_ref_t end_block =
scc_hir_builder_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_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_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_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_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_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_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_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, rhs;
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) {
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, true);
return scc_hir_builder_store(&ctx->builder, lhs, rhs);
}
rhs = scc_ast2ir_expr(ctx, expr->binary.rhs, false);
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, false);
// 映射操作符
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: // &&
return scc_ast2ir_logical_expr(ctx, expr, lhs, rhs);
/* 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);
}
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);
// /* 一元操作符 */
// SCC_AST_OP_UNARY_PLUS, // + (一元)
// SCC_AST_OP_UNARY_MINUS, // - (一元)
// SCC_AST_OP_ADDRESS_OF, // &
// SCC_AST_OP_INDIRECTION, // *
// SCC_AST_OP_BITWISE_NOT, // ~
// SCC_AST_OP_LOGICAL_NOT, // !
// SCC_AST_OP_PREFIX_INCREMENT, // ++ (前缀)
// SCC_AST_OP_PREFIX_DECREMENT, // -- (前缀)
// SCC_AST_OP_POSTFIX_INCREMENT, // ++ (后缀)
// SCC_AST_OP_POSTFIX_DECREMENT, // -- (后缀)
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);
}
default:
LOG_FATAL("Unsupported unary operator: %d", expr->unary.op);
return 0;
}
UNREACHABLE();
break;
}
case SCC_AST_EXPR_COND: {
TODO();
break;
}
case SCC_AST_EXPR_CALL: {
// 转换参数
scc_hir_value_ref_vec_t args;
scc_vec_init(args);
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);
scc_vec_push(args, arg_node);
}
// 创建调用节点(需要查找函数定义)
scc_hir_func_ref_t func = (scc_hir_value_ref_t)(usize)scc_hashtable_get(
&ctx->symtab, expr->call.callee->identifier._target->name);
if (!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, 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);
// 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:
break;
case SCC_AST_EXPR_SIZE_OF: {
TODO();
// 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: {
} break;
case SCC_AST_EXPR_LVALUE:
break;
// SCC_AST_EXPR_BUILTIN,// 内置表达式 ... directive map to ir builtin
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'
scc_hir_type_ref_t type_ref = scc_hir_builder_type_i32(&ctx->builder);
const char *lexme = expr->literal.lexme;
Assert(lexme[0] == '\'');
u8 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;
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(
&ctx->builder.cprog->module, in);
if (ir_type->tag == SCC_HIR_TYPE_PTR) {
scc_hir_type_t *target_type = scc_hir_module_get_type(
&ctx->builder.cprog->module, 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_bblock(&ctx->builder, "if_true");
scc_hir_value_ref_t false_block =
scc_hir_builder_bblock(&ctx->builder, "if_false");
scc_hir_value_ref_t merge_block =
scc_hir_builder_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,
false_block);
// 生成true分支
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_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_set_current_bblock(&ctx->builder, merge_block);
break;
}
case SCC_AST_STMT_WHILE: {
scc_hir_value_ref_t cond_block =
scc_hir_builder_bblock(&ctx->builder, "while_cond");
scc_hir_value_ref_t body_block =
scc_hir_builder_bblock(&ctx->builder, "while_body");
scc_hir_value_ref_t exit_block =
scc_hir_builder_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_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_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_set_current_bblock(&ctx->builder, exit_block);
break;
}
case SCC_AST_STMT_DO_WHILE: {
scc_hir_value_ref_t cond_block =
scc_hir_builder_bblock(&ctx->builder, "do_while_cond");
scc_hir_value_ref_t body_block =
scc_hir_builder_bblock(&ctx->builder, "do_while_body");
scc_hir_value_ref_t exit_block =
scc_hir_builder_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_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_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_set_current_bblock(&ctx->builder, exit_block);
break;
}
case SCC_AST_STMT_FOR: {
scc_hir_value_ref_t cond_block =
scc_hir_builder_bblock(&ctx->builder, "for_cond");
scc_hir_value_ref_t body_block =
scc_hir_builder_bblock(&ctx->builder, "for_body");
scc_hir_value_ref_t incr_block =
scc_hir_builder_bblock(&ctx->builder, "for_incr");
scc_hir_value_ref_t exit_block =
scc_hir_builder_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_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_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_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_set_current_bblock(&ctx->builder, exit_block);
break;
}
// SCC_AST_STMT_SWITCH, // switch 语句
// SCC_AST_STMT_CASE, // case 语句
// SCC_AST_STMT_DEFAULT, // default 语句
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_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(&ctx->builder.cprog->module,
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(&ctx->builder.cprog->module,
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 {
// 标量类型
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);
scc_hashtable_set(&ctx->symtab, decl->name,
(void *)(usize)func_ref);
}
if (decl->func.body == nullptr) {
// function decl
break;
}
scc_hir_builder_begin_func(&ctx->builder, func_ref);
scc_hir_builder_begin_bblock(&ctx->builder, "entry");
scc_vec_foreach(scc_ast_canon_type(decl->func.type)->function.params,
i) {
scc_ast_decl_t *param = scc_vec_at(
scc_ast_canon_type(decl->func.type)->function.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: {
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;
}
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);
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);
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->symtab);
}