/** * @file ast_dump.c * @brief AST dump 实现 */ #include #define VERTICAL "| " #define BRANCH "|-" #define LAST_BRANCH "`-" #define SPACE " " // 默认颜色配置 #define DEFAULT_NODE_COLOR ANSI_FG_BLUE #define DEFAULT_VALUE_COLOR ANSI_FG_GREEN #define DEFAULT_BRANCH_COLOR ANSI_FG_YELLOW #define DEFAULT_RESET_COLOR ANSI_NONE // 通用宏定义 #define PRINT_COLORED(ctx, color_field, fmt, ...) \ do { \ if (ctx->use_color) { \ scc_printf("%s" fmt "%s", ctx->color_field, ##__VA_ARGS__, \ ctx->reset_color); \ } else { \ scc_printf(fmt, ##__VA_ARGS__); \ } \ } while (0) #define PRINT_VALUE(ctx, fmt, ...) \ PRINT_COLORED(ctx, value_color, fmt, ##__VA_ARGS__) #define PRINT_NODE_TYPE(ctx, node) \ PRINT_COLORED(ctx, node_color, "%s", get_node_type_str(node->type)) #define PRINT_QUOTED_VALUE(ctx, value) \ do { \ PRINT_VALUE(ctx, "'%s'", value); \ } while (0) // 扩展上下文深度 static void ensure_context_depth(scc_ast_dump_ctx_t *ctx, int new_depth) { if ((size_t)new_depth >= ctx->max_depth) { size_t old_size = ctx->max_depth * sizeof(cbool); ctx->max_depth = new_depth + 16; // 预分配更多空间 ctx->is_last_child = (cbool *)scc_realloc( ctx->is_last_child, ctx->max_depth * sizeof(cbool)); scc_memset((char *)ctx->is_last_child + old_size, 0, ctx->max_depth * sizeof(cbool) - old_size); } } // 打印缩进 static void print_indent(scc_ast_dump_ctx_t *ctx) { for (int i = 0; i < ctx->depth; i++) { if (i == ctx->depth - 1) { // 最后一层打印分支符号 if (ctx->use_color) { scc_printf("%s%s%s", ctx->branch_color, ctx->is_last_child[i] ? LAST_BRANCH : BRANCH, ctx->reset_color); } else { scc_printf("%s", ctx->is_last_child[i] ? LAST_BRANCH : BRANCH); } } else { // 中间层根据是否是最后一个子节点决定是否打印垂直线 if (ctx->use_color) { scc_printf("%s%s%s", ctx->branch_color, ctx->is_last_child[i] ? SPACE : VERTICAL, ctx->reset_color); } else { scc_printf("%s", ctx->is_last_child[i] ? SPACE : VERTICAL); } } } } // 获取节点类型的字符串表示 static const char *get_node_type_str(scc_ast_node_type_t type) { switch (type) { // 声明类型 case SCC_AST_DECL_VAR: return "VarDecl"; case SCC_AST_DECL_FUNC: return "FuncDecl"; case SCC_AST_DECL_PARAM: return "ParamDecl"; case SCC_AST_DECL_STRUCT: return "StructDecl"; case SCC_AST_DECL_UNION: return "UnionDecl"; case SCC_AST_DECL_ENUM: return "EnumDecl"; case SCC_AST_DECL_TYPEDEF: return "TypedefDecl"; // 语句类型 case SCC_AST_STMT_COMPOUND: return "CompoundStmt"; case SCC_AST_STMT_EXPR: return "ExprStmt"; case SCC_AST_STMT_IF: return "IfStmt"; case SCC_AST_STMT_WHILE: return "WhileStmt"; case SCC_AST_STMT_DO_WHILE: return "DoStmt"; case SCC_AST_STMT_FOR: return "ForStmt"; case SCC_AST_STMT_SWITCH: return "SwitchStmt"; case SCC_AST_STMT_CASE: return "CaseStmt"; case SCC_AST_STMT_DEFAULT: return "DefaultStmt"; case SCC_AST_STMT_BREAK: return "BreakStmt"; case SCC_AST_STMT_CONTINUE: return "ContinueStmt"; case SCC_AST_STMT_RETURN: return "ReturnStmt"; case SCC_AST_STMT_GOTO: return "GotoStmt"; case SCC_AST_STMT_LABEL: return "LabelStmt"; // 表达式类型 case SCC_AST_EXPR_BINARY: return "BinaryOperator"; case SCC_AST_EXPR_UNARY: return "UnaryOperator"; case SCC_AST_EXPR_COND: return "ConditionalOperator"; case SCC_AST_EXPR_CALL: return "CallExpr"; case SCC_AST_EXPR_ARRAY_SUBSCRIPT: return "ArraySubscriptExpr"; case SCC_AST_EXPR_MEMBER: return "MemberExpr"; case SCC_AST_EXPR_PTR_MEMBER: return "PtrMemberExpr"; case SCC_AST_EXPR_CAST: return "CastExpr"; case SCC_AST_EXPR_SIZE_OF: return "SizeOfExpr"; case SCC_AST_EXPR_ALIGN_OF: return "AlignOfExpr"; case SCC_AST_EXPR_COMPOUND_LITERAL: return "CompoundLiteralExpr"; case SCC_AST_EXPR_INT_LITERAL: return "IntegerLiteral"; case SCC_AST_EXPR_FLOAT_LITERAL: return "FloatingLiteral"; case SCC_AST_EXPR_CHAR_LITERAL: return "CharacterLiteral"; case SCC_AST_EXPR_STRING_LITERAL: return "StringLiteral"; case SCC_AST_EXPR_IDENTIFIER: return "DeclRefExpr"; // 类型类型 case SCC_AST_TYPE_BUILTIN: return "BuiltinType"; case SCC_AST_TYPE_POINTER: return "PointerType"; case SCC_AST_TYPE_ARRAY: return "ArrayType"; case SCC_AST_TYPE_FUNCTION: return "FunctionType"; case SCC_AST_TYPE_STRUCT: return "RecordType"; case SCC_AST_TYPE_UNION: return "RecordType"; case SCC_AST_TYPE_ENUM: return "EnumType"; case SCC_AST_TYPE_TYPEDEF: return "TypedefType"; // 根节点 case SCC_AST_TRANSLATION_UNIT: return "TranslationUnitDecl"; default: return "UnknownNode"; } } // 获取内置类型名称 static const char *get_builtin_type_str(scc_ast_builtin_type_t type) { switch (type) { case TYPE_VOID: return "void"; case TYPE_CHAR: return "char"; case TYPE_SHORT: return "short"; case TYPE_INT: return "int"; case TYPE_LONG: return "long"; case TYPE_LONG_LONG: return "long long"; case TYPE_FLOAT: return "float"; case TYPE_DOUBLE: return "double"; case TYPE_LONG_DOUBLE: return "long double"; case TYPE_BOOL: return "_Bool"; case TYPE_COMPLEX_FLOAT: return "float _Complex"; case TYPE_COMPLEX_DOUBLE: return "double _Complex"; case TYPE_COMPLEX_LONG_DOUBLE: return "long double _Complex"; default: return ""; } } // 获取操作符字符串 static const char *get_op_str(scc_ast_expr_op_t op) { switch (op) { case SCC_AST_OP_ASSIGN: return "="; case SCC_AST_OP_ASSIGN_ADD: return "+="; case SCC_AST_OP_ASSIGN_SUB: return "-="; case SCC_AST_OP_ASSIGN_MUL: return "*="; case SCC_AST_OP_ASSIGN_DIV: return "/="; case SCC_AST_OP_ASSIGN_MOD: return "%="; case SCC_AST_OP_ASSIGN_AND: return "&="; case SCC_AST_OP_ASSIGN_XOR: return "^="; case SCC_AST_OP_ASSIGN_OR: return "|="; case SCC_AST_OP_ASSIGN_LSHIFT: return "<<="; case SCC_AST_OP_ASSIGN_RSHIFT: return ">>="; case SCC_AST_OP_CONDITIONAL: return "? :"; case SCC_AST_OP_LOGICAL_OR: return "||"; case SCC_AST_OP_LOGICAL_AND: return "&&"; case SCC_AST_OP_BITWISE_OR: return "|"; case SCC_AST_OP_BITWISE_XOR: return "^"; case SCC_AST_OP_BITWISE_AND: return "&"; case SCC_AST_OP_EQUAL: return "=="; case SCC_AST_OP_NOT_EQUAL: return "!="; case SCC_AST_OP_LESS: return "<"; case SCC_AST_OP_GREATER: return ">"; case SCC_AST_OP_LESS_EQUAL: return "<="; case SCC_AST_OP_GREATER_EQUAL: return ">="; case SCC_AST_OP_LEFT_SHIFT: return "<<"; case SCC_AST_OP_RIGHT_SHIFT: return ">>"; case SCC_AST_OP_ADD: return "+"; case SCC_AST_OP_SUB: return "-"; case SCC_AST_OP_MUL: return "*"; case SCC_AST_OP_DIV: return "/"; case SCC_AST_OP_MOD: return "%"; case SCC_AST_OP_UNARY_PLUS: return "+"; case SCC_AST_OP_UNARY_MINUS: return "-"; case SCC_AST_OP_ADDRESS_OF: return "&"; case SCC_AST_OP_INDIRECTION: return "*"; case SCC_AST_OP_BITWISE_NOT: return "~"; case SCC_AST_OP_LOGICAL_NOT: return "!"; case SCC_AST_OP_PREFIX_INCREMENT: return "++"; case SCC_AST_OP_PREFIX_DECREMENT: return "--"; case SCC_AST_OP_POSTFIX_INCREMENT: return "++"; case SCC_AST_OP_POSTFIX_DECREMENT: return "--"; case SCC_AST_OP_MEMBER_ACCESS: return "."; case SCC_AST_OP_PTR_MEMBER_ACCESS: return "->"; default: return ""; } } // 通用的开始节点打印函数 static inline void start_node_dump(scc_ast_node_t *node, scc_ast_dump_ctx_t *ctx) { print_indent(ctx); PRINT_NODE_TYPE(ctx, node); } // 通用的结束节点打印函数 static inline void end_node_dump(scc_ast_dump_ctx_t *ctx) { scc_printf("\n"); } // 通用的递归转储辅助函数 static inline void dump_child_node(scc_ast_node_t *child, scc_ast_dump_ctx_t *ctx, cbool is_last) { if (!child) return; ctx->depth++; ensure_context_depth(ctx, ctx->depth); ctx->is_last_child[ctx->depth - 1] = is_last; scc_ast_dump_node(child, ctx); ctx->depth--; } // 用于构建复合类型名称的宏 #define BUILD_TYPE_NAME(ctx, prefix, name) \ do { \ if (ctx->use_color) { \ scc_printf("%s'%s%s%s'%s", ctx->value_color, prefix, name, \ ctx->reset_color, ctx->reset_color); \ } else { \ scc_printf("'%s%s'", prefix, name); \ } \ } while (0) // 递归转储类型 static void dump_type_impl(scc_ast_type_t *type, scc_ast_dump_ctx_t *ctx) { if (!type) return; start_node_dump(&type->base, ctx); // 根据类型输出特定信息 switch (type->base.type) { case SCC_AST_TYPE_BUILTIN: PRINT_QUOTED_VALUE(ctx, get_builtin_type_str(type->builtin.builtin)); break; case SCC_AST_TYPE_POINTER: if (type->pointer.pointee && type->pointer.pointee->base.type == SCC_AST_TYPE_BUILTIN) { const char *base_type = get_builtin_type_str(type->pointer.pointee->builtin.builtin); if (ctx->use_color) { scc_printf("%s'%s *'%s", ctx->value_color, base_type, ctx->reset_color); } else { scc_printf("'%s *'", base_type); } } else { PRINT_QUOTED_VALUE(ctx, "pointer"); } break; case SCC_AST_TYPE_ARRAY: PRINT_QUOTED_VALUE(ctx, "array"); break; case SCC_AST_TYPE_FUNCTION: PRINT_QUOTED_VALUE(ctx, "function"); break; case SCC_AST_TYPE_STRUCT: if (type->record.name) { BUILD_TYPE_NAME(ctx, "struct ", type->record.name); } else { PRINT_QUOTED_VALUE(ctx, "anonymous struct"); } break; case SCC_AST_TYPE_UNION: if (type->record.name) { BUILD_TYPE_NAME(ctx, "union ", type->record.name); } else { PRINT_QUOTED_VALUE(ctx, "anonymous union"); } break; case SCC_AST_TYPE_ENUM: if (type->enumeration.name) { BUILD_TYPE_NAME(ctx, "enum ", type->enumeration.name); } else { PRINT_QUOTED_VALUE(ctx, "anonymous enum"); } break; case SCC_AST_TYPE_TYPEDEF: PRINT_QUOTED_VALUE(ctx, type->typedef_type.name); break; default: break; } end_node_dump(ctx); // 递归转储子节点 switch (type->base.type) { case SCC_AST_TYPE_POINTER: dump_child_node((scc_ast_node_t *)type->pointer.pointee, ctx, true); break; case SCC_AST_TYPE_ARRAY: dump_child_node((scc_ast_node_t *)type->array.element, ctx, type->array.size == NULL); if (type->array.size) { dump_child_node((scc_ast_node_t *)type->array.size, ctx, true); } break; default: break; } } // 递归转储表达式 static void dump_expr_impl(scc_ast_expr_t *expr, scc_ast_dump_ctx_t *ctx) { if (!expr) return; start_node_dump(&expr->base, ctx); // 根据表达式类型输出特定信息 switch (expr->base.type) { case SCC_AST_EXPR_BINARY: PRINT_QUOTED_VALUE(ctx, get_op_str(expr->binary.op)); break; case SCC_AST_EXPR_UNARY: PRINT_QUOTED_VALUE(ctx, get_op_str(expr->unary.op)); break; case SCC_AST_EXPR_INT_LITERAL: PRINT_VALUE(ctx, " %lld", expr->literal.value.i); break; case SCC_AST_EXPR_FLOAT_LITERAL: PRINT_VALUE(ctx, " %f", expr->literal.value.f); break; case SCC_AST_EXPR_CHAR_LITERAL: PRINT_VALUE(ctx, " '%c'", (char)expr->literal.value.ch); break; case SCC_AST_EXPR_STRING_LITERAL: PRINT_VALUE(ctx, " \"%s\"", expr->literal.value.cstr.data); break; case SCC_AST_EXPR_IDENTIFIER: if (expr->identifier.name) { PRINT_QUOTED_VALUE(ctx, expr->identifier.name); } break; case SCC_AST_EXPR_SIZE_OF: case SCC_AST_EXPR_ALIGN_OF: PRINT_QUOTED_VALUE(ctx, (expr->base.type == SCC_AST_EXPR_SIZE_OF) ? "sizeof" : "alignof"); break; default: break; } end_node_dump(ctx); // 使用辅助函数处理子节点转储 switch (expr->base.type) { case SCC_AST_EXPR_BINARY: dump_child_node((scc_ast_node_t *)expr->binary.lhs, ctx, false); dump_child_node((scc_ast_node_t *)expr->binary.rhs, ctx, true); break; case SCC_AST_EXPR_UNARY: dump_child_node((scc_ast_node_t *)expr->unary.operand, ctx, true); break; case SCC_AST_EXPR_COND: dump_child_node((scc_ast_node_t *)expr->cond.cond, ctx, false); dump_child_node((scc_ast_node_t *)expr->cond.then_expr, ctx, false); dump_child_node((scc_ast_node_t *)expr->cond.else_expr, ctx, true); break; case SCC_AST_EXPR_CALL: dump_child_node((scc_ast_node_t *)expr->call.callee, ctx, false); // 转储参数 for (size_t i = 0; i < expr->call.args.size; i++) { dump_child_node((scc_ast_node_t *)expr->call.args.data[i], ctx, i == expr->call.args.size - 1); } break; case SCC_AST_EXPR_ARRAY_SUBSCRIPT: dump_child_node((scc_ast_node_t *)expr->subscript.array, ctx, false); dump_child_node((scc_ast_node_t *)expr->subscript.index, ctx, true); break; case SCC_AST_EXPR_MEMBER: case SCC_AST_EXPR_PTR_MEMBER: dump_child_node((scc_ast_node_t *)expr->member.base, ctx, false); // 打印成员访问信息 print_indent(ctx); PRINT_COLORED(ctx, node_color, "Member [\"%s\"]", expr->member.member_name); scc_printf("\n"); break; case SCC_AST_EXPR_CAST: dump_child_node((scc_ast_node_t *)expr->cast.type, ctx, false); dump_child_node((scc_ast_node_t *)expr->cast.expr, ctx, true); break; case SCC_AST_EXPR_SIZE_OF: case SCC_AST_EXPR_ALIGN_OF: if (expr->attr_of.expr) { dump_child_node((scc_ast_node_t *)expr->attr_of.expr, ctx, true); } else if (expr->attr_of.type) { dump_child_node((scc_ast_node_t *)expr->attr_of.type, ctx, true); } break; case SCC_AST_EXPR_COMPOUND_LITERAL: dump_child_node((scc_ast_node_t *)expr->compound_literal.type, ctx, false); // 初始化列表 for (size_t i = 0; i < expr->compound_literal.init_list.size; i++) { dump_child_node( (scc_ast_node_t *)expr->compound_literal.init_list.data[i], ctx, i == expr->compound_literal.init_list.size - 1); } break; default: break; } } // 递归转储语句 static void dump_stmt_impl(scc_ast_stmt_t *stmt, scc_ast_dump_ctx_t *ctx) { if (!stmt) return; start_node_dump(&stmt->base, ctx); // 根据语句类型输出特定信息 switch (stmt->base.type) { case SCC_AST_STMT_IF: scc_printf("\n"); // if语句总是换行显示子节点 dump_child_node((scc_ast_node_t *)stmt->if_stmt.cond, ctx, false); dump_child_node((scc_ast_node_t *)stmt->if_stmt.then_stmt, ctx, !stmt->if_stmt.opt_else_stmt); if (stmt->if_stmt.opt_else_stmt) { dump_child_node((scc_ast_node_t *)stmt->if_stmt.opt_else_stmt, ctx, true); } return; case SCC_AST_STMT_WHILE: scc_printf("\n"); // 循环和switch语句换行显示子节点 dump_child_node((scc_ast_node_t *)stmt->while_stmt.cond, ctx, false); dump_child_node((scc_ast_node_t *)stmt->while_stmt.body, ctx, true); return; case SCC_AST_STMT_DO_WHILE: scc_printf("\n"); // 循环和switch语句换行显示子节点 dump_child_node((scc_ast_node_t *)stmt->do_while_stmt.body, ctx, false); dump_child_node((scc_ast_node_t *)stmt->do_while_stmt.cond, ctx, true); return; case SCC_AST_STMT_SWITCH: scc_printf("\n"); // 循环和switch语句换行显示子节点 dump_child_node((scc_ast_node_t *)stmt->switch_stmt.cond, ctx, false); dump_child_node((scc_ast_node_t *)stmt->switch_stmt.body, ctx, true); return; case SCC_AST_STMT_FOR: scc_printf("\n"); // for语句换行显示子节点 if (stmt->for_stmt.init) { dump_child_node((scc_ast_node_t *)stmt->for_stmt.init, ctx, false); } if (stmt->for_stmt.cond) { dump_child_node((scc_ast_node_t *)stmt->for_stmt.cond, ctx, false); } if (stmt->for_stmt.iter) { dump_child_node((scc_ast_node_t *)stmt->for_stmt.iter, ctx, false); } dump_child_node((scc_ast_node_t *)stmt->for_stmt.body, ctx, true); return; case SCC_AST_STMT_RETURN: if (stmt->return_stmt.expr) { scc_printf("\n"); dump_child_node((scc_ast_node_t *)stmt->return_stmt.expr, ctx, true); return; } break; case SCC_AST_STMT_GOTO: if (stmt->goto_stmt.label) { PRINT_VALUE(ctx, " Label: %s", stmt->goto_stmt.label); } break; case SCC_AST_STMT_LABEL: if (stmt->label_stmt.label) { PRINT_VALUE(ctx, " %s", stmt->label_stmt.label); } break; default: break; } end_node_dump(ctx); // 递归转储其他子节点 switch (stmt->base.type) { case SCC_AST_STMT_COMPOUND: for (size_t i = 0; i < stmt->compound.block_items.size; i++) { scc_ast_node_t *item = (scc_ast_node_t *)stmt->compound.block_items.data[i]; dump_child_node(item, ctx, i == stmt->compound.block_items.size - 1); } break; case SCC_AST_STMT_EXPR: if (stmt->expr.expr) { dump_child_node((scc_ast_node_t *)stmt->expr.expr, ctx, true); } break; case SCC_AST_STMT_CASE: dump_child_node((scc_ast_node_t *)stmt->case_stmt.expr, ctx, false); dump_child_node((scc_ast_node_t *)stmt->case_stmt.stmt, ctx, true); break; case SCC_AST_STMT_DEFAULT: dump_child_node((scc_ast_node_t *)stmt->default_stmt.stmt, ctx, true); break; default: break; } } // 递归转储声明 static void dump_decl_impl(scc_ast_decl_t *decl, scc_ast_dump_ctx_t *ctx) { if (!decl) return; start_node_dump(&decl->base, ctx); // 根据声明类型输出特定信息 switch (decl->base.type) { case SCC_AST_DECL_VAR: if (decl->var.name) { PRINT_QUOTED_VALUE(ctx, decl->var.name); } break; case SCC_AST_DECL_FUNC: if (decl->func.name) { PRINT_QUOTED_VALUE(ctx, decl->func.name); } break; case SCC_AST_DECL_PARAM: if (decl->param.name) { PRINT_QUOTED_VALUE(ctx, decl->param.name); } break; case SCC_AST_DECL_STRUCT: if (decl->record.name) { PRINT_QUOTED_VALUE(ctx, decl->record.name); } break; case SCC_AST_DECL_UNION: if (decl->record.name) { PRINT_QUOTED_VALUE(ctx, decl->record.name); } break; case SCC_AST_DECL_ENUM: if (decl->enumeration.name) { PRINT_QUOTED_VALUE(ctx, decl->enumeration.name); } break; case SCC_AST_DECL_TYPEDEF: if (decl->typedef_decl.name) { PRINT_QUOTED_VALUE(ctx, decl->typedef_decl.name); } break; default: break; } end_node_dump(ctx); // 递归转储子节点 switch (decl->base.type) { case SCC_AST_DECL_VAR: if (decl->var.type) { dump_child_node((scc_ast_node_t *)decl->var.type, ctx, decl->var.init == NULL); if (decl->var.init) { dump_child_node((scc_ast_node_t *)decl->var.init, ctx, true); } } break; case SCC_AST_DECL_FUNC: if (decl->func.type) { dump_child_node((scc_ast_node_t *)decl->func.type, ctx, decl->func.body == NULL); if (decl->func.body) { dump_child_node((scc_ast_node_t *)decl->func.body, ctx, true); } } break; case SCC_AST_DECL_PARAM: if (decl->param.type) { dump_child_node((scc_ast_node_t *)decl->param.type, ctx, true); } break; case SCC_AST_DECL_STRUCT: case SCC_AST_DECL_UNION: for (size_t i = 0; i < decl->record.fields.size; i++) { dump_child_node((scc_ast_node_t *)decl->record.fields.data[i], ctx, i == decl->record.fields.size - 1); } break; case SCC_AST_DECL_ENUM: for (size_t i = 0; i < decl->enumeration.enumerators.size; i++) { dump_child_node( (scc_ast_node_t *)decl->enumeration.enumerators.data[i], ctx, i == decl->enumeration.enumerators.size - 1); } break; case SCC_AST_DECL_TYPEDEF: if (decl->typedef_decl.type) { dump_child_node((scc_ast_node_t *)decl->typedef_decl.type, ctx, true); } break; default: break; } } // 递归转储翻译单元 static void dump_unit_impl(scc_ast_translation_unit_t *unit, scc_ast_dump_ctx_t *ctx) { if (!unit) return; start_node_dump(&unit->base, ctx); scc_printf("\n"); for (size_t i = 0; i < unit->declarations.size; i++) { dump_child_node((scc_ast_node_t *)unit->declarations.data[i], ctx, i == unit->declarations.size - 1); } } // 实现上下文管理函数 void scc_ast_dump_ctx_init(scc_ast_dump_ctx_t *ctx, cbool use_color) { scc_memset(ctx, 0, sizeof(*ctx)); ctx->use_color = use_color; ctx->node_color = use_color ? DEFAULT_NODE_COLOR : ""; ctx->value_color = use_color ? DEFAULT_VALUE_COLOR : ""; ctx->branch_color = use_color ? DEFAULT_BRANCH_COLOR : ""; ctx->reset_color = use_color ? DEFAULT_RESET_COLOR : ""; ensure_context_depth(ctx, 0); ctx->is_last_child[0] = true; } void scc_ast_dump_ctx_drop(scc_ast_dump_ctx_t *ctx) { if (ctx->is_last_child) { scc_free(ctx->is_last_child); ctx->is_last_child = NULL; } } void scc_ast_dump_node(scc_ast_node_t *node, scc_ast_dump_ctx_t *ctx) { if (!node) return; if (SCC_AST_IS_A(scc_ast_expr_t, node)) { dump_expr_impl(SCC_AST_CAST_TO(scc_ast_expr_t, node), ctx); } else if (SCC_AST_IS_A(scc_ast_stmt_t, node)) { dump_stmt_impl(SCC_AST_CAST_TO(scc_ast_stmt_t, node), ctx); } else if (SCC_AST_IS_A(scc_ast_decl_t, node)) { dump_decl_impl(SCC_AST_CAST_TO(scc_ast_decl_t, node), ctx); } else if (SCC_AST_IS_A(scc_ast_type_t, node)) { dump_type_impl(SCC_AST_CAST_TO(scc_ast_type_t, node), ctx); } else if (SCC_AST_IS_A(scc_ast_translation_unit_t, node)) { dump_unit_impl(SCC_AST_CAST_TO(scc_ast_translation_unit_t, node), ctx); } }