- 在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模块创建完整的头文件结构,包括指令定义、转换器等组件
565 lines
20 KiB
C
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);
|
|
}
|