feat(ast2ir): 添加浮点类型支持和复合初始化功能

- 在ABI类型计算中添加FLOAT和DOUBLE类型的映射
- 修复AST操作符注释中的歧义描述
- 为ast2ir上下文添加类型缓存以解决递归结构体定义问题
- 实现复合初始化表达式的支持,包括数组和结构体初始化
- 添加前置和后置自增/自减操作符的IR转换
- 实现三元条件表达式的IR生成
- 添加类型转换(cast)和sizeof操作符的支持
- 重构数组长度推断逻辑并添加类型大小计算函数
- 实现结构体和联合体的递归类型解析
- 添加函数指针调用相关的IR节点类型定义

fix(ast): 修正间接操作符的注释说明

refactor(ast2ir): 优化代码结构并添加必要的断言验证
This commit is contained in:
zzy
2026-05-19 17:35:24 +08:00
parent 3df858fb85
commit 2c13ac54df
21 changed files with 808 additions and 177 deletions

View File

@@ -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: case SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG:
kind = SCC_ABI_TYPE_U_LONG_LONG; kind = SCC_ABI_TYPE_U_LONG_LONG;
break; 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: default:
Panic("Unsupported AST type: %d", Panic("Unsupported AST type: %d",
scc_ast_canon_type(ast_type)->builtin.type); scc_ast_canon_type(ast_type)->builtin.type);

View File

