#include #include #include #include #include static scc_ast_qual_type_t *got_type_callback(scc_sema_ctx_t *sema_ctx, const char *name); static void gen_symbol_name(const scc_ast_decl_t *decl, scc_str_t *name) { switch (decl->base.type) { case SCC_AST_DECL_ENUM: *name = scc_str_from_cstr("$E_"); scc_str_append_cstr(name, decl->name, scc_strlen(decl->name)); break; case SCC_AST_DECL_STRUCT: *name = scc_str_from_cstr("$S_"); scc_str_append_cstr(name, decl->name, scc_strlen(decl->name)); break; case SCC_AST_DECL_UNION: *name = scc_str_from_cstr("$U_"); scc_str_append_cstr(name, decl->name, scc_strlen(decl->name)); break; default: break; } } static void symtab_add_symbol(scc_sema_symtab_t *sema_symtab, scc_ast_decl_t *decl, scc_ast_node_t *ast_node_ref) { if (decl->name == nullptr) return; scc_str_t name = scc_str_empty(); gen_symbol_name(decl, &name); if (scc_str_is_empty(&name)) { scc_sema_symtab_add_symbol(sema_symtab, decl->name, ast_node_ref); } else { const char *pooled = scc_strpool_intern(&sema_symtab->name_pool, scc_str_as_cstr(&name)); scc_sema_symtab_add_symbol(sema_symtab, pooled, ast_node_ref); scc_str_drop(&name); } } static void type_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; scc_ast_qual_type_t *type = SCC_AST_CAST_TO(scc_ast_qual_type_t, node); if (node_type == SCC_AST_TYPE_STRUCT) { symtab_add_symbol(sema_symtab, type->type->record.decl, &type->base); } else if (node_type == SCC_AST_TYPE_UNION) { symtab_add_symbol(sema_symtab, type->type->record.decl, &type->base); } else if (node_type == SCC_AST_TYPE_ENUM) { symtab_add_symbol(sema_symtab, type->type->record.decl, &type->base); } return; } /* ---------- 类型解析辅助函数 (用于成员访问) ---------- */ // 从 qual_type 解析到底层的 struct/union 声明(跟随 typedef 链) static scc_ast_decl_t *resolve_to_struct_decl(scc_ast_qual_type_t *type) { if (!type) return nullptr; // 跟随 typedef 链 while (type->base.type == SCC_AST_TYPE_TYPEDEF) { if (!type->type || !type->type->typedef_type.decl) return nullptr; if (type->type->typedef_type.decl->base.type != SCC_AST_DECL_TYPEDEF) return nullptr; type = type->type->typedef_type.decl->typedef_decl.type; if (!type) return nullptr; } if (type->base.type == SCC_AST_TYPE_STRUCT || type->base.type == SCC_AST_TYPE_UNION) { if (type->type) return type->type->record.decl; } return nullptr; } // 从表达式中解析出其 qual_type(用于确定基表达式的类型) static scc_ast_qual_type_t *resolve_expr_qual_type(scc_sema_ctx_t *sema_ctx, scc_ast_expr_t *expr) { if (!expr) return nullptr; switch (expr->base.type) { case SCC_AST_EXPR_IDENTIFIER: { scc_ast_decl_t *decl = expr->identifier._target; if (!decl) return nullptr; if (decl->base.type == SCC_AST_DECL_VAR) return decl->var.type; if (decl->base.type == SCC_AST_DECL_PARAM) return decl->param.type; return nullptr; } case SCC_AST_EXPR_MEMBER: { scc_ast_qual_type_t *base_type = resolve_expr_qual_type(sema_ctx, expr->member.base); if (!base_type) return nullptr; scc_ast_decl_t *sd = resolve_to_struct_decl(base_type); if (!sd) return nullptr; scc_ast_decl_vec_t *fields = &sd->record.fields; if (expr->member._target_idx >= scc_vec_size(*fields)) return nullptr; scc_ast_decl_t *field = scc_vec_at(*fields, expr->member._target_idx); if (field->base.type == SCC_AST_DECL_VAR) return field->var.type; return nullptr; } case SCC_AST_EXPR_PTR_MEMBER: { scc_ast_qual_type_t *base_type = resolve_expr_qual_type(sema_ctx, expr->member.base); if (!base_type || base_type->base.type != SCC_AST_TYPE_POINTER) return nullptr; scc_ast_qual_type_t *pointee = base_type->type ? base_type->type->pointer.pointee : nullptr; if (!pointee) return nullptr; scc_ast_decl_t *sd = resolve_to_struct_decl(pointee); if (!sd) return nullptr; scc_ast_decl_vec_t *fields = &sd->record.fields; if (expr->member._target_idx >= scc_vec_size(*fields)) return nullptr; scc_ast_decl_t *field = scc_vec_at(*fields, expr->member._target_idx); if (field->base.type == SCC_AST_DECL_VAR) return field->var.type; return nullptr; } case SCC_AST_EXPR_UNARY: { if (expr->unary.op == SCC_AST_OP_INDIRECTION) { scc_ast_qual_type_t *op_type = resolve_expr_qual_type(sema_ctx, expr->unary.operand); if (!op_type || op_type->base.type != SCC_AST_TYPE_POINTER) return nullptr; return op_type->type ? op_type->type->pointer.pointee : nullptr; } return nullptr; } default: return nullptr; } } static void expr_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; 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 = scc_sema_symtab_lookup_symbol(sema_symtab, expr->identifier.name); if (sym_node == nullptr) { SCC_ERROR(expr->base.loc, "sema error: Identifier '%s' not found", expr->identifier.name); } else if (!SCC_AST_IS_A(scc_ast_decl_t, sym_node)) { SCC_ERROR(expr->base.loc, "sema error: Identifier '%s' is not a variable", expr->identifier.name); } else { expr->identifier._target = SCC_AST_CAST_TO(scc_ast_decl_t, sym_node); } return; } if (node_type == SCC_AST_EXPR_MEMBER || node_type == SCC_AST_EXPR_PTR_MEMBER) { scc_ast_expr_t *base = expr->member.base; // 获取基表达式的 qual_type scc_ast_qual_type_t *base_type = resolve_expr_qual_type(sema_ctx, base); if (!base_type) { SCC_ERROR(expr->base.loc, "cannot determine type for member access"); return; } // 对于 ->,基表达式应为指针类型,解引用得到目标 struct/union scc_ast_decl_t *struct_decl = nullptr; if (node_type == SCC_AST_EXPR_PTR_MEMBER) { if (base_type->base.type != SCC_AST_TYPE_POINTER) { SCC_ERROR(expr->base.loc, "base expression of '->' must be a pointer"); return; } scc_ast_qual_type_t *pointee = base_type->type ? base_type->type->pointer.pointee : nullptr; if (!pointee) { SCC_ERROR(expr->base.loc, "cannot dereference pointer for '->'"); return; } struct_decl = resolve_to_struct_decl(pointee); } else { struct_decl = resolve_to_struct_decl(base_type); } if (!struct_decl) { SCC_ERROR(expr->base.loc, "base expression is not a struct or union"); return; } // 按名称查找字段,计算 field index scc_ast_decl_vec_t *fields = &struct_decl->record.fields; cbool found = false; for (usize i = 0; i < scc_vec_size(*fields); i++) { scc_ast_decl_t *field = scc_vec_at(*fields, i); if (field && field->name && scc_strcmp(field->name, expr->member.name) == 0) { expr->member._target_idx = i; found = true; break; } } if (!found) { SCC_ERROR(expr->base.loc, "struct/union has no member '%s'", expr->member.name); } return; } return; } 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); return; } switch (((scc_ast_stmt_t *)node)->base.type) { case SCC_AST_STMT_WHILE: case SCC_AST_STMT_DO_WHILE: case SCC_AST_STMT_FOR: scc_vec_push(sema_ctx->break_stack, (scc_ast_stmt_t *)node); scc_vec_push(sema_ctx->continue_stack, (scc_ast_stmt_t *)node); break; case SCC_AST_STMT_SWITCH: scc_vec_push(sema_ctx->break_stack, (scc_ast_stmt_t *)node); break; default: Panic("Unhandled statement type"); break; } return; } else if (node_type == scc_ast_stmt_t_END) { if (node == nullptr) { scc_sema_symtab_leave_scope(sema_symtab); return; } switch (((scc_ast_stmt_t *)node)->base.type) { case SCC_AST_STMT_WHILE: case SCC_AST_STMT_DO_WHILE: case SCC_AST_STMT_FOR: scc_vec_pop(sema_ctx->break_stack); scc_vec_pop(sema_ctx->continue_stack); break; case SCC_AST_STMT_SWITCH: scc_vec_pop(sema_ctx->break_stack); break; default: Panic("Unhandled statement type"); break; } return; } if (node_type == SCC_AST_UNKNOWN || node == nullptr) { return; } scc_ast_stmt_t *stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node); switch (stmt->base.type) { case SCC_AST_STMT_BREAK: { if (scc_vec_size(sema_ctx->break_stack) == 0) SCC_ERROR(stmt->base.loc, "break not in loop/switch"); else stmt->jump._target = scc_vec_at( sema_ctx->break_stack, scc_vec_size(sema_ctx->break_stack) - 1); } break; case SCC_AST_STMT_CONTINUE: { if (scc_vec_size(sema_ctx->continue_stack) == 0) SCC_ERROR(stmt->base.loc, "continue not in loop"); else stmt->jump._target = scc_vec_at(sema_ctx->continue_stack, scc_vec_size(sema_ctx->continue_stack) - 1); } break; case SCC_AST_STMT_GOTO: { scc_ast_stmt_t *goto_stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node); scc_sema_label_scope_t *scope = &sema_ctx->label_scope; if (scope->function_scope_depth != 1) { SCC_ERROR(goto_stmt->base.loc, "goto not inside any function"); break; } // 尝试直接查找标签 scc_ast_node_t *target = scc_hashtable_get(&scope->labels, goto_stmt->goto_stmt.label); if (target) { goto_stmt->goto_stmt._target = SCC_AST_CAST_TO(scc_ast_stmt_t, target); } else { // 未找到则加入待处理列表 scc_vec_push(scope->pending_gotos, goto_stmt); } } break; case SCC_AST_STMT_LABEL: { scc_ast_stmt_t *label_stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node); scc_sema_label_scope_t *scope = &sema_ctx->label_scope; // 获取当前函数标签作用域 if (scope->function_scope_depth != 1) { SCC_ERROR(label_stmt->base.loc, "label not inside any function"); break; } // 检查重复定义 if (scc_hashtable_get(&scope->labels, label_stmt->label_stmt.label)) { SCC_ERROR(label_stmt->base.loc, "duplicate label '%s'", label_stmt->label_stmt.label); break; } // 添加标签 scc_hashtable_set(&scope->labels, label_stmt->label_stmt.label, &label_stmt->base); // 检查是否有等待该标签的 goto scc_vec_foreach(scope->pending_gotos, i) { scc_ast_stmt_t *goto_stmt = scc_vec_at(scope->pending_gotos, i); if (goto_stmt == nullptr) continue; if (scc_strcmp(goto_stmt->goto_stmt.label, label_stmt->label_stmt.label) == 0) { goto_stmt->goto_stmt._target = label_stmt; scc_vec_at(scope->pending_gotos, i) = nullptr; } } } break; default: break; } return; } 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) { // 创建标签作用域 scc_sema_label_scope_t *scope = &sema_ctx->label_scope; scope->function_scope_depth += 1; scc_hashtable_cstr_init(&scope->labels); scc_vec_init(scope->pending_gotos); // 进入普通符号表作用域(用于参数和局部变量) scc_sema_symtab_enter_scope(sema_symtab); return; } else if (node_type == scc_ast_decl_t_END) { scc_sema_label_scope_t *scope = &sema_ctx->label_scope; scope->function_scope_depth -= 1; // 处理尚未绑定的 goto scc_vec_foreach(scope->pending_gotos, i) { scc_ast_stmt_t *goto_stmt = scc_vec_at(scope->pending_gotos, i); if (goto_stmt == nullptr) { continue; } // 标签未定义 -> 报错 SCC_ERROR(goto_stmt->base.loc, "label '%s' used but not defined", goto_stmt->goto_stmt.label); } // 清理 scc_hashtable_drop(&scope->labels); scc_vec_free(scope->pending_gotos); // 退出普通符号表作用域 scc_sema_symtab_leave_scope(sema_symtab); return; } if (node_type == SCC_AST_UNKNOWN || node == nullptr) { return; } scc_ast_decl_t *decl = SCC_AST_CAST_TO(scc_ast_decl_t, node); if (node_type == SCC_AST_DECL_TYPEDEF) { if (decl->name == nullptr) { SCC_ERROR(decl->base.loc, "typedef without name"); return; } symtab_add_symbol(sema_symtab, decl, &decl->typedef_decl.type->base); } else if (node_type == SCC_AST_DECL_VAR) { symtab_add_symbol(sema_symtab, decl, &decl->base); } else if (node_type == SCC_AST_DECL_PARAM) { if (decl->name == nullptr) { if (decl->param.type->base.type == SCC_AST_TYPE_BUILTIN && (decl->param.type->type->builtin.type == SCC_AST_BUILTIN_TYPE_VA_LIST || decl->param.type->type->builtin.type == SCC_AST_BUILTIN_TYPE_VOID)) { return; } SCC_ERROR(decl->base.loc, "sema error: Parameter must have a name"); return; } symtab_add_symbol(sema_symtab, decl, &decl->base); } else if (node_type == SCC_AST_DECL_FUNC) { if (decl->name == nullptr) { SCC_ERROR(decl->base.loc, "sema error: Function must have a name"); } else { // FIXME 重名函数... symtab_add_symbol(sema_symtab, decl, &decl->base); } } return; } static scc_ast_qual_type_t *got_type_callback(scc_sema_ctx_t *sema_ctx, const char *name) { scc_sema_symtab_t *sema_symtab = sema_ctx->context; scc_ast_node_t *node = scc_sema_symtab_lookup_symbol(sema_symtab, name); if (SCC_AST_IS_A(scc_ast_qual_type_t, node)) { return (scc_ast_qual_type_t *)node; } return nullptr; } 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) { LOG_FATAL("out of memory"); return; } sema_ctx->context = sema_symtab; sema_ctx->on_decl = decl_callback; sema_ctx->on_expr = expr_callback; sema_ctx->on_stmt = stmt_callback; sema_ctx->on_type = type_callback; sema_ctx->got_type = got_type_callback; sema_ctx->label_scope = (scc_sema_label_scope_t){0}; scc_sema_symtab_init(sema_symtab); scc_vec_init(sema_ctx->break_stack); scc_vec_init(sema_ctx->continue_stack); scc_ast_qual_type_t *type = SCC_AST_ALLOC_QUAL_TYPE(sema_ctx->ast_module); scc_ast_type_builtin_init(type, sema_ctx->ast_module, SCC_AST_BUILTIN_TYPE_VA_LIST, scc_pos_create()); scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_va_list", &type->base); scc_ast_decl_t *decl = SCC_AST_ALLOC_DECL(sema_ctx->ast_module); scc_ast_decl_val_init(decl, type, "__scc_builtin__", nullptr, scc_pos_create()); scc_sema_symtab_add_symbol(sema_symtab, "__func__", &decl->base); scc_ast_qual_type_t *built_func_type = SCC_AST_ALLOC_QUAL_TYPE(sema_ctx->ast_module); // FIXME hack built_func_type->base.type = SCC_AST_TYPE_FUNCTION; scc_ast_decl_t *builin_func = SCC_AST_ALLOC_DECL(sema_ctx->ast_module); scc_ast_decl_func_init(builin_func, built_func_type, "__scc_builtin_func", nullptr, scc_pos_create()); scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_va_start", &builin_func->base); scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_va_end", &builin_func->base); scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_va_arg", &builin_func->base); scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_va_copy", &builin_func->base); } void scc_sema_drop(scc_sema_ctx_t *sema_ctx) { Assert(scc_vec_size(sema_ctx->break_stack) == 0 && scc_vec_size(sema_ctx->continue_stack) == 0); scc_vec_free(sema_ctx->break_stack); scc_vec_free(sema_ctx->continue_stack); if (sema_ctx->context) { scc_sema_symtab_drop(sema_ctx->context); scc_free(sema_ctx->context); sema_ctx->context = nullptr; } }