From 88846d747964182a6cb645b6d2faaf825e13eb4e Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Fri, 5 Jun 2026 13:07:41 +0800 Subject: [PATCH] =?UTF-8?q?refactor(log):=20=E7=BB=9F=E4=B8=80=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E7=B3=BB=E7=BB=9F=E5=B9=B6=E6=B7=BB=E5=8A=A0=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E5=99=A8=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为所有模块添加统一的 scc_*_log.h 日志头文件,删除旧的 lexer_log.h/c - 将运行时日志从 scc_utils 迁移到 scc_core 目录,统一日志管理 - 在解析器表达式/语句/类型解析中添加 LOG_TRACE 调试日志 - 实现 SCCF 链接器 (sccf_linker) 支持多目标文件链接 - 重构 CLI 主程序 (main.c/config.c),新增 cmd_log.h 调试支持 - 优化 x86 指令编码操作数对齐检查 - 修复预处理器的指令处理和宏展开逻辑 --- libs/ast2ir/include/scc_ast2ir_log.h | 26 + libs/ast2ir/src/scc_ast2ir.c | 7 + libs/ast2ir/src/scc_ast2ir_expr.c | 17 +- libs/ir/hir/include/scc_hir_log.h | 26 + libs/ir/hir/src/scc_hir.c | 3 + libs/ir/hir/src/scc_hir_builder.c | 2 + libs/ir/hir/src/scc_hir_dump.c | 2 + libs/ir/lir/include/scc_lir_log.h | 26 + libs/ir/lir/src/scc_hir2lir.c | 7 + libs/ir/lir/src/scc_lir.c | 2 + libs/ir/lir/src/scc_lir_module.c | 5 +- libs/ir/mir/include/scc_mir_log.h | 26 + libs/ir/mir/src/arch/scc_x86_mir.c | 2 + libs/ir/mir/src/scc_lir2mir.c | 5 + libs/ir/mir/src/scc_mir.c | 3 + libs/ir/mir/src/scc_mir_pass.c | 17 + libs/ir2mcode/include/scc_ir2mcode_log.h | 26 + libs/ir2mcode/src/scc_ir2mcode.c | 6 + libs/ir2mcode/src/scc_ir2sccf.c | 11 +- libs/lexer/include/lexer_log.h | 48 -- libs/lexer/include/scc_lexer_log.h | 26 + libs/lexer/src/lexer.c | 12 +- libs/lexer/src/lexer_log.c | 7 - libs/lexer/src/main.c | 14 +- libs/mcode/include/scc_mcode.h | 8 +- libs/mcode/include/scc_mcode_log.h | 26 + libs/mcode/src/scc_mcode.c | 2 + libs/mcode/src/scc_x86_encode.c | 31 +- libs/parser/include/parser_utils.h | 1 - libs/parser/include/scc_parser_log.h | 26 + libs/parser/src/parse_decl.c | 16 +- libs/parser/src/parse_expr.c | 30 + libs/parser/src/parse_stmt.c | 41 +- libs/parser/src/parse_type.c | 36 +- libs/parser/src/scc_parser.c | 6 + libs/parser/src/scc_sema.c | 8 +- libs/parser/src/sema_symtab.c | 7 + libs/pproc/include/scc_pproc_log.h | 26 + libs/pproc/src/pproc_directive.c | 26 +- libs/pproc/src/pproc_expand.c | 17 +- libs/pproc/src/pproc_if.c | 2 + libs/pproc/src/pproc_include.c | 5 +- libs/pproc/src/pproc_macro.c | 2 + libs/pproc/src/scc_pproc.c | 3 + libs/pproc/tests/test_pproc_unit.c | 5 + libs/sccf/cbuild.toml | 1 + libs/sccf/include/sccf_linker.h | 6 + libs/sccf/include/sccf_log.h | 26 + libs/sccf/src/sccf_builder.c | 1 + libs/sccf/src/sccf_linker.c | 259 ++++++++ libs/sccf/src/sccf_log.c | 2 + libs/sstream/include/scc_sstream.h | 3 +- libs/sstream/include/scc_sstream_log.h | 26 + libs/sstream/src/scc_sstream.c | 5 +- libs/target/pe/include/scc_pe_log.h | 26 + libs/target/pe/src/scc_pe_builder.c | 8 +- libs/target/pe/src/scc_pe_idata.c | 2 + libs/target/sccf2target/src/sccf2pe.c | 1 + runtime/log/include/log.c | 5 +- runtime/log/include/log.h | 26 +- runtime/scc_core/include/scc_core_log.h | 2 +- runtime/scc_core/include/scc_log.h | 35 ++ .../scc_pos_log.c => scc_core/src/scc_log.c} | 39 +- runtime/scc_utils/include/scc_pos_log.h | 31 - runtime/scc_utils/src/hashtable.c | 7 +- src/bin/sccfdump.c | 205 ++++--- src/cmd_log.h | 25 + src/config.c | 14 +- src/config.h | 3 +- src/main.c | 558 ++++++++++++------ 70 files changed, 1497 insertions(+), 469 deletions(-) create mode 100644 libs/ast2ir/include/scc_ast2ir_log.h create mode 100644 libs/ir/hir/include/scc_hir_log.h create mode 100644 libs/ir/lir/include/scc_lir_log.h create mode 100644 libs/ir/lir/src/scc_lir.c create mode 100644 libs/ir/mir/include/scc_mir_log.h create mode 100644 libs/ir2mcode/include/scc_ir2mcode_log.h delete mode 100644 libs/lexer/include/lexer_log.h create mode 100644 libs/lexer/include/scc_lexer_log.h delete mode 100644 libs/lexer/src/lexer_log.c create mode 100644 libs/mcode/include/scc_mcode_log.h create mode 100644 libs/mcode/src/scc_mcode.c create mode 100644 libs/parser/include/scc_parser_log.h create mode 100644 libs/pproc/include/scc_pproc_log.h create mode 100644 libs/sccf/include/sccf_log.h create mode 100644 libs/sccf/src/sccf_linker.c create mode 100644 libs/sccf/src/sccf_log.c create mode 100644 libs/sstream/include/scc_sstream_log.h create mode 100644 libs/target/pe/include/scc_pe_log.h create mode 100644 runtime/scc_core/include/scc_log.h rename runtime/{scc_utils/src/scc_pos_log.c => scc_core/src/scc_log.c} (50%) delete mode 100644 runtime/scc_utils/include/scc_pos_log.h create mode 100644 src/cmd_log.h diff --git a/libs/ast2ir/include/scc_ast2ir_log.h b/libs/ast2ir/include/scc_ast2ir_log.h new file mode 100644 index 0000000..7315b07 --- /dev/null +++ b/libs/ast2ir/include/scc_ast2ir_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_AST2IR_LOG_H__ +#define __SCC_AST2IR_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_ast2ir_log; +extern logger_t __scc_ast2ir_user; + +#define SCC_LOG_HANDLER &__scc_ast2ir_user +#define LOG_DEFAULT_HANDLER &__scc_ast2ir_log +#include + +#ifdef __SCC_AST2IR_LOG_IMPL__ +logger_t __scc_ast2ir_log = { + .name = "ast2ir", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_ast2ir_user = { + .name = "ast2ir", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/libs/ast2ir/src/scc_ast2ir.c b/libs/ast2ir/src/scc_ast2ir.c index 0108964..6600495 100644 --- a/libs/ast2ir/src/scc_ast2ir.c +++ b/libs/ast2ir/src/scc_ast2ir.c @@ -1,3 +1,6 @@ +#define __SCC_AST2IR_LOG_IMPL__ +#include + #include #include #include @@ -192,6 +195,7 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) { return; } + LOG_DEBUG("stmt type=%d", stmt->base.type); switch (stmt->base.type) { case SCC_AST_STMT_COMPOUND: { scc_vec_foreach(stmt->compound.block_items, i) { @@ -542,6 +546,7 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl, break; } case SCC_AST_DECL_FUNC: { + LOG_DEBUG("function '%s'", decl->name); scc_hir_type_ref_t func_type_ref = scc_ast2ir_type(ctx, decl->func.type); scc_hir_func_ref_t func_ref = @@ -674,6 +679,8 @@ void scc_ast2ir_run(scc_ast2ir_ctx_t *ctx, const scc_ast_translation_unit_t *tu) { Assert(ctx != nullptr && tu != nullptr); + LOG_INFO("translating %zu declaration(s) to HIR", + scc_vec_size(tu->declarations)); scc_vec_foreach(tu->declarations, i) { scc_ast_decl_t *decl = scc_vec_at(tu->declarations, i); scc_ast2ir_decl(ctx, decl, true); diff --git a/libs/ast2ir/src/scc_ast2ir_expr.c b/libs/ast2ir/src/scc_ast2ir_expr.c index 5c3330f..7df1969 100644 --- a/libs/ast2ir/src/scc_ast2ir_expr.c +++ b/libs/ast2ir/src/scc_ast2ir_expr.c @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -158,9 +160,11 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, return 0; } + LOG_DEBUG("expr type=%d is_lvalue=%d", expr->base.type, (int)is_lvalue); cbool is_assign = true; switch (expr->base.type) { case SCC_AST_EXPR_BINARY: { + LOG_DEBUG(" binary op=%d", expr->binary.op); scc_ast_expr_t tmp_expr; scc_hir_value_ref_t lhs = SCC_HIR_REF_nullptr, rhs = SCC_HIR_REF_nullptr; @@ -365,6 +369,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: { + LOG_DEBUG(" unary op=%d", expr->unary.op); if (expr->unary.op == SCC_AST_OP_ADDRESS_OF) { return scc_ast2ir_expr(ctx, expr->unary.operand, true); } else if (expr->unary.op == SCC_AST_OP_INDIRECTION) { @@ -508,6 +513,7 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, UNREACHABLE(); } break; case SCC_AST_EXPR_COND: { + LOG_DEBUG(" ternary conditional"); scc_hir_type_ref_t true_type = SCC_HIR_REF_nullptr; scc_hir_type_ref_t false_type = SCC_HIR_REF_nullptr; @@ -559,7 +565,10 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, return scc_hir_builder_load(&ctx->builder, result_slot); } break; case SCC_AST_EXPR_CALL: { - // 转换参数 + LOG_DEBUG(" call '%s'", + expr->call.callee->identifier._target + ? expr->call.callee->identifier._target->name + : "?"); scc_hir_value_ref_vec_t args; scc_vec_init(args); @@ -640,7 +649,7 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, return node; } case SCC_AST_EXPR_ARRAY_SUBSCRIPT: { - // 1. 计算数组/指针基址(右值,得到地址) + LOG_DEBUG(" array subscript"); scc_hir_value_ref_t base_ptr = scc_ast2ir_expr(ctx, expr->subscript.array, true); // 2. 计算下标值 @@ -670,7 +679,7 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, } } case SCC_AST_EXPR_MEMBER: { - // 1. 获取基对象的左值(地址) + LOG_DEBUG(" member access field_idx=%zu", expr->member._target_idx); scc_hir_value_ref_t base_ptr = scc_ast2ir_expr(ctx, expr->member.base, true); // 2. 通过偏移生成字段地址 @@ -688,7 +697,7 @@ 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_PTR_MEMBER: { - // 1. 计算指针值(obj->field 等价于 (*obj).field) + LOG_DEBUG(" ptr member access"); scc_hir_value_ref_t obj_ptr = scc_ast2ir_expr(ctx, expr->member.base, false); // 2. 解引用得到对象地址,再访问成员 diff --git a/libs/ir/hir/include/scc_hir_log.h b/libs/ir/hir/include/scc_hir_log.h new file mode 100644 index 0000000..a98e0b7 --- /dev/null +++ b/libs/ir/hir/include/scc_hir_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_HIR_LOG_H__ +#define __SCC_HIR_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_hir_log; +extern logger_t __scc_hir_user; + +#define SCC_LOG_HANDLER &__scc_hir_user +#define LOG_DEFAULT_HANDLER &__scc_hir_log +#include + +#ifdef __SCC_HIR_LOG_IMPL__ +logger_t __scc_hir_log = { + .name = "hir", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_hir_user = { + .name = "hir", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/libs/ir/hir/src/scc_hir.c b/libs/ir/hir/src/scc_hir.c index 51d5ff2..35be9b0 100644 --- a/libs/ir/hir/src/scc_hir.c +++ b/libs/ir/hir/src/scc_hir.c @@ -1,3 +1,6 @@ +#define __SCC_HIR_LOG_IMPL__ +#include + #include void scc_hir_type_init(scc_hir_type_t *in, scc_hir_type_tag_t tag) { diff --git a/libs/ir/hir/src/scc_hir_builder.c b/libs/ir/hir/src/scc_hir_builder.c index d65e33b..5183fb9 100644 --- a/libs/ir/hir/src/scc_hir_builder.c +++ b/libs/ir/hir/src/scc_hir_builder.c @@ -1,3 +1,5 @@ +#include + #include #include #include diff --git a/libs/ir/hir/src/scc_hir_dump.c b/libs/ir/hir/src/scc_hir_dump.c index 3780c06..dd104fe 100644 --- a/libs/ir/hir/src/scc_hir_dump.c +++ b/libs/ir/hir/src/scc_hir_dump.c @@ -1,3 +1,5 @@ +#include + #include #include #include diff --git a/libs/ir/lir/include/scc_lir_log.h b/libs/ir/lir/include/scc_lir_log.h new file mode 100644 index 0000000..220fc72 --- /dev/null +++ b/libs/ir/lir/include/scc_lir_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_LIR_LOG_H__ +#define __SCC_LIR_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_lir_log; +extern logger_t __scc_lir_user; + +#define SCC_LOG_HANDLER &__scc_lir_user +#define LOG_DEFAULT_HANDLER &__scc_lir_log +#include + +#ifdef __SCC_LIR_LOG_IMPL__ +logger_t __scc_lir_log = { + .name = "lir", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_lir_user = { + .name = "lir", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/libs/ir/lir/src/scc_hir2lir.c b/libs/ir/lir/src/scc_hir2lir.c index c198eed..9837664 100644 --- a/libs/ir/lir/src/scc_hir2lir.c +++ b/libs/ir/lir/src/scc_hir2lir.c @@ -2,6 +2,7 @@ * @file scc_hir2lir.c * @brief 将高级 IR (scc_ir) 降级为低层 LIR (scc_lir) */ +#include #include #include @@ -323,6 +324,7 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, if (scc_hashtable_get(&ctx->value_to_vreg, (void *)(uintptr_t)value_ref)) return; + LOG_TRACE("translate val_ref=%zu tag=%d", (size_t)value_ref, value->tag); u8 size_bits = 0; scc_lir_ext_t ext = SCC_LIR_EXT_NONE; ir_type_to_lir_size_ext(ctx->hir_module, value->type, &size_bits, &ext); @@ -643,6 +645,9 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value, static void translate_func(ir2lir_ctx_t *ctx, scc_hir_func_t *ir_func) { scc_hir_func_meta_t *func_meta = SCC_HIR_FUNC_META(ir_func); + LOG_DEBUG("translate func '%s' (%zu bblocks)", + ir_func->name ? ir_func->name : "?", + scc_vec_size(ir_func->bblocks)); scc_lir_func_meta_t *lir_func_meta = scc_malloc(sizeof(scc_lir_func_meta_t)); @@ -689,6 +694,8 @@ static void translate_func(ir2lir_ctx_t *ctx, scc_hir_func_t *ir_func) { } void scc_hir2lir(scc_lir_module_t *module, scc_hir_cprog_t *cprog) { + LOG_INFO("HIR -> LIR lowering start (%zu funcs)", + scc_vec_size(cprog->func_defs)); Assert(module != nullptr && cprog != nullptr); // FIXME diff --git a/libs/ir/lir/src/scc_lir.c b/libs/ir/lir/src/scc_lir.c new file mode 100644 index 0000000..61030f2 --- /dev/null +++ b/libs/ir/lir/src/scc_lir.c @@ -0,0 +1,2 @@ +#define __SCC_LIR_LOG_IMPL__ +#include diff --git a/libs/ir/lir/src/scc_lir_module.c b/libs/ir/lir/src/scc_lir_module.c index 484d820..d218df6 100644 --- a/libs/ir/lir/src/scc_lir_module.c +++ b/libs/ir/lir/src/scc_lir_module.c @@ -1,3 +1,5 @@ +#include + #include void scc_lir_module_init(scc_lir_module_t *lir_module) { @@ -13,7 +15,8 @@ void scc_lir_module_drop(scc_lir_module_t *lir_module) { scc_lir_symbol_meta_t *meta = lir_module->symbol_metas.data[i]; usize cfg_idx = i + 1; /* cfg_module.symbols[0] is null sentinel */ if (cfg_idx < scc_vec_size(lir_module->cfg_module.symbols)) { - scc_cfg_symbol_t *sym = &lir_module->cfg_module.symbols.data[cfg_idx]; + scc_cfg_symbol_t *sym = + &lir_module->cfg_module.symbols.data[cfg_idx]; if (sym->kind == SCC_CFG_SYMBOL_KIND_DATA && meta->data.init_data) { scc_free(meta->data.init_data); } diff --git a/libs/ir/mir/include/scc_mir_log.h b/libs/ir/mir/include/scc_mir_log.h new file mode 100644 index 0000000..c1f4bb3 --- /dev/null +++ b/libs/ir/mir/include/scc_mir_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_MIR_LOG_H__ +#define __SCC_MIR_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_mir_log; +extern logger_t __scc_mir_user; + +#define SCC_LOG_HANDLER &__scc_mir_user +#define LOG_DEFAULT_HANDLER &__scc_mir_log +#include + +#ifdef __SCC_MIR_LOG_IMPL__ +logger_t __scc_mir_log = { + .name = "mir", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_mir_user = { + .name = "mir", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/libs/ir/mir/src/arch/scc_x86_mir.c b/libs/ir/mir/src/arch/scc_x86_mir.c index 608b341..3a41475 100644 --- a/libs/ir/mir/src/arch/scc_x86_mir.c +++ b/libs/ir/mir/src/arch/scc_x86_mir.c @@ -1,3 +1,5 @@ +#include + #include static inline scc_x86_iform_t diff --git a/libs/ir/mir/src/scc_lir2mir.c b/libs/ir/mir/src/scc_lir2mir.c index 9a13209..d375aa5 100644 --- a/libs/ir/mir/src/scc_lir2mir.c +++ b/libs/ir/mir/src/scc_lir2mir.c @@ -1,9 +1,14 @@ +#include + #include #include +#include #include void scc_lir2mir(scc_mir_module_t *mir_module, const scc_lir_module_t *lir_module) { + LOG_INFO("LIR -> MIR conversion (%zu funcs)", + scc_vec_size(lir_module->cfg_module.funcs)); // Move mir_module->cfg_module = lir_module->cfg_module; diff --git a/libs/ir/mir/src/scc_mir.c b/libs/ir/mir/src/scc_mir.c index eeee1d7..509aa5a 100644 --- a/libs/ir/mir/src/scc_mir.c +++ b/libs/ir/mir/src/scc_mir.c @@ -1,3 +1,6 @@ +#define __SCC_MIR_LOG_IMPL__ +#include + #include void scc_mir_func_meta_init(scc_mir_func_meta_t *func_meta) { diff --git a/libs/ir/mir/src/scc_mir_pass.c b/libs/ir/mir/src/scc_mir_pass.c index b62897b..c41308f 100644 --- a/libs/ir/mir/src/scc_mir_pass.c +++ b/libs/ir/mir/src/scc_mir_pass.c @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -11,17 +13,23 @@ void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) { Assert(ctx && ctx->impl_fn && module); + LOG_DEBUG(" frame layout for %zu funcs", + scc_vec_size(module->cfg_module.funcs)); scc_vec_foreach(module->cfg_module.funcs, i) { if (i == 0) continue; scc_mir_func_t *func = &scc_vec_at(module->cfg_module.funcs, i); ctx->offset = SCC_MIR_FUNC_META(func)->frame_size; + LOG_TRACE(" func[%zu] frame_size=%zu", (size_t)i, + (size_t)ctx->offset); ctx->impl_fn(ctx, module, func); } } void scc_prolog_epilog(scc_prolog_epilog_t *ctx, scc_mir_module_t *module) { Assert(ctx && ctx->epilog && ctx->prolog && module); + LOG_DEBUG(" prolog/epilog for %zu funcs", + scc_vec_size(module->cfg_module.funcs)); scc_vec_foreach(module->cfg_module.funcs, i) { if (i == 0) continue; @@ -58,29 +66,38 @@ void scc_prolog_epilog(scc_prolog_epilog_t *ctx, scc_mir_module_t *module) { } void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage) { + LOG_INFO("running MIR passes (stage=%d, %zu funcs)", (int)stage, + scc_vec_size(mir_module->cfg_module.funcs)); + + LOG_DEBUG(" pass 1/3: register allocation"); scc_reg_alloc_ctx_t reg_alloc_ctx = {.func = nullptr, .ops = {0}}; scc_reg_alloc_fill_arch_x86(®_alloc_ctx.ops); scc_win_pc_x64_reg_alloc_fill(®_alloc_ctx.ops); scc_reg_alloc(®_alloc_ctx, mir_module); if (stage == SCC_MIR_STAGE_REGALLOC) { + LOG_DEBUG(" stop after regalloc"); return; } void scc_x86_peephole_optimize(scc_mir_module_t * module); // scc_x86_peephole_optimize(mir_module); + LOG_DEBUG(" pass 2/3: frame layout"); scc_frame_layout_t frame_layout_ctx = {0}; scc_win_pc_x64_frame_layout_init(&frame_layout_ctx); scc_frame_layout(&frame_layout_ctx, mir_module); if (stage == SCC_MIR_STAGE_FRAME_LAYOUT) { + LOG_DEBUG(" stop after frame layout"); return; } + LOG_DEBUG(" pass 3/3: prolog/epilog"); scc_prolog_epilog_t prolog_epilog_ctx = {0}; scc_win_pc_x64_prolog_epilog_init(&prolog_epilog_ctx); scc_prolog_epilog(&prolog_epilog_ctx, mir_module); if (stage == SCC_MIR_STAGE_PROLOGUE_EPILOGUE) { + LOG_DEBUG(" stop after prolog/epilog"); return; } } diff --git a/libs/ir2mcode/include/scc_ir2mcode_log.h b/libs/ir2mcode/include/scc_ir2mcode_log.h new file mode 100644 index 0000000..e6292cb --- /dev/null +++ b/libs/ir2mcode/include/scc_ir2mcode_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_IR2MCODE_LOG_H__ +#define __SCC_IR2MCODE_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_ir2mcode_log; +extern logger_t __scc_ir2mcode_user; + +#define SCC_LOG_HANDLER &__scc_ir2mcode_user +#define LOG_DEFAULT_HANDLER &__scc_ir2mcode_log +#include + +#ifdef __SCC_IR2MCODE_LOG_IMPL__ +logger_t __scc_ir2mcode_log = { + .name = "ir2mcode", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_ir2mcode_user = { + .name = "ir2mcode", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/libs/ir2mcode/src/scc_ir2mcode.c b/libs/ir2mcode/src/scc_ir2mcode.c index 6e5e2c8..a10e2be 100644 --- a/libs/ir2mcode/src/scc_ir2mcode.c +++ b/libs/ir2mcode/src/scc_ir2mcode.c @@ -1,3 +1,6 @@ +#define __SCC_IR2MCODE_LOG_IMPL__ +#include + #include #include #include @@ -117,10 +120,13 @@ void scc_ir2mcode_patch(scc_mcode_t *mcode, scc_reloc_t *reloc, i64 value) { void scc_ir2mcode(scc_mcode_t *mcode, scc_reloc_vec_t *relocs, const scc_mir_module_t *mir_module) { Assert(mir_module != nullptr && mcode != nullptr); + LOG_INFO("MIR -> machine code (%zu funcs)", + scc_vec_size(mir_module->cfg_module.funcs)); scc_vec_foreach(mir_module->cfg_module.funcs, i) { if (i == 0) continue; scc_mir_func_t *func = &scc_vec_at(mir_module->cfg_module.funcs, i); + LOG_DEBUG(" func[%zu]: %s", (size_t)i, func->name ? func->name : "?"); scc_vec_foreach(func->bblocks, i) { scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i); const scc_cfg_bblock_t *bb = diff --git a/libs/ir2mcode/src/scc_ir2sccf.c b/libs/ir2mcode/src/scc_ir2sccf.c index 3d19bef..b7bc66a 100644 --- a/libs/ir2mcode/src/scc_ir2sccf.c +++ b/libs/ir2mcode/src/scc_ir2sccf.c @@ -1,3 +1,5 @@ +#include + #include static inline void scc_ir_sym_to_sccf_sym(const scc_cfg_symbol_t *symbol, @@ -47,6 +49,8 @@ static inline void scc_ir_symbol_to_sect_data(const scc_cfg_symbol_t *symbol, static void emit_mir_module(sccf_builder_t *builder, scc_mcode_t *mcode, scc_mir_module_t *mir_module) { + LOG_DEBUG("emit MIR to SCCF (%zu funcs)", + scc_vec_size(mir_module->cfg_module.funcs)); scc_hashtable_t bblock_offset; @@ -54,6 +58,8 @@ static void emit_mir_module(sccf_builder_t *builder, scc_mcode_t *mcode, if (i == 0) continue; scc_mir_func_t *func = &scc_vec_at(mir_module->cfg_module.funcs, i); + LOG_DEBUG(" emit func[%zu] '%s'", (size_t)i, + func->name ? func->name : "?"); sccf_sym_t *sym = sccf_builder_get_symbol_unsafe(builder, func->name); Assert(sym != nullptr); @@ -111,8 +117,9 @@ static void emit_mir_module(sccf_builder_t *builder, scc_mcode_t *mcode, } void scc_ir2sccf(sccf_builder_t *builder, scc_mir_module_t *mir_module) { - // mir_module->symbol_metas - // mir_module->cfg_module.funcs + LOG_INFO("MIR -> SCCF conversion (%zu symbols, %zu funcs)", + scc_vec_size(mir_module->cfg_module.symbols), + scc_vec_size(mir_module->cfg_module.funcs)); sccf_builder_init(builder); sccf_sect_data_t sect_data; scc_vec_init(sect_data); diff --git a/libs/lexer/include/lexer_log.h b/libs/lexer/include/lexer_log.h deleted file mode 100644 index 1cf23a0..0000000 --- a/libs/lexer/include/lexer_log.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __SCC_LEXER_LOG_H__ -#define __SCC_LEXER_LOG_H__ - -#include - -#ifndef LEX_LOG_LEVEL -#define LEX_LOG_LEVEL 4 -#endif - -#if LEX_LOG_LEVEL <= 1 -#define LEX_NOTSET(fmt, ...) MLOG_NOTSET(&__scc_lexer_log, fmt, ##__VA_ARGS__) -#else -#define LEX_NOTSET(fmt, ...) -#endif - -#if LEX_LOG_LEVEL <= 2 -#define LEX_DEBUG(fmt, ...) MLOG_DEBUG(&__scc_lexer_log, fmt, ##__VA_ARGS__) -#else -#define LEX_DEBUG(fmt, ...) -#endif - -#if LEX_LOG_LEVEL <= 3 -#define LEX_INFO(fmt, ...) MLOG_INFO(&__scc_lexer_log, fmt, ##__VA_ARGS__) -#else -#define LEX_INFO(fmt, ...) -#endif - -#if LEX_LOG_LEVEL <= 4 -#define LEX_WARN(fmt, ...) MLOG_WARN(&__scc_lexer_log, fmt, ##__VA_ARGS__) -#else -#define LEX_WARN(fmt, ...) -#endif - -#if LEX_LOG_LEVEL <= 5 -#define LEX_ERROR(fmt, ...) MLOG_ERROR(&__scc_lexer_log, fmt, ##__VA_ARGS__) -#else -#define LEX_ERROR(fmt, ...) -#endif - -#if LEX_LOG_LEVEL <= 6 -#define LEX_FATAL(fmt, ...) MLOG_FATAL(&__scc_lexer_log, fmt, ##__VA_ARGS__) -#else -#define LEX_FATAL(fmt, ...) -#endif - -extern logger_t __scc_lexer_log; - -#endif /* __SCC_LEXER_LOG_H__ */ diff --git a/libs/lexer/include/scc_lexer_log.h b/libs/lexer/include/scc_lexer_log.h new file mode 100644 index 0000000..8eaec41 --- /dev/null +++ b/libs/lexer/include/scc_lexer_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_LEXER_LOG_H__ +#define __SCC_LEXER_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_lexer_log; +extern logger_t __scc_lexer_user; + +#define SCC_LOG_HANDLER &__scc_lexer_user +#define LOG_DEFAULT_HANDLER &__scc_lexer_log +#include + +#ifdef __SCC_LEXER_LOG_IMPL__ +logger_t __scc_lexer_log = { + .name = "lexer", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_lexer_user = { + .name = "lexer", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif /* __SCC_LEXER_LOG_H__ */ diff --git a/libs/lexer/src/lexer.c b/libs/lexer/src/lexer.c index ab62c58..a1b1a75 100644 --- a/libs/lexer/src/lexer.c +++ b/libs/lexer/src/lexer.c @@ -1,4 +1,6 @@ -#include +#define __SCC_LEXER_LOG_IMPL__ +#include + #include static const struct { @@ -153,7 +155,7 @@ void scc_lexer_get_token(scc_lexer_t *lexer, scc_lexer_tok_t *token) { while (1) { if (!next_char(lexer, &lex, &cur)) { // 文件结束,注释未闭合 - LOG_ERROR("Unterminated block comment"); + SCC_ERROR(start_loc, "unterminated block comment"); break; } if (cur.character == '*' && peek_char(lexer, &next) && @@ -234,7 +236,7 @@ void scc_lexer_get_token(scc_lexer_t *lexer, scc_lexer_tok_t *token) { next_char(lexer, &lex, &cur); // 开头的 ' while (1) { if (!peek_char(lexer, &cur)) { - LOG_ERROR("Unterminated character literal"); + SCC_ERROR(start_loc, "unterminated character literal"); break; } if (cur.character == '\'') { @@ -257,7 +259,7 @@ void scc_lexer_get_token(scc_lexer_t *lexer, scc_lexer_tok_t *token) { next_char(lexer, &lex, &cur); // 开头的 " while (1) { if (!peek_char(lexer, &cur)) { - LOG_ERROR("Unterminated string literal"); + SCC_ERROR(start_loc, "unterminated string literal"); break; } if (cur.character == '"') { @@ -487,7 +489,7 @@ void scc_lexer_get_token(scc_lexer_t *lexer, scc_lexer_tok_t *token) { token->type = token->type; // 上面已设 token->loc = start_loc; token->lexeme = lex; // 转移所有权 - LEX_DEBUG("get token `%s` (%s) at %s:%d:%d", scc_get_tok_name(token->type), + LOG_DEBUG("get token `%s` (%s) at %s:%d:%d", scc_get_tok_name(token->type), scc_str_as_cstr(&token->lexeme), token->loc.name, token->loc.line, token->loc.col); } diff --git a/libs/lexer/src/lexer_log.c b/libs/lexer/src/lexer_log.c deleted file mode 100644 index c6cff2d..0000000 --- a/libs/lexer/src/lexer_log.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -logger_t __scc_lexer_log = { - .name = "lexer", - .level = LOG_LEVEL_ALL, - .handler = log_default_handler, -}; diff --git a/libs/lexer/src/main.c b/libs/lexer/src/main.c index f45c6d7..ad1953c 100644 --- a/libs/lexer/src/main.c +++ b/libs/lexer/src/main.c @@ -1,3 +1,4 @@ +#define LEX_LOG_LEVEL 1 #include #include #include @@ -24,12 +25,11 @@ int g_num_arr[3]; int main(int argc, char *argv[]) { // int num = 0; if (argc == 3 && strcmp(argv[2], "--debug") == 0) { - log_set_level(nullptr, LOG_LEVEL_ALL); + log_set_level(&__scc_lexer_log, LOG_LEVEL_ALL); } else { - // FIXME it is a hack lexer_logger - log_set_level(&__scc_lexer_log, LOG_LEVEL_NOTSET); - log_set_level(nullptr, LOG_LEVEL_INFO | LOG_LEVEL_WARN | - LOG_LEVEL_ERROR | LOG_LEVEL_FATAL); + log_set_level(&__scc_lexer_log, + LOG_LEVEL_INFO | LOG_LEVEL_WARN | LOG_LEVEL_ERROR | + LOG_LEVEL_FATAL); } const char *file_name = __FILE__; @@ -57,7 +57,7 @@ int main(int argc, char *argv[]) { break; } - LOG_INFO("get token [%-8s] `%s` at %s:%d:%d", + LEX_INFO("get token [%-8s] `%s` at %s:%d:%d", scc_get_tok_name(token.type), scc_str_as_cstr(&token.lexeme), token.loc.name, token.loc.line, token.loc.col); scc_str_drop(&token.lexeme); @@ -65,6 +65,6 @@ int main(int argc, char *argv[]) { scc_sstream_drop_ring(ref); scc_sstream_drop(&stream); - LOG_INFO("Lexer is Ok..."); + LEX_INFO("Lexer is Ok..."); return 0; } diff --git a/libs/mcode/include/scc_mcode.h b/libs/mcode/include/scc_mcode.h index 284e681..6199d52 100644 --- a/libs/mcode/include/scc_mcode.h +++ b/libs/mcode/include/scc_mcode.h @@ -43,14 +43,14 @@ static inline void scc_mcode_drop(scc_mcode_t *mcode) { * 避免拷贝大块代码数据。 */ static inline void scc_mcode_adopt_buf(scc_mcode_t *mcode, - scc_mcode_buff_t *buf) { + scc_mcode_buff_t *buf) { scc_vec_free(mcode->code); mcode->code.size = buf->size; mcode->code.cap = buf->cap; mcode->code.data = buf->data; buf->size = 0; buf->cap = 0; - buf->data = NULL; + buf->data = nullptr; } /** @@ -61,14 +61,14 @@ static inline void scc_mcode_adopt_buf(scc_mcode_t *mcode, * 避免拷贝大块代码数据。 */ static inline void scc_mcode_disown_buf(scc_mcode_t *mcode, - scc_mcode_buff_t *out) { + scc_mcode_buff_t *out) { scc_vec_free(*out); out->size = mcode->code.size; out->cap = mcode->code.cap; out->data = mcode->code.data; mcode->code.size = 0; mcode->code.cap = 0; - mcode->code.data = NULL; + mcode->code.data = nullptr; } static inline void scc_mcode_add_u8(scc_mcode_t *mcode, u8 data) { diff --git a/libs/mcode/include/scc_mcode_log.h b/libs/mcode/include/scc_mcode_log.h new file mode 100644 index 0000000..b6d7791 --- /dev/null +++ b/libs/mcode/include/scc_mcode_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_MCODE_LOG_H__ +#define __SCC_MCODE_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_mcode_log; +extern logger_t __scc_mcode_user; + +#define SCC_LOG_HANDLER &__scc_mcode_user +#define LOG_DEFAULT_HANDLER &__scc_mcode_log +#include + +#ifdef __SCC_MCODE_LOG_IMPL__ +logger_t __scc_mcode_log = { + .name = "mcode", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_mcode_user = { + .name = "mcode", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/libs/mcode/src/scc_mcode.c b/libs/mcode/src/scc_mcode.c new file mode 100644 index 0000000..3e31512 --- /dev/null +++ b/libs/mcode/src/scc_mcode.c @@ -0,0 +1,2 @@ +#define __SCC_MCODE_LOG_IMPL__ +#include diff --git a/libs/mcode/src/scc_x86_encode.c b/libs/mcode/src/scc_x86_encode.c index 018406f..c1e8c44 100644 --- a/libs/mcode/src/scc_x86_encode.c +++ b/libs/mcode/src/scc_x86_encode.c @@ -1,14 +1,9 @@ +#include + #include #include #include -#if 1 -#ifdef LOG_INFO -#undef LOG_INFO -#endif -#define LOG_INFO(...) -#endif - /* ---------- 内部辅助 ---------- */ static inline void emit_u8(scc_mcode_t *m, uint8_t v) { scc_mcode_add_u8(m, v); @@ -167,7 +162,7 @@ static void emit_rex(scc_mcode_t *m, const scc_x86_encoding_t *enc, if (b != SCC_X86_REG_INVALID && reg_rex_bit(b)) rex |= 1; if (rex != 0x40) { - LOG_INFO("[REX] emit 0x%02x", (uint8_t)rex); + LOG_TRACE("[REX] emit 0x%02x", (uint8_t)rex); emit_u8(m, (uint8_t)rex); } } @@ -249,7 +244,7 @@ static void emit_immediate(scc_mcode_t *m, const scc_x86_encoding_t *enc, else if (!scc_strcmp(oc2, "q")) imm_size = 8; - LOG_INFO("[IMM] val=%lld size=%d", imm_val, imm_size); + LOG_TRACE("[IMM] val=%lld size=%d", imm_val, imm_size); switch (imm_size) { case 1: emit_u8(m, (uint8_t)imm_val); @@ -287,8 +282,8 @@ static void emit_modrm_sib_disp(scc_mcode_t *m, for (int i = 0; i < num_ops; i++) { const char *tname = tmpl[i].name; if (ops[i].kind == SCC_X86_OPR_REG) { - LOG_INFO("[OPD] %d: REG kind, name=\"%s\" reg=%d", i, tname, - ops[i].reg); + LOG_TRACE("[OPD] %d: REG kind, name=\"%s\" reg=%d", i, tname, + ops[i].reg); if (scc_strcmp(tname, "REG0") == 0) reg_r = ops[i].reg; else if (scc_strcmp(tname, "REG1") == 0) @@ -307,8 +302,8 @@ static void emit_modrm_sib_disp(scc_mcode_t *m, imm_idx = i; } } - LOG_INFO("[MODRM] reg_r=%d (ord=%d) reg_b=%d (ord=%d)", reg_r, - scc_reg_ordinal(reg_r), reg_b, scc_reg_ordinal(reg_b)); + LOG_TRACE("[MODRM] reg_r=%d (ord=%d) reg_b=%d (ord=%d)", reg_r, + scc_reg_ordinal(reg_r), reg_b, scc_reg_ordinal(reg_b)); uint8_t modrm = 0; @@ -426,8 +421,8 @@ static void emit_modrm_sib_disp(scc_mcode_t *m, reg_b == SCC_X86_REG_INVALID) { modrm = 0xC0 | (reg_low3(reg_r) & 7); emit_u8(m, modrm); - LOG_INFO("[MODRM] single reg operand treated as rm, emit 0x%02x", - modrm); + LOG_TRACE("[MODRM] single reg operand treated as rm, emit 0x%02x", + modrm); } else { modrm = 0xC0; if (enc->modrm_reg_fix >= 0) @@ -449,7 +444,7 @@ static void emit_modrm_sib_disp(scc_mcode_t *m, } } - LOG_INFO("[MODRM] emit byte 0x%02x", modrm); + LOG_TRACE("[MODRM] emit byte 0x%02x", modrm); // 立即数在 ModRM 后发射 if (imm_idx >= 0) { @@ -469,7 +464,7 @@ int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform, int num_ops = info->num_explicit_ops; const scc_x86_encoding_t *enc = &info->encode; const scc_x86_operand_t *tmpl = info->ops; - LOG_INFO("[ENCODE] %s", info->iform_name); + LOG_TRACE("[ENCODE] %s", info->iform_name); scc_x86_reg_t reg_field = SCC_X86_REG_INVALID; scc_x86_reg_t rm_field = SCC_X86_REG_INVALID; @@ -521,7 +516,7 @@ int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform, } int op_width = infer_operand_width(info, ops); - LOG_INFO("[OPWIDTH] %d bits", op_width); + LOG_TRACE("[OPWIDTH] %d bits", op_width); if (!enc->has_modrm) { rm_field = reg_field; diff --git a/libs/parser/include/parser_utils.h b/libs/parser/include/parser_utils.h index a89505d..0d7fd01 100644 --- a/libs/parser/include/parser_utils.h +++ b/libs/parser/include/parser_utils.h @@ -71,7 +71,6 @@ static inline void scc_parser_reset(scc_parser_t *parser) { scc_ring_reset(*parser->ring); } -#include static inline scc_pos_t scc_parser_got_current_pos(scc_parser_t *parser) { const scc_lexer_tok_t *tok = scc_parser_peek(parser); scc_pos_t pos = scc_pos_create(); diff --git a/libs/parser/include/scc_parser_log.h b/libs/parser/include/scc_parser_log.h new file mode 100644 index 0000000..04c54af --- /dev/null +++ b/libs/parser/include/scc_parser_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_PARSER_LOG_H__ +#define __SCC_PARSER_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_parser_log; +extern logger_t __scc_parser_user; + +#define SCC_LOG_HANDLER &__scc_parser_user +#define LOG_DEFAULT_HANDLER &__scc_parser_log +#include + +#ifdef __SCC_PARSER_LOG_IMPL__ +logger_t __scc_parser_log = { + .name = "parser", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_parser_user = { + .name = "parser", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/libs/parser/src/parse_decl.c b/libs/parser/src/parse_decl.c index 15509f3..461ec80 100644 --- a/libs/parser/src/parse_decl.c +++ b/libs/parser/src/parse_decl.c @@ -150,6 +150,7 @@ A.2.4 External definitions declaration declaration-list declaration */ +#include #include #include @@ -157,6 +158,7 @@ A.2.4 External definitions scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser, scc_ast_expr_t *base) { + LOG_DEBUG("scc_parse_initializer()"); /* initializer: assignment-expression @@ -179,10 +181,11 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser, tok_ptr = scc_parser_peek(parser); scc_ast_expr_t *init = nullptr; if (!(tok_ptr && tok_ptr->type == SCC_TOK_L_BRACE)) { - // TODO int a = 1, b = 1; + LOG_TRACE(" simple initializer (assignment-expr)"); init = scc_parse_assignment_expression(parser); return init; } + LOG_TRACE(" compound initializer {...}"); scc_parser_next_consume(parser, &tok); scc_pos_t pos = tok.loc; scc_lexer_tok_drop(&tok); @@ -205,8 +208,11 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser, scc_parser_next_consume(parser, &tok); lhs = SCC_AST_ALLOC_EXPR(parser->ast_module); Assert(lhs != nullptr); - scc_ast_expr_member_init(lhs, ptr, scc_ast_module_intern(parser->ast_module, scc_str_as_cstr(&tok.lexeme)), - tok.loc); + scc_ast_expr_member_init( + lhs, ptr, + scc_ast_module_intern(parser->ast_module, + scc_str_as_cstr(&tok.lexeme)), + tok.loc); if (!scc_parser_consume_if(parser, SCC_TOK_ASSIGN)) { ptr = lhs; continue; @@ -261,6 +267,7 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser, } scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) { + LOG_DEBUG("scc_parse_declaration()"); const scc_lexer_tok_t *tok_ptr = nullptr; scc_ast_decl_t *decl_list = nullptr; @@ -283,12 +290,14 @@ CONTINUE: } tok_ptr = scc_parser_peek(parser); if (tok_ptr->type == SCC_TOK_ASSIGN) { + LOG_TRACE(" declaration with initializer"); scc_parser_next_consume(parser, nullptr); // TODO maybe memory leak scc_ast_expr_t *lvalue = SCC_AST_ALLOC_EXPR(parser->ast_module); scc_ast_expr_lvalue_init(lvalue, decl->var.type, decl->base.loc); decl->var.init = scc_parse_initializer(parser, lvalue); } else if (tok_ptr->type == SCC_TOK_L_BRACE) { + LOG_DEBUG(" function definition '%s'", decl->name ? decl->name : "?"); scc_parse_decl_sema(parser, decl); // 进入函数作用域(用于参数和标签) @@ -317,6 +326,7 @@ CONTINUE: tok_ptr = scc_parser_peek(parser); if (tok_ptr->type == SCC_TOK_SEMICOLON) { + LOG_TRACE(" declaration ends with ';'"); scc_parser_next_consume(parser, nullptr); if (decl_list) scc_vec_push(decl_list_vec, decl); diff --git a/libs/parser/src/parse_expr.c b/libs/parser/src/parse_expr.c index bc08ee2..47bbb4a 100644 --- a/libs/parser/src/parse_expr.c +++ b/libs/parser/src/parse_expr.c @@ -104,6 +104,7 @@ A.2.1 Expressions constant-expression: conditional-expression */ +#include #include #include @@ -342,6 +343,7 @@ static void parser_sync(scc_parser_t *parser) { static scc_ast_expr_t *parse_expression_with_precedence(scc_parser_t *parser, int min_prec) { + LOG_TRACE("parse_expression_with_precedence(min_prec=%d)", min_prec); // 从最底层(cast-expression)开始 scc_ast_expr_t *left = parse_cast_expression(parser); if (!left) @@ -361,6 +363,7 @@ static scc_ast_expr_t *parse_expression_with_precedence(scc_parser_t *parser, if (!scc_parser_next_consume(parser, &op_tok)) break; scc_ast_expr_op_t op = map_token_to_binary_op(op_tok.type); + LOG_TRACE(" binary op=%d at prec=%d", op, prec); scc_lexer_tok_drop(&op_tok); // 解析右操作数(优先级 +1,确保左结合) @@ -377,10 +380,12 @@ static scc_ast_expr_t *parse_expression_with_precedence(scc_parser_t *parser, scc_ast_expr_binary_init(expr, op, left, right, left->base.loc); left = expr; } + LOG_TRACE(" => expr type=%d", left ? left->base.type : -1); return left; } // 赋值表达式(右结合) scc_ast_expr_t *scc_parse_assignment_expression(scc_parser_t *parser) { + LOG_TRACE("scc_parse_assignment_expression()"); // 先解析左侧的 unary-expression(C 标准规定赋值左边必须是 // unary-expression) scc_ast_expr_t *left = nullptr; @@ -400,6 +405,7 @@ scc_ast_expr_t *scc_parse_assignment_expression(scc_parser_t *parser) { if (!scc_parser_next_consume(parser, &op_tok)) return left; scc_ast_expr_op_t op = map_token_to_assign_op(op_tok.type); + LOG_TRACE(" assignment op=%d", op); scc_lexer_tok_drop(&op_tok); // 解析右侧(右结合:继续调用 parse_assignment_expression) @@ -420,6 +426,7 @@ scc_ast_expr_t *scc_parse_assignment_expression(scc_parser_t *parser) { // 条件表达式(右结合) static scc_ast_expr_t *parse_conditional_expression(scc_parser_t *parser) { + LOG_TRACE("parse_conditional_expression()"); scc_ast_expr_t *cond_expr = parse_expression_with_precedence(parser, PREC_LOGICAL_OR); if (!cond_expr) @@ -466,6 +473,7 @@ static scc_ast_expr_t *parse_conditional_expression(scc_parser_t *parser) { // 类型转换表达式 (type-name) cast-expression static scc_ast_expr_t *parse_cast_expression(scc_parser_t *parser) { + LOG_TRACE("parse_cast_expression()"); const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser); scc_ast_qual_type_t *type = nullptr; if (tok_ptr && tok_ptr->type == SCC_TOK_L_PAREN) { @@ -476,6 +484,7 @@ static scc_ast_expr_t *parse_cast_expression(scc_parser_t *parser) { if (type) { // 消耗了类型名后,下一个应该是 ')' if (scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) { + LOG_TRACE(" detected type cast"); // 是类型转换,解析后面的 cast-expression(注意 cast-expression // 可以嵌套) scc_ast_expr_t *operand = parse_cast_expression(parser); @@ -524,6 +533,7 @@ static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) { & * + - ~ ! */ const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser); + LOG_TRACE("parse_unary_expression()"); if (!tok_ptr) return nullptr; @@ -543,6 +553,7 @@ static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) { if (!scc_parser_next_consume(parser, &tok)) return nullptr; scc_ast_expr_op_t op = map_token_to_unary_op(tok.type, true); + LOG_TRACE(" unary op=%d", op); scc_pos_t pos = tok.loc; scc_lexer_tok_drop(&tok); @@ -574,6 +585,7 @@ static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) { // sizeof 表达式(特殊处理两种形式) static scc_ast_expr_t *parse_sizeof_expression(scc_parser_t *parser) { + LOG_TRACE("parse_sizeof_expression()"); scc_lexer_tok_t tok_ptr; if (!scc_parser_next_consume(parser, &tok_ptr) || tok_ptr.type != SCC_TOK_SIZEOF) { @@ -606,6 +618,7 @@ static scc_ast_expr_t *parse_sizeof_expression(scc_parser_t *parser) { } Assert(type_name != nullptr); + LOG_TRACE(" sizeof(type)"); scc_ast_expr_sizeof_init(expr, type_name, nullptr, pos); return expr; } @@ -613,6 +626,7 @@ next: // 尝试解析 sizeof unary-expression scc_ast_expr_t *operand = parse_unary_expression(parser); if (operand != nullptr) { + LOG_TRACE(" sizeof(expr)"); scc_ast_expr_sizeof_init(expr, nullptr, operand, pos); return expr; } @@ -623,6 +637,7 @@ next: // 后缀表达式 static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) { + LOG_TRACE("parse_postfix_expression()"); scc_ast_expr_t *left = parse_primary_expression(parser); const scc_lexer_tok_t *tok_ptr = nullptr; scc_pos_t pos = scc_pos_create(); @@ -658,6 +673,7 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) { switch (tok_ptr->type) { case SCC_TOK_L_BRACKET: // left[expr] { + LOG_TRACE(" postfix: array subscript"); if (!scc_parser_next_consume(parser, nullptr)) return left; pos = left->base.loc; @@ -681,6 +697,7 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) { } case SCC_TOK_L_PAREN: // left(args) { + LOG_TRACE(" postfix: function call"); if (!scc_parser_next_consume(parser, nullptr)) goto done; pos = left->base.loc; @@ -718,6 +735,8 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) { } case SCC_TOK_DOT: case SCC_TOK_DEREF: { + LOG_TRACE(" postfix: member access (%s)", + tok_ptr->type == SCC_TOK_DOT ? "." : "->"); scc_lexer_tok_t op_tok; if (!scc_parser_next_consume(parser, &op_tok)) goto done; @@ -751,6 +770,7 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) { case SCC_TOK_ADD_ADD: // left++ case SCC_TOK_SUB_SUB: // left-- { + LOG_TRACE(" postfix: inc/dec"); scc_lexer_tok_t op_tok; if (!scc_parser_next_consume(parser, &op_tok)) goto done; @@ -781,6 +801,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) { string-literal ( expression ) */ + LOG_TRACE("parse_primary_expression()"); const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser); if (!tok_ptr) return nullptr; @@ -789,6 +810,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) { scc_ast_expr_t *expr = nullptr; switch (tok_ptr->type) { case SCC_TOK_IDENT: { + LOG_TRACE(" primary: identifier"); if (!scc_parser_next_consume(parser, &tok)) return nullptr; expr = SCC_AST_ALLOC_EXPR(parser->ast_module); @@ -801,6 +823,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) { break; } case SCC_TOK_INT_LITERAL: { + LOG_TRACE(" primary: int literal"); if (!scc_parser_next_consume(parser, &tok)) return nullptr; expr = SCC_AST_ALLOC_EXPR(parser->ast_module); @@ -813,6 +836,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) { break; } case SCC_TOK_FLOAT_LITERAL: { + LOG_TRACE(" primary: float literal"); if (!scc_parser_next_consume(parser, &tok)) return nullptr; expr = SCC_AST_ALLOC_EXPR(parser->ast_module); @@ -825,6 +849,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) { break; } case SCC_TOK_CHAR_LITERAL: { + LOG_TRACE(" primary: char literal"); if (!scc_parser_next_consume(parser, &tok)) return nullptr; expr = SCC_AST_ALLOC_EXPR(parser->ast_module); @@ -837,6 +862,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) { break; } case SCC_TOK_STRING_LITERAL: { + LOG_TRACE(" primary: string literal"); scc_str_t string = scc_str_empty(); scc_lexer_tok_t tok; while (1) { @@ -863,6 +889,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) { break; } case SCC_TOK_L_PAREN: + LOG_TRACE(" primary: parenthesized expression"); scc_parser_next_consume(parser, nullptr); expr = scc_parse_expression(parser); if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) { @@ -882,6 +909,7 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) { } scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser) { + LOG_DEBUG("scc_parse_expression()"); scc_ast_expr_t *left = scc_parse_assignment_expression(parser); if (!left) return nullptr; @@ -892,6 +920,7 @@ scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser) { if (tok_ptr == nullptr || tok_ptr->type != SCC_TOK_COMMA) { break; } + LOG_TRACE(" comma expression"); scc_pos_t pos = tok_ptr->loc; scc_parser_next_consume(parser, nullptr); @@ -909,6 +938,7 @@ scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser) { } scc_ast_expr_t *scc_parser_constant_expression(scc_parser_t *parser) { + LOG_DEBUG("scc_parser_constant_expression()"); // TODO check constant return parse_conditional_expression(parser); } diff --git a/libs/parser/src/parse_stmt.c b/libs/parser/src/parse_stmt.c index 5cdc491..181e422 100644 --- a/libs/parser/src/parse_stmt.c +++ b/libs/parser/src/parse_stmt.c @@ -46,12 +46,14 @@ A.2.3 Statements break ; return expression(opt) ; */ +#include #include #include #include static inline scc_ast_expr_t *ast_parse_paren_expression(scc_parser_t *parser) { + LOG_TRACE("ast_parse_paren_expression()"); if (!scc_parser_consume_if(parser, SCC_TOK_L_PAREN)) { SCC_ERROR(scc_parser_got_current_pos(parser), "Expected '(' before like `( expression )` ."); @@ -68,6 +70,7 @@ static inline scc_ast_expr_t *ast_parse_paren_expression(scc_parser_t *parser) { static scc_ast_stmt_t *parse_label_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_TRACE("parse_label_statement()"); scc_lexer_tok_t tok = {0}; if (!scc_parser_next_consume(parser, &tok)) { return nullptr; @@ -85,12 +88,16 @@ static scc_ast_stmt_t *parse_label_statement(scc_parser_t *parser, scc_ast_stmt_t *stmt = SCC_AST_ALLOC_STMT(parser->ast_module); Assert(stmt != nullptr); - scc_ast_stmt_label_init(stmt, scc_ast_module_intern(parser->ast_module, scc_str_as_cstr(&tok.lexeme)), statement, pos); + scc_ast_stmt_label_init( + stmt, + scc_ast_module_intern(parser->ast_module, scc_str_as_cstr(&tok.lexeme)), + statement, pos); return stmt; } static scc_ast_stmt_t *parse_case_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_TRACE("parse_case_statement()"); if (!scc_parser_consume_if(parser, SCC_TOK_CASE)) { return nullptr; } @@ -121,6 +128,7 @@ static scc_ast_stmt_t *parse_case_statement(scc_parser_t *parser, static scc_ast_stmt_t *parse_default_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_TRACE("parse_default_statement()"); if (!scc_parser_consume_if(parser, SCC_TOK_DEFAULT)) { return nullptr; } @@ -143,6 +151,7 @@ static scc_ast_stmt_t *parse_default_statement(scc_parser_t *parser, static scc_ast_stmt_t *parse_compound_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_DEBUG("parse_compound_statement()"); if (!scc_parser_consume_if(parser, SCC_TOK_L_BRACE)) { return nullptr; } @@ -174,6 +183,7 @@ static scc_ast_stmt_t *parse_compound_statement(scc_parser_t *parser, } static scc_ast_stmt_t *parse_if_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_DEBUG("parse_if_statement()"); if (!scc_parser_consume_if(parser, SCC_TOK_IF)) { return nullptr; } @@ -195,6 +205,7 @@ static scc_ast_stmt_t *parse_if_statement(scc_parser_t *parser, scc_pos_t pos) { static scc_ast_stmt_t *parse_switch_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_DEBUG("parse_switch_statement()"); if (!scc_parser_consume_if(parser, SCC_TOK_SWITCH)) { return nullptr; } @@ -213,6 +224,7 @@ static scc_ast_stmt_t *parse_switch_statement(scc_parser_t *parser, static scc_ast_stmt_t *parse_while_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_DEBUG("parse_while_statement()"); if (!scc_parser_consume_if(parser, SCC_TOK_WHILE)) { return nullptr; } @@ -231,6 +243,7 @@ static scc_ast_stmt_t *parse_while_statement(scc_parser_t *parser, static scc_ast_stmt_t *parse_do_while_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_DEBUG("parse_do_while_statement()"); if (!scc_parser_consume_if(parser, SCC_TOK_DO)) { return nullptr; } @@ -259,6 +272,7 @@ static scc_ast_stmt_t *parse_do_while_statement(scc_parser_t *parser, static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_DEBUG("parse_for_statement()"); if (!scc_parser_consume_if(parser, SCC_TOK_FOR)) { return nullptr; } @@ -314,12 +328,17 @@ static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser, static scc_ast_stmt_t *parse_jump_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_DEBUG("parse_jump_statement()"); scc_ast_stmt_t *stmt = SCC_AST_ALLOC_STMT(parser->ast_module); if (scc_parser_consume_if(parser, SCC_TOK_GOTO)) { scc_lexer_tok_t tok = {0}; if (scc_parser_next_consume(parser, &tok)) { - scc_ast_stmt_goto_init(stmt, scc_ast_module_intern(parser->ast_module, scc_str_as_cstr(&tok.lexeme)), pos); + scc_ast_stmt_goto_init( + stmt, + scc_ast_module_intern(parser->ast_module, + scc_str_as_cstr(&tok.lexeme)), + pos); } else { SCC_ERROR(scc_parser_got_current_pos(parser), "Expected label after goto."); @@ -343,6 +362,7 @@ static scc_ast_stmt_t *parse_jump_statement(scc_parser_t *parser, static scc_ast_stmt_t *parse_expression_statement(scc_parser_t *parser, scc_pos_t pos) { + LOG_TRACE("parse_expression_statement()"); if (scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) { scc_ast_stmt_t *stmt = SCC_AST_ALLOC_STMT(parser->ast_module); @@ -366,6 +386,7 @@ static scc_ast_stmt_t *parse_expression_statement(scc_parser_t *parser, } scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) { + LOG_DEBUG("scc_parse_statement()"); scc_ast_stmt_t *stmt; const scc_lexer_tok_t *tok_ref; tok_ref = scc_parser_peek(parser); @@ -412,6 +433,7 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) { statement */ case SCC_TOK_L_BRACE: + LOG_TRACE(" stmt: compound"); stmt = parse_compound_statement(parser, pos); goto RETURN; /* @@ -422,9 +444,11 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) { switch ( expression ) statement */ case SCC_TOK_IF: + LOG_TRACE(" stmt: if"); stmt = parse_if_statement(parser, pos); goto RETURN; case SCC_TOK_SWITCH: + LOG_TRACE(" stmt: switch"); stmt = parse_switch_statement(parser, pos); goto RETURN; /* @@ -438,12 +462,15 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) { statement */ case SCC_TOK_WHILE: + LOG_TRACE(" stmt: while"); stmt = parse_while_statement(parser, pos); goto RETURN; case SCC_TOK_DO: + LOG_TRACE(" stmt: do-while"); stmt = parse_do_while_statement(parser, pos); goto RETURN; case SCC_TOK_FOR: + LOG_TRACE(" stmt: for"); stmt = parse_for_statement(parser, pos); goto RETURN; /* @@ -455,9 +482,19 @@ scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser) { return expression(opt) ; */ case SCC_TOK_GOTO: + LOG_TRACE(" stmt: goto"); + stmt = parse_jump_statement(parser, pos); + goto RETURN; case SCC_TOK_CONTINUE: + LOG_TRACE(" stmt: continue"); + stmt = parse_jump_statement(parser, pos); + goto RETURN; case SCC_TOK_BREAK: + LOG_TRACE(" stmt: break"); + stmt = parse_jump_statement(parser, pos); + goto RETURN; case SCC_TOK_RETURN: + LOG_TRACE(" stmt: return"); stmt = parse_jump_statement(parser, pos); goto RETURN; default: diff --git a/libs/parser/src/parse_type.c b/libs/parser/src/parse_type.c index 05e0c62..ccd310f 100644 --- a/libs/parser/src/parse_type.c +++ b/libs/parser/src/parse_type.c @@ -155,6 +155,7 @@ EXAMPLE The constructions [ constant-expression ] . identifier */ +#include #include #include @@ -186,6 +187,7 @@ parse_direct_abstract_declarator(scc_parser_t *parser, * - 函数说明符 (inline) */ cbool scc_parse_is_decl_specifier_start(scc_parser_t *parser) { + LOG_TRACE("scc_parse_is_decl_specifier_start()"); const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser); if (tok_ptr == nullptr) { return false; @@ -230,6 +232,7 @@ cbool scc_parse_is_decl_specifier_start(scc_parser_t *parser) { } cbool scc_parse_is_type_specifier_start(scc_parser_t *parser) { + LOG_TRACE("scc_parse_is_type_specifier_start()"); const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser); if (tok_ptr == nullptr) { return false; @@ -551,7 +554,8 @@ static scc_ast_qual_type_t *parse_record_type(scc_parser_t *parser, if (tok_ptr->type == SCC_TOK_IDENT) { scc_parser_next_consume(parser, &tok); tok_ptr = scc_parser_peek(parser); - name = scc_ast_module_intern(parser->ast_module, scc_str_as_cstr(&tok.lexeme)); + name = scc_ast_module_intern(parser->ast_module, + scc_str_as_cstr(&tok.lexeme)); } else if (tok_ptr->type != SCC_TOK_L_BRACE) { SCC_ERROR(scc_parser_got_current_pos(parser), "Expected name in struct/union/enum specifier"); @@ -581,7 +585,8 @@ static scc_ast_qual_type_t *parse_record_type(scc_parser_t *parser, type = scc_parse_got_type(parser, scc_str_as_cstr(&symbol_name)); if (type == nullptr) { - scc_ast_canon_type_t *canon = scc_ast_module_alloc_type(parser->ast_module); + scc_ast_canon_type_t *canon = + scc_ast_module_alloc_type(parser->ast_module); scc_ast_decl_t *decl = SCC_AST_ALLOC_DECL(parser->ast_module); scc_ast_node_kind_t decl_kind; @@ -620,6 +625,8 @@ static scc_ast_qual_type_t *parse_record_type(scc_parser_t *parser, static scc_ast_qual_type_t * parse_struct_union_type(scc_parser_t *parser, scc_ast_node_kind_t type_kind) { + LOG_DEBUG("parse_struct_union_type(kind=%s)", + type_kind == SCC_AST_TYPE_STRUCT ? "struct" : "union"); /* (6.7.2.1) struct-or-union-specifier: @@ -699,6 +706,7 @@ parse_struct_union_type(scc_parser_t *parser, scc_ast_node_kind_t type_kind) { } static scc_ast_qual_type_t *parse_enum_type(scc_parser_t *parser) { + LOG_DEBUG("parse_enum_type()"); /* (6.7.2.2) enum-specifier: @@ -749,9 +757,11 @@ static scc_ast_qual_type_t *parse_enum_type(scc_parser_t *parser) { scc_ast_decl_t *enum_item_decl = SCC_AST_ALLOC_DECL(parser->ast_module); Assert(enum_item_decl != nullptr); - scc_ast_decl_val_init(enum_item_decl, type, - scc_ast_module_intern(parser->ast_module, scc_str_as_cstr(&tok.lexeme)), enum_item_init, - tok.loc); + scc_ast_decl_val_init( + enum_item_decl, type, + scc_ast_module_intern(parser->ast_module, + scc_str_as_cstr(&tok.lexeme)), + enum_item_init, tok.loc); scc_vec_push(decl->record.fields, enum_item_decl); tok_ptr = scc_parser_peek(parser); @@ -788,6 +798,7 @@ static scc_ast_qual_type_t *parse_enum_type(scc_parser_t *parser) { } static scc_ast_qual_type_t *parse_type_specifier(scc_parser_t *parser) { + LOG_TRACE("parse_type_specifier()"); type_spec_info_t info = {0}; if (!scc_parse_is_type_specifier_start(parser)) return nullptr; @@ -927,6 +938,7 @@ duplicate_error: static scc_ast_qual_type_t * parse_pointer(scc_parser_t *parser, scc_ast_qual_type_t *pointee, scc_ast_qual_type_t **delay_pointee_ptr) { + LOG_TRACE("parse_pointer()"); /* pointer: * type-qualifier-list(opt) @@ -955,6 +967,7 @@ parse_pointer(scc_parser_t *parser, scc_ast_qual_type_t *pointee, static void parse_parameter_type_list(scc_parser_t *parser, scc_ast_decl_vec_t *params) { + LOG_TRACE("parse_parameter_type_list()"); /* (6.7.5) parameter-type-list: parameter-list @@ -1110,6 +1123,7 @@ static scc_ast_qual_type_t * parse_direct_declarator(scc_parser_t *parser, scc_ast_qual_type_t *base, scc_ast_qual_type_t **delay_pointee_ptr, scc_lexer_tok_t *tok_ident) { + LOG_TRACE("parse_direct_declarator()"); const scc_lexer_tok_t *tok_ptr = nullptr; scc_ast_qual_type_t *ret = nullptr; scc_ast_canon_type_t *canon = scc_ast_module_alloc_type(parser->ast_module); @@ -1200,6 +1214,7 @@ static scc_ast_qual_type_t * parse_direct_abstract_declarator(scc_parser_t *parser, scc_ast_qual_type_t *base, scc_ast_qual_type_t **delay_pointee_ptr) { + LOG_TRACE("parse_direct_abstract_declarator()"); const scc_lexer_tok_t *tok_ptr = nullptr; scc_ast_qual_type_t *ret = nullptr; scc_ast_canon_type_t *canon = scc_ast_module_alloc_type(parser->ast_module); @@ -1250,6 +1265,7 @@ parse_direct_abstract_declarator(scc_parser_t *parser, scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser, scc_ast_qual_type_t *type) { + LOG_DEBUG("scc_parse_declarator()"); scc_lexer_tok_t decl_name_tok = {0}; scc_ast_qual_type_t *decl_type = parse_declarator(parser, type, nullptr, &decl_name_tok); @@ -1260,9 +1276,11 @@ scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser, decl_name_tok.type == SCC_TOK_UNKNOWN); // FIXME memory leak - const char *name = decl_name_tok.type == SCC_TOK_IDENT - ? scc_ast_module_intern(parser->ast_module, scc_str_as_cstr(&decl_name_tok.lexeme)) - : nullptr; + const char *name = + decl_name_tok.type == SCC_TOK_IDENT + ? scc_ast_module_intern(parser->ast_module, + scc_str_as_cstr(&decl_name_tok.lexeme)) + : nullptr; if (decl_type->base.type == SCC_AST_TYPE_FUNCTION) { scc_ast_decl_func_init(decl, decl_type, name, nullptr, @@ -1297,6 +1315,7 @@ scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser, } scc_ast_qual_type_t *scc_parse_declaration_specifiers(scc_parser_t *parser) { + LOG_DEBUG("scc_parse_declaration_specifiers()"); if (!scc_parse_is_decl_specifier_start(parser)) { return nullptr; } @@ -1319,6 +1338,7 @@ scc_ast_qual_type_t *scc_parse_declaration_specifiers(scc_parser_t *parser) { } scc_ast_qual_type_t *scc_parse_type_name(scc_parser_t *parser) { + LOG_DEBUG("scc_parse_type_name()"); if (!(scc_parse_is_type_specifier_start(parser) || scc_parse_is_type_qualifier_start(parser))) { return nullptr; diff --git a/libs/parser/src/scc_parser.c b/libs/parser/src/scc_parser.c index 362ec1c..e552cc0 100644 --- a/libs/parser/src/scc_parser.c +++ b/libs/parser/src/scc_parser.c @@ -1,3 +1,6 @@ +#define __SCC_PARSER_LOG_IMPL__ +#include + #include #include @@ -55,6 +58,7 @@ void scc_parser_drop(scc_parser_t *parser) { } scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) { + LOG_INFO("start parsing translation unit"); scc_ast_translation_unit_t *unit = scc_malloc(sizeof(scc_ast_translation_unit_t)); if (!unit) @@ -71,6 +75,8 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) { while (1) { scc_ast_decl_t *decl = scc_parse_declaration(parser); if (decl != nullptr) { + LOG_DEBUG("parsed declaration type=%d name='%s'", decl->base.type, + decl->name ? decl->name : "?"); scc_vec_push(unit->declarations, decl); } else { parser->errcode = 1; diff --git a/libs/parser/src/scc_sema.c b/libs/parser/src/scc_sema.c index 757a9fa..9ffc9ea 100644 --- a/libs/parser/src/scc_sema.c +++ b/libs/parser/src/scc_sema.c @@ -1,5 +1,7 @@ +#include + #include -#include +#include #include #include @@ -159,6 +161,7 @@ static void expr_callback(scc_sema_ctx_t *sema_ctx, if (node_type == SCC_AST_UNKNOWN || node == nullptr) { return; } + LOG_TRACE("sema_expr: type=%d", node_type); scc_ast_expr_t *expr = SCC_AST_CAST_TO(scc_ast_expr_t, node); if (node_type == SCC_AST_EXPR_IDENTIFIER) { scc_ast_node_t *sym_node = @@ -242,6 +245,7 @@ static void stmt_callback(scc_sema_ctx_t *sema_ctx, scc_ast_node_kind_t node_type, void *node) { scc_sema_symtab_t *sema_symtab = sema_ctx->context; + LOG_TRACE("sema_stmt: node_type=%d", node_type); if (node_type == scc_ast_stmt_t_BEGIN) { if (node == nullptr) { scc_sema_symtab_enter_scope(sema_symtab); @@ -364,6 +368,7 @@ static void decl_callback(scc_sema_ctx_t *sema_ctx, scc_ast_node_kind_t node_type, void *node) { scc_sema_symtab_t *sema_symtab = sema_ctx->context; + LOG_TRACE("sema_decl: node_type=%d", node_type); // Function declaration scope // FIXME 使用 node_type 区分其他未来的scope if (node_type == scc_ast_decl_t_BEGIN) { @@ -447,6 +452,7 @@ static scc_ast_qual_type_t *got_type_callback(scc_sema_ctx_t *sema_ctx, } void scc_sema_init(scc_sema_ctx_t *sema_ctx, scc_ast_module_t *ast_module) { + LOG_DEBUG("scc_sema_init()"); sema_ctx->ast_module = ast_module; scc_sema_symtab_t *sema_symtab = scc_malloc(sizeof(scc_sema_symtab_t)); if (sema_symtab == nullptr) { diff --git a/libs/parser/src/sema_symtab.c b/libs/parser/src/sema_symtab.c index aae9dc6..0af11e1 100644 --- a/libs/parser/src/sema_symtab.c +++ b/libs/parser/src/sema_symtab.c @@ -1,3 +1,5 @@ +#include + #include void scc_sema_symtab_init(scc_sema_symtab_t *symtab) { @@ -45,12 +47,17 @@ void scc_sema_symtab_leave_scope(scc_sema_symtab_t *symtab) { scc_ast_node_t *scc_sema_symtab_add_symbol(scc_sema_symtab_t *symtab, const char *name, scc_ast_node_t *ast_node_ref) { + Assert(name != nullptr && "symbol name must not be null"); + Assert(ast_node_ref != nullptr && "symbol node must not be null"); + LOG_TRACE("symtab_add: '%s'", name); return scc_hashtable_set(&symtab->current_scope->symbols, name, ast_node_ref); } scc_ast_node_t *scc_sema_symtab_lookup_symbol(scc_sema_symtab_t *symtab, const char *name) { + Assert(name != nullptr && "lookup name must not be null"); + LOG_TRACE("symtab_lookup: '%s'", name); scc_ast_node_t *node = nullptr; for (scc_sema_scope_t *scope = symtab->current_scope; scope != nullptr; scope = scope->parent) { diff --git a/libs/pproc/include/scc_pproc_log.h b/libs/pproc/include/scc_pproc_log.h new file mode 100644 index 0000000..82958fe --- /dev/null +++ b/libs/pproc/include/scc_pproc_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_PPROC_LOG_H__ +#define __SCC_PPROC_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_pproc_log; +extern logger_t __scc_pproc_user; + +#define SCC_LOG_HANDLER &__scc_pproc_user +#define LOG_DEFAULT_HANDLER &__scc_pproc_log +#include + +#ifdef __SCC_PPROC_LOG_IMPL__ +logger_t __scc_pproc_log = { + .name = "pproc", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_pproc_user = { + .name = "pproc", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/libs/pproc/src/pproc_directive.c b/libs/pproc/src/pproc_directive.c index 31674df..6761497 100644 --- a/libs/pproc/src/pproc_directive.c +++ b/libs/pproc/src/pproc_directive.c @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -353,7 +355,7 @@ void scc_pproc_handle_directive(scc_pproc_t *pp) { goto ERROR; case SCC_PP_TOK_EMBED: goto ERROR; -#define __SCC_PPROC_LOG_PNT(func_name) \ +#define __SCC_PPROC_LOG_ERR() \ do { \ scc_lexer_tok_drop(&tok); \ while (1) { \ @@ -362,17 +364,33 @@ void scc_pproc_handle_directive(scc_pproc_t *pp) { return; \ } \ if (scc_get_tok_subtype(tok.type) == SCC_TOK_SUBTYPE_LITERAL) { \ - func_name(tok.loc, "%s", scc_str_as_cstr(&tok.lexeme)); \ + SCC_ERROR(tok.loc, "%s", scc_str_as_cstr(&tok.lexeme)); \ + } \ + scc_lexer_tok_drop(&tok); \ + } \ + return; \ + } while (0) + +#define __SCC_PPROC_LOG_WARN() \ + do { \ + scc_lexer_tok_drop(&tok); \ + while (1) { \ + ok = scc_lexer_next_non_blank(pp->cur_ring, &tok); \ + if (tok.type == SCC_TOK_ENDLINE || ok == false) { \ + return; \ + } \ + if (scc_get_tok_subtype(tok.type) == SCC_TOK_SUBTYPE_LITERAL) { \ + SCC_WARN(tok.loc, "%s", scc_str_as_cstr(&tok.lexeme)); \ } \ scc_lexer_tok_drop(&tok); \ } \ return; \ } while (0) case SCC_PP_TOK_ERROR: { - __SCC_PPROC_LOG_PNT(SCC_ERROR); + __SCC_PPROC_LOG_ERR(); } case SCC_PP_TOK_WARNING: { - __SCC_PPROC_LOG_PNT(SCC_WARN); + __SCC_PPROC_LOG_WARN(); } case SCC_PP_TOK_PRAGMA: SCC_WARN(tok.loc, "pragma ignored"); diff --git a/libs/pproc/src/pproc_expand.c b/libs/pproc/src/pproc_expand.c index bd2fc5b..b6edd05 100644 --- a/libs/pproc/src/pproc_expand.c +++ b/libs/pproc/src/pproc_expand.c @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -125,6 +127,8 @@ void scc_pproc_expand_by_src(scc_pproc_macro_table_t *macro_table, scc_lexer_tok_ring_t *output, const scc_pproc_macro_t *macro, cbool need_keep_org_pos) { + LOG_DEBUG("expand macro '%s' type=%s", scc_str_as_cstr(¯o->name), + macro->type == SCC_PP_MACRO_OBJECT ? "object" : "function"); scc_lexer_tok_vec_t expaned_buffer; scc_vec_init(expaned_buffer); @@ -412,6 +416,8 @@ static void concact(scc_pproc_expand_t *ctx, scc_lexer_tok_vec_t *tok_buffer, static inline void expand_function_macro(scc_pproc_expand_t *ctx, const scc_pproc_macro_t *macro) { + LOG_DEBUG("expand function macro '%s' (line %d)", + scc_str_as_cstr(¯o->name), ctx->call_pos.line); scc_lexer_tok_vec_t tok_buffer; scc_vec_init(tok_buffer); @@ -543,6 +549,7 @@ static inline void expand_function_macro(scc_pproc_expand_t *ctx, static inline void expand_object_macro(scc_pproc_expand_t *ctx, const scc_pproc_macro_t *macro) { + LOG_DEBUG("expand object macro '%s'", scc_str_as_cstr(¯o->name)); scc_lexer_tok_vec_t tok_buffer; scc_vec_init(tok_buffer); @@ -578,13 +585,13 @@ static inline void expand_object_macro(scc_pproc_expand_t *ctx, static cbool parse_defined(scc_pproc_expand_t *expand_ctx, scc_pos_t *tok_pos) { scc_lexer_tok_t next_tok = {0}; if (scc_lexer_next_non_blank(expand_ctx->input, &next_tok) == false) { - SCC_ERROR(*tok_pos, "Unexpected before defined EOF"); + SCC_ERROR(*tok_pos, "unexpected before 'defined' EOF"); } if (next_tok.type == SCC_TOK_L_PAREN) { scc_lexer_tok_drop(&next_tok); scc_lexer_next_non_blank(expand_ctx->input, &next_tok); if (scc_get_tok_subtype(next_tok.type) != SCC_TOK_SUBTYPE_IDENTIFIER) { - SCC_ERROR(next_tok.loc, "Expected identifier before defined"); + SCC_ERROR(next_tok.loc, "expected identifier before 'defined'"); scc_lexer_tok_drop(&next_tok); } @@ -603,7 +610,7 @@ static cbool parse_defined(scc_pproc_expand_t *expand_ctx, scc_pos_t *tok_pos) { scc_lexer_tok_drop(&next_tok); return false; } else { - SCC_ERROR(next_tok.loc, "Expected ')'"); + SCC_ERROR(next_tok.loc, "expected ')'"); scc_lexer_tok_drop(&next_tok); } } @@ -652,10 +659,14 @@ void scc_pproc_expand_macro(scc_pproc_expand_t *expand_ctx) { if (macro == nullptr || need_skip(expand_ctx, macro)) { // FIXME maybe keyword is error or don't parse c keyword or number + LOG_DEBUG("skip macro expansion for '%s'", + scc_str_as_cstr(&tok.lexeme)); tok.type += SCC_TOK_DISABLED; scc_vec_push(expand_ctx->output, tok); continue; } + LOG_DEBUG("expand macro '%s' type=%s", scc_str_as_cstr(&tok.lexeme), + macro->type == SCC_PP_MACRO_OBJECT ? "object" : "function"); expand_ctx->need_rescan = true; expand_ctx->call_pos = tok.loc; diff --git a/libs/pproc/src/pproc_if.c b/libs/pproc/src/pproc_if.c index 25f0271..ffa18d4 100644 --- a/libs/pproc/src/pproc_if.c +++ b/libs/pproc/src/pproc_if.c @@ -1,3 +1,5 @@ +#include + #include #include diff --git a/libs/pproc/src/pproc_include.c b/libs/pproc/src/pproc_include.c index d7b5208..ad1de14 100644 --- a/libs/pproc/src/pproc_include.c +++ b/libs/pproc/src/pproc_include.c @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -39,9 +41,8 @@ static int switch_file_stack(scc_pproc_t *pp, scc_str_t *fname, scc_pos_t *pos, return -1; FOPEN: if ((int)scc_vec_size(pp->file_stack) >= pp->config.max_include_depth) { - SCC_FATAL(*pos, "include depth exceeds maximum (%d)", + LOG_FATAL("Include depth exceeds maximum (%d)", pp->config.max_include_depth); - LOG_FATAL("Include depth is too deep..."); } scc_pproc_file_t *file = scc_malloc(sizeof(scc_pproc_file_t)); diff --git a/libs/pproc/src/pproc_macro.c b/libs/pproc/src/pproc_macro.c index cddce6b..bd1c88e 100644 --- a/libs/pproc/src/pproc_macro.c +++ b/libs/pproc/src/pproc_macro.c @@ -1,3 +1,5 @@ +#include + #include // 创建宏对象 diff --git a/libs/pproc/src/scc_pproc.c b/libs/pproc/src/scc_pproc.c index c70d5a8..28b77e6 100644 --- a/libs/pproc/src/scc_pproc.c +++ b/libs/pproc/src/scc_pproc.c @@ -1,3 +1,6 @@ +#define __SCC_PPROC_LOG_IMPL__ +#include + #include #include #include diff --git a/libs/pproc/tests/test_pproc_unit.c b/libs/pproc/tests/test_pproc_unit.c index 85108af..8dc9348 100644 --- a/libs/pproc/tests/test_pproc_unit.c +++ b/libs/pproc/tests/test_pproc_unit.c @@ -626,6 +626,11 @@ static void test_c99_docs(void) { "fprintf(stderr, \"X = %d\\n\", x);\n" "puts(\"The first, second, and third items.\");\n" "((x>y)?puts(\"x>y\"): printf(\"x is %d but y is %d\", x, y));\n"); + + TEST_CASE("Typedef"); + CHECK_PP_OUTPUT_EXACT( + "#define SCC_AP_DIGIT u64\ntypedef SCC_AP_DIGIT scc_ap_digit;", + "typedef u64 scc_ap_digit;"); } #define TEST_LIST_CASE(func_name) {#func_name, func_name} diff --git a/libs/sccf/cbuild.toml b/libs/sccf/cbuild.toml index b269066..b842c48 100644 --- a/libs/sccf/cbuild.toml +++ b/libs/sccf/cbuild.toml @@ -5,4 +5,5 @@ version = "0.1.0" dependencies = [ { name = "scc_core", path = "../../runtime/scc_core" }, { name = "scc_utils", path = "../../runtime/scc_utils" }, + { name = "mcode", path = "../mcode" }, ] diff --git a/libs/sccf/include/sccf_linker.h b/libs/sccf/include/sccf_linker.h index 1236101..74a44b1 100644 --- a/libs/sccf/include/sccf_linker.h +++ b/libs/sccf/include/sccf_linker.h @@ -13,6 +13,12 @@ typedef struct { scc_hashtable_t str2offset; sccf_sym_vec_t symtab; sccf_reloc_vec_t relocs; + const char *entry_symbol_name; } sccf_linker_t; +void sccf_linker_init(sccf_linker_t *linker); +void sccf_linker_add_sccf(sccf_linker_t *linker, const sccf_t *sccf); +void sccf_linker_set_entry_symbol_name(sccf_linker_t *linker, const char *name); +const sccf_t *sccf_linker_link(sccf_linker_t *linker); + #endif /* __SCC_FORMAT_LINKER_H__ */ diff --git a/libs/sccf/include/sccf_log.h b/libs/sccf/include/sccf_log.h new file mode 100644 index 0000000..bd4e62d --- /dev/null +++ b/libs/sccf/include/sccf_log.h @@ -0,0 +1,26 @@ +#ifndef __SCCF_LOG_H__ +#define __SCCF_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_sccf_log; +extern logger_t __scc_sccf_user; + +#define SCC_LOG_HANDLER &__scc_sccf_user +#define LOG_DEFAULT_HANDLER &__scc_sccf_log +#include + +#ifdef __SCCF_LOG_IMPL__ +logger_t __scc_sccf_log = { + .name = "sccf", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_sccf_user = { + .name = "sccf", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/libs/sccf/src/sccf_builder.c b/libs/sccf/src/sccf_builder.c index c15d78d..676f38e 100644 --- a/libs/sccf/src/sccf_builder.c +++ b/libs/sccf/src/sccf_builder.c @@ -1,4 +1,5 @@ #include +#include void sccf_builder_init(sccf_builder_t *builder) { builder->aligned = 64; diff --git a/libs/sccf/src/sccf_linker.c b/libs/sccf/src/sccf_linker.c new file mode 100644 index 0000000..2045dc6 --- /dev/null +++ b/libs/sccf/src/sccf_linker.c @@ -0,0 +1,259 @@ +#include +#include +#include + +void sccf_linker_init(sccf_linker_t *linker) { + sccf_builder_init(&linker->builder); + scc_vec_init(linker->link_sccfs); + scc_strpool_init(&linker->strpool); + scc_hashtable_cstr_init(&linker->str2offset); + scc_vec_init(linker->symtab); + scc_vec_init(linker->relocs); + linker->entry_symbol_name = "_scc_entry"; +} + +void sccf_linker_add_sccf(sccf_linker_t *linker, const sccf_t *sccf) { + scc_vec_push(linker->link_sccfs, *sccf); +} + +void sccf_linker_set_entry_symbol_name(sccf_linker_t *linker, const char *name) { + linker->entry_symbol_name = name ? name : "_scc_entry"; +} + +// Per-module extracted data (borrowed references to the original SCCF data) +typedef struct { + usize code_base; // offset of this module's code in merged_code + usize data_base; // offset of this module's data in merged_data + usize code_size; + usize data_size; + u8 *code_data; + u8 *data_data; + char *strtab_data; + usize strtab_size; + sccf_sym_t *sym_data; + usize sym_count; + sccf_reloc_t *reloc_data; + usize reloc_count; +} mod_ctx_t; + +// Look up a section in an SCCF module by type, extract info +static void extract_mod_sections(sccf_t *mod, mod_ctx_t *ctx) { + scc_vec_foreach(mod->sect_headers, i) { + sccf_sect_header_t *sh = &scc_vec_at(mod->sect_headers, i); + sccf_sect_data_t *sd = &scc_vec_at(mod->sect_datas, i); + + switch (sh->sccf_sect_type) { + case SCCF_SECT_CODE: + ctx->code_data = scc_vec_unsafe_get_data(*sd); + ctx->code_size = scc_vec_size(*sd); + break; + case SCCF_SECT_DATA: + ctx->data_data = scc_vec_unsafe_get_data(*sd); + ctx->data_size = scc_vec_size(*sd); + break; + case SCCF_SECT_STRTAB: + ctx->strtab_data = (char *)scc_vec_unsafe_get_data(*sd); + ctx->strtab_size = scc_vec_size(*sd); + break; + case SCCF_SECT_SYMTAB: + ctx->sym_data = (sccf_sym_t *)scc_vec_unsafe_get_data(*sd); + ctx->sym_count = scc_vec_size(*sd) / sizeof(sccf_sym_t); + break; + case SCCF_SECT_RELOCS: + ctx->reloc_data = (sccf_reloc_t *)scc_vec_unsafe_get_data(*sd); + ctx->reloc_count = scc_vec_size(*sd) / sizeof(sccf_reloc_t); + break; + default: + break; + } + } +} + +const sccf_t *sccf_linker_link(sccf_linker_t *linker) { + usize num_modules = scc_vec_size(linker->link_sccfs); + if (num_modules <= 1) { + return sccf_builder_to_sccf(&linker->builder); + } + + sccf_builder_t *builder = &linker->builder; + + // Concatenated section data + sccf_sect_data_t merged_code, merged_data; + scc_vec_init(merged_code); + scc_vec_init(merged_data); + + // Per-module context + SCC_VEC(mod_ctx_t) mods; + scc_vec_init(mods); + + // Phase 1: extract data from each module, concatenate code and data sections + scc_vec_foreach(linker->link_sccfs, m) { + sccf_t *mod = &scc_vec_at(linker->link_sccfs, m); + mod_ctx_t ctx = {0}; + + extract_mod_sections(mod, &ctx); + + ctx.code_base = scc_vec_size(merged_code); + for (usize j = 0; j < ctx.code_size; j++) { + scc_vec_push(merged_code, ctx.code_data[j]); + } + + ctx.data_base = scc_vec_size(merged_data); + for (usize j = 0; j < ctx.data_size; j++) { + scc_vec_push(merged_data, ctx.data_data[j]); + } + + scc_vec_push(mods, ctx); + } + + // Phase 2: build unified symbol table. + // For each module, map local symbol index -> global symbol index. + // GLOBAL/EXTERN symbols are deduplicated by name. + // LOCAL symbols get unique entries per module (even if names collide). + + typedef SCC_VEC(usize) idx_map_t; + SCC_VEC(idx_map_t) maps; + scc_vec_init(maps); + + // First pass: collect all GLOBAL symbol definitions into the unified table + scc_vec_foreach(mods, m) { + mod_ctx_t *ctx = &scc_vec_at(mods, m); + idx_map_t map; + scc_vec_init(map); + + // Index 0 = null symbol + scc_vec_push(map, 0); + + for (usize j = 1; j < ctx->sym_count; j++) { + sccf_sym_t *sym = &ctx->sym_data[j]; + const char *name = &ctx->strtab_data[sym->name_offset]; + + // Look up in unified table + usize global_idx = + (usize)scc_hashtable_get(&linker->str2offset, name); + + if (global_idx == 0) { + // New symbol: add to builder's symtab/strtab + sccf_sym_t adjusted = *sym; + if (adjusted.sccf_sect_type == SCCF_SECT_CODE) { + adjusted.sccf_sect_offset += ctx->code_base; + } else if (adjusted.sccf_sect_type == SCCF_SECT_DATA) { + adjusted.sccf_sect_offset += ctx->data_base; + } + + usize name_off = scc_vec_size(builder->strtab); + const char *p = name; + while (*p) { + scc_vec_push(builder->strtab, *p); + p++; + } + scc_vec_push(builder->strtab, '\0'); + adjusted.name_offset = name_off; + + global_idx = scc_vec_size(builder->symtab); + scc_vec_push(builder->symtab, adjusted); + scc_hashtable_set(&linker->str2offset, name, + (void *)global_idx); + + } else { + // Symbol already exists in unified table. + // If the new entry is a definition and existing is UNDEF/EXTERN, + // update the existing entry with the definition. + sccf_sym_t *existing = &scc_vec_at(builder->symtab, global_idx); + bool existing_is_ref = + existing->sccf_sym_type == SCCF_SYM_TYPE_UNDEF || + existing->sccf_sym_type == SCCF_SYM_TYPE_EXTERN; + bool new_is_def = + sym->sccf_sym_type != SCCF_SYM_TYPE_UNDEF && + sym->sccf_sym_type != SCCF_SYM_TYPE_EXTERN; + + if (new_is_def && existing_is_ref) { + sccf_sym_t adjusted = *sym; + if (adjusted.sccf_sect_type == SCCF_SECT_CODE) { + adjusted.sccf_sect_offset += ctx->code_base; + } else if (adjusted.sccf_sect_type == SCCF_SECT_DATA) { + adjusted.sccf_sect_offset += ctx->data_base; + } + adjusted.name_offset = existing->name_offset; + *existing = adjusted; + } + } + + scc_vec_push(map, global_idx); + } + scc_vec_push(maps, map); + } + + // Phase 3: process relocations. + // For each module, for each non-empty relocation: + // - Look up the target symbol in the unified table + // - If the symbol is now resolved (was EXTERN/UNDEF, now GLOBAL), + // patch the merged code in-place + // - If still unresolved, keep the relocation for DLL import resolution + + // Build mcode wrapper around merged_code for patching. + // adopt_buf transfers ownership, so merged_code is emptied then refilled by + // disown_buf after patching. The cast is safe: both sccf_sect_data_t and + // scc_mcode_buff_t are SCC_VEC(u8) with identical layout. + scc_mcode_t mcode; + scc_mcode_init(&mcode, SCC_MCODE_ARCH_X86_64); + scc_mcode_adopt_buf(&mcode, (scc_mcode_buff_t *)&merged_code); + + scc_vec_foreach(mods, m) { + mod_ctx_t *ctx = &scc_vec_at(mods, m); + idx_map_t *map = &scc_vec_at(maps, m); + + for (usize j = 0; j < ctx->reloc_count; j++) { + sccf_reloc_t reloc = ctx->reloc_data[j]; + if (reloc.reloc_type == SCCF_RELOC_TYPE_EMPTY) + continue; + + Assert(reloc.sym_idx < scc_vec_size(*map)); + + usize global_idx = scc_vec_at(*map, reloc.sym_idx); + Assert(global_idx < scc_vec_size(builder->symtab)); + sccf_sym_t *target = &scc_vec_at(builder->symtab, global_idx); + + if (target->sccf_sym_type == SCCF_SYM_TYPE_EXTERN || + target->sccf_sym_type == SCCF_SYM_TYPE_UNDEF) { + // Still unresolved: keep for DLL import resolution + reloc.sym_idx = global_idx; + sccf_builder_add_reloc(builder, reloc); + } else { + // Resolved: patch code in-place + usize patch_site = reloc.offset + reloc.addend + ctx->code_base; + usize target_off = target->sccf_sect_offset; + + scc_x86_patch(&mcode, SCC_X86_PATCH_PC32, patch_site, + target_off); + } + } + } + + // Return merged data ownership from mcode back to merged_code + scc_mcode_disown_buf(&mcode, (scc_mcode_buff_t *)&merged_code); + scc_mcode_drop(&mcode); + + // Phase 4: add merged sections to builder + if (scc_vec_size(merged_code) > 0) { + sccf_builder_add_text_section(builder, &merged_code); + } + if (scc_vec_size(merged_data) > 0) { + sccf_builder_add_data_section(builder, &merged_data); + } + + // Set entry point + sccf_builder_set_entry_symbol_name(builder, linker->entry_symbol_name); + + // Cleanup per-module data + scc_vec_foreach(maps, i) { + scc_vec_free(scc_vec_at(maps, i)); + } + scc_vec_free(maps); + // mod_ctx entries borrow references — no vec data to free for them + scc_vec_free(mods); + scc_vec_free(merged_code); + scc_vec_free(merged_data); + + return sccf_builder_to_sccf(builder); +} diff --git a/libs/sccf/src/sccf_log.c b/libs/sccf/src/sccf_log.c new file mode 100644 index 0000000..d3f4c18 --- /dev/null +++ b/libs/sccf/src/sccf_log.c @@ -0,0 +1,2 @@ +#define __SCCF_LOG_IMPL__ +#include diff --git a/libs/sstream/include/scc_sstream.h b/libs/sstream/include/scc_sstream.h index 4ec372a..144fa2e 100644 --- a/libs/sstream/include/scc_sstream.h +++ b/libs/sstream/include/scc_sstream.h @@ -1,10 +1,11 @@ #ifndef __SCC_SSTREAM_H__ #define __SCC_SSTREAM_H__ +#include + #include #include #include -#include typedef struct { scc_pos_t pos; diff --git a/libs/sstream/include/scc_sstream_log.h b/libs/sstream/include/scc_sstream_log.h new file mode 100644 index 0000000..54a0f99 --- /dev/null +++ b/libs/sstream/include/scc_sstream_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_SSTREAM_LOG_H__ +#define __SCC_SSTREAM_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_sstream_log; +extern logger_t __scc_sstream_user; + +#define SCC_LOG_HANDLER &__scc_sstream_user +#define LOG_DEFAULT_HANDLER &__scc_sstream_log +#include + +#ifdef __SCC_SSTREAM_LOG_IMPL__ +logger_t __scc_sstream_log = { + .name = "sstream", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_sstream_user = { + .name = "sstream", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif /* __SCC_SSTREAM_LOG_H__ */ diff --git a/libs/sstream/src/scc_sstream.c b/libs/sstream/src/scc_sstream.c index a879072..acc18df 100644 --- a/libs/sstream/src/scc_sstream.c +++ b/libs/sstream/src/scc_sstream.c @@ -1,3 +1,6 @@ +#define __SCC_SSTREAM_LOG_IMPL__ +#include + #include // 内部扫描函数:从指定位置扫描下一个有效字符 @@ -91,7 +94,7 @@ int scc_sstream_init(scc_sstream_t *stream, const char *fname, int ring_size) { if (fsize == 0) { stream->fill_pos = scc_pos_create(); stream->fill_pos.name = fname; - SCC_WARN(stream->fill_pos, "file size is 0"); + LOG_WARN("file size is 0"); scc_sstream_init_by_buffer(stream, "", 0, false, ring_size); return 0; } diff --git a/libs/target/pe/include/scc_pe_log.h b/libs/target/pe/include/scc_pe_log.h new file mode 100644 index 0000000..2c50651 --- /dev/null +++ b/libs/target/pe/include/scc_pe_log.h @@ -0,0 +1,26 @@ +#ifndef __SCC_PE_LOG_H__ +#define __SCC_PE_LOG_H__ + +typedef struct logger logger_t; +extern logger_t __scc_pe_log; +extern logger_t __scc_pe_user; + +#define SCC_LOG_HANDLER &__scc_pe_user +#define LOG_DEFAULT_HANDLER &__scc_pe_log +#include + +#ifdef __SCC_PE_LOG_IMPL__ +logger_t __scc_pe_log = { + .name = "pe", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_pe_user = { + .name = "pe", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/libs/target/pe/src/scc_pe_builder.c b/libs/target/pe/src/scc_pe_builder.c index 2792e45..434f3d0 100644 --- a/libs/target/pe/src/scc_pe_builder.c +++ b/libs/target/pe/src/scc_pe_builder.c @@ -1,9 +1,7 @@ -#include +#define __SCC_PE_LOG_IMPL__ +#include -#ifdef LOG_INFO -#undef LOG_INFO -#endif -#define LOG_INFO(...) +#include #define reserve_align(offset, size) ((offset) + ((size) - 1)) & ~((size) - 1) diff --git a/libs/target/pe/src/scc_pe_idata.c b/libs/target/pe/src/scc_pe_idata.c index 49c98ca..20a3f82 100644 --- a/libs/target/pe/src/scc_pe_idata.c +++ b/libs/target/pe/src/scc_pe_idata.c @@ -1,3 +1,5 @@ +#include + #include // RVA Relative Virtual Address diff --git a/libs/target/sccf2target/src/sccf2pe.c b/libs/target/sccf2target/src/sccf2pe.c index 5a395a5..71c15fc 100644 --- a/libs/target/sccf2target/src/sccf2pe.c +++ b/libs/target/sccf2target/src/sccf2pe.c @@ -1,5 +1,6 @@ #include #include +#include #include #include diff --git a/runtime/log/include/log.c b/runtime/log/include/log.c index 2fa02be..1a24a72 100644 --- a/runtime/log/include/log.c +++ b/runtime/log/include/log.c @@ -25,8 +25,8 @@ int log_default_handler(logger_t *module, log_level_t level, const char *file, case LOG_LEVEL_TRACE: level_str = "TRACE"; break; default: level_str = "NOTSET"; break; } - /// @note: 定义 __LOG_NO_COLOR__ 会取消颜色输出 - #ifndef __LOG_NO_COLOR__ +/// @note: 定义 __LOG_NO_COLOR__ 会取消颜色输出 +#ifndef __LOG_NO_COLOR__ const char *color_code; switch (level) { case LOG_LEVEL_DEBUG: color_code = ANSI_FG_CYAN; break; @@ -54,7 +54,6 @@ int log_default_handler(logger_t *module, log_level_t level, const char *file, } va_end(args); log_puts(module->buf); - log_puts("\n"); // for clangd warning // clang-analyzer-deadcode.DeadStores (void)color_code; diff --git a/runtime/log/include/log.h b/runtime/log/include/log.h index ce0a1a3..95b93a1 100644 --- a/runtime/log/include/log.h +++ b/runtime/log/include/log.h @@ -74,9 +74,12 @@ typedef int (*log_handler)(logger_t *module, log_level_t level, * 每个日志器实例维护独立的配置和缓冲区 */ struct logger { - const char *name; ///< 日志器名称(用于模块区分) - log_level_t level; ///< 当前设置的日志级别 - log_handler handler; ///< 日志处理回调函数 + const char *name; ///< 日志器名称(用于模块区分) + log_level_t level; ///< 当前设置的日志级别 + union { + log_handler handler; + void *user_handler; + }; ///< 日志处理回调函数 void *user_data; ///< 用户自定义数据 char buf[LOGGER_MAX_BUF_SIZE]; ///< 格式化缓冲区 }; @@ -84,6 +87,9 @@ struct logger { int log_default_handler(logger_t *module, log_level_t level, const char *file, int line, const char *func, const char *fmt, ...); extern logger_t __default_logger_root; +#ifndef LOG_DEFAULT_HANDLER +#define LOG_DEFAULT_HANDLER &__default_logger_root +#endif /** * @brief 初始化日志实例 其余参数设置为默认值 @@ -135,13 +141,13 @@ void log_set_handler(logger_t *logger, log_handler handler); /// @name 快捷日志宏 /// @{ -#define LOG_NOTSET(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志 -#define LOG_DEBUG(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志(需启用DEBUG级别) -#define LOG_INFO(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志) -#define LOG_WARN(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题) -#define LOG_ERROR(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误) -#define LOG_FATAL(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前) -#define LOG_TRACE(...) SCC_LOG_IMPL(&__default_logger_root, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪) +#define LOG_NOTSET(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_NOTSET, __VA_ARGS__) ///< 未分类日志 +#define LOG_DEBUG(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_DEBUG, __VA_ARGS__) ///< 调试日志(需启用DEBUG级别) +#define LOG_INFO(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_INFO, __VA_ARGS__) ///< 信息日志(常规运行日志) +#define LOG_WARN(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_WARN, __VA_ARGS__) ///< 警告日志(潜在问题) +#define LOG_ERROR(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_ERROR, __VA_ARGS__) ///< 错误日志(可恢复错误) +#define LOG_FATAL(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_FATAL, __VA_ARGS__) ///< 致命错误日志(程序终止前) +#define LOG_TRACE(...) SCC_LOG_IMPL(LOG_DEFAULT_HANDLER, LOG_LEVEL_TRACE, __VA_ARGS__) ///< 追踪日志(调用栈跟踪) /// @} /* clang-format on */ diff --git a/runtime/scc_core/include/scc_core_log.h b/runtime/scc_core/include/scc_core_log.h index e1711d1..1fe4014 100644 --- a/runtime/scc_core/include/scc_core_log.h +++ b/runtime/scc_core/include/scc_core_log.h @@ -6,7 +6,7 @@ #endif #ifndef log_puts -#define log_puts(str) scc_printf("%s", str) +#define log_puts(str) scc_printf("%s\n", str) #endif #ifndef log_abort diff --git a/runtime/scc_core/include/scc_log.h b/runtime/scc_core/include/scc_log.h new file mode 100644 index 0000000..9bd1334 --- /dev/null +++ b/runtime/scc_core/include/scc_log.h @@ -0,0 +1,35 @@ +#ifndef __SCC_POS_LOG_H__ +#define __SCC_POS_LOG_H__ + +#include "scc_pos.h" +#include + +int scc_log_handler(logger_t *module, log_level_t level, const char *file, + int line, int col, const char *fmt, ...); +typedef int (*scc_log_fn_t)(logger_t *module, log_level_t level, + const char *file, int line, int col, + const char *fmt, ...); +extern logger_t __scc_pos_log; + +#define SCC_POS_LOG(logger, level, pos, fmt, ...) \ + do { \ + ((scc_log_fn_t)(logger)->user_handler)( \ + (logger), (level), scc_pos_pnt_val(pos), (fmt), ##__VA_ARGS__); \ + } while (0) + +#ifndef SCC_LOG_HANDLER +#define SCC_LOG_HANDLER &__scc_pos_log +#endif + +#define SCC_DEBUG(pos, fmt, ...) \ + SCC_POS_LOG(SCC_LOG_HANDLER, LOG_LEVEL_DEBUG, pos, fmt, ##__VA_ARGS__) +#define SCC_INFO(pos, fmt, ...) \ + SCC_POS_LOG(SCC_LOG_HANDLER, LOG_LEVEL_INFO, pos, fmt, ##__VA_ARGS__) +#define SCC_WARN(pos, fmt, ...) \ + SCC_POS_LOG(SCC_LOG_HANDLER, LOG_LEVEL_WARN, pos, fmt, ##__VA_ARGS__) +#define SCC_ERROR(pos, fmt, ...) \ + SCC_POS_LOG(SCC_LOG_HANDLER, LOG_LEVEL_ERROR, pos, fmt, ##__VA_ARGS__) +#define SCC_FATAL(pos, fmt, ...) \ + SCC_POS_LOG(SCC_LOG_HANDLER, LOG_LEVEL_FATAL, pos, fmt, ##__VA_ARGS__) + +#endif /* __SCC_POS_LOG_H__ */ diff --git a/runtime/scc_utils/src/scc_pos_log.c b/runtime/scc_core/src/scc_log.c similarity index 50% rename from runtime/scc_utils/src/scc_pos_log.c rename to runtime/scc_core/src/scc_log.c index 1f32c81..b0a90f7 100644 --- a/runtime/scc_utils/src/scc_pos_log.c +++ b/runtime/scc_core/src/scc_log.c @@ -1,21 +1,17 @@ -#include - -static int pos_log_handler(logger_t *module, log_level_t level, - const char *file, int line, const char *func, - const char *fmt, ...) { +#include +int scc_log_handler(logger_t *module, log_level_t level, const char *file, + int line, int col, const char *fmt, ...) { /* clang-format off */ - (void) module, (void)file, (void)line, (void)func; // 不再使用 - const char *level_str = nullptr; switch (level) { - case LOG_LEVEL_DEBUG: level_str = "DEBUG"; break; - case LOG_LEVEL_INFO: level_str = "INFO "; break; - case LOG_LEVEL_WARN: level_str = "WARN "; break; - case LOG_LEVEL_ERROR: level_str = "ERROR"; break; - case LOG_LEVEL_FATAL: level_str = "FATAL"; break; - case LOG_LEVEL_TRACE: level_str = "TRACE"; break; - default: level_str = "NOTSET"; break; + case LOG_LEVEL_DEBUG: level_str = "debug"; break; + case LOG_LEVEL_INFO: level_str = "info "; break; + case LOG_LEVEL_WARN: level_str = "warn "; break; + case LOG_LEVEL_ERROR: level_str = "error"; break; + case LOG_LEVEL_FATAL: level_str = "fatal"; break; + case LOG_LEVEL_TRACE: level_str = "trace"; break; + default: level_str = "notset"; break; } /// @note: 定义 __LOG_NO_COLOR__ 会取消颜色输出 #ifndef __LOG_NO_COLOR__ @@ -32,18 +28,19 @@ static int pos_log_handler(logger_t *module, log_level_t level, #endif /* clang-format on */ char buf[LOGGER_MAX_BUF_SIZE]; - int off = scc_snprintf(buf, sizeof(buf), "%s[%s]%s ", - color_code ? color_code : "", level_str, - color_code ? ANSI_NONE : ""); + + int offset = + scc_snprintf(module->buf, sizeof(module->buf), "%s[%s] %s - %s:%d:%d%s", + color_code ? color_code : "", level_str, module->name, + file, line, col, color_code ? ANSI_NONE : ""); va_list args; va_start(args, fmt); - scc_vsnprintf(buf + off, sizeof(buf) - off, fmt, args); + scc_vsnprintf(module->buf + offset, sizeof(module->buf) - offset, fmt, + args); va_end(args); log_puts(buf); - log_puts("\n"); - if (level == LOG_LEVEL_FATAL) { log_abort(); } @@ -52,6 +49,6 @@ static int pos_log_handler(logger_t *module, log_level_t level, logger_t __scc_pos_log = { .name = "pos_log", - .handler = pos_log_handler, + .user_handler = scc_log_handler, .level = LOG_LEVEL_ALL, }; diff --git a/runtime/scc_utils/include/scc_pos_log.h b/runtime/scc_utils/include/scc_pos_log.h deleted file mode 100644 index 3171cf3..0000000 --- a/runtime/scc_utils/include/scc_pos_log.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __SCC_POS_LOG_H__ -#define __SCC_POS_LOG_H__ - -#include "scc_pos.h" -#include - -extern logger_t __scc_pos_log; - -#define SCC_POS_LOG(level, pos, fmt, ...) \ - do { \ - char _full_msg[LOGGER_MAX_BUF_SIZE]; \ - int _n = scc_snprintf(_full_msg, sizeof(_full_msg), \ - scc_pos_pnt_fmt ": ", scc_pos_pnt_val(pos)); \ - scc_snprintf(_full_msg + _n, sizeof(_full_msg) - _n, fmt, \ - ##__VA_ARGS__); \ - __scc_pos_log.handler(&__scc_pos_log, level, nullptr, 0, nullptr, \ - "%s", _full_msg); \ - } while (0) - -#define SCC_DEBUG(pos, fmt, ...) \ - SCC_POS_LOG(LOG_LEVEL_DEBUG, pos, fmt, ##__VA_ARGS__) -#define SCC_INFO(pos, fmt, ...) \ - SCC_POS_LOG(LOG_LEVEL_INFO, pos, fmt, ##__VA_ARGS__) -#define SCC_WARN(pos, fmt, ...) \ - SCC_POS_LOG(LOG_LEVEL_WARN, pos, fmt, ##__VA_ARGS__) -#define SCC_ERROR(pos, fmt, ...) \ - SCC_POS_LOG(LOG_LEVEL_ERROR, pos, fmt, ##__VA_ARGS__) -#define SCC_FATAL(pos, fmt, ...) \ - SCC_POS_LOG(LOG_LEVEL_FATAL, pos, fmt, ##__VA_ARGS__) - -#endif /* __SCC_POS_LOG_H__ */ diff --git a/runtime/scc_utils/src/hashtable.c b/runtime/scc_utils/src/hashtable.c index 02df854..56c0a28 100644 --- a/runtime/scc_utils/src/hashtable.c +++ b/runtime/scc_utils/src/hashtable.c @@ -45,7 +45,8 @@ void scc_hashtable_usize_init(scc_hashtable_t *ht) { } static usize next_power_of_two(usize n) { - if (n == 0) return 32; + if (n == 0) + return 32; n--; n |= n >> 1; n |= n >> 2; @@ -56,8 +57,8 @@ static usize next_power_of_two(usize n) { return n + 1; } -static scc_hashtable_entry_t *find_entry(scc_hashtable_t *ht, const void *key, - u32 hash) { +static scc_hashtable_entry_t *find_entry(const scc_hashtable_t *ht, + const void *key, u32 hash) { if (ht->entries.cap == 0) return nullptr; diff --git a/src/bin/sccfdump.c b/src/bin/sccfdump.c index 727beff..0e8e1e9 100644 --- a/src/bin/sccfdump.c +++ b/src/bin/sccfdump.c @@ -1,5 +1,7 @@ -#include +#include + #include +#include void init_platform(void); @@ -20,67 +22,96 @@ typedef struct { static const char *arch_name(sccf_enum_t arch) { switch (arch) { - case SCCF_ARCH_UNKNOWN: return "UNKNOWN"; - case SCCF_ARCH_RISCV32: return "RISC-V 32"; - case SCCF_ARCH_RISCV64: return "RISC-V 64"; - case SCCF_ARCH_X86: return "x86"; - case SCCF_ARCH_AMD64: return "AMD64"; - default: return "UNKNOWN"; + case SCCF_ARCH_UNKNOWN: + return "UNKNOWN"; + case SCCF_ARCH_RISCV32: + return "RISC-V 32"; + case SCCF_ARCH_RISCV64: + return "RISC-V 64"; + case SCCF_ARCH_X86: + return "x86"; + case SCCF_ARCH_AMD64: + return "AMD64"; + default: + return "UNKNOWN"; } } static const char *type_name(sccf_enum_t type) { switch (type) { - case SCCF_TYPE_FLAG_EXECUTABLE: return "executable"; - case SCCF_TYPE_FLAG_RELOCATABLE: return "relocatable"; - case SCCF_TYPE_FLAG_EXE_RELOC: return "exe+reloc"; - default: return "UNKNOWN"; + case SCCF_TYPE_FLAG_EXECUTABLE: + return "executable"; + case SCCF_TYPE_FLAG_RELOCATABLE: + return "relocatable"; + case SCCF_TYPE_FLAG_EXE_RELOC: + return "exe+reloc"; + default: + return "UNKNOWN"; } } static const char *sect_type_name(sccf_enum_t t) { switch (t) { - case SCCF_SECT_NONE: return "NONE"; - case SCCF_SECT_CODE: return "CODE"; - case SCCF_SECT_DATA: return "DATA"; - case SCCF_SECT_RODATA: return "RODATA"; - case SCCF_SECT_UNINIT_DATA: return "BSS"; - case SCCF_SECT_SYMTAB: return "SYMTAB"; - case SCCF_SECT_STRTAB: return "STRTAB"; - case SCCF_SECT_RELOCS: return "RELOCS"; - default: return "UNKNOWN"; + case SCCF_SECT_NONE: + return "NONE"; + case SCCF_SECT_CODE: + return "CODE"; + case SCCF_SECT_DATA: + return "DATA"; + case SCCF_SECT_RODATA: + return "RODATA"; + case SCCF_SECT_UNINIT_DATA: + return "BSS"; + case SCCF_SECT_SYMTAB: + return "SYMTAB"; + case SCCF_SECT_STRTAB: + return "STRTAB"; + case SCCF_SECT_RELOCS: + return "RELOCS"; + default: + return "UNKNOWN"; } } static const char *sym_type_name(sccf_enum_t t) { switch (t) { - case SCCF_SYM_TYPE_UNDEF: return "UNDEF"; - case SCCF_SYM_TYPE_FUNC: return "FUNC"; - case SCCF_SYM_TYPE_DATA: return "DATA"; - case SCCF_SYM_TYPE_EXTERN: return "EXTERN"; - default: return "?"; + case SCCF_SYM_TYPE_UNDEF: + return "UNDEF"; + case SCCF_SYM_TYPE_FUNC: + return "FUNC"; + case SCCF_SYM_TYPE_DATA: + return "DATA"; + case SCCF_SYM_TYPE_EXTERN: + return "EXTERN"; + default: + return "?"; } } static const char *sym_bind_name(sccf_enum_t b) { switch (b) { - case SCCF_SYM_BIND_LOCAL: return "LOCAL"; - case SCCF_SYM_BIND_GLOBAL: return "GLOBAL"; - case SCCF_SYM_BIND_WEAK: return "WEAK"; - default: return "?"; + case SCCF_SYM_BIND_LOCAL: + return "LOCAL"; + case SCCF_SYM_BIND_GLOBAL: + return "GLOBAL"; + case SCCF_SYM_BIND_WEAK: + return "WEAK"; + default: + return "?"; } } static void dump_header(const sccf_header_t *hdr) { scc_printf("header:\n"); - scc_printf(" magic: %c%c%c%c%c%c%c%c\n", - hdr->magic[0], hdr->magic[1], hdr->magic[2], hdr->magic[3], - hdr->magic[4], hdr->magic[5], hdr->magic[6], hdr->magic[7]); + scc_printf(" magic: %c%c%c%c%c%c%c%c\n", hdr->magic[0], hdr->magic[1], + hdr->magic[2], hdr->magic[3], hdr->magic[4], hdr->magic[5], + hdr->magic[6], hdr->magic[7]); scc_printf(" type: %u (%s)\n", hdr->type, type_name(hdr->type)); scc_printf(" version: %u\n", hdr->version); scc_printf(" arch: %u (%s)\n", hdr->arch, arch_name(hdr->arch)); scc_printf(" entry: 0x%llx\n", (unsigned long long)hdr->entry_point); - scc_printf(" sect_count: %llu\n", (unsigned long long)hdr->sect_header_num); + scc_printf(" sect_count: %llu\n", + (unsigned long long)hdr->sect_header_num); } static void dump_sections(u8 *base) { @@ -88,14 +119,14 @@ static void dump_sections(u8 *base) { scc_printf("sections:\n"); for (usize i = 0; i < (usize)hdr->sect_header_num; i++) { const sccf_sect_header_t *sh = sccf_sect_header(base, i); - if (!sh) break; - scc_printf(" [%-2llu] %-8s size=%-8llu data_sz=%-8llu align=%-8llu name=%.8s\n", - (unsigned long long)i, - sect_type_name(sh->sccf_sect_type), - (unsigned long long)sh->size, - (unsigned long long)sh->data_size, - (unsigned long long)sh->addralign, - sh->name); + if (!sh) + break; + scc_printf(" [%-2llu] %-8s size=%-8llu data_sz=%-8llu align=%-8llu " + "name=%.8s\n", + (unsigned long long)i, sect_type_name(sh->sccf_sect_type), + (unsigned long long)sh->size, + (unsigned long long)sh->data_size, + (unsigned long long)sh->addralign, sh->name); } } @@ -106,7 +137,7 @@ static void dump_symbols(u8 *base) { return; } usize str_idx = sccf_find_sect_by_type(base, SCCF_SECT_STRTAB); - const char *strtab = NULL; + const char *strtab = nullptr; if (str_idx < ((const sccf_header_t *)base)->sect_header_num) { strtab = (const char *)sccf_sect_data(base, str_idx); } @@ -119,12 +150,10 @@ static void dump_symbols(u8 *base) { for (usize i = 0; i < count; i++) { const char *name = strtab ? strtab + syms[i].name_offset : ""; scc_printf(" [%-2llu] %-8s %-6s %-8s 0x%-6llx %s\n", - (unsigned long long)i, - sym_type_name(syms[i].sccf_sym_type), - sym_bind_name(syms[i].sccf_sym_bind), - sect_type_name(syms[i].sccf_sect_type), - (unsigned long long)syms[i].sccf_sect_offset, - name); + (unsigned long long)i, sym_type_name(syms[i].sccf_sym_type), + sym_bind_name(syms[i].sccf_sym_bind), + sect_type_name(syms[i].sccf_sect_type), + (unsigned long long)syms[i].sccf_sect_offset, name); } } @@ -137,16 +166,17 @@ static void dump_relocs(u8 *base) { const sccf_sect_header_t *sh = sccf_sect_header(base, reloc_idx); usize count = sh->size / sizeof(sccf_reloc_t); - const sccf_reloc_t *relocs = (const sccf_reloc_t *)sccf_sect_data(base, reloc_idx); + const sccf_reloc_t *relocs = + (const sccf_reloc_t *)sccf_sect_data(base, reloc_idx); scc_printf("relocations:\n"); for (usize i = 0; i < count; i++) { - scc_printf(" [%-2llu] type=%-3u sect=%-8s sym=%-2llu offset=0x%-6llx\n", - (unsigned long long)i, - relocs[i].reloc_type, - sect_type_name(relocs[i].sect_type), - (unsigned long long)relocs[i].sym_idx, - (unsigned long long)relocs[i].offset); + scc_printf( + " [%-2llu] type=%-3u sect=%-8s sym=%-2llu offset=0x%-6llx\n", + (unsigned long long)i, relocs[i].reloc_type, + sect_type_name(relocs[i].sect_type), + (unsigned long long)relocs[i].sym_idx, + (unsigned long long)relocs[i].offset); } } @@ -160,19 +190,23 @@ static void dump_hex(u8 *base, int verbose) { continue; u8 *data = sccf_sect_data(base, i); - if (!data || sh->size == 0) continue; + if (!data || sh->size == 0) + continue; scc_printf("section [%-2llu] %.8s (%llu bytes):\n", - (unsigned long long)i, sh->name, (unsigned long long)sh->size); + (unsigned long long)i, sh->name, + (unsigned long long)sh->size); usize limit = verbose ? sh->size : (sh->size > 256 ? 256 : sh->size); for (usize j = 0; j < limit; j++) { - if (j % 16 == 0) scc_printf(" %08llx: ", (unsigned long long)j); + if (j % 16 == 0) + scc_printf(" %08llx: ", (unsigned long long)j); scc_printf("%02x ", data[j]); - if ((j + 1) % 16 == 0 || j + 1 == limit) scc_printf("\n"); + if ((j + 1) % 16 == 0 || j + 1 == limit) + scc_printf("\n"); } if (limit < sh->size) scc_printf(" ... (%llu more bytes)\n", - (unsigned long long)(sh->size - limit)); + (unsigned long long)(sh->size - limit)); } } @@ -240,7 +274,8 @@ int main(int argc, const char **argv, const char **envp) { config.get_section_idx = -1; scc_argparse_t argparse; - scc_argparse_init(&argparse, hints[HINT_PROG_NAME], hints[HINT_DESCRIPTION]); + scc_argparse_init(&argparse, hints[HINT_PROG_NAME], + hints[HINT_DESCRIPTION]); argparse.lang = lang; scc_argparse_cmd_t *root = scc_argparse_get_root(&argparse); @@ -286,13 +321,17 @@ int main(int argc, const char **argv, const char **envp) { scc_argparse_cmd_add_opt(root, &opt_verbose); scc_argparse_opt_t opt_get_section; - scc_argparse_opt_init(&opt_get_section, 0, "get-section", hints[HINT_GET_SECTION]); - scc_argparse_spec_setup_string(&opt_get_section.spec, &config.get_section_name); + scc_argparse_opt_init(&opt_get_section, 0, "get-section", + hints[HINT_GET_SECTION]); + scc_argparse_spec_setup_string(&opt_get_section.spec, + &config.get_section_name); scc_argparse_cmd_add_opt(root, &opt_get_section); scc_argparse_opt_t opt_get_section_idx; - scc_argparse_opt_init(&opt_get_section_idx, 0, "get-section-idx", hints[HINT_GET_SECTION_IDX]); - scc_argparse_spec_setup_int(&opt_get_section_idx.spec, &config.get_section_idx); + scc_argparse_opt_init(&opt_get_section_idx, 0, "get-section-idx", + hints[HINT_GET_SECTION_IDX]); + scc_argparse_spec_setup_int(&opt_get_section_idx.spec, + &config.get_section_idx); scc_argparse_cmd_add_opt(root, &opt_get_section_idx); scc_argparse_arg_t arg_file; @@ -310,14 +349,14 @@ int main(int argc, const char **argv, const char **envp) { scc_file_t fp = scc_fopen(config.filepath, SCC_FILE_READ); if (!fp) { - LOG_ERROR("cannot open %s", config.filepath); + SCC_ERROR((scc_pos_t){0}, "cannot open %s", config.filepath); return 1; } usize fsize = scc_fsize(fp); if (fsize < sizeof(sccf_header_t)) { - LOG_ERROR("file too small: %s (%llu bytes)", config.filepath, - (unsigned long long)fsize); + SCC_ERROR((scc_pos_t){0}, "file too small: %s (%llu bytes)", + config.filepath, (unsigned long long)fsize); scc_fclose(fp); return 1; } @@ -328,7 +367,7 @@ int main(int argc, const char **argv, const char **envp) { usize nread = scc_fread(fp, scc_vec_unsafe_get_data(buf), fsize); scc_fclose(fp); if (nread != fsize) { - LOG_ERROR("short read %s", config.filepath); + SCC_ERROR((scc_pos_t){0}, "short read %s", config.filepath); scc_vec_free(buf); return 1; } @@ -347,14 +386,15 @@ int main(int argc, const char **argv, const char **envp) { const sccf_header_t *hdr = (const sccf_header_t *)base; for (usize i = 0; i < (usize)hdr->sect_header_num; i++) { const sccf_sect_header_t *sh = sccf_sect_header(base, i); - if (sh && scc_memcmp(sh->name, - config.get_section_name, 8) == 0) { + if (sh && + scc_memcmp(sh->name, config.get_section_name, 8) == 0) { idx = i; break; } } if (idx == (usize)-1) { - LOG_ERROR("section not found: %s", config.get_section_name); + SCC_ERROR((scc_pos_t){0}, "section not found: %s", + config.get_section_name); scc_vec_free(buf); return 1; } @@ -362,7 +402,8 @@ int main(int argc, const char **argv, const char **envp) { const sccf_sect_header_t *sh = sccf_sect_header(base, idx); if (!sh) { - LOG_ERROR("invalid section index: %d", config.get_section_idx); + SCC_ERROR((scc_pos_t){0}, "invalid section index: %d", + config.get_section_idx); scc_vec_free(buf); return 1; } @@ -377,7 +418,8 @@ int main(int argc, const char **argv, const char **envp) { } else if (config.output) { scc_file_t ofp = scc_fopen(config.output, SCC_FILE_WRITE); if (!ofp) { - LOG_ERROR("cannot open output: %s", config.output); + SCC_ERROR((scc_pos_t){0}, "cannot open output: %s", + config.output); scc_vec_free(buf); return 1; } @@ -398,12 +440,17 @@ int main(int argc, const char **argv, const char **envp) { dump_symbols(base); dump_relocs(base); } else { - if (config.dump_header) dump_header(&sccf.header); - if (config.dump_sections) dump_sections(base); - if (config.dump_symbols) dump_symbols(base); - if (config.dump_relocs) dump_relocs(base); + if (config.dump_header) + dump_header(&sccf.header); + if (config.dump_sections) + dump_sections(base); + if (config.dump_symbols) + dump_symbols(base); + if (config.dump_relocs) + dump_relocs(base); } - if (config.dump_hex) dump_hex(base, config.verbose); + if (config.dump_hex) + dump_hex(base, config.verbose); scc_vec_free(buf); return 0; diff --git a/src/cmd_log.h b/src/cmd_log.h new file mode 100644 index 0000000..2239de5 --- /dev/null +++ b/src/cmd_log.h @@ -0,0 +1,25 @@ +#ifndef __SCC_CMD_LOG_H__ +#define __SCC_CMD_LOG_H__ +typedef struct logger logger_t; +extern logger_t __scc_cmd_log; +extern logger_t __scc_cmd_user; + +#define SCC_LOG_HANDLER &__scc_cmd_user +#define LOG_DEFAULT_HANDLER &__scc_cmd_log +#include + +#ifdef __SCC_CMD_LOG_IMPL__ +logger_t __scc_cmd_log = { + .name = "scc", + .level = LOG_LEVEL_ALL, + .handler = log_default_handler, +}; + +logger_t __scc_cmd_user = { + .name = "scc", + .level = LOG_LEVEL_ALL, + .user_handler = scc_log_handler, +}; +#endif + +#endif diff --git a/src/config.c b/src/config.c index 4484ad4..1e71976 100644 --- a/src/config.c +++ b/src/config.c @@ -9,6 +9,7 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, SCC_HINT_INPUT_FILE, SCC_HINT_INCLUDE_PATH, SCC_HINT_DEFINED_MACRO, + SCC_HINT_LOG_CONFIG, SCC_HINT_TARGET_DESC, SCC_HINT_VERBOSE, @@ -35,6 +36,7 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, [SCC_HINT_INPUT_FILE] = "Input source file", [SCC_HINT_INCLUDE_PATH] = "Add directory to the include search paths", [SCC_HINT_DEFINED_MACRO] = "Define a macro", + [SCC_HINT_LOG_CONFIG] = "Set per-module log level (eg. --log pproc=debug)", [SCC_HINT_TARGET_DESC] = "Target description(eg. x86_64-pc-windows-msvc)", [SCC_HINT_VERBOSE] = "Increase verbosity (can be used multiple times)", @@ -62,6 +64,7 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, [SCC_HINT_INPUT_FILE] = "输入源文件", [SCC_HINT_INCLUDE_PATH] = "添加系统头文件到搜索路径", [SCC_HINT_DEFINED_MACRO] = "定义宏", + [SCC_HINT_LOG_CONFIG] = "设置模块日志级别 (eg. --log pproc=debug)", [SCC_HINT_TARGET_DESC] = "目标机器描述(eg. x86_64-pc-windows-msvc)", [SCC_HINT_VERBOSE] = "增加详细输出(可多次使用)", @@ -106,10 +109,10 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, scc_argparse_spec_setup_string(&opt_output.spec, &(config->output_file)); scc_argparse_cmd_add_opt(root, &opt_output); - // input file (必需) + // input file(s) (必需, 支持多个) scc_argparse_arg_t arg_input; scc_argparse_arg_init(&arg_input, "input", scc_hints[SCC_HINT_INPUT_FILE]); - scc_argparse_spec_setup_string(&arg_input.spec, &(config->input_file)); + scc_argparse_spec_setup_list(&arg_input.spec, &(config->input_files)); scc_argparse_spec_set_required(&arg_input.spec, true); scc_argparse_cmd_add_arg(root, &arg_input); @@ -127,6 +130,13 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, scc_argparse_spec_setup_list(&opt_define.spec, &(config->define_macros)); scc_argparse_cmd_add_opt(root, &opt_define); + // --log (设置模块日志级别) + scc_argparse_opt_t opt_log; + scc_argparse_opt_init(&opt_log, 0, "log", + scc_hints[SCC_HINT_LOG_CONFIG]); + scc_argparse_spec_setup_list(&opt_log.spec, &(config->log_configs)); + scc_argparse_cmd_add_opt(root, &opt_log); + // --entry-point-symbol (设置入口点符号名称) scc_argparse_opt_t opt_entry_point_symbol; scc_argparse_opt_init(&opt_entry_point_symbol, 0, "entry-point-symbol", diff --git a/src/config.h b/src/config.h index 58c1e91..78416a9 100644 --- a/src/config.h +++ b/src/config.h @@ -23,12 +23,13 @@ typedef enum scc_emit_stage { } scc_emit_stage_t; typedef struct { - const char *input_file; + scc_argparse_list_t input_files; const char *output_file; const char *target_description; int verbose; scc_argparse_list_t include_paths; scc_argparse_list_t define_macros; + scc_argparse_list_t log_configs; /* --log module=level */ const char *entry_point_symbol; scc_emit_stage_t emit_stage; diff --git a/src/main.c b/src/main.c index ce5244d..475b8d6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,6 @@ +#define __SCC_CMD_LOG_IMPL__ +#include "cmd_log.h" + #include #include #include @@ -16,6 +19,7 @@ #include #include #include +#include #define __SCC_TYPE_ABI_WIN_X64_IMPL__ #include @@ -71,6 +75,7 @@ static void print_file(scc_lexer_tok_ring_t *ring, scc_file_t fp) { static void tree_dump_output(const char *str, usize len, void *user) { scc_fprintf(user, "%.*s", (int)len, str); } + static inline int mir_dump(scc_file_t fp, scc_mir_module_t *mir_module) { scc_tree_dump_t tree_dump; scc_mir_dump_ctx_t mir_dump_ctx; @@ -87,85 +92,35 @@ static inline int mir_dump(scc_file_t fp, scc_mir_module_t *mir_module) { return 0; } -int main(int argc, const char **argv, const char **envp) { - init_platform(); - -#ifndef SCC_DEFAULT_ARGPARSE_LANG -#define SCC_DEFAULT_ARGPARSE_LANG SCC_ARGPARSE_LANG_ZH -#endif - - scc_argparse_lang_t argparse_lang = SCC_DEFAULT_ARGPARSE_LANG; - for (const char **env = envp; *env != nullptr; env++) { - const char *env_str = *env; - if (scc_strcmp(env_str, "LANG=zh_CN.UTF-8") == 0) { - argparse_lang = SCC_ARGPARSE_LANG_ZH; - } - } - - scc_config_t config = { - .input_file = nullptr, - .verbose = 0, - .output_file = nullptr, - .entry_point_symbol = nullptr, - .emit_stage = SCC_EMIT_STAGE_DEFAULT, - .target_description = "x86_64-pc-windows-msvc", - }; - scc_vec_init(config.include_paths); - - scc_argparse_t argparse; - setup_argparse(&argparse, &config, argparse_lang); - int ret = scc_argparse_parse(&argparse, argc, argv); - if (ret != 0) { - scc_argparse_drop(&argparse); - return 0; - } - scc_argparse_drop(&argparse); - - scc_file_t fp = nullptr; - if (config.output_file) { - cbool is_stdout = scc_strcmp(config.output_file, "-") == 0; - if (!is_stdout) { - fp = scc_fopen(config.output_file, SCC_FILE_WRITE); - if (fp == nullptr) { - LOG_FATAL("Failed to open file %s", config.output_file); - return 1; - } - } else { - fp = scc_stdout; - } - } - +// Compile a single source file to an SCCF builder. +// Returns 0 on success, non-zero on error. +// The caller must keep the builder alive until after linking. +static int compile_file_to_sccf(const char *input_file, scc_config_t *config, + sccf_builder_t *builder) { int error_code = 0; - cbool need_end = false; scc_sstream_t sstream; - error_code = scc_sstream_init(&sstream, config.input_file, 1024); + error_code = scc_sstream_init(&sstream, input_file, 1024); if (error_code) { - goto sstream_drop; - need_end = true; + return error_code; } + LOG_INFO("=== phase 1/6: lexing '%s' ===", input_file); scc_lexer_t lexer; scc_lexer_init(&lexer, scc_sstream_to_ring(&sstream)); - if (config.emit_stage == SCC_EMIT_STAGE_LEX) { - scc_lexer_tok_ring_t *tok_ring = - scc_lexer_to_ring(&lexer, 8, fp == nullptr ? false : true); - if (fp == nullptr) { - print_ring(tok_ring, config.verbose); - } else { - print_file(tok_ring, fp); - } - scc_lexer_drop_ring(tok_ring); - need_end = true; - goto lexer_drop; + if (config->emit_stage == SCC_EMIT_STAGE_LEX) { + // Early-lex is handled per-file at call site + scc_lexer_drop(&lexer); + scc_sstream_drop(&sstream); + return -1; } + LOG_INFO("=== phase 2/6: preprocessing '%s' ===", input_file); scc_pproc_t pproc; scc_pproc_init(&pproc, scc_lexer_to_ring(&lexer, 8, true)); - // FIXME maybe using config to got download path and add include path scc_pproc_add_include_path_cstr(&pproc, "./.scc_include"); - scc_vec_foreach(config.include_paths, i) { + scc_vec_foreach(config->include_paths, i) { scc_pproc_add_include_path_cstr(&pproc, - scc_vec_at(config.include_paths, i)); + scc_vec_at(config->include_paths, i)); } scc_lexer_tok_vec_t pproc_tok_vec; scc_vec_init(pproc_tok_vec); @@ -191,20 +146,10 @@ int main(int argc, const char **argv, const char **envp) { scc_pproc_add_object_macro(&pproc.macro_table, &pproc_predefined_macros[i], &pproc_tok_vec); } - if (config.emit_stage == SCC_EMIT_STAGE_PP) { - scc_lexer_tok_ring_t *tok_ring = - scc_pproc_to_ring(&pproc, 8, true, true); - if (fp == nullptr) { - print_ring(tok_ring, config.verbose); - } else { - print_file(tok_ring, fp); - } - need_end = true; - goto pproc_drop; - } scc_lexer_tok_ring_t *tok_ring = scc_pproc_to_ring(&pproc, 1024, false, false); + LOG_INFO("=== phase 3/6: parsing '%s' ===", input_file); scc_parser_t parser; scc_ast_module_t ast_module; scc_ast_module_init(&ast_module); @@ -214,34 +159,11 @@ int main(int argc, const char **argv, const char **envp) { scc_ast_translation_unit_t *translation_unit = scc_parse_translation_unit(&parser); if (parser.errcode != 0) { - return parser.errcode; - } - - scc_sema_drop(&sema_ctx); - scc_parser_drop(&parser); -pproc_drop: - scc_pproc_drop(&pproc); -lexer_drop: - scc_lexer_drop(&lexer); -sstream_drop: - scc_sstream_drop(&sstream); - if (error_code || need_end) { - return error_code; - } - - if (config.emit_stage == SCC_EMIT_STAGE_AST) { - scc_tree_dump_t tree_dump; - if (fp == nullptr) { - scc_tree_dump_init(&tree_dump, true); - } else { - scc_tree_dump_init(&tree_dump, false); - } - scc_ast_dump_node(&tree_dump, (scc_ast_node_t *)translation_unit); - scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp)); - scc_tree_dump_drop(&tree_dump); - return 0; + error_code = parser.errcode; + goto cleanup_pproc; } + LOG_INFO("=== phase 4/6: AST -> HIR ==="); scc_ast2ir_ctx_t ast2ir_ctx; scc_hir_cprog_t cprog; scc_hir_cprog_init(&cprog, &SCC_TYPE_ABI_WIN_X64); @@ -250,112 +172,366 @@ sstream_drop: scc_ast2ir_run(&ast2ir_ctx, translation_unit); scc_ast2ir_ctx_drop(&ast2ir_ctx); - if (config.emit_stage == SCC_EMIT_STAGE_HIR) { - scc_hir_dump_t ir_dump_ctx; - scc_tree_dump_t tree_dump; - if (fp == nullptr) { - scc_tree_dump_init(&tree_dump, true); - } else { - scc_tree_dump_init(&tree_dump, false); - } - scc_hir_dump_init(&ir_dump_ctx, &tree_dump, &cprog); - // scc_ir_dump_cprog(&ir_dump_ctx); - scc_hir_dump_cprog_linear(&ir_dump_ctx); - - scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp)); - scc_tree_dump_drop(&tree_dump); - return 0; - } - + LOG_INFO("=== phase 5/6: HIR -> LIR -> MIR ==="); + // HIR -> LIR scc_lir_module_t lir_module; scc_lir_module_init(&lir_module); scc_hir2lir(&lir_module, &cprog); - if (config.emit_stage == SCC_EMIT_STAGE_LIR) { - scc_lir_dump_ctx_t lir_dump_ctx; - scc_tree_dump_t tree_dump; - if (fp == nullptr) { - scc_tree_dump_init(&tree_dump, true); - } else { - scc_tree_dump_init(&tree_dump, false); - } - scc_lir_dump_init(&lir_dump_ctx, &tree_dump, &lir_module); - // scc_ir_dump_cprog(&ir_dump_ctx); - scc_lir_dump_module(&lir_dump_ctx); - - scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp)); - scc_tree_dump_drop(&tree_dump); - return 0; - } + // LIR -> MIR scc_mir_module_t mir_module; scc_mir_module_init(&mir_module); scc_lir2mir(&mir_module, &lir_module); - switch (config.emit_stage) { - case SCC_EMIT_STAGE_MIR: - return mir_dump(fp, &mir_module); - case SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC: - scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC); - return mir_dump(fp, &mir_module); - case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT: - scc_mir_pass(&mir_module, SCC_MIR_STAGE_FRAME_LAYOUT); - return mir_dump(fp, &mir_module); - case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG: - scc_mir_pass(&mir_module, SCC_MIR_STAGE_PROLOGUE_EPILOGUE); - return mir_dump(fp, &mir_module); - default: - scc_mir_pass(&mir_module, SCC_MIR_STAGE_ANY); - break; + // MIR passes + scc_mir_pass(&mir_module, SCC_MIR_STAGE_ANY); + + LOG_INFO("=== phase 6/6: MIR -> SCCF ==="); + // MIR -> SCCF + // NOTE: scc_ir2sccf calls sccf_builder_init(builder) internally + scc_ir2sccf(builder, &mir_module); + + // Cleanup per-file resources (reverse order) + scc_mir_module_drop(&mir_module); + scc_lir_module_drop(&lir_module); + scc_hir_cprog_drop(&cprog); + scc_sema_drop(&sema_ctx); + scc_parser_drop(&parser); + scc_pproc_drop(&pproc); + scc_lexer_drop(&lexer); + scc_sstream_drop(&sstream); + + return 0; + +cleanup_pproc: + scc_pproc_drop(&pproc); + scc_lexer_drop(&lexer); + scc_sstream_drop(&sstream); + return error_code; +} + +int main(int argc, const char **argv, const char **envp) { + init_platform(); + +#ifndef SCC_DEFAULT_ARGPARSE_LANG +#define SCC_DEFAULT_ARGPARSE_LANG SCC_ARGPARSE_LANG_ZH +#endif + + scc_argparse_lang_t argparse_lang = SCC_DEFAULT_ARGPARSE_LANG; + for (const char **env = envp; *env != nullptr; env++) { + const char *env_str = *env; + if (scc_strcmp(env_str, "LANG=zh_CN.UTF-8") == 0) { + argparse_lang = SCC_ARGPARSE_LANG_ZH; + } } - if (config.emit_stage == SCC_EMIT_STAGE_FLATBIN) { - scc_mcode_t mcode = {0}; - scc_mcode_init(&mcode, SCC_MCODE_ARCH_X86_64); - scc_ir2mcode(&mcode, nullptr, &mir_module); - if (fp == nullptr) { - LOG_WARN("emit flatbin can't write to stdout"); + scc_config_t config = { + .verbose = 0, + .output_file = nullptr, + .entry_point_symbol = nullptr, + .emit_stage = SCC_EMIT_STAGE_DEFAULT, + .target_description = "x86_64-pc-windows-msvc", + }; + scc_vec_init(config.input_files); + scc_vec_init(config.include_paths); + scc_vec_init(config.define_macros); + scc_vec_init(config.log_configs); + + scc_argparse_t argparse; + setup_argparse(&argparse, &config, argparse_lang); + int ret = scc_argparse_parse(&argparse, argc, argv); + if (ret != 0) { + scc_argparse_drop(&argparse); + return 0; + } + scc_argparse_drop(&argparse); + + // // Apply log configuration from --log and -v + // scc_log_set_verbosity(config.verbose); + // scc_vec_foreach(config.log_configs, i) { + // scc_log_apply_config(scc_vec_at(config.log_configs, i)); + // } + + usize num_inputs = scc_vec_size(config.input_files); + if (num_inputs == 0) { + LOG_ERROR("no input files"); + return 1; + } + + scc_file_t fp = nullptr; + if (config.output_file) { + cbool is_stdout = scc_strcmp(config.output_file, "-") == 0; + if (!is_stdout) { + fp = scc_fopen(config.output_file, SCC_FILE_WRITE); + if (fp == nullptr) { + LOG_FATAL("Failed to open file %s", config.output_file); + return 1; + } + } else { + fp = scc_stdout; + } + } + + // Single-file mode: original fast path + if (num_inputs == 1) { + const char *input_file = scc_vec_at(config.input_files, 0); + + scc_sstream_t sstream; + int error_code = scc_sstream_init(&sstream, input_file, 1024); + if (error_code) { + return error_code; + } + + scc_lexer_t lexer; + scc_lexer_init(&lexer, scc_sstream_to_ring(&sstream)); + if (config.emit_stage == SCC_EMIT_STAGE_LEX) { + scc_lexer_tok_ring_t *tok_ring = + scc_lexer_to_ring(&lexer, 8, fp == nullptr ? false : true); + if (fp == nullptr) { + print_ring(tok_ring, config.verbose); + } else { + print_file(tok_ring, fp); + } + scc_lexer_drop_ring(tok_ring); + scc_lexer_drop(&lexer); + scc_sstream_drop(&sstream); return 0; } - usize mcode_size = scc_mcode_size(&mcode); - usize ret = scc_fwrite(fp, scc_mcode_unsafe_data(&mcode), mcode_size); - if (ret != mcode_size) { - LOG_ERROR("write flatbin failed, write %zu but need write %zu\n", - ret, mcode_size); - return 1; + + scc_pproc_t pproc; + scc_pproc_init(&pproc, scc_lexer_to_ring(&lexer, 8, true)); + scc_pproc_add_include_path_cstr(&pproc, "./.scc_include"); + scc_vec_foreach(config.include_paths, i) { + scc_pproc_add_include_path_cstr( + &pproc, scc_vec_at(config.include_paths, i)); } - return 0; + scc_lexer_tok_vec_t pproc_tok_vec; + scc_vec_init(pproc_tok_vec); + scc_lexer_tok_t tok = { + .lexeme = scc_str_from_cstr("1"), + .type = SCC_TOK_INT_LITERAL, + .loc.name = "", + .loc.line = 0, + .loc.col = 0, + .loc.offset = 0, + }; + scc_vec_push(pproc_tok_vec, tok); + scc_str_t pproc_predefined_macros[] = { + scc_str_from_cstr("__SCC__"), + scc_str_from_cstr("_WIN64"), + scc_str_from_cstr("_WIN32"), + scc_str_from_cstr("__x86_64__"), + }; + for (usize i = 0; i < SCC_ARRLEN(pproc_predefined_macros); i += 1) { + scc_vec_init(pproc_tok_vec); + scc_lexer_tok_t coped_tok = scc_lexer_tok_copy(&tok); + scc_vec_push(pproc_tok_vec, coped_tok); + scc_pproc_add_object_macro(&pproc.macro_table, + &pproc_predefined_macros[i], + &pproc_tok_vec); + } + if (config.emit_stage == SCC_EMIT_STAGE_PP) { + scc_lexer_tok_ring_t *tok_ring = + scc_pproc_to_ring(&pproc, 8, true, true); + if (fp == nullptr) { + print_ring(tok_ring, config.verbose); + } else { + print_file(tok_ring, fp); + } + scc_pproc_drop(&pproc); + scc_lexer_drop(&lexer); + scc_sstream_drop(&sstream); + return 0; + } + + scc_lexer_tok_ring_t *tok_ring = + scc_pproc_to_ring(&pproc, 1024, false, false); + scc_parser_t parser; + scc_ast_module_t ast_module; + scc_ast_module_init(&ast_module); + scc_sema_ctx_t sema_ctx; + scc_sema_init(&sema_ctx, &ast_module); + scc_parser_init(&parser, tok_ring, &ast_module, &sema_ctx); + scc_ast_translation_unit_t *translation_unit = + scc_parse_translation_unit(&parser); + if (parser.errcode != 0) { + scc_sema_drop(&sema_ctx); + scc_parser_drop(&parser); + scc_pproc_drop(&pproc); + scc_lexer_drop(&lexer); + scc_sstream_drop(&sstream); + return parser.errcode; + } + + scc_sema_drop(&sema_ctx); + scc_parser_drop(&parser); + scc_pproc_drop(&pproc); + scc_lexer_drop(&lexer); + scc_sstream_drop(&sstream); + + if (config.emit_stage == SCC_EMIT_STAGE_AST) { + scc_tree_dump_t tree_dump; + if (fp == nullptr) { + scc_tree_dump_init(&tree_dump, true); + } else { + scc_tree_dump_init(&tree_dump, false); + } + scc_ast_dump_node(&tree_dump, (scc_ast_node_t *)translation_unit); + scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp)); + scc_tree_dump_drop(&tree_dump); + return 0; + } + + scc_ast2ir_ctx_t ast2ir_ctx; + scc_hir_cprog_t cprog; + scc_hir_cprog_init(&cprog, &SCC_TYPE_ABI_WIN_X64); + scc_ast2ir_ctx_init(&ast2ir_ctx, &SCC_TYPE_ABI_WIN_X64, &ast_module, + &cprog); + scc_ast2ir_run(&ast2ir_ctx, translation_unit); + scc_ast2ir_ctx_drop(&ast2ir_ctx); + + if (config.emit_stage == SCC_EMIT_STAGE_HIR) { + scc_hir_dump_t ir_dump_ctx; + scc_tree_dump_t tree_dump; + if (fp == nullptr) { + scc_tree_dump_init(&tree_dump, true); + } else { + scc_tree_dump_init(&tree_dump, false); + } + scc_hir_dump_init(&ir_dump_ctx, &tree_dump, &cprog); + scc_hir_dump_cprog_linear(&ir_dump_ctx); + + scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp)); + scc_tree_dump_drop(&tree_dump); + return 0; + } + + scc_lir_module_t lir_module; + scc_lir_module_init(&lir_module); + scc_hir2lir(&lir_module, &cprog); + if (config.emit_stage == SCC_EMIT_STAGE_LIR) { + scc_lir_dump_ctx_t lir_dump_ctx; + scc_tree_dump_t tree_dump; + if (fp == nullptr) { + scc_tree_dump_init(&tree_dump, true); + } else { + scc_tree_dump_init(&tree_dump, false); + } + scc_lir_dump_init(&lir_dump_ctx, &tree_dump, &lir_module); + scc_lir_dump_module(&lir_dump_ctx); + + scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp)); + scc_tree_dump_drop(&tree_dump); + return 0; + } + + scc_mir_module_t mir_module; + scc_mir_module_init(&mir_module); + scc_lir2mir(&mir_module, &lir_module); + + switch (config.emit_stage) { + case SCC_EMIT_STAGE_MIR: + return mir_dump(fp, &mir_module); + case SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC: + scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC); + return mir_dump(fp, &mir_module); + case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT: + scc_mir_pass(&mir_module, SCC_MIR_STAGE_FRAME_LAYOUT); + return mir_dump(fp, &mir_module); + case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG: + scc_mir_pass(&mir_module, SCC_MIR_STAGE_PROLOGUE_EPILOGUE); + return mir_dump(fp, &mir_module); + default: + scc_mir_pass(&mir_module, SCC_MIR_STAGE_ANY); + break; + } + + if (config.emit_stage == SCC_EMIT_STAGE_FLATBIN) { + scc_mcode_t mcode = {0}; + scc_mcode_init(&mcode, SCC_MCODE_ARCH_X86_64); + scc_ir2mcode(&mcode, nullptr, &mir_module); + if (fp == nullptr) { + LOG_WARN("emit flatbin can't write to stdout"); + return 0; + } + usize mcode_size = scc_mcode_size(&mcode); + usize fwritten = + scc_fwrite(fp, scc_mcode_unsafe_data(&mcode), mcode_size); + if (fwritten != mcode_size) { + LOG_ERROR("write flatbin failed, write %zu but need %zu", + fwritten, mcode_size); + return 1; + } + return 0; + } + + // Single-file: compile to SCCF then directly to PE + sccf_builder_t sccf_builder = {0}; + scc_ir2sccf(&sccf_builder, &mir_module); + sccf_builder_set_entry_symbol_name(&sccf_builder, + config.entry_point_symbol); + const sccf_t *sccf = sccf_builder_to_sccf(&sccf_builder); + if (config.emit_stage == SCC_EMIT_STAGE_SCCF) { + if (fp == nullptr) { + scc_printf("output exe at %s\n", config.output_file); + } else { + sccf_builder_to_file(&sccf_builder, config.output_file); + } + return 0; + } + + if (config.emit_stage == SCC_EMIT_STAGE_DEFAULT || + config.emit_stage == SCC_EMIT_STAGE_TARGET) { + scc_pe_builder_t pe_builder; + sccf2pe(&pe_builder, sccf); + if (fp == nullptr) { + scc_printf("output exe at %s\n", config.output_file); + } else { + scc_pe_dump_to_file(&pe_builder, config.output_file); + } + return 0; + } + + Panic("unknown emit stage"); + return 1; } - sccf_builder_t sccf_builder = {0}; - sccf_builder_init(&sccf_builder); - scc_ir2sccf(&sccf_builder, &mir_module); - sccf_builder_set_entry_symbol_name(&sccf_builder, - config.entry_point_symbol); - const sccf_t *sccf = sccf_builder_to_sccf(&sccf_builder); - if (config.emit_stage == SCC_EMIT_STAGE_SCCF) { - // sccf_buffer_t buffer; - // scc_vec_init(buffer); - // sccf_builder_to_buffer(&sccf_builder, &buffer); - if (fp == nullptr) { - scc_printf("output exe at %s\n", config.output_file); - } else { - sccf_builder_to_file(&sccf_builder, config.output_file); - } - return 0; + // Multi-file mode (num_inputs > 1) + if (config.emit_stage != SCC_EMIT_STAGE_DEFAULT) { + LOG_ERROR("--emit is not supported with multiple input files"); + return 1; } - if (config.emit_stage == SCC_EMIT_STAGE_DEFAULT || - config.emit_stage == SCC_EMIT_STAGE_TARGET) { - scc_pe_builder_t pe_builder; - sccf2pe(&pe_builder, sccf); - if (fp == nullptr) { - scc_printf("output exe at %s\n", config.output_file); - } else { - scc_pe_dump_to_file(&pe_builder, config.output_file); + // First pass: compile each file to SCCF + sccf_linker_t linker; + sccf_linker_init(&linker); + sccf_linker_set_entry_symbol_name(&linker, config.entry_point_symbol); + + scc_vec_foreach(config.input_files, i) { + const char *input = scc_vec_at(config.input_files, i); + sccf_builder_t builder = {0}; + + int err = compile_file_to_sccf(input, &config, &builder); + if (err != 0) { + return err; } - return 0; + + // Transfer this file's SCCF to the linker. + // The builder data stays alive on the heap; the linker stores a shallow + // copy. We must NOT drop/free the builder while the linker references + // it. + sccf_linker_add_sccf(&linker, sccf_builder_to_sccf(&builder)); } - Panic("unknown emit stage"); - return 1; + // Second pass: link all SCCF modules and emit PE + const sccf_t *linked = sccf_linker_link(&linker); + scc_pe_builder_t pe_builder; + sccf2pe(&pe_builder, linked); + if (fp == nullptr) { + scc_printf("output exe at %s\n", config.output_file); + } else { + scc_pe_dump_to_file(&pe_builder, config.output_file); + } + + return 0; }