feat(ast2ir): 添加浮点类型支持和复合初始化功能
- 在ABI类型计算中添加FLOAT和DOUBLE类型的映射 - 修复AST操作符注释中的歧义描述 - 为ast2ir上下文添加类型缓存以解决递归结构体定义问题 - 实现复合初始化表达式的支持,包括数组和结构体初始化 - 添加前置和后置自增/自减操作符的IR转换 - 实现三元条件表达式的IR生成 - 添加类型转换(cast)和sizeof操作符的支持 - 重构数组长度推断逻辑并添加类型大小计算函数 - 实现结构体和联合体的递归类型解析 - 添加函数指针调用相关的IR节点类型定义 fix(ast): 修正间接操作符的注释说明 refactor(ast2ir): 优化代码结构并添加必要的断言验证
This commit is contained in:
@@ -61,6 +61,12 @@ void scc_abi_compute_ast_type_layout(const scc_abi_type_calc_t *ctx, void *type,
|
||||
case SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG:
|
||||
kind = SCC_ABI_TYPE_U_LONG_LONG;
|
||||
break;
|
||||
case SCC_AST_BUILTIN_TYPE_FLOAT:
|
||||
kind = SCC_ABI_TYPE_FLOAT;
|
||||
break;
|
||||
case SCC_AST_BUILTIN_TYPE_DOUBLE:
|
||||
kind = SCC_ABI_TYPE_DOUBLE;
|
||||
break;
|
||||
default:
|
||||
Panic("Unsupported AST type: %d",
|
||||
scc_ast_canon_type(ast_type)->builtin.type);
|
||||
|
||||
@@ -262,7 +262,7 @@ typedef enum scc_ast_expr_op {
|
||||
SCC_AST_OP_UNARY_PLUS, // + (一元)
|
||||
SCC_AST_OP_UNARY_MINUS, // - (一元)
|
||||
SCC_AST_OP_ADDRESS_OF, // &
|
||||
SCC_AST_OP_INDIRECTION, // *
|
||||
SCC_AST_OP_INDIRECTION, // * (取地址)
|
||||
SCC_AST_OP_BITWISE_NOT, // ~
|
||||
SCC_AST_OP_LOGICAL_NOT, // !
|
||||
SCC_AST_OP_PREFIX_INCREMENT, // ++ (前缀)
|
||||
|
||||
@@ -11,6 +11,7 @@ typedef struct {
|
||||
scc_hashtable_t break_cache; ///< break cache
|
||||
scc_hashtable_t continue_cache; ///< continue cache
|
||||
scc_hashtable_t symtab; ///< symbol to ir_ref
|
||||
scc_hashtable_t type_cache; ///< scc_ast_canon_type_t* -> scc_hir_type_ref_t
|
||||
// scc_strpool_t strpool; ///< string pool
|
||||
const scc_abi_type_calc_t *abi;
|
||||
cbool hint_using_value; // 转换时尽可能使用value而不是alloc
|
||||
|
||||
@@ -27,39 +27,24 @@ static scc_hir_type_ref_t parse_base_type(scc_ast2ir_ctx_t *ctx,
|
||||
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;
|
||||
}
|
||||
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:
|
||||
Panic("unsupported initializer for zero-length array");
|
||||
// 指针可以视作无符号整数
|
||||
return false;
|
||||
}
|
||||
resolved_array_type->data.array.len = new_len;
|
||||
}
|
||||
|
||||
// 辅助函数:生成数组初始化代码
|
||||
@@ -123,6 +108,142 @@ static void emit_array_initialization(scc_ast2ir_ctx_t *ctx,
|
||||
// 这里简单忽略,实际可生成 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(
|
||||
&ctx->builder.cprog->module, 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) {}
|
||||
|
||||
usize scc_hir_type_size(scc_ast2ir_ctx_t *ctx, const scc_hir_type_t *type) {
|
||||
switch (type->tag) {
|
||||
case SCC_HIR_TYPE_void:
|
||||
return 0;
|
||||
case SCC_HIR_TYPE_i8:
|
||||
return 1;
|
||||
case SCC_HIR_TYPE_i16:
|
||||
return 2;
|
||||
case SCC_HIR_TYPE_i32:
|
||||
return 4;
|
||||
case SCC_HIR_TYPE_i64:
|
||||
return 8;
|
||||
case SCC_HIR_TYPE_i128:
|
||||
return 16;
|
||||
case SCC_HIR_TYPE_u8:
|
||||
return 1;
|
||||
case SCC_HIR_TYPE_u16:
|
||||
return 2;
|
||||
case SCC_HIR_TYPE_u32:
|
||||
return 4;
|
||||
case SCC_HIR_TYPE_u64:
|
||||
return 8;
|
||||
case SCC_HIR_TYPE_u128:
|
||||
return 16;
|
||||
case SCC_HIR_TYPE_f16:
|
||||
return 2;
|
||||
case SCC_HIR_TYPE_f32:
|
||||
return 4;
|
||||
case SCC_HIR_TYPE_f64:
|
||||
return 8;
|
||||
case SCC_HIR_TYPE_f128:
|
||||
return 16;
|
||||
|
||||
case SCC_HIR_TYPE_PTR: {
|
||||
// 目标指针大小,可以定义为 8(64位)或从 ABI 获取
|
||||
// 假设你的目标架构是 64 位
|
||||
return 8;
|
||||
}
|
||||
|
||||
case SCC_HIR_TYPE_ARRAY: {
|
||||
usize elem_size = scc_hir_type_size(
|
||||
ctx, scc_hir_module_get_type(&ctx->builder.cprog->module,
|
||||
type->data.array.base));
|
||||
return elem_size * type->data.array.len;
|
||||
}
|
||||
|
||||
case SCC_HIR_TYPE_FUNC:
|
||||
// 函数类型大小一般是指针大小
|
||||
return 8;
|
||||
|
||||
case SCC_HIR_TYPE_STRUCT:
|
||||
case SCC_HIR_TYPE_UNION:
|
||||
// 暂时无法计算,保守返回 0 或报错
|
||||
LOG_ERROR("Cannot compute size of struct/union without layout info");
|
||||
return 0;
|
||||
|
||||
default:
|
||||
LOG_ERROR("Unknown type tag %d", type->tag);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:计算数组实际长度(如果原长度为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) {
|
||||
@@ -189,22 +310,64 @@ scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||||
} 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
|
||||
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 (scc_ast_canon_type(ast_type)->record.decl == nullptr) {
|
||||
Panic("%s record fields is nullptr",
|
||||
scc_ast_canon_type(ast_type)->record.name);
|
||||
// 可以给占位符一个调试名
|
||||
if (canon->record.name) {
|
||||
placeholder.name = canon->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);
|
||||
|
||||
// === 3. 直接添加到模块,不经过 builder 的 uniquing ===
|
||||
// 因为此时我们不需要类型去重,只需要一个确定不移的引用
|
||||
scc_hir_type_ref_t place_ref =
|
||||
scc_hir_module_add_type(&ctx->builder.cprog->module, &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(&ctx->builder.cprog->module, 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(
|
||||
@@ -337,7 +500,8 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
switch (expr->base.type) {
|
||||
case SCC_AST_EXPR_BINARY: {
|
||||
scc_ast_expr_t tmp_expr;
|
||||
scc_hir_value_ref_t lhs, rhs;
|
||||
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);
|
||||
@@ -407,6 +571,7 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
break;
|
||||
}
|
||||
if (is_assign) {
|
||||
Assert(rhs != SCC_HIR_REF_nullptr);
|
||||
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, true);
|
||||
return scc_hir_builder_store(&ctx->builder, lhs, rhs);
|
||||
}
|
||||
@@ -452,7 +617,7 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
}
|
||||
// 创建操作节点
|
||||
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);
|
||||
@@ -470,17 +635,6 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
}
|
||||
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 */
|
||||
@@ -517,17 +671,138 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
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;
|
||||
scc_hir_type_ref_t promoted_type = old_type;
|
||||
// scc_ast2ir_promoted_type(ctx, old_type);
|
||||
scc_hir_value_ref_t promoted = old_val;
|
||||
// scc_ast2ir_apply_promotion(ctx, old_val);
|
||||
|
||||
scc_hir_value_ref_t one = scc_hir_builder_integer(
|
||||
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder),
|
||||
&(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 (old_type != promoted_type) {
|
||||
// stored_val = scc_hir_builder_conv(&ctx->builder, new_val,
|
||||
// old_type, CONV_TRUNC);
|
||||
// }
|
||||
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;
|
||||
scc_hir_type_ref_t promoted_type = old_type;
|
||||
// scc_ast2ir_promoted_type(ctx, old_type);
|
||||
scc_hir_value_ref_t promoted = old_val;
|
||||
// scc_ast2ir_apply_promotion(ctx, old_val);
|
||||
|
||||
scc_hir_value_ref_t one = scc_hir_builder_integer(
|
||||
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder),
|
||||
&(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 (old_type != promoted_type)
|
||||
// stored_val = trunc;
|
||||
scc_hir_builder_store(&ctx->builder, addr, stored_val);
|
||||
|
||||
// 后缀返回旧的、未提升的值(但 C
|
||||
// 要求返回提升后的旧值?实际是旧值按右值规则,应得到提升后的值)
|
||||
// 标准规定后缀++的结果是操作数原来的值,但会经过整数提升。
|
||||
// 所以需要返回 promoted(已提升的旧值)。
|
||||
Assert(promoted != SCC_HIR_REF_nullptr);
|
||||
return promoted; // 旧值,但类型已提升为
|
||||
// int 等
|
||||
} break;
|
||||
default:
|
||||
LOG_FATAL("Unsupported unary operator: %d", expr->unary.op);
|
||||
return 0;
|
||||
}
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
case SCC_AST_EXPR_COND: {
|
||||
TODO();
|
||||
break;
|
||||
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;
|
||||
@@ -610,12 +885,79 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
return scc_hir_builder_load(&ctx->builder, field_ptr);
|
||||
}
|
||||
case SCC_AST_EXPR_CAST: {
|
||||
TODO();
|
||||
} break;
|
||||
// 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(
|
||||
&ctx->builder.cprog->module, operand);
|
||||
scc_hir_type_t *dst_type =
|
||||
scc_hir_module_get_type(&ctx->builder.cprog->module, target_type);
|
||||
|
||||
usize src_size =
|
||||
scc_hir_type_size(ctx, src_type); // 你可能有这个函数,否则自行计算
|
||||
usize dst_size = scc_hir_type_size(ctx, dst_type);
|
||||
|
||||
int conv_kind;
|
||||
if (dst_size > src_size) {
|
||||
// 目标更大,需要扩展。根据源类型有无符号决定符号扩展还是零扩展
|
||||
conv_kind =
|
||||
scc_hir_type_is_signed(src_type->tag) ? CONV_SEXT : CONV_ZEXT;
|
||||
} else if (dst_size < src_size) {
|
||||
conv_kind = 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(&ctx->builder.cprog->module,
|
||||
&conv_node);
|
||||
}
|
||||
case SCC_AST_EXPR_SIZE_OF: {
|
||||
TODO();
|
||||
// return scc_hir_builder_integer(
|
||||
// &ctx->builder, scc_hir_builder_type_u64(&ctx->builder), val);
|
||||
// 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(&ctx->builder.cprog->module, 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(&ctx->builder.cprog->module, hir_type);
|
||||
usize dst_size = scc_hir_type_size(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();
|
||||
@@ -623,10 +965,50 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
// &ctx->builder, scc_hir_builder_type_u64(&ctx->builder), val);
|
||||
}
|
||||
case SCC_AST_EXPR_COMPOUND: {
|
||||
TODO();
|
||||
// 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(&ctx->builder.cprog->module, 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: {
|
||||
TODO();
|
||||
UNREACHABLE(); // should only appear as compound.base
|
||||
} break;
|
||||
case SCC_AST_EXPR_BUILTIN: {
|
||||
TODO();
|
||||
@@ -923,10 +1305,10 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
|
||||
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);
|
||||
// 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 =
|
||||
@@ -1009,6 +1391,10 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
|
||||
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 =
|
||||
@@ -1023,9 +1409,11 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
|
||||
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);
|
||||
}
|
||||
@@ -1149,6 +1537,7 @@ void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_abi_type_calc_t *abi,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1157,5 +1546,6 @@ void scc_ast2ir_ctx_drop(scc_ast2ir_ctx_t *ctx) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,11 @@ void scc_hir_builder_init(scc_hir_builder_t *builder, scc_hir_cprog_t *cprog);
|
||||
*/
|
||||
void scc_hir_builder_drop(scc_hir_builder_t *builder);
|
||||
|
||||
static inline scc_hir_module_t *
|
||||
scc_hir_builder_get_module(scc_hir_builder_t *builder) {
|
||||
return &builder->cprog->module;
|
||||
}
|
||||
|
||||
scc_hir_func_ref_t scc_hir_builder_func(scc_hir_builder_t *builder,
|
||||
scc_hir_type_ref_t type_ref,
|
||||
const char *name);
|
||||
@@ -92,7 +97,7 @@ scc_hir_value_ref_t scc_hir_builder_alloca(scc_hir_builder_t *builder,
|
||||
const char *name);
|
||||
|
||||
#define SCC_HIR_BUILDER_TYPE_FUNC(scc_type) \
|
||||
[[maybe_unused]] static inline scc_hir_type_ref_t \
|
||||
SCC_MAYBE_UNUSED static inline scc_hir_type_ref_t \
|
||||
scc_hir_builder_type_##scc_type(scc_hir_builder_t *builder) { \
|
||||
scc_hir_type_t type_desc; \
|
||||
scc_hir_type_init(&type_desc, SCC_HIR_TYPE_##scc_type); \
|
||||
|
||||
@@ -89,7 +89,9 @@ typedef enum scc_hir_value_tag {
|
||||
SCC_HIR_VALUE_TAG_OP, ///< 二元运算
|
||||
SCC_HIR_VALUE_TAG_BRANCH, ///< 有条件分支
|
||||
SCC_HIR_VALUE_TAG_JUMP, ///< 无条件跳转
|
||||
SCC_HIR_VALUE_TAG_JUMP_INDIRECT, ///< 无条件跳转(地址)
|
||||
SCC_HIR_VALUE_TAG_CALL, ///< 调用函数
|
||||
SCC_HIR_VALUE_TAG_CALL_INDIRECT, ///< 调用函数(地址)
|
||||
SCC_HIR_VALUE_TAG_RET, ///< 函数返回
|
||||
} scc_hir_value_tag_t;
|
||||
|
||||
@@ -222,11 +224,15 @@ struct scc_hir_value {
|
||||
scc_hir_bblock_ref_t true_bblock;
|
||||
scc_hir_bblock_ref_t false_bblock;
|
||||
} branch;
|
||||
struct {
|
||||
union {
|
||||
scc_hir_value_ref_t target_ptr;
|
||||
scc_hir_bblock_ref_t target_bblock;
|
||||
} jump;
|
||||
struct {
|
||||
scc_hir_func_ref_t callee; // TODO function pointer call
|
||||
union {
|
||||
scc_hir_func_ref_t func_ref;
|
||||
scc_hir_value_ref_t ptr_ref;
|
||||
} callee;
|
||||
scc_hir_value_ref_vec_t args;
|
||||
} call;
|
||||
struct {
|
||||
|
||||
@@ -105,7 +105,7 @@ void scc_hir_value_init(scc_hir_value_t *in, const char *name,
|
||||
break;
|
||||
case SCC_HIR_VALUE_TAG_CALL:
|
||||
scc_vec_init(in->data.call.args);
|
||||
in->data.call.callee = 0;
|
||||
in->data.call.callee.func_ref = 0;
|
||||
break;
|
||||
case SCC_HIR_VALUE_TAG_RET:
|
||||
in->data.ret.ret_val = 0;
|
||||
|
||||
@@ -625,7 +625,7 @@ scc_hir_value_ref_t scc_hir_builder_call(scc_hir_builder_t *builder,
|
||||
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
||||
scc_hir_value_t call_node = {0};
|
||||
call_node.tag = SCC_HIR_VALUE_TAG_CALL;
|
||||
call_node.data.call.callee = callee;
|
||||
call_node.data.call.callee.func_ref = callee;
|
||||
|
||||
scc_vec_init(call_node.data.call.args);
|
||||
for (usize i = 0; i < arg_count; i++) {
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#include <scc_tree_dump.h>
|
||||
|
||||
#define GET_MODULE(ctx) (&(ctx->cprog->module))
|
||||
|
||||
static void dump_type_with_visited(scc_hir_dump_t *ctx,
|
||||
scc_hir_type_ref_t type_ref,
|
||||
scc_hashtable_t *visited);
|
||||
static const char *get_node_type_str(scc_hir_value_tag_t tag) {
|
||||
static const char *node_types[] = {
|
||||
[SCC_HIR_VALUE_TAG_NULLPTR] = "NullPtr",
|
||||
@@ -168,9 +170,9 @@ static void dump_jump_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
||||
|
||||
static void dump_call_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||||
if (value->data.call.callee) {
|
||||
scc_hir_func_t *callee =
|
||||
scc_hir_module_get_func(GET_MODULE(ctx), value->data.call.callee);
|
||||
if (value->data.call.callee.func_ref) {
|
||||
scc_hir_func_t *callee = scc_hir_module_get_func(
|
||||
GET_MODULE(ctx), value->data.call.callee.func_ref);
|
||||
scc_tree_dump_value(ctx->dump_ctx, "func='%s'",
|
||||
callee ? (callee->name ? callee->name : "<unnamed>")
|
||||
: "<invalid>");
|
||||
@@ -256,60 +258,12 @@ void scc_hir_dump_value(scc_hir_dump_t *ctx, scc_hir_value_ref_t value_ref) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void scc_hir_dump_type(scc_hir_dump_t *ctx, scc_hir_type_ref_t type_ref) {
|
||||
if (!ctx || !type_ref) {
|
||||
LOG_ERROR("invalid parameter");
|
||||
return;
|
||||
scc_hashtable_t visited;
|
||||
scc_hashtable_usize_init(&visited);
|
||||
dump_type_with_visited(ctx, type_ref, &visited);
|
||||
scc_hashtable_drop(&visited);
|
||||
}
|
||||
scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref);
|
||||
if (!type) {
|
||||
LOG_ERROR("invalid type ref");
|
||||
return;
|
||||
}
|
||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||||
scc_tree_dump_node(ctx->dump_ctx, "Type: ");
|
||||
scc_tree_dump_value(ctx->dump_ctx, "%s", get_type_tag_str(type->tag));
|
||||
|
||||
switch (type->tag) {
|
||||
case SCC_HIR_TYPE_PTR:
|
||||
if (type->data.pointer.base) {
|
||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||||
scc_hir_dump_type(ctx, type->data.pointer.base);
|
||||
scc_tree_dump_pop(ctx->dump_ctx);
|
||||
}
|
||||
break;
|
||||
case SCC_HIR_TYPE_ARRAY:
|
||||
if (type->data.array.len > 0) {
|
||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||||
scc_tree_dump_node(ctx->dump_ctx, "Array Length: ");
|
||||
scc_tree_dump_value(ctx->dump_ctx, "%zu", type->data.array.len);
|
||||
scc_tree_dump_append(ctx->dump_ctx, "\n");
|
||||
}
|
||||
if (type->data.array.base) {
|
||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||||
scc_hir_dump_type(ctx, type->data.array.base);
|
||||
scc_tree_dump_pop(ctx->dump_ctx);
|
||||
}
|
||||
break;
|
||||
case SCC_HIR_TYPE_FUNC:
|
||||
for (usize i = 0; i < scc_vec_size(type->data.function.params); i++) {
|
||||
cbool is_last = (i + 1 == scc_vec_size(type->data.function.params));
|
||||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
||||
scc_hir_dump_type(ctx, scc_vec_at(type->data.function.params, i));
|
||||
scc_tree_dump_pop(ctx->dump_ctx);
|
||||
}
|
||||
if (type->data.function.ret_type) {
|
||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||||
scc_hir_dump_type(ctx, type->data.function.ret_type);
|
||||
scc_tree_dump_pop(ctx->dump_ctx);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void scc_hir_dump_bblock(scc_hir_dump_t *ctx, scc_hir_bblock_ref_t bblock_ref) {
|
||||
if (!ctx || !bblock_ref) {
|
||||
LOG_ERROR("invalid parameter");
|
||||
@@ -379,13 +333,94 @@ void scc_hir_dump_cprog(scc_hir_dump_t *ctx) {
|
||||
}
|
||||
|
||||
// ----- 线性输出(保留原逻辑,改用新 API)-----
|
||||
void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
|
||||
scc_hir_type_ref_t type_ref) {
|
||||
scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref);
|
||||
if (!ctx || !type) {
|
||||
|
||||
// 在 scc_hir_dump.c 中添加以下静态辅助函数(放在文件前部,现有函数之前)
|
||||
|
||||
static void dump_type_linear_with_visited(scc_hir_dump_t *ctx,
|
||||
scc_hir_type_ref_t type_ref,
|
||||
scc_hashtable_t *visited);
|
||||
static void dump_type_with_visited(scc_hir_dump_t *ctx,
|
||||
scc_hir_type_ref_t type_ref,
|
||||
scc_hashtable_t *visited) {
|
||||
if (!ctx || !type_ref) {
|
||||
LOG_ERROR("invalid parameter");
|
||||
return;
|
||||
}
|
||||
// 检查循环
|
||||
if (scc_hashtable_get(visited, (void *)(usize)type_ref)) {
|
||||
scc_tree_dump_append(ctx->dump_ctx, " <recursive>");
|
||||
return;
|
||||
}
|
||||
scc_hashtable_set(visited, (void *)(usize)type_ref, (void *)1);
|
||||
|
||||
scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref);
|
||||
if (!type) {
|
||||
LOG_ERROR("invalid type ref");
|
||||
return;
|
||||
}
|
||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||||
scc_tree_dump_node(ctx->dump_ctx, "Type: ");
|
||||
scc_tree_dump_value(ctx->dump_ctx, "%s", get_type_tag_str(type->tag));
|
||||
|
||||
switch (type->tag) {
|
||||
case SCC_HIR_TYPE_PTR:
|
||||
if (type->data.pointer.base) {
|
||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||||
dump_type_with_visited(ctx, type->data.pointer.base, visited);
|
||||
scc_tree_dump_pop(ctx->dump_ctx);
|
||||
}
|
||||
break;
|
||||
case SCC_HIR_TYPE_ARRAY:
|
||||
if (type->data.array.len > 0) {
|
||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||||
scc_tree_dump_node(ctx->dump_ctx, "Array Length: ");
|
||||
scc_tree_dump_value(ctx->dump_ctx, "%zu", type->data.array.len);
|
||||
scc_tree_dump_append(ctx->dump_ctx, "\n");
|
||||
}
|
||||
if (type->data.array.base) {
|
||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||||
dump_type_with_visited(ctx, type->data.array.base, visited);
|
||||
scc_tree_dump_pop(ctx->dump_ctx);
|
||||
}
|
||||
break;
|
||||
case SCC_HIR_TYPE_FUNC:
|
||||
for (usize i = 0; i < scc_vec_size(type->data.function.params); i++) {
|
||||
cbool is_last = (i + 1 == scc_vec_size(type->data.function.params));
|
||||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
||||
dump_type_with_visited(
|
||||
ctx, scc_vec_at(type->data.function.params, i), visited);
|
||||
scc_tree_dump_pop(ctx->dump_ctx);
|
||||
}
|
||||
if (type->data.function.ret_type) {
|
||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||||
dump_type_with_visited(ctx, type->data.function.ret_type, visited);
|
||||
scc_tree_dump_pop(ctx->dump_ctx);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_type_linear_with_visited(scc_hir_dump_t *ctx,
|
||||
scc_hir_type_ref_t type_ref,
|
||||
scc_hashtable_t *visited) {
|
||||
if (!ctx || !type_ref) {
|
||||
LOG_ERROR("invalid parameter");
|
||||
return;
|
||||
}
|
||||
// 检查循环
|
||||
if (scc_hashtable_get(visited, (void *)(usize)type_ref)) {
|
||||
scc_tree_dump_append(ctx->dump_ctx, " <recursive>");
|
||||
return;
|
||||
}
|
||||
scc_hashtable_set(visited, (void *)(usize)type_ref, (void *)1);
|
||||
|
||||
scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref);
|
||||
if (!type) {
|
||||
LOG_ERROR("invalid type ref");
|
||||
return;
|
||||
}
|
||||
switch (type->tag) {
|
||||
case SCC_HIR_TYPE_unknown:
|
||||
case SCC_HIR_TYPE_void:
|
||||
@@ -407,24 +442,25 @@ void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
|
||||
break;
|
||||
case SCC_HIR_TYPE_ARRAY:
|
||||
scc_tree_dump_append(ctx->dump_ctx, "[");
|
||||
scc_hir_dump_type_linear(ctx, type->data.array.base);
|
||||
dump_type_linear_with_visited(ctx, type->data.array.base, visited);
|
||||
scc_tree_dump_append_fmt(ctx->dump_ctx, ", %zu]", type->data.array.len);
|
||||
break;
|
||||
case SCC_HIR_TYPE_PTR:
|
||||
scc_tree_dump_append(ctx->dump_ctx, "*");
|
||||
scc_hir_dump_type_linear(ctx, type->data.pointer.base);
|
||||
dump_type_linear_with_visited(ctx, type->data.pointer.base, visited);
|
||||
break;
|
||||
case SCC_HIR_TYPE_FUNC:
|
||||
scc_tree_dump_append(ctx->dump_ctx, "(");
|
||||
for (usize i = 0; i < scc_vec_size(type->data.function.params); i++) {
|
||||
if (i > 0)
|
||||
scc_tree_dump_append(ctx->dump_ctx, ", ");
|
||||
scc_hir_dump_type_linear(ctx,
|
||||
scc_vec_at(type->data.function.params, i));
|
||||
dump_type_linear_with_visited(
|
||||
ctx, scc_vec_at(type->data.function.params, i), visited);
|
||||
}
|
||||
if (type->data.function.ret_type) {
|
||||
scc_tree_dump_append(ctx->dump_ctx, ") -> ");
|
||||
scc_hir_dump_type_linear(ctx, type->data.function.ret_type);
|
||||
dump_type_linear_with_visited(ctx, type->data.function.ret_type,
|
||||
visited);
|
||||
} else {
|
||||
scc_tree_dump_append(ctx->dump_ctx, ")");
|
||||
}
|
||||
@@ -434,9 +470,9 @@ void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
|
||||
scc_tree_dump_append_fmt(ctx->dump_ctx, "%s {",
|
||||
type->tag == SCC_HIR_TYPE_STRUCT ? "struct"
|
||||
: "union");
|
||||
scc_vec_foreach(type->data.aggregate.fields, i) {
|
||||
scc_hir_dump_type_linear(
|
||||
ctx, scc_vec_at(type->data.aggregate.fields, i));
|
||||
for (usize i = 0; i < scc_vec_size(type->data.aggregate.fields); i++) {
|
||||
dump_type_linear_with_visited(
|
||||
ctx, scc_vec_at(type->data.aggregate.fields, i), visited);
|
||||
scc_tree_dump_append(ctx->dump_ctx, ";");
|
||||
}
|
||||
scc_tree_dump_append(ctx->dump_ctx, "}");
|
||||
@@ -447,6 +483,14 @@ void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
|
||||
scc_hir_type_ref_t type_ref) {
|
||||
scc_hashtable_t visited;
|
||||
scc_hashtable_usize_init(&visited);
|
||||
dump_type_linear_with_visited(ctx, type_ref, &visited);
|
||||
scc_hashtable_drop(&visited);
|
||||
}
|
||||
|
||||
static void format_ref_or_value(scc_hir_dump_t *ctx,
|
||||
scc_hir_value_ref_t value_ref) {
|
||||
scc_hir_value_t *value =
|
||||
@@ -580,8 +624,8 @@ void scc_hir_dump_value_linear(scc_hir_dump_t *ctx,
|
||||
value->data.jump.target_bblock);
|
||||
break;
|
||||
case SCC_HIR_VALUE_TAG_CALL: {
|
||||
scc_hir_func_t *func =
|
||||
scc_hir_module_get_func(GET_MODULE(ctx), value->data.call.callee);
|
||||
scc_hir_func_t *func = scc_hir_module_get_func(
|
||||
GET_MODULE(ctx), value->data.call.callee.func_ref);
|
||||
scc_tree_dump_append_fmt(ctx->dump_ctx, "call @%s(",
|
||||
func ? (func->name ? func->name : "<unnamed>")
|
||||
: "<invalid>");
|
||||
|
||||
@@ -358,8 +358,8 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value,
|
||||
break;
|
||||
}
|
||||
case SCC_HIR_VALUE_TAG_CALL: {
|
||||
scc_hir_func_t *callee =
|
||||
scc_hir_module_get_func(ctx->hir_module, value->data.call.callee);
|
||||
scc_hir_func_t *callee = scc_hir_module_get_func(
|
||||
ctx->hir_module, value->data.call.callee.func_ref);
|
||||
int arg_count = scc_vec_size(value->data.call.args);
|
||||
scc_lir_val_t *lir_args = scc_malloc(sizeof(scc_lir_val_t) * arg_count);
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __SCC_SEMA_H__
|
||||
|
||||
#include <scc_ast.h>
|
||||
#include <scc_utils.h>
|
||||
|
||||
typedef struct scc_sema_ctx scc_sema_ctx_t;
|
||||
/**
|
||||
@@ -13,6 +14,12 @@ typedef void (*scc_sema_callback_t)(scc_sema_ctx_t *context,
|
||||
typedef scc_ast_qual_type_t *(*scc_sema_got_type_t)(scc_sema_ctx_t *context,
|
||||
const char *name);
|
||||
|
||||
typedef struct scc_label_scope {
|
||||
int function_scope_depth;
|
||||
scc_hashtable_t labels; // 标签名 -> scc_ast_stmt_t* (LABEL节点)
|
||||
scc_ast_stmt_vec_t pending_gotos; // 尚未找到目标的goto语句
|
||||
} scc_sema_label_scope_t;
|
||||
|
||||
/**
|
||||
* @brief 语义分析回调集合
|
||||
*/
|
||||
@@ -26,6 +33,7 @@ struct scc_sema_ctx {
|
||||
|
||||
scc_ast_stmt_vec_t break_stack;
|
||||
scc_ast_stmt_vec_t continue_stack;
|
||||
scc_sema_label_scope_t label_scope;
|
||||
void *context;
|
||||
};
|
||||
|
||||
|
||||
@@ -290,7 +290,10 @@ CONTINUE:
|
||||
decl->var.init = scc_parse_initializer(parser, lvalue);
|
||||
} else if (tok_ptr->type == SCC_TOK_L_BRACE) {
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
scc_sema_decl(parser, scc_ast_decl_t_BEGIN, nullptr);
|
||||
|
||||
// 进入函数作用域(用于参数和标签)
|
||||
scc_sema_decl(parser, scc_ast_decl_t_BEGIN, decl);
|
||||
|
||||
// FIXME hack struct
|
||||
scc_vec_foreach(decl->func.type->type->function.params, i) {
|
||||
scc_ast_decl_t *param =
|
||||
@@ -299,7 +302,10 @@ CONTINUE:
|
||||
scc_parse_decl_sema(parser, param);
|
||||
}
|
||||
scc_ast_stmt_t *body = scc_parse_statement(parser);
|
||||
scc_sema_decl(parser, scc_ast_decl_t_END, nullptr);
|
||||
|
||||
// 退出函数作用域
|
||||
scc_sema_decl(parser, scc_ast_decl_t_END, decl);
|
||||
|
||||
Assert(decl->base.type == SCC_AST_DECL_FUNC);
|
||||
decl->func.body = body;
|
||||
Assert(decl->func.type != nullptr);
|
||||
|
||||
@@ -73,6 +73,7 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
|
||||
if (decl != nullptr) {
|
||||
scc_vec_push(unit->declarations, decl);
|
||||
} else {
|
||||
parser->errcode = 1;
|
||||
break;
|
||||
}
|
||||
if (parser->errcode != 0) { // FIXME errcode
|
||||
|
||||
@@ -133,37 +133,72 @@ static void stmt_callback(scc_sema_ctx_t *sema_ctx,
|
||||
}
|
||||
scc_ast_stmt_t *stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node);
|
||||
switch (stmt->base.type) {
|
||||
case SCC_AST_STMT_BREAK:
|
||||
case SCC_AST_STMT_BREAK: {
|
||||
if (scc_vec_size(sema_ctx->break_stack) == 0)
|
||||
SCC_ERROR(stmt->base.loc, "break not in loop/switch");
|
||||
else
|
||||
stmt->jump._target = scc_vec_at(
|
||||
sema_ctx->break_stack, scc_vec_size(sema_ctx->break_stack) - 1);
|
||||
break;
|
||||
case SCC_AST_STMT_CONTINUE:
|
||||
} break;
|
||||
case SCC_AST_STMT_CONTINUE: {
|
||||
if (scc_vec_size(sema_ctx->continue_stack) == 0)
|
||||
SCC_ERROR(stmt->base.loc, "continue not in loop");
|
||||
else
|
||||
stmt->jump._target =
|
||||
scc_vec_at(sema_ctx->continue_stack,
|
||||
scc_vec_size(sema_ctx->continue_stack) - 1);
|
||||
case SCC_AST_STMT_GOTO:
|
||||
scc_ast_node_t *target_node =
|
||||
scc_sema_symtab_lookup_symbol(sema_symtab, stmt->goto_stmt.label);
|
||||
if (target_node == nullptr) {
|
||||
SCC_ERROR(stmt->base.loc, "");
|
||||
} break;
|
||||
case SCC_AST_STMT_GOTO: {
|
||||
scc_ast_stmt_t *goto_stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node);
|
||||
scc_sema_label_scope_t *scope = &sema_ctx->label_scope;
|
||||
if (scope->function_scope_depth != 1) {
|
||||
SCC_ERROR(goto_stmt->base.loc, "goto not inside any function");
|
||||
break;
|
||||
}
|
||||
if (!SCC_AST_IS_A(scc_ast_stmt_t, target_node)) {
|
||||
SCC_ERROR(stmt->base.loc, "");
|
||||
|
||||
// 尝试直接查找标签
|
||||
scc_ast_node_t *target =
|
||||
scc_hashtable_get(&scope->labels, goto_stmt->goto_stmt.label);
|
||||
if (target) {
|
||||
goto_stmt->goto_stmt._target =
|
||||
SCC_AST_CAST_TO(scc_ast_stmt_t, target);
|
||||
} else {
|
||||
// 未找到则加入待处理列表
|
||||
scc_vec_push(scope->pending_gotos, goto_stmt);
|
||||
}
|
||||
} break;
|
||||
case SCC_AST_STMT_LABEL: {
|
||||
scc_ast_stmt_t *label_stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node);
|
||||
scc_sema_label_scope_t *scope = &sema_ctx->label_scope;
|
||||
// 获取当前函数标签作用域
|
||||
if (scope->function_scope_depth != 1) {
|
||||
SCC_ERROR(label_stmt->base.loc, "label not inside any function");
|
||||
break;
|
||||
}
|
||||
stmt->goto_stmt._target = SCC_AST_CAST_TO(scc_ast_stmt_t, target_node);
|
||||
break;
|
||||
case SCC_AST_STMT_LABEL:
|
||||
scc_sema_symtab_add_symbol(sema_symtab, stmt->label_stmt.label,
|
||||
&stmt->base);
|
||||
|
||||
// 检查重复定义
|
||||
if (scc_hashtable_get(&scope->labels, label_stmt->label_stmt.label)) {
|
||||
SCC_ERROR(label_stmt->base.loc, "duplicate label '%s'",
|
||||
label_stmt->label_stmt.label);
|
||||
break;
|
||||
}
|
||||
|
||||
// 添加标签
|
||||
scc_hashtable_set(&scope->labels, label_stmt->label_stmt.label,
|
||||
&label_stmt->base);
|
||||
|
||||
// 检查是否有等待该标签的 goto
|
||||
scc_vec_foreach(scope->pending_gotos, i) {
|
||||
scc_ast_stmt_t *goto_stmt = scc_vec_at(scope->pending_gotos, i);
|
||||
if (goto_stmt == nullptr)
|
||||
continue;
|
||||
if (scc_strcmp(goto_stmt->goto_stmt.label,
|
||||
label_stmt->label_stmt.label) == 0) {
|
||||
goto_stmt->goto_stmt._target = label_stmt;
|
||||
scc_vec_at(scope->pending_gotos, i) = nullptr;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -175,10 +210,37 @@ static void decl_callback(scc_sema_ctx_t *sema_ctx,
|
||||
scc_sema_symtab_t *sema_symtab = sema_ctx->context;
|
||||
|
||||
// Function declaration scope
|
||||
// FIXME 使用 node_type 区分其他未来的scope
|
||||
if (node_type == scc_ast_decl_t_BEGIN) {
|
||||
// 创建标签作用域
|
||||
scc_sema_label_scope_t *scope = &sema_ctx->label_scope;
|
||||
scope->function_scope_depth += 1;
|
||||
scc_hashtable_cstr_init(&scope->labels);
|
||||
scc_vec_init(scope->pending_gotos);
|
||||
|
||||
// 进入普通符号表作用域(用于参数和局部变量)
|
||||
scc_sema_symtab_enter_scope(sema_symtab);
|
||||
return;
|
||||
} else if (node_type == scc_ast_decl_t_END) {
|
||||
scc_sema_label_scope_t *scope = &sema_ctx->label_scope;
|
||||
scope->function_scope_depth -= 1;
|
||||
|
||||
// 处理尚未绑定的 goto
|
||||
scc_vec_foreach(scope->pending_gotos, i) {
|
||||
scc_ast_stmt_t *goto_stmt = scc_vec_at(scope->pending_gotos, i);
|
||||
if (goto_stmt == nullptr) {
|
||||
continue;
|
||||
}
|
||||
// 标签未定义 -> 报错
|
||||
SCC_ERROR(goto_stmt->base.loc, "label '%s' used but not defined",
|
||||
goto_stmt->goto_stmt.label);
|
||||
}
|
||||
|
||||
// 清理
|
||||
scc_hashtable_drop(&scope->labels);
|
||||
scc_vec_free(scope->pending_gotos);
|
||||
|
||||
// 退出普通符号表作用域
|
||||
scc_sema_symtab_leave_scope(sema_symtab);
|
||||
return;
|
||||
}
|
||||
@@ -242,6 +304,7 @@ void scc_sema_init(scc_sema_ctx_t *sema_ctx, scc_ast_ctx_t *ast_ctx) {
|
||||
sema_ctx->on_stmt = stmt_callback;
|
||||
sema_ctx->on_type = type_callback;
|
||||
sema_ctx->got_type = got_type_callback;
|
||||
sema_ctx->label_scope = (scc_sema_label_scope_t){0};
|
||||
|
||||
scc_sema_symtab_init(sema_symtab);
|
||||
|
||||
|
||||
@@ -99,11 +99,11 @@ void scc_pproc_parse_include(scc_pproc_t *pp, scc_lexer_tok_t *include_tok,
|
||||
for (int i = 1; i < len - 1; i++) {
|
||||
scc_str_append_ch(&fname, includename[i]);
|
||||
}
|
||||
scc_str_drop(&line);
|
||||
int is_system = includename[0] == '<';
|
||||
if (switch_file_stack(pp, &fname, &pos, is_system)) {
|
||||
// LOG_ERROR()
|
||||
}
|
||||
scc_str_drop(&line);
|
||||
scc_str_drop(&fname);
|
||||
return;
|
||||
ERROR:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @brief Arbitrary Precision Library
|
||||
*
|
||||
*/
|
||||
#ifdef __AP_SCC__
|
||||
#ifdef __SCC__
|
||||
#include <scc_core.h>
|
||||
#define SCC_AP_DIGIT u64
|
||||
#define SCC_AP_PANIC Panic
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#define __scc_log_unreachable() (__builtin_unreachable())
|
||||
#elif defined _MSC_VER // MSVC
|
||||
#define __scc_log_unreachable() (__assume(false))
|
||||
#elif defined __SCC_BUILTIN__ // The SCC Compiler (my compiler)
|
||||
#elif defined __SCC_BUILTIN_UNREACHEABLE__ // The SCC Compiler (my compiler)
|
||||
#define __scc_log_unreachable() (__scc_builtin_unreachable())
|
||||
#else
|
||||
#define __scc_log_unreachable() ((void)0)
|
||||
@@ -184,7 +184,7 @@ void log_set_handler(logger_t *logger, log_handler handler);
|
||||
* 或使用 _Static_assert (C11)
|
||||
*/
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define StaticAssert static_assert
|
||||
#define StaticAssert _Static_assert
|
||||
#else
|
||||
#define StaticAssert(cond, msg) extern char __static_assertion[(cond) ? 1 : -1]
|
||||
#endif
|
||||
|
||||
@@ -13,4 +13,14 @@
|
||||
#define scc_min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define scc_max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define SCC_MAYBE_UNUSED __attribute__((unused))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SCC_MAYBE_UNUSED __pragma(warning(suppress : 4100))
|
||||
#elif defined(__clang__)
|
||||
#define SCC_MAYBE_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define SCC_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#endif // __SCC_CORE_MACRO_H__
|
||||
|
||||
@@ -15,13 +15,16 @@
|
||||
#include "scc_core_type.h"
|
||||
#define __scc_vec_realloc scc_realloc
|
||||
#define __scc_vec_free scc_free
|
||||
#define __scc_vec_memcpy scc_memcpy
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef size_t usize;
|
||||
#define __scc_vec_realloc realloc
|
||||
#define __scc_vec_free free
|
||||
#define __scc_vec_memcpy memcpy
|
||||
|
||||
#ifndef LOG_FATAL
|
||||
#include <stdio.h>
|
||||
@@ -169,4 +172,86 @@ typedef size_t usize;
|
||||
(vec).data = array; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_realloc(vec, elem_size, new_cap)
|
||||
* @brief 内部宏:按 elem_size 重新分配内存
|
||||
*/
|
||||
#define scc_vec_sized_realloc(vec, elem_size, new_cap) \
|
||||
do { \
|
||||
void *new_data = \
|
||||
__scc_vec_realloc((vec).data, (new_cap) * (elem_size)); \
|
||||
if (!new_data) \
|
||||
LOG_FATAL("scc_vec_sized_realloc: failed\n"); \
|
||||
(vec).data = new_data; \
|
||||
(vec).cap = new_cap; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_push(vec, elem_size, src_ptr)
|
||||
* @brief 添加一个元素(从 src_ptr 拷贝 elem_size 字节)
|
||||
* @param vec SCC_VEC(type) 定义的向量变量(type 可为 char 或 void)
|
||||
* @param elem_size 每个元素占用的字节数
|
||||
* @param src_ptr 源数据的指针
|
||||
* @param copy_size 要拷贝的字节数
|
||||
*
|
||||
* @note 使用前需确保 vec.data 类型与 src_ptr 无关,内部会按字节拷贝。
|
||||
* 推荐声明时为 `SCC_VEC(char)` 或 `SCC_VEC(unsigned char)`。
|
||||
*/
|
||||
#define scc_vec_sized_push(vec, elem_size, src_ptr, copy_size) \
|
||||
do { \
|
||||
if ((vec).size >= (vec).cap) { \
|
||||
usize new_cap = (vec).cap ? (vec).cap * 2 : 4; \
|
||||
scc_vec_sized_realloc(vec, elem_size, new_cap); \
|
||||
} \
|
||||
char *slot = (char *)(vec).data + (vec).size * (elem_size); \
|
||||
__scc_vec_memcpy(slot, (src_ptr), (copy_size)); \
|
||||
(vec).size++; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_at_ptr(vec, elem_size, idx)
|
||||
* @brief 获取第 idx 个元素的指针(void*)
|
||||
* @return 指向元素的指针,需转换为具体类型使用
|
||||
*/
|
||||
#define scc_vec_sized_at_ptr(vec, elem_size, idx) \
|
||||
((void *)((char *)(vec).data + (idx) * (elem_size)))
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_foreach(vec, elem_size, elem_ptr_var, block)
|
||||
* @brief 遍历所有元素
|
||||
* @param elem_ptr_var 循环内的变量名(void* 类型)
|
||||
* @param block 循环体语句块
|
||||
*/
|
||||
#define scc_vec_sized_foreach(vec, elem_size, elem_ptr_var, block) \
|
||||
do { \
|
||||
for (usize __i = 0; __i < (vec).size; ++__i) { \
|
||||
void *elem_ptr_var = scc_vec_sized_at_ptr(vec, elem_size, __i); \
|
||||
block; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_pop(vec, elem_size)
|
||||
* @brief 弹出最后一个元素(仅减小 size,不返回数据)
|
||||
*/
|
||||
#define scc_vec_sized_pop(vec, elem_size) \
|
||||
do { \
|
||||
if ((vec).size == 0) \
|
||||
LOG_FATAL("scc_vec_sized_pop: empty\n"); \
|
||||
(vec).size--; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_clear(vec)
|
||||
* @brief 清空向量(重置 size = 0,不释放内存)
|
||||
*/
|
||||
#define scc_vec_sized_clear(vec) ((vec).size = 0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_free(vec)
|
||||
* @brief 释放向量内存(与原始 scc_vec_free 相同,可复用)
|
||||
* @note 注意:如果元素内部有堆资源,需在释放前自行遍历调用析构函数。
|
||||
*/
|
||||
#define scc_vec_sized_free(vec) scc_vec_free(vec)
|
||||
|
||||
#endif /* __SCC_CORE_VEC_H__ */
|
||||
|
||||
@@ -39,8 +39,15 @@ usize scc_fread(scc_file_t file, void *buffer, usize size) {
|
||||
return scc_pal_fread(file, buffer, size);
|
||||
}
|
||||
|
||||
usize scc_fwrite(scc_file_t file, const void *buffer, usize size) {
|
||||
return scc_pal_fwrite(file, buffer, size);
|
||||
usize scc_fwrite(scc_file_t file, const void *buf, usize size) {
|
||||
if (file == scc_stdout) {
|
||||
scc_pal_write(buf, size);
|
||||
} else if (file == scc_stderr) {
|
||||
scc_pal_ewrite(buf, size);
|
||||
} else {
|
||||
return scc_pal_fwrite(file, buf, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cbool scc_fexists(const char *path) {
|
||||
|
||||
@@ -155,7 +155,6 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
||||
static const char *emit_stages[] = {
|
||||
[SCC_EMIT_STAGE_LEX] = "lex",
|
||||
[SCC_EMIT_STAGE_PP] = "pp",
|
||||
|
||||
[SCC_EMIT_STAGE_AST] = "ast", // -T
|
||||
[SCC_EMIT_STAGE_HIR] = "hir", // -H
|
||||
[SCC_EMIT_STAGE_LIR] = "lir", // -L
|
||||
|
||||
Reference in New Issue
Block a user