Files
scc/libs/ast/src/ast_dump.c
T
zzy e850b5c981 feat(ir): 启用LIR模块并重构HIR组件结构
- 在cbuild.toml中启用lir依赖项,取消注释相关配置
- 重构libs/README.md文档,添加详细的库说明和层级结构
- 重命名头文件以统一命名规范:ast_def.h → scc_ast_def.h,
  ast_dump.h → scc_ast_dump.h, hir相关文件添加scc前缀
- 更新include路径以匹配新的文件命名
- 在cfg模块中添加symbol ID类型和linkage枚举,完善符号表功能
- 实现cfg模块中的符号添加、查找和获取功能
- 修改HIR中meta字段替换原有的attribute字段,更新相关访问宏
- 修复HIR构建器中的函数元数据访问错误
- 为LIR模块创建完整的头文件结构,包括指令定义、转换器等组件
2026-04-21 20:35:37 +08:00

565 lines
20 KiB
C

/**
* @file ast_dump.c
* @brief AST dump 实现
*/
#include <scc_ast_dump.h>
#include <scc_tree_dump.h>
static const char *node_type_names[] = {
[SCC_AST_UNKNOWN] = "Unknown",
[scc_ast_decl_t_BEGIN] = "ERROR",
[SCC_AST_DECL_LIST] = "DeclList",
[SCC_AST_DECL_VAR] = "VarDecl",
[SCC_AST_DECL_FUNC] = "FuncDecl",
[SCC_AST_DECL_PARAM] = "ParamDecl",
[SCC_AST_DECL_STRUCT] = "StructDecl",
[SCC_AST_DECL_UNION] = "UnionDecl",
[SCC_AST_DECL_ENUM] = "EnumDecl",
[SCC_AST_DECL_TYPEDEF] = "TypedefDecl",
[scc_ast_decl_t_END] = "ERROR",
[scc_ast_stmt_t_BEGIN] = "ERROR",
[SCC_AST_STMT_COMPOUND] = "CompoundStmt",
[SCC_AST_STMT_EXPR] = "ExprStmt",
[SCC_AST_STMT_IF] = "IfStmt",
[SCC_AST_STMT_WHILE] = "WhileStmt",
[SCC_AST_STMT_DO_WHILE] = "DoWhileStmt",
[SCC_AST_STMT_FOR] = "ForStmt",
[SCC_AST_STMT_SWITCH] = "SwitchStmt",
[SCC_AST_STMT_CASE] = "CaseStmt",
[SCC_AST_STMT_DEFAULT] = "DefaultStmt",
[SCC_AST_STMT_BREAK] = "BreakStmt",
[SCC_AST_STMT_CONTINUE] = "ContinueStmt",
[SCC_AST_STMT_RETURN] = "ReturnStmt",
[SCC_AST_STMT_GOTO] = "GotoStmt",
[SCC_AST_STMT_LABEL] = "LabelStmt",
[scc_ast_stmt_t_END] = "ERROR",
[scc_ast_expr_t_BEGIN] = "ERROR",
[SCC_AST_EXPR_BINARY] = "BinaryExpr",
[SCC_AST_EXPR_UNARY] = "UnaryExpr",
[SCC_AST_EXPR_COND] = "ConditionalExpr",
[SCC_AST_EXPR_CALL] = "CallExpr",
[SCC_AST_EXPR_ARRAY_SUBSCRIPT] = "ArraySubscriptExpr",
[SCC_AST_EXPR_MEMBER] = "MemberExpr",
[SCC_AST_EXPR_PTR_MEMBER] = "PtrMemberExpr",
[SCC_AST_EXPR_CAST] = "CastExpr",
[SCC_AST_EXPR_SIZE_OF] = "SizeofExpr",
[SCC_AST_EXPR_ALIGN_OF] = "AlignofExpr",
[SCC_AST_EXPR_COMPOUND] = "CompoundExpr",
[SCC_AST_EXPR_LVALUE] = "LvalueExpr",
[SCC_AST_EXPR_INT_LITERAL] = "IntLiteralExpr",
[SCC_AST_EXPR_FLOAT_LITERAL] = "FloatLiteralExpr",
[SCC_AST_EXPR_CHAR_LITERAL] = "CharLiteralExpr",
[SCC_AST_EXPR_STRING_LITERAL] = "StringLiteralExpr",
[SCC_AST_EXPR_IDENTIFIER] = "IdentifierExpr",
[scc_ast_expr_t_END] = "ERROR",
[scc_ast_type_t_BEGIN] = "ERROR",
[SCC_AST_TYPE_BUILTIN] = "BuiltinType",
[SCC_AST_TYPE_POINTER] = "PointerType",
[SCC_AST_TYPE_ARRAY] = "ArrayType",
[SCC_AST_TYPE_FUNCTION] = "FunctionType",
[SCC_AST_TYPE_STRUCT] = "StructType",
[SCC_AST_TYPE_UNION] = "UnionType",
[SCC_AST_TYPE_ENUM] = "EnumType",
[SCC_AST_TYPE_TYPEDEF] = "TypedefType",
[scc_ast_type_t_END] = "ERROR",
[scc_ast_translation_unit_t_BEGIN] = "ERROR",
[SCC_AST_TRANSLATION_UNIT] = "TranslationUnit",
[scc_ast_translation_unit_t_END] = "ERROR",
};
static const char *get_node_type_str(scc_ast_node_kind_t type) {
return node_type_names[type];
}
static const char *builtin_type_names[] = {
[SCC_AST_BUILTIN_TYPE_UNKNOWN] = "<unknown type>",
[SCC_AST_BUILTIN_TYPE_VA_LIST] = "...",
[SCC_AST_BUILTIN_TYPE_VOID] = "void",
[SCC_AST_BUILTIN_TYPE_BOOL] = "bool",
[SCC_AST_BUILTIN_TYPE_CHAR] = "char",
[SCC_AST_BUILTIN_TYPE_SHORT] = "short",
[SCC_AST_BUILTIN_TYPE_INT] = "int",
[SCC_AST_BUILTIN_TYPE_LONG] = "long",
[SCC_AST_BUILTIN_TYPE_LONG_LONG] = "long long",
[SCC_AST_BUILTIN_TYPE_UNSIGNED_CHAR] = "unsigned char",
[SCC_AST_BUILTIN_TYPE_UNSIGNED_SHORT] = "unsigned short",
[SCC_AST_BUILTIN_TYPE_UNSIGNED_INT] = "unsigned int",
[SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG] = "unsigned long",
[SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG] = "unsigned long long",
[SCC_AST_BUILTIN_TYPE_SIGNED_CHAR] = "signed char",
[SCC_AST_BUILTIN_TYPE_SIGNED_SHORT] = "signed short",
[SCC_AST_BUILTIN_TYPE_SIGNED_INT] = "signed int",
[SCC_AST_BUILTIN_TYPE_SIGNED_LONG] = "signed long",
[SCC_AST_BUILTIN_TYPE_SIGNED_LONG_LONG] = "signed long long",
[SCC_AST_BUILTIN_TYPE_FLOAT] = "float",
[SCC_AST_BUILTIN_TYPE_DOUBLE] = "double",
[SCC_AST_BUILTIN_TYPE_LONG_DOUBLE] = "long double",
[SCC_AST_BUILTIN_TYPE_COMPLEX_FLOAT] = "complex float",
[SCC_AST_BUILTIN_TYPE_COMPLEX_DOUBLE] = "complex double",
[SCC_AST_BUILTIN_TYPE_COMPLEX_LONG_DOUBLE] = "complex long double",
};
static const char *get_builtin_type_str(scc_ast_builtin_type_t type) {
return builtin_type_names[type];
}
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 "--";
default:
return "<op>";
}
}
static inline void dump_child_node(scc_tree_dump_t *td, scc_ast_node_t *child,
cbool is_last) {
if (!child)
return;
scc_tree_dump_push(td, is_last);
scc_ast_dump_node(td, child);
scc_tree_dump_pop(td);
}
static inline void dump_quals(scc_ast_decl_specifier_t quals,
scc_tree_dump_t *td) {
if (quals.is_atomic)
scc_tree_dump_value(td, " atomic");
if (quals.is_restrict)
scc_tree_dump_value(td, " restrict");
if (quals.is_volatile)
scc_tree_dump_value(td, " volatile");
if (quals.is_const)
scc_tree_dump_value(td, " const");
if (quals.is_inline)
scc_tree_dump_value(td, " inline");
if (quals.is_extern)
scc_tree_dump_value(td, " extern");
}
static void dump_type_impl(scc_ast_type_t *type, scc_tree_dump_t *td) {
if (!type)
return;
scc_tree_dump_begin_line(td);
scc_tree_dump_node(td, "%s", get_node_type_str(type->base.type));
dump_quals(type->quals, td);
switch (type->base.type) {
case SCC_AST_TYPE_BUILTIN:
scc_tree_dump_value(td, " '%s'",
get_builtin_type_str(type->builtin.type));
break;
case SCC_AST_TYPE_POINTER:
scc_tree_dump_value(td, " pointer");
break;
case SCC_AST_TYPE_ARRAY:
scc_tree_dump_value(td, " array");
break;
case SCC_AST_TYPE_FUNCTION:
scc_tree_dump_value(td, " function");
break;
case SCC_AST_TYPE_STRUCT:
if (type->record.name)
scc_tree_dump_value(td, " 'struct %s'", type->record.name);
else
scc_tree_dump_value(td, " <anonymous struct>");
break;
case SCC_AST_TYPE_UNION:
if (type->record.name)
scc_tree_dump_value(td, " 'union %s'", type->record.name);
else
scc_tree_dump_value(td, " <anonymous union>");
break;
case SCC_AST_TYPE_ENUM:
if (type->record.name)
scc_tree_dump_value(td, " 'enum %s'", type->record.name);
else
scc_tree_dump_value(td, " anonymous enum");
break;
case SCC_AST_TYPE_TYPEDEF:
scc_tree_dump_value(td, " '%s'", type->typedef_type.name);
break;
default:
break;
}
switch (type->base.type) {
case SCC_AST_TYPE_POINTER:
dump_child_node(td, (scc_ast_node_t *)type->pointer.pointee, true);
break;
case SCC_AST_TYPE_ARRAY:
dump_child_node(td, (scc_ast_node_t *)type->array.element,
type->array.size == nullptr);
if (type->array.size)
dump_child_node(td, (scc_ast_node_t *)type->array.size, true);
break;
case SCC_AST_TYPE_FUNCTION:
scc_tree_dump_push(td, false);
scc_tree_dump_begin_line(td);
scc_tree_dump_node(td, "%s", "ReturnType");
dump_child_node(td, (scc_ast_node_t *)type->function.return_type, true);
scc_tree_dump_pop(td);
scc_tree_dump_push(td, true);
if (scc_vec_size(type->function.params) != 0) {
scc_vec_foreach(type->function.params, i) {
scc_ast_decl_t *param = scc_vec_at(type->function.params, i);
dump_type_impl(param->param.type, td);
}
} else {
scc_tree_dump_begin_line(td);
scc_tree_dump_value(td, "()");
}
scc_tree_dump_pop(td);
break;
default:
break;
}
}
static void dump_expr_impl(scc_ast_expr_t *expr, scc_tree_dump_t *td) {
if (!expr)
return;
scc_tree_dump_begin_line(td);
scc_tree_dump_node(td, "%s", get_node_type_str(expr->base.type));
switch (expr->base.type) {
case SCC_AST_EXPR_BINARY:
scc_tree_dump_value(td, " '%s'", get_op_str(expr->binary.op));
break;
case SCC_AST_EXPR_UNARY:
scc_tree_dump_value(td, " '%s'", get_op_str(expr->unary.op));
break;
case SCC_AST_EXPR_INT_LITERAL:
case SCC_AST_EXPR_FLOAT_LITERAL:
case SCC_AST_EXPR_CHAR_LITERAL:
case SCC_AST_EXPR_STRING_LITERAL:
scc_tree_dump_value(td, " %s", expr->literal.lexme);
break;
case SCC_AST_EXPR_IDENTIFIER:
if (expr->identifier.name)
scc_tree_dump_value(td, " '%s'", expr->identifier.name);
break;
case SCC_AST_EXPR_SIZE_OF:
case SCC_AST_EXPR_ALIGN_OF:
scc_tree_dump_value(
td, " '%s'",
(expr->base.type == SCC_AST_EXPR_SIZE_OF) ? "sizeof" : "alignof");
break;
default:
break;
}
switch (expr->base.type) {
case SCC_AST_EXPR_BINARY:
dump_child_node(td, (scc_ast_node_t *)expr->binary.lhs, false);
dump_child_node(td, (scc_ast_node_t *)expr->binary.rhs, true);
break;
case SCC_AST_EXPR_UNARY:
dump_child_node(td, (scc_ast_node_t *)expr->unary.operand, true);
break;
case SCC_AST_EXPR_COND:
dump_child_node(td, (scc_ast_node_t *)expr->cond.cond, false);
dump_child_node(td, (scc_ast_node_t *)expr->cond.then_expr, false);
dump_child_node(td, (scc_ast_node_t *)expr->cond.else_expr, true);
break;
case SCC_AST_EXPR_CALL:
dump_child_node(td, (scc_ast_node_t *)expr->call.callee, false);
for (size_t i = 0; i < expr->call.args.size; i++) {
dump_child_node(td, (scc_ast_node_t *)expr->call.args.data[i],
i == expr->call.args.size - 1);
}
break;
case SCC_AST_EXPR_ARRAY_SUBSCRIPT:
dump_child_node(td, (scc_ast_node_t *)expr->subscript.array, false);
dump_child_node(td, (scc_ast_node_t *)expr->subscript.index, true);
break;
case SCC_AST_EXPR_MEMBER:
case SCC_AST_EXPR_PTR_MEMBER:
dump_child_node(td, (scc_ast_node_t *)expr->member.base, false);
scc_tree_dump_push(td, true);
scc_tree_dump_begin_line(td);
scc_tree_dump_node(
td, "%s",
expr->base.type == SCC_AST_EXPR_MEMBER ? "Member" : "PtrMember");
scc_tree_dump_value(td, " %s", expr->member.name);
scc_tree_dump_pop(td);
break;
case SCC_AST_EXPR_CAST:
dump_child_node(td, (scc_ast_node_t *)expr->cast.type, false);
dump_child_node(td, (scc_ast_node_t *)expr->cast.expr, true);
break;
case SCC_AST_EXPR_SIZE_OF:
case SCC_AST_EXPR_ALIGN_OF:
if (expr->attr_of.expr)
dump_child_node(td, (scc_ast_node_t *)expr->attr_of.expr, true);
else if (expr->attr_of.type)
dump_child_node(td, (scc_ast_node_t *)expr->attr_of.type, true);
break;
case SCC_AST_EXPR_LVALUE:
dump_child_node(td, (scc_ast_node_t *)expr->lvalue.type, true);
break;
case SCC_AST_EXPR_COMPOUND:
dump_child_node(td, (scc_ast_node_t *)expr->compound.base, false);
{
usize size = scc_vec_size(expr->compound.lhs_exprs);
for (usize i = 0; i < size; i++) {
dump_child_node(
td,
(scc_ast_node_t *)scc_vec_at(expr->compound.lhs_exprs, i),
false);
dump_child_node(
td,
(scc_ast_node_t *)scc_vec_at(expr->compound.rhs_exprs, i),
i + 1 == size);
}
}
break;
default:
break;
}
}
static void dump_stmt_impl(scc_ast_stmt_t *stmt, scc_tree_dump_t *td) {
if (!stmt)
return;
scc_tree_dump_begin_line(td);
scc_tree_dump_node(td, "%s", get_node_type_str(stmt->base.type));
switch (stmt->base.type) {
case SCC_AST_STMT_RETURN:
if (!stmt->return_stmt.expr) {
return;
}
dump_child_node(td, (scc_ast_node_t *)stmt->return_stmt.expr, true);
return;
case SCC_AST_STMT_GOTO:
if (stmt->goto_stmt.label)
scc_tree_dump_value(td, " Label: %s", stmt->goto_stmt.label);
return;
case SCC_AST_STMT_LABEL:
if (stmt->label_stmt.label)
scc_tree_dump_value(td, " %s", stmt->label_stmt.label);
dump_child_node(td, (scc_ast_node_t *)stmt->label_stmt.stmt, true);
return;
case SCC_AST_STMT_BREAK:
case SCC_AST_STMT_CONTINUE:
return;
case SCC_AST_STMT_DEFAULT:
dump_child_node(td, (scc_ast_node_t *)stmt->default_stmt.stmt, true);
return;
case SCC_AST_STMT_COMPOUND:
scc_vec_foreach(stmt->compound.block_items, i) {
dump_child_node(
td, (scc_ast_node_t *)scc_vec_at(stmt->compound.block_items, i),
i + 1 == stmt->compound.block_items.size);
}
return;
case SCC_AST_STMT_EXPR:
if (stmt->expr.expr)
dump_child_node(td, (scc_ast_node_t *)stmt->expr.expr, true);
return;
case SCC_AST_STMT_IF:
dump_child_node(td, (scc_ast_node_t *)stmt->if_stmt.cond, false);
dump_child_node(td, (scc_ast_node_t *)stmt->if_stmt.then_stmt,
!stmt->if_stmt.opt_else_stmt);
if (stmt->if_stmt.opt_else_stmt)
dump_child_node(td, (scc_ast_node_t *)stmt->if_stmt.opt_else_stmt,
true);
return;
case SCC_AST_STMT_WHILE:
dump_child_node(td, (scc_ast_node_t *)stmt->while_stmt.cond, false);
dump_child_node(td, (scc_ast_node_t *)stmt->while_stmt.body, true);
return;
case SCC_AST_STMT_DO_WHILE:
dump_child_node(td, (scc_ast_node_t *)stmt->while_stmt.body, false);
dump_child_node(td, (scc_ast_node_t *)stmt->while_stmt.cond, true);
return;
case SCC_AST_STMT_SWITCH:
dump_child_node(td, (scc_ast_node_t *)stmt->switch_stmt.cond, false);
dump_child_node(td, (scc_ast_node_t *)stmt->switch_stmt.body, true);
return;
case SCC_AST_STMT_FOR:
if (stmt->for_stmt.init)
dump_child_node(td, (scc_ast_node_t *)stmt->for_stmt.init, false);
if (stmt->for_stmt.cond)
dump_child_node(td, (scc_ast_node_t *)stmt->for_stmt.cond, false);
if (stmt->for_stmt.incr)
dump_child_node(td, (scc_ast_node_t *)stmt->for_stmt.incr, false);
dump_child_node(td, (scc_ast_node_t *)stmt->for_stmt.body, true);
return;
case SCC_AST_STMT_CASE:
dump_child_node(td, (scc_ast_node_t *)stmt->case_stmt.expr, false);
dump_child_node(td, (scc_ast_node_t *)stmt->case_stmt.stmt, true);
return;
default:
break;
}
}
static void dump_decl_impl(scc_ast_decl_t *decl, scc_tree_dump_t *td) {
if (!decl)
return;
scc_tree_dump_begin_line(td);
scc_tree_dump_node(td, "%s", get_node_type_str(decl->base.type));
if (decl->name)
scc_tree_dump_value(td, " '%s'", decl->name);
switch (decl->base.type) {
case SCC_AST_DECL_LIST:
scc_vec_foreach(decl->list.vars, i) {
dump_child_node(td,
(scc_ast_node_t *)scc_vec_at(decl->list.vars, i),
i + 1 == scc_vec_size(decl->list.vars));
}
break;
case SCC_AST_DECL_VAR:
if (decl->var.type) {
dump_child_node(td, (scc_ast_node_t *)decl->var.type,
decl->var.init == nullptr);
if (decl->var.init)
dump_child_node(td, (scc_ast_node_t *)decl->var.init, true);
}
break;
case SCC_AST_DECL_FUNC:
if (decl->func.type) {
dump_child_node(td, (scc_ast_node_t *)decl->func.type,
decl->func.body == nullptr);
if (decl->func.body)
dump_child_node(td, (scc_ast_node_t *)decl->func.body, true);
}
break;
case SCC_AST_DECL_PARAM:
if (decl->param.type)
dump_child_node(td, (scc_ast_node_t *)decl->param.type, true);
break;
case SCC_AST_DECL_STRUCT:
case SCC_AST_DECL_UNION:
case SCC_AST_DECL_ENUM:
scc_vec_foreach(decl->record.fields, i) {
dump_child_node(
td, (scc_ast_node_t *)scc_vec_at(decl->record.fields, i),
i + 1 == scc_vec_size(decl->record.fields));
}
break;
case SCC_AST_DECL_TYPEDEF:
if (decl->typedef_decl.type)
dump_child_node(td, (scc_ast_node_t *)decl->typedef_decl.type,
true);
break;
default:
break;
}
}
static void dump_unit_impl(scc_ast_translation_unit_t *unit,
scc_tree_dump_t *td) {
if (!unit)
return;
scc_tree_dump_begin_line(td);
scc_tree_dump_node(td, "%s", get_node_type_str(unit->base.type));
scc_vec_foreach(unit->declarations, i) {
dump_child_node(td, (scc_ast_node_t *)scc_vec_at(unit->declarations, i),
i + 1 == scc_vec_size(unit->declarations));
}
}
void scc_ast_dump_node(scc_tree_dump_t *td, const scc_ast_node_t *node) {
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), td);
else if (SCC_AST_IS_A(scc_ast_stmt_t, node))
dump_stmt_impl(SCC_AST_CAST_TO(scc_ast_stmt_t, node), td);
else if (SCC_AST_IS_A(scc_ast_decl_t, node))
dump_decl_impl(SCC_AST_CAST_TO(scc_ast_decl_t, node), td);
else if (SCC_AST_IS_A(scc_ast_type_t, node))
dump_type_impl(SCC_AST_CAST_TO(scc_ast_type_t, node), td);
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), td);
}