@@ -262,7 +262,7 @@ typedef enum scc_ast_expr_op {
SCC_AST_OP_UNARY_PLUS, // + (一元) SCC_AST_OP_UNARY_PLUS, // + (一元)
SCC_AST_OP_UNARY_MINUS, // - (一元) SCC_AST_OP_UNARY_MINUS, // - (一元)
SCC_AST_OP_ADDRESS_OF, // & SCC_AST_OP_ADDRESS_OF, // &
SCC_AST_OP_INDIRECTION, // * SCC_AST_OP_INDIRECTION, // * (取地址)
SCC_AST_OP_BITWISE_NOT, // ~ SCC_AST_OP_BITWISE_NOT, // ~
SCC_AST_OP_LOGICAL_NOT, // ! SCC_AST_OP_LOGICAL_NOT, // !
SCC_AST_OP_PREFIX_INCREMENT, // ++ (前缀) SCC_AST_OP_PREFIX_INCREMENT, // ++ (前缀)

View File

@@ -11,6 +11,7 @@ typedef struct {
scc_hashtable_t break_cache; ///< break cache scc_hashtable_t break_cache; ///< break cache
scc_hashtable_t continue_cache; ///< continue cache scc_hashtable_t continue_cache; ///< continue cache
scc_hashtable_t symtab; ///< symbol to ir_ref 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 // scc_strpool_t strpool; ///< string pool
const scc_abi_type_calc_t *abi; const scc_abi_type_calc_t *abi;
cbool hint_using_value; // 转换时尽可能使用value而不是alloc cbool hint_using_value; // 转换时尽可能使用value而不是alloc

View File

@@ -27,39 +27,24 @@ static scc_hir_type_ref_t parse_base_type(scc_ast2ir_ctx_t *ctx,
return SCC_HIR_REF_nullptr; return SCC_HIR_REF_nullptr;
} }
// static inline void parse_struct_union_layout(scc_ast_qual_type_t *type) {} static inline bool scc_hir_type_is_signed(scc_hir_type_tag_t tag) {
switch (tag) {
// 辅助函数计算数组实际长度如果原长度为0 case SCC_HIR_TYPE_i8:
static void resolve_array_length(scc_ast2ir_ctx_t *ctx, case SCC_HIR_TYPE_i16:
const scc_hir_type_t *orig_array_type, case SCC_HIR_TYPE_i32:
scc_hir_type_t *resolved_array_type, case SCC_HIR_TYPE_i64:
const scc_ast_expr_t *init_expr) { case SCC_HIR_TYPE_i128:
*resolved_array_type = *orig_array_type; // 拷贝 return true;
Assert(orig_array_type->tag == SCC_HIR_TYPE_ARRAY); case SCC_HIR_TYPE_u8:
if (orig_array_type->data.array.len != 0) case SCC_HIR_TYPE_u16:
return; // 长度已知,无需推断 case SCC_HIR_TYPE_u32:
case SCC_HIR_TYPE_u64:
usize new_len = 0; case SCC_HIR_TYPE_u128:
switch (init_expr->base.type) { return false;
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: 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 循环,但为简化暂不处理 // 这里简单忽略,实际可生成 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: {
// 目标指针大小,可以定义为 864位或从 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, scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
const scc_ast_qual_type_t *ast_type) { const scc_ast_qual_type_t *ast_type) {
if (ctx == nullptr || ast_type == nullptr) { if (ctx == nullptr || ast_type == nullptr) {
@@ -189,22 +310,64 @@ scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
} break; } break;
case SCC_AST_TYPE_STRUCT: case SCC_AST_TYPE_STRUCT:
case SCC_AST_TYPE_UNION: { 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_STRUCT
: SCC_HIR_TYPE_UNION); : SCC_HIR_TYPE_UNION);
if (scc_ast_canon_type(ast_type)->record.decl == nullptr) { // 可以给占位符一个调试名
Panic("%s record fields is nullptr", if (canon->record.name) {
scc_ast_canon_type(ast_type)->record.name); placeholder.name = canon->record.name;
} }
scc_vec_foreach(
scc_ast_canon_type(ast_type)->record.decl->record.fields, i) { // === 3. 直接添加到模块,不经过 builder 的 uniquing ===
scc_ast_decl_t *decl_field = scc_vec_at( // 因为此时我们不需要类型去重,只需要一个确定不移的引用
scc_ast_canon_type(ast_type)->record.decl->record.fields, i); scc_hir_type_ref_t place_ref =
Assert(decl_field->base.type == SCC_AST_DECL_VAR); scc_hir_module_add_type(&ctx->builder.cprog->module, &placeholder);
scc_hir_type_ref_t field_type =
scc_ast2ir_type(ctx, decl_field->var.type); // === 4. 将映射写入缓存(关键!必须在递归前) ===
scc_vec_push(ir_type.data.aggregate.fields, field_type); 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; } break;
case SCC_AST_TYPE_ENUM: case SCC_AST_TYPE_ENUM:
scc_ast_canon_type_t *int_canon_type = scc_ast_ctx_get_builtin_type( 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) { switch (expr->base.type) {
case SCC_AST_EXPR_BINARY: { case SCC_AST_EXPR_BINARY: {
scc_ast_expr_t tmp_expr; 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) { switch (expr->binary.op) {
case SCC_AST_OP_ASSIGN: // = case SCC_AST_OP_ASSIGN: // =
rhs = scc_ast2ir_expr(ctx, expr->binary.rhs, false); 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; break;
} }
if (is_assign) { if (is_assign) {
Assert(rhs != SCC_HIR_REF_nullptr);
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, true); lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, true);
return scc_hir_builder_store(&ctx->builder, lhs, rhs); 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); return scc_hir_builder_binop(&ctx->builder, op, lhs, rhs);
} } break;
case SCC_AST_EXPR_UNARY: { case SCC_AST_EXPR_UNARY: {
if (expr->unary.op == SCC_AST_OP_ADDRESS_OF) { if (expr->unary.op == SCC_AST_OP_ADDRESS_OF) {
return scc_ast2ir_expr(ctx, expr->unary.operand, true); 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_hir_value_ref_t operand =
scc_ast2ir_expr(ctx, expr->unary.operand, is_lvalue); 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) { switch (expr->unary.op) {
case SCC_AST_OP_UNARY_PLUS: case SCC_AST_OP_UNARY_PLUS:
/* just pass */ /* 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, return scc_hir_builder_binop(&ctx->builder, SCC_HIR_OP_EQ, zero_ref,
operand); 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: default:
LOG_FATAL("Unsupported unary operator: %d", expr->unary.op); LOG_FATAL("Unsupported unary operator: %d", expr->unary.op);
return 0; return 0;
} }
UNREACHABLE(); UNREACHABLE();
break; } break;
}
case SCC_AST_EXPR_COND: { case SCC_AST_EXPR_COND: {
TODO(); scc_hir_type_ref_t true_type = SCC_HIR_REF_nullptr;
break; 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: { case SCC_AST_EXPR_CALL: {
// 转换参数 // 转换参数
scc_hir_value_ref_vec_t args; 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); return scc_hir_builder_load(&ctx->builder, field_ptr);
} }
case SCC_AST_EXPR_CAST: { case SCC_AST_EXPR_CAST: {
TODO(); // 1. 转换操作数(右值)
} break; 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: { case SCC_AST_EXPR_SIZE_OF: {
TODO(); // 1. 将 sizeof 的操作数(类型或表达式)转换为 IR 类型
// return scc_hir_builder_integer( scc_hir_type_ref_t hir_type;
// &ctx->builder, scc_hir_builder_type_u64(&ctx->builder), val); 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: { case SCC_AST_EXPR_ALIGN_OF: {
TODO(); 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); // &ctx->builder, scc_hir_builder_type_u64(&ctx->builder), val);
} }
case SCC_AST_EXPR_COMPOUND: { 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; } break;
case SCC_AST_EXPR_LVALUE: { case SCC_AST_EXPR_LVALUE: {
TODO(); UNREACHABLE(); // should only appear as compound.base
} break; } break;
case SCC_AST_EXPR_BUILTIN: { case SCC_AST_EXPR_BUILTIN: {
TODO(); TODO();
@@ -923,10 +1305,10 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
break; break;
} }
case SCC_AST_STMT_GOTO: { case SCC_AST_STMT_GOTO: {
scc_hir_bblock_ref_t target = (usize)scc_hashtable_get( // scc_hir_bblock_ref_t target = (usize)scc_hashtable_get(
&ctx->ast2ir_cache, (void *)stmt->goto_stmt._target); // &ctx->ast2ir_cache, (void *)stmt->goto_stmt._target);
Assert(target != SCC_HIR_REF_nullptr); // Assert(target != SCC_HIR_REF_nullptr);
scc_hir_builder_jump(&ctx->builder, target); // scc_hir_builder_jump(&ctx->builder, target);
} break; } break;
case SCC_AST_STMT_LABEL: { case SCC_AST_STMT_LABEL: {
scc_hir_value_ref_t label_block = 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) { if (type.tag == SCC_HIR_TYPE_ARRAY) {
emit_array_initialization(ctx, alloc_val_node, &type, emit_array_initialization(ctx, alloc_val_node, &type,
decl->var.init); 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 { } else {
// 标量类型 // 标量类型
scc_hir_value_ref_t init_val = 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_ast2ir_type(ctx, decl->func.type);
scc_hir_func_ref_t func_ref = scc_hir_func_ref_t func_ref =
(usize)scc_hashtable_get(&ctx->symtab, decl->name); (usize)scc_hashtable_get(&ctx->symtab, decl->name);
if (func_ref == SCC_HIR_REF_nullptr) { if (func_ref == SCC_HIR_REF_nullptr) {
func_ref = func_ref =
scc_hir_builder_func(&ctx->builder, func_type_ref, decl->name); 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, scc_hashtable_set(&ctx->symtab, decl->name,
(void *)(usize)func_ref); (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->break_cache);
scc_hashtable_usize_init(&ctx->continue_cache); scc_hashtable_usize_init(&ctx->continue_cache);
scc_hashtable_cstr_init(&ctx->symtab); scc_hashtable_cstr_init(&ctx->symtab);
scc_hashtable_usize_init(&ctx->type_cache);
ctx->hint_using_value = false; 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->ast2ir_cache);
scc_hashtable_drop(&ctx->break_cache); scc_hashtable_drop(&ctx->break_cache);
scc_hashtable_drop(&ctx->continue_cache); scc_hashtable_drop(&ctx->continue_cache);
scc_hashtable_drop(&ctx->type_cache);
scc_hashtable_drop(&ctx->symtab); scc_hashtable_drop(&ctx->symtab);
} }

View File

@@ -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); 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_func_ref_t scc_hir_builder_func(scc_hir_builder_t *builder,
scc_hir_type_ref_t type_ref, scc_hir_type_ref_t type_ref,
const char *name); const char *name);
@@ -92,7 +97,7 @@ scc_hir_value_ref_t scc_hir_builder_alloca(scc_hir_builder_t *builder,
const char *name); const char *name);
#define SCC_HIR_BUILDER_TYPE_FUNC(scc_type) \ #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_builder_type_##scc_type(scc_hir_builder_t *builder) { \
scc_hir_type_t type_desc; \ scc_hir_type_t type_desc; \
scc_hir_type_init(&type_desc, SCC_HIR_TYPE_##scc_type); \ scc_hir_type_init(&type_desc, SCC_HIR_TYPE_##scc_type); \

View File

@@ -89,7 +89,9 @@ typedef enum scc_hir_value_tag {
SCC_HIR_VALUE_TAG_OP, ///< 二元运算 SCC_HIR_VALUE_TAG_OP, ///< 二元运算
SCC_HIR_VALUE_TAG_BRANCH, ///< 有条件分支 SCC_HIR_VALUE_TAG_BRANCH, ///< 有条件分支
SCC_HIR_VALUE_TAG_JUMP, ///< 无条件跳转 SCC_HIR_VALUE_TAG_JUMP, ///< 无条件跳转
SCC_HIR_VALUE_TAG_JUMP_INDIRECT, ///< 无条件跳转(地址)
SCC_HIR_VALUE_TAG_CALL, ///< 调用函数 SCC_HIR_VALUE_TAG_CALL, ///< 调用函数
SCC_HIR_VALUE_TAG_CALL_INDIRECT, ///< 调用函数(地址)
SCC_HIR_VALUE_TAG_RET, ///< 函数返回 SCC_HIR_VALUE_TAG_RET, ///< 函数返回
} scc_hir_value_tag_t; } 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 true_bblock;
scc_hir_bblock_ref_t false_bblock; scc_hir_bblock_ref_t false_bblock;
} branch; } branch;
struct { union {
scc_hir_value_ref_t target_ptr;
scc_hir_bblock_ref_t target_bblock; scc_hir_bblock_ref_t target_bblock;
} jump; } jump;
struct { 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; scc_hir_value_ref_vec_t args;
} call; } call;
struct { struct {

View File

@@ -105,7 +105,7 @@ void scc_hir_value_init(scc_hir_value_t *in, const char *name,
break; break;
case SCC_HIR_VALUE_TAG_CALL: case SCC_HIR_VALUE_TAG_CALL:
scc_vec_init(in->data.call.args); scc_vec_init(in->data.call.args);
in->data.call.callee = 0; in->data.call.callee.func_ref = 0;
break; break;
case SCC_HIR_VALUE_TAG_RET: case SCC_HIR_VALUE_TAG_RET:
in->data.ret.ret_val = 0; in->data.ret.ret_val = 0;

View File

@@ -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_BUILDER_CHECK_NO_BORROW(builder);
scc_hir_value_t call_node = {0}; scc_hir_value_t call_node = {0};
call_node.tag = SCC_HIR_VALUE_TAG_CALL; 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); scc_vec_init(call_node.data.call.args);
for (usize i = 0; i < arg_count; i++) { for (usize i = 0; i < arg_count; i++) {

View File

@@ -3,7 +3,9 @@
#include <scc_tree_dump.h> #include <scc_tree_dump.h>
#define GET_MODULE(ctx) (&(ctx->cprog->module)) #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 *get_node_type_str(scc_hir_value_tag_t tag) {
static const char *node_types[] = { static const char *node_types[] = {
[SCC_HIR_VALUE_TAG_NULLPTR] = "NullPtr", [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) { static void dump_call_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
scc_tree_dump_begin_line(ctx->dump_ctx); scc_tree_dump_begin_line(ctx->dump_ctx);
if (value->data.call.callee) { if (value->data.call.callee.func_ref) {
scc_hir_func_t *callee = scc_hir_func_t *callee = scc_hir_module_get_func(
scc_hir_module_get_func(GET_MODULE(ctx), value->data.call.callee); GET_MODULE(ctx), value->data.call.callee.func_ref);
scc_tree_dump_value(ctx->dump_ctx, "func='%s'", scc_tree_dump_value(ctx->dump_ctx, "func='%s'",
callee ? (callee->name ? callee->name : "<unnamed>") callee ? (callee->name ? callee->name : "<unnamed>")
: "<invalid>"); : "<invalid>");
@@ -256,60 +258,12 @@ void scc_hir_dump_value(scc_hir_dump_t *ctx, scc_hir_value_ref_t value_ref) {
break; break;
} }
} }
void scc_hir_dump_type(scc_hir_dump_t *ctx, scc_hir_type_ref_t type_ref) { void scc_hir_dump_type(scc_hir_dump_t *ctx, scc_hir_type_ref_t type_ref) {
if (!ctx || !type_ref) { scc_hashtable_t visited;
LOG_ERROR("invalid parameter"); scc_hashtable_usize_init(&visited);
return; 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) { void scc_hir_dump_bblock(scc_hir_dump_t *ctx, scc_hir_bblock_ref_t bblock_ref) {
if (!ctx || !bblock_ref) { if (!ctx || !bblock_ref) {
LOG_ERROR("invalid parameter"); LOG_ERROR("invalid parameter");
@@ -379,13 +333,94 @@ void scc_hir_dump_cprog(scc_hir_dump_t *ctx) {
} }
// ----- 线性输出(保留原逻辑,改用新 API----- // ----- 线性输出(保留原逻辑,改用新 API-----
void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
scc_hir_type_ref_t type_ref) { // 在 scc_hir_dump.c 中添加以下静态辅助函数(放在文件前部,现有函数之前)
scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref);
if (!ctx || !type) { 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"); LOG_ERROR("invalid parameter");
return; 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) { switch (type->tag) {
case SCC_HIR_TYPE_unknown: case SCC_HIR_TYPE_unknown:
case SCC_HIR_TYPE_void: case SCC_HIR_TYPE_void:
@@ -407,24 +442,25 @@ void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
break; break;
case SCC_HIR_TYPE_ARRAY: case SCC_HIR_TYPE_ARRAY:
scc_tree_dump_append(ctx->dump_ctx, "["); 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); scc_tree_dump_append_fmt(ctx->dump_ctx, ", %zu]", type->data.array.len);
break; break;
case SCC_HIR_TYPE_PTR: case SCC_HIR_TYPE_PTR:
scc_tree_dump_append(ctx->dump_ctx, "*"); 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; break;
case SCC_HIR_TYPE_FUNC: case SCC_HIR_TYPE_FUNC:
scc_tree_dump_append(ctx->dump_ctx, "("); scc_tree_dump_append(ctx->dump_ctx, "(");
for (usize i = 0; i < scc_vec_size(type->data.function.params); i++) { for (usize i = 0; i < scc_vec_size(type->data.function.params); i++) {
if (i > 0) if (i > 0)
scc_tree_dump_append(ctx->dump_ctx, ", "); scc_tree_dump_append(ctx->dump_ctx, ", ");
scc_hir_dump_type_linear(ctx, dump_type_linear_with_visited(
scc_vec_at(type->data.function.params, i)); ctx, scc_vec_at(type->data.function.params, i), visited);
} }
if (type->data.function.ret_type) { if (type->data.function.ret_type) {
scc_tree_dump_append(ctx->dump_ctx, ") -> "); 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 { } else {
scc_tree_dump_append(ctx->dump_ctx, ")"); 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 {", scc_tree_dump_append_fmt(ctx->dump_ctx, "%s {",
type->tag == SCC_HIR_TYPE_STRUCT ? "struct" type->tag == SCC_HIR_TYPE_STRUCT ? "struct"
: "union"); : "union");
scc_vec_foreach(type->data.aggregate.fields, i) { for (usize i = 0; i < scc_vec_size(type->data.aggregate.fields); i++) {
scc_hir_dump_type_linear( dump_type_linear_with_visited(
ctx, scc_vec_at(type->data.aggregate.fields, i)); ctx, scc_vec_at(type->data.aggregate.fields, i), visited);
scc_tree_dump_append(ctx->dump_ctx, ";"); scc_tree_dump_append(ctx->dump_ctx, ";");
} }
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, static void format_ref_or_value(scc_hir_dump_t *ctx,
scc_hir_value_ref_t value_ref) { scc_hir_value_ref_t value_ref) {
scc_hir_value_t *value = 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); value->data.jump.target_bblock);
break; break;
case SCC_HIR_VALUE_TAG_CALL: { case SCC_HIR_VALUE_TAG_CALL: {
scc_hir_func_t *func = scc_hir_func_t *func = scc_hir_module_get_func(
scc_hir_module_get_func(GET_MODULE(ctx), value->data.call.callee); GET_MODULE(ctx), value->data.call.callee.func_ref);
scc_tree_dump_append_fmt(ctx->dump_ctx, "call @%s(", scc_tree_dump_append_fmt(ctx->dump_ctx, "call @%s(",
func ? (func->name ? func->name : "<unnamed>") func ? (func->name ? func->name : "<unnamed>")
: "<invalid>"); : "<invalid>");

View File

@@ -358,8 +358,8 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value,
break; break;
} }
case SCC_HIR_VALUE_TAG_CALL: { case SCC_HIR_VALUE_TAG_CALL: {
scc_hir_func_t *callee = scc_hir_func_t *callee = scc_hir_module_get_func(
scc_hir_module_get_func(ctx->hir_module, value->data.call.callee); ctx->hir_module, value->data.call.callee.func_ref);
int arg_count = scc_vec_size(value->data.call.args); 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); scc_lir_val_t *lir_args = scc_malloc(sizeof(scc_lir_val_t) * arg_count);
for (int i = 0; i < arg_count; i++) { for (int i = 0; i < arg_count; i++) {

View File

@@ -2,6 +2,7 @@
#define __SCC_SEMA_H__ #define __SCC_SEMA_H__
#include <scc_ast.h> #include <scc_ast.h>
#include <scc_utils.h>
typedef struct scc_sema_ctx scc_sema_ctx_t; 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, typedef scc_ast_qual_type_t *(*scc_sema_got_type_t)(scc_sema_ctx_t *context,
const char *name); 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 语义分析回调集合 * @brief 语义分析回调集合
*/ */
@@ -26,6 +33,7 @@ struct scc_sema_ctx {
scc_ast_stmt_vec_t break_stack; scc_ast_stmt_vec_t break_stack;
scc_ast_stmt_vec_t continue_stack; scc_ast_stmt_vec_t continue_stack;
scc_sema_label_scope_t label_scope;
void *context; void *context;
}; };

View File

@@ -290,7 +290,10 @@ CONTINUE:
decl->var.init = scc_parse_initializer(parser, lvalue); decl->var.init = scc_parse_initializer(parser, lvalue);
} else if (tok_ptr->type == SCC_TOK_L_BRACE) { } else if (tok_ptr->type == SCC_TOK_L_BRACE) {
scc_parse_decl_sema(parser, decl); 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 // FIXME hack struct
scc_vec_foreach(decl->func.type->type->function.params, i) { scc_vec_foreach(decl->func.type->type->function.params, i) {
scc_ast_decl_t *param = scc_ast_decl_t *param =
@@ -299,7 +302,10 @@ CONTINUE:
scc_parse_decl_sema(parser, param); scc_parse_decl_sema(parser, param);
} }
scc_ast_stmt_t *body = scc_parse_statement(parser); 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); Assert(decl->base.type == SCC_AST_DECL_FUNC);
decl->func.body = body; decl->func.body = body;
Assert(decl->func.type != nullptr); Assert(decl->func.type != nullptr);

View File

@@ -73,6 +73,7 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
if (decl != nullptr) { if (decl != nullptr) {
scc_vec_push(unit->declarations, decl); scc_vec_push(unit->declarations, decl);
} else { } else {
parser->errcode = 1;
break; break;
} }
if (parser->errcode != 0) { // FIXME errcode if (parser->errcode != 0) { // FIXME errcode

View File

@@ -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); scc_ast_stmt_t *stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node);
switch (stmt->base.type) { switch (stmt->base.type) {
case SCC_AST_STMT_BREAK: case SCC_AST_STMT_BREAK: {
if (scc_vec_size(sema_ctx->break_stack) == 0) if (scc_vec_size(sema_ctx->break_stack) == 0)
SCC_ERROR(stmt->base.loc, "break not in loop/switch"); SCC_ERROR(stmt->base.loc, "break not in loop/switch");
else else
stmt->jump._target = scc_vec_at( stmt->jump._target = scc_vec_at(
sema_ctx->break_stack, scc_vec_size(sema_ctx->break_stack) - 1); sema_ctx->break_stack, scc_vec_size(sema_ctx->break_stack) - 1);
break; } break;
case SCC_AST_STMT_CONTINUE: case SCC_AST_STMT_CONTINUE: {
if (scc_vec_size(sema_ctx->continue_stack) == 0) if (scc_vec_size(sema_ctx->continue_stack) == 0)
SCC_ERROR(stmt->base.loc, "continue not in loop"); SCC_ERROR(stmt->base.loc, "continue not in loop");
else else
stmt->jump._target = stmt->jump._target =
scc_vec_at(sema_ctx->continue_stack, scc_vec_at(sema_ctx->continue_stack,
scc_vec_size(sema_ctx->continue_stack) - 1); scc_vec_size(sema_ctx->continue_stack) - 1);
case SCC_AST_STMT_GOTO: } break;
scc_ast_node_t *target_node = case SCC_AST_STMT_GOTO: {
scc_sema_symtab_lookup_symbol(sema_symtab, stmt->goto_stmt.label); scc_ast_stmt_t *goto_stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node);
if (target_node == nullptr) { scc_sema_label_scope_t *scope = &sema_ctx->label_scope;
SCC_ERROR(stmt->base.loc, ""); if (scope->function_scope_depth != 1) {
SCC_ERROR(goto_stmt->base.loc, "goto not inside any function");
break; 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; break;
} }
stmt->goto_stmt._target = SCC_AST_CAST_TO(scc_ast_stmt_t, target_node);
break; // 检查重复定义
case SCC_AST_STMT_LABEL: if (scc_hashtable_get(&scope->labels, label_stmt->label_stmt.label)) {
scc_sema_symtab_add_symbol(sema_symtab, stmt->label_stmt.label, SCC_ERROR(label_stmt->base.loc, "duplicate label '%s'",
&stmt->base); label_stmt->label_stmt.label);
break; 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: default:
break; break;
} }
@@ -175,10 +210,37 @@ static void decl_callback(scc_sema_ctx_t *sema_ctx,
scc_sema_symtab_t *sema_symtab = sema_ctx->context; scc_sema_symtab_t *sema_symtab = sema_ctx->context;
// Function declaration scope // Function declaration scope
// FIXME 使用 node_type 区分其他未来的scope
if (node_type == scc_ast_decl_t_BEGIN) { 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); scc_sema_symtab_enter_scope(sema_symtab);
return; return;
} else if (node_type == scc_ast_decl_t_END) { } 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); scc_sema_symtab_leave_scope(sema_symtab);
return; 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_stmt = stmt_callback;
sema_ctx->on_type = type_callback; sema_ctx->on_type = type_callback;
sema_ctx->got_type = got_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); scc_sema_symtab_init(sema_symtab);

View File

@@ -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++) { for (int i = 1; i < len - 1; i++) {
scc_str_append_ch(&fname, includename[i]); scc_str_append_ch(&fname, includename[i]);
} }
scc_str_drop(&line);
int is_system = includename[0] == '<'; int is_system = includename[0] == '<';
if (switch_file_stack(pp, &fname, &pos, is_system)) { if (switch_file_stack(pp, &fname, &pos, is_system)) {
// LOG_ERROR() // LOG_ERROR()
} }
scc_str_drop(&line);
scc_str_drop(&fname); scc_str_drop(&fname);
return; return;
ERROR: ERROR:

View File

@@ -4,7 +4,7 @@
* @brief Arbitrary Precision Library * @brief Arbitrary Precision Library
* *
*/ */
#ifdef __AP_SCC__ #ifdef __SCC__
#include <scc_core.h> #include <scc_core.h>
#define SCC_AP_DIGIT u64 #define SCC_AP_DIGIT u64
#define SCC_AP_PANIC Panic #define SCC_AP_PANIC Panic

View File

@@ -21,7 +21,7 @@
#define __scc_log_unreachable() (__builtin_unreachable()) #define __scc_log_unreachable() (__builtin_unreachable())
#elif defined _MSC_VER // MSVC #elif defined _MSC_VER // MSVC
#define __scc_log_unreachable() (__assume(false)) #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()) #define __scc_log_unreachable() (__scc_builtin_unreachable())
#else #else
#define __scc_log_unreachable() ((void)0) #define __scc_log_unreachable() ((void)0)
@@ -184,7 +184,7 @@ void log_set_handler(logger_t *logger, log_handler handler);
* 或使用 _Static_assert (C11) * 或使用 _Static_assert (C11)
*/ */
#if __STDC_VERSION__ >= 201112L #if __STDC_VERSION__ >= 201112L
#define StaticAssert static_assert #define StaticAssert _Static_assert
#else #else
#define StaticAssert(cond, msg) extern char __static_assertion[(cond) ? 1 : -1] #define StaticAssert(cond, msg) extern char __static_assertion[(cond) ? 1 : -1]
#endif #endif

View File

@@ -13,4 +13,14 @@
#define scc_min(a, b) ((a) < (b) ? (a) : (b)) #define scc_min(a, b) ((a) < (b) ? (a) : (b))
#define scc_max(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__ #endif // __SCC_CORE_MACRO_H__

View File

@@ -15,13 +15,16 @@
#include "scc_core_type.h" #include "scc_core_type.h"
#define __scc_vec_realloc scc_realloc #define __scc_vec_realloc scc_realloc
#define __scc_vec_free scc_free #define __scc_vec_free scc_free
#define __scc_vec_memcpy scc_memcpy
#else #else
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
typedef size_t usize; typedef size_t usize;
#define __scc_vec_realloc realloc #define __scc_vec_realloc realloc
#define __scc_vec_free free #define __scc_vec_free free
#define __scc_vec_memcpy memcpy
#ifndef LOG_FATAL #ifndef LOG_FATAL
#include <stdio.h> #include <stdio.h>
@@ -169,4 +172,86 @@ typedef size_t usize;
(vec).data = array; \ (vec).data = array; \
} while (0) } 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__ */ #endif /* __SCC_CORE_VEC_H__ */

View File

@@ -39,8 +39,15 @@ usize scc_fread(scc_file_t file, void *buffer, usize size) {
return scc_pal_fread(file, buffer, size); return scc_pal_fread(file, buffer, size);
} }
usize scc_fwrite(scc_file_t file, const void *buffer, usize size) { usize scc_fwrite(scc_file_t file, const void *buf, usize size) {
return scc_pal_fwrite(file, buffer, 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) { cbool scc_fexists(const char *path) {

View File

@@ -155,7 +155,6 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
static const char *emit_stages[] = { static const char *emit_stages[] = {
[SCC_EMIT_STAGE_LEX] = "lex", [SCC_EMIT_STAGE_LEX] = "lex",
[SCC_EMIT_STAGE_PP] = "pp", [SCC_EMIT_STAGE_PP] = "pp",
[SCC_EMIT_STAGE_AST] = "ast", // -T [SCC_EMIT_STAGE_AST] = "ast", // -T
[SCC_EMIT_STAGE_HIR] = "hir", // -H [SCC_EMIT_STAGE_HIR] = "hir", // -H
[SCC_EMIT_STAGE_LIR] = "lir", // -L [SCC_EMIT_STAGE_LIR] = "lir", // -L