/** * @file ast_dump.c * @brief AST dump 实现 */ #include #include 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] = "", [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 ""; } } 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, " "); 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, " "); 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); }