From e6511c508ce31af71207b2dfa1e6918d0641db80 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Wed, 11 Mar 2026 21:53:19 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ast):=20=E8=B0=83=E6=95=B4AST=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E4=BD=93=E5=92=8C=E6=9E=9A=E4=B8=BE=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E5=A3=B0=E6=98=8E=E8=A1=A8=E7=A4=BA=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将结构体、联合和枚举类型的字段表示从向量改为声明指针, 允许name和decl字段为null,更新相关初始化函数的断言检查, 使结构更加灵活并支持不完整类型定义。 BREAKING CHANGE: 修改了scc_ast_type结构体中record和enumeration 子类型的字段表示方法,从fields向量改为decl指针。 --- libs/ast/include/ast_def.h | 4 +- libs/ast/include/scc_ast.h | 47 +++----- libs/ast/src/ast_dump.c | 61 +++++++--- libs/lexer/include/scc_lexer_token.h | 1 + libs/parser/include/scc_parser.h | 5 + libs/parser/include/scc_sema.h | 3 + libs/parser/src/parse_decl.c | 35 +++--- libs/parser/src/parse_expr.c | 2 - libs/parser/src/parse_type.c | 172 ++++++++++++++++++++++++++- libs/parser/src/scc_parser.c | 10 ++ libs/parser/src/scc_sema.c | 1 + libs/parser/tests/test_parser_unit.c | 113 ++++++++++++------ 12 files changed, 338 insertions(+), 116 deletions(-) diff --git a/libs/ast/include/ast_def.h b/libs/ast/include/ast_def.h index 7dd8c39..eb34884 100644 --- a/libs/ast/include/ast_def.h +++ b/libs/ast/include/ast_def.h @@ -181,11 +181,11 @@ struct scc_ast_type { } function; struct { const char *name; - scc_ast_decl_vec_t fields; // 结构体/联合字段 + scc_ast_decl_t *decl; // can be null } record; struct { const char *name; - scc_ast_expr_vec_t enumerators; // 枚举项 + scc_ast_decl_t *decl; // can be null } enumeration; struct { const char *name; diff --git a/libs/ast/include/scc_ast.h b/libs/ast/include/scc_ast.h index d5a271e..f1c07ed 100644 --- a/libs/ast/include/scc_ast.h +++ b/libs/ast/include/scc_ast.h @@ -57,11 +57,11 @@ static inline void scc_ast_decl_param_init(scc_ast_decl_t *decl, decl->param.type = type; } -// fields can be null +// name and fields can be null static inline void scc_ast_decl_struct_init(scc_ast_decl_t *decl, const char *name, scc_ast_decl_vec_t *fields_move) { - Assert(decl != null && name != null); + Assert(decl != null); decl->base.loc = scc_pos_create(); decl->base.type = SCC_AST_DECL_STRUCT; decl->name = name; @@ -73,11 +73,11 @@ static inline void scc_ast_decl_struct_init(scc_ast_decl_t *decl, } } -// fields can be null +// name and fields can be null static inline void scc_ast_decl_union_init(scc_ast_decl_t *decl, const char *name, scc_ast_decl_vec_t *fields_move) { - Assert(decl != null && name != null); + Assert(decl != null); decl->base.loc = scc_pos_create(); decl->base.type = SCC_AST_DECL_UNION; decl->name = name; @@ -89,11 +89,11 @@ static inline void scc_ast_decl_union_init(scc_ast_decl_t *decl, } } -// fields can be null +// name and fields can be null static inline void scc_ast_decl_enum_init(scc_ast_decl_t *decl, const char *name, scc_ast_expr_vec_t *fields_move) { - Assert(decl != null && name != null); + Assert(decl != null); decl->base.loc = scc_pos_create(); decl->base.type = SCC_AST_DECL_ENUM; decl->name = name; @@ -454,48 +454,39 @@ static inline void scc_ast_type_function_init(scc_ast_type_t *type, static inline void _scc_ast_type_record_init(scc_ast_type_t *type, scc_ast_node_type_t type_kind, const char *name, - scc_ast_decl_vec_t *members) { - Assert(type != null && name != null); + scc_ast_decl_t *decl) { + Assert(type != null); type->base.loc = scc_pos_create(); type->base.type = type_kind; type->quals = (scc_ast_decl_specifier_t){0}; // FIXME - if (members == null) { - scc_vec_init(type->record.fields); - } else { - type->record.fields = *members; - scc_vec_init(*members); - } + type->record.name = name; + type->record.decl = decl; } -// name and members can be null +// name and decl can be null static inline void scc_ast_type_struct_init(scc_ast_type_t *type, const char *name, - scc_ast_decl_vec_t *members) { - _scc_ast_type_record_init(type, SCC_AST_TYPE_STRUCT, name, members); + scc_ast_decl_t *decl) { + _scc_ast_type_record_init(type, SCC_AST_TYPE_STRUCT, name, decl); } -// name and members can be null +// name and decl can be null static inline void scc_ast_type_union_init(scc_ast_type_t *type, const char *name, - scc_ast_decl_vec_t *members) { - _scc_ast_type_record_init(type, SCC_AST_TYPE_UNION, name, members); + scc_ast_decl_t *decl) { + _scc_ast_type_record_init(type, SCC_AST_TYPE_UNION, name, decl); } -// name and members can be null +// name and decl can be null static inline void scc_ast_type_enum_init(scc_ast_type_t *type, const char *name, - scc_ast_expr_vec_t *members) { + scc_ast_decl_t *decl) { Assert(type != null); type->base.loc = scc_pos_create(); type->base.type = SCC_AST_TYPE_ENUM; type->quals = (scc_ast_decl_specifier_t){0}; // FIXME type->enumeration.name = name; - if (members == null) { - scc_vec_init(type->enumeration.enumerators); - } else { - type->enumeration.enumerators = *members; - scc_vec_init(*members); - } + type->enumeration.decl = null; } static inline void scc_ast_type_typedef_init(scc_ast_type_t *type, diff --git a/libs/ast/src/ast_dump.c b/libs/ast/src/ast_dump.c index d580608..5deb39c 100644 --- a/libs/ast/src/ast_dump.c +++ b/libs/ast/src/ast_dump.c @@ -282,33 +282,19 @@ static void dump_type_impl(scc_ast_type_t *type, scc_tree_dump_ctx_t *ctx) { break; case SCC_AST_TYPE_FUNCTION: PRINT_QUOTED_VALUE(ctx, "function"); - scc_tree_dump_printf(ctx, "\n"); - if (type->function.return_type) { - dump_type_impl(type->function.return_type, ctx); - } - if (scc_vec_size(type->function.param_types) != 0) { - scc_vec_foreach(type->function.param_types, i) { - scc_ast_decl_t *param = - scc_vec_at(type->function.param_types, i); - if (param->name) { - // FIXME param name - } - dump_type_impl(param->param.type, ctx); - } - } 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"); + PRINT_QUOTED_VALUE(ctx, ""); } 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"); + PRINT_QUOTED_VALUE(ctx, ""); } break; case SCC_AST_TYPE_ENUM: @@ -339,6 +325,40 @@ static void dump_type_impl(scc_ast_type_t *type, scc_tree_dump_ctx_t *ctx) { dump_child_node((scc_ast_node_t *)type->array.size, ctx, true); } break; + case SCC_AST_TYPE_STRUCT: + if (type->enumeration.decl) { + dump_child_node((scc_ast_node_t *)type->enumeration.decl, ctx, + true); + } + break; + case SCC_AST_TYPE_ENUM: + if (type->record.decl) { + dump_child_node((scc_ast_node_t *)type->record.decl, ctx, true); + } + break; + case SCC_AST_TYPE_FUNCTION: + scc_vec_push(ctx->stack, false); + scc_tree_print_indent(ctx); + SCC_TREE_DUMP_PRINT_PURE(ctx, ctx->node_color, "%s\n", "ReturnType"); + dump_child_node((scc_ast_node_t *)type->function.return_type, ctx, + true); + scc_vec_pop(ctx->stack); + + scc_vec_push(ctx->stack, true); + if (scc_vec_size(type->function.param_types) != 0) { + scc_vec_foreach(type->function.param_types, i) { + scc_ast_decl_t *param = + scc_vec_at(type->function.param_types, i); + if (param->name) { + // FIXME param name + } + dump_type_impl(param->param.type, ctx); + } + } else { + PRINT_QUOTED_VALUE(ctx, "()"); + } + scc_vec_pop(ctx->stack); + break; default: break; } @@ -416,10 +436,13 @@ static void dump_expr_impl(scc_ast_expr_t *expr, scc_tree_dump_ctx_t *ctx) { case SCC_AST_EXPR_MEMBER: case SCC_AST_EXPR_PTR_MEMBER: dump_child_node((scc_ast_node_t *)expr->member.base, ctx, false); - // 打印成员访问信息 + scc_vec_push(ctx->stack, true); scc_tree_print_indent(ctx); - PRINT_NODE(ctx, "Member [\"%s\"]", expr->member.name); - scc_tree_dump_printf(ctx, "\n"); + SCC_TREE_DUMP_PRINT_PURE( + ctx, ctx->node_color, "%s %s\n", + expr->base.type == SCC_AST_EXPR_MEMBER ? "Member" : "PtrMember", + expr->member.name); + scc_vec_pop(ctx->stack); break; case SCC_AST_EXPR_CAST: diff --git a/libs/lexer/include/scc_lexer_token.h b/libs/lexer/include/scc_lexer_token.h index 21474e0..e101c0e 100644 --- a/libs/lexer/include/scc_lexer_token.h +++ b/libs/lexer/include/scc_lexer_token.h @@ -188,6 +188,7 @@ scc_tok_subtype_t scc_get_tok_subtype(scc_tok_type_t type); const char *scc_get_tok_name(scc_tok_type_t type); static inline void scc_lexer_tok_drop(scc_lexer_tok_t *tok) { + Assert(tok != null); tok->type = SCC_TOK_UNKNOWN; tok->loc.col = 0; tok->loc.line = 0; diff --git a/libs/parser/include/scc_parser.h b/libs/parser/include/scc_parser.h index ef101f4..9e702a4 100644 --- a/libs/parser/include/scc_parser.h +++ b/libs/parser/include/scc_parser.h @@ -4,6 +4,7 @@ #include "scc_sema.h" #include #include +#include #include /** @@ -13,11 +14,15 @@ typedef struct scc_parser { scc_lexer_tok_ring_t *ring; usize checkpoint; + scc_hashtable_t type_ht; + scc_sema_callbacks_t sema_callbacks; scc_ast_translation_unit_t *translation_unit; int errcode; } scc_parser_t; +// static inline scc_ast_type_t *scc_parser_ + /** * @brief 初始化解析器 * @param parser 解析器实例 diff --git a/libs/parser/include/scc_sema.h b/libs/parser/include/scc_sema.h index 6aa83d2..15a4781 100644 --- a/libs/parser/include/scc_sema.h +++ b/libs/parser/include/scc_sema.h @@ -9,6 +9,8 @@ typedef void (*scc_sema_callback_t)(void *context, scc_ast_node_type_t node_type, void *node); +typedef scc_ast_type_t *(*scc_sema_got_type_t)(void *context, const char *name); + /** * @brief 语义分析回调集合 */ @@ -17,6 +19,7 @@ typedef struct scc_sema_callbacks { scc_sema_callback_t on_stmt; scc_sema_callback_t on_expr; scc_sema_callback_t on_type; + scc_sema_got_type_t got_type; void *context; } scc_sema_callbacks_t; diff --git a/libs/parser/src/parse_decl.c b/libs/parser/src/parse_decl.c index dfeeaf3..b1123d9 100644 --- a/libs/parser/src/parse_decl.c +++ b/libs/parser/src/parse_decl.c @@ -155,25 +155,6 @@ A.2.4 External definitions #include scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) { - /** - * ISO/IEC 9899:TC3 - * 6.7 Declarations - * Syntax - * - * declaration: - * declaration-specifiers init-declarator-list(opt) ; - * declaration-specifiers: - * storage-class-specifier declaration-specifiers(opt) - * type-specifier declaration-specifiers(opt) - * type-qualifier declaration-specifiers(opt) - * function-specifier declaration-specifiers(opt) - * init-declarator-list: - * init-declarator - * init-declarator-list , init-declarator - * init-declarator: - * declarator - * declarator = initializer - */ cbool ok; scc_lexer_tok_t tok; @@ -184,8 +165,20 @@ scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) { } if (SCC_AST_IS_A(scc_ast_type_t, type_or_decl)) { - LOG_WARN("declaration dose not declare anything"); - return null; + scc_ast_type_t *type = SCC_AST_CAST_TO(scc_ast_type_t, type_or_decl); + if (type->base.type == SCC_AST_TYPE_STRUCT || + type->base.type == SCC_AST_TYPE_UNION) { + Assert(type->record.decl != null); + decl = type->record.decl; + scc_free(type_or_decl); // FIXME + } else if (type->base.type == SCC_AST_TYPE_ENUM) { + Assert(type->enumeration.decl != null); + decl = type->enumeration.decl; + scc_free(type_or_decl); // FIXME + } else { + LOG_WARN("declaration dose not declare anything"); + return null; + } } else if (SCC_AST_IS_A(scc_ast_decl_t, type_or_decl)) { decl = SCC_AST_CAST_TO(scc_ast_decl_t, type_or_decl); } else { diff --git a/libs/parser/src/parse_expr.c b/libs/parser/src/parse_expr.c index a709813..2a7d440 100644 --- a/libs/parser/src/parse_expr.c +++ b/libs/parser/src/parse_expr.c @@ -806,8 +806,6 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) { return null; } const char *name = scc_cstring_as_cstr(&ident_tok.lexeme); - scc_lexer_tok_drop(&ident_tok); - scc_ast_expr_t *member = expr_create( parser, op_tok.type == SCC_TOK_DOT ? SCC_AST_EXPR_MEMBER : SCC_AST_EXPR_PTR_MEMBER); diff --git a/libs/parser/src/parse_type.c b/libs/parser/src/parse_type.c index 4d65a08..b560a95 100644 --- a/libs/parser/src/parse_type.c +++ b/libs/parser/src/parse_type.c @@ -460,6 +460,167 @@ static scc_ast_type_t *build_type_from_info(type_spec_info_t *info) { // 注意:限定符(const, volatile)不应在此处处理,应由上层函数负责 return type; } +static scc_ast_type_t *parse_record_type(scc_parser_t *parser, + scc_ast_node_type_t type_kind) { + /* + (6.7.2.1) + struct-or-union-specifier: + struct-or-union identifier(opt) { struct-declaration-list } + struct-or-union identifier + (6.7.2.1) + struct-or-union: + struct + union + (6.7.2.1) + struct-declaration-list: + struct-declaration + struct-declaration-list struct-declaration + (6.7.2.1) + struct-declaration: + specifier-qualifier-list struct-declarator-list ; + (6.7.2.1) + specifier-qualifier-list: + type-specifier specifier-qualifier-list(opt) + type-qualifier specifier-qualifier-list(opt) + (6.7.2.1) + struct-declarator-list: + struct-declarator + struct-declarator-list , struct-declarator + (6.7.2.1) + struct-declarator: + declarator + declarator(opt) : constant-expression + */ + // FIXME check struct/union + scc_parser_next_consume(parser, null); + const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser); + scc_lexer_tok_t tok; + const char *name = null; + scc_ast_decl_t *decl = null; + scc_ast_decl_vec_t member; + scc_vec_init(member); + + if (tok_ptr->type == SCC_TOK_IDENT) { + scc_parser_next_consume(parser, &tok); + name = scc_cstring_as_cstr(&tok.lexeme); + tok_ptr = scc_parser_peek(parser); + } + + if (tok_ptr && tok_ptr->type == SCC_TOK_L_BRACE) { + scc_parser_next_consume(parser, null); + while (1) { + tok_ptr = scc_parser_peek(parser); + if (tok_ptr == null) { + LOG_ERROR("Unexpected EOF in enum specifier"); + break; + } + + scc_ast_node_t *node = _scc_parse_type(parser); + scc_ast_decl_t *decl = null; + if (node != null) { + decl = SCC_AST_CAST_TO(scc_ast_decl_t, node); + } + if (decl != null) { + scc_vec_push(member, decl); + continue; + } + + if (tok_ptr->type == SCC_TOK_SEMICOLON) { + // FIXME check semicolon + scc_parser_next_consume(parser, null); + } else if (tok_ptr->type == SCC_TOK_R_BRACE) { + scc_parser_next_consume(parser, null); + break; + } else { + LOG_ERROR("Unexpected token in enum specifier"); + scc_parser_next_consume(parser, null); + break; + } + } + + decl = scc_malloc(sizeof(scc_ast_decl_t)); + Assert(decl != null); + if (type_kind == SCC_AST_TYPE_STRUCT) { + scc_ast_decl_struct_init(decl, name, &member); + } else { + scc_ast_decl_union_init(decl, name, &member); + } + } + + scc_ast_type_t *type = ast_type_alloc(); + _scc_ast_type_record_init(type, type_kind, name, decl); + return type; +} +static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) { + /* + (6.7.2.2) + enum-specifier: + enum identifier(opt) { enumerator-list } + enum identifier(opt) { enumerator-list , } + enum identifier + (6.7.2.2) + enumerator-list: + enumerator + enumerator-list , enumerator + (6.7.2.2) + enumerator: + enumeration-constant + enumeration-constant = constant-expression + */ + if (!scc_parser_consume_if(parser, SCC_TOK_ENUM)) { + LOG_ERROR("Expected 'enum'"); + return null; + } + const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser); + scc_lexer_tok_t tok; + const char *name = null; + scc_ast_decl_t *decl = null; + scc_ast_expr_vec_t member; + scc_vec_init(member); + + if (tok_ptr->type == SCC_TOK_IDENT) { + scc_parser_next_consume(parser, &tok); + tok_ptr = scc_parser_peek(parser); + name = scc_cstring_as_cstr(&tok.lexeme); + } + + if (tok_ptr && tok_ptr->type == SCC_TOK_L_BRACE) { + scc_parser_next_consume(parser, null); + while (1) { + tok_ptr = scc_parser_peek(parser); + if (tok_ptr == null) { + LOG_ERROR("Unexpected EOF in enum specifier"); + break; + } + + scc_ast_expr_t *expr = scc_parse_expression(parser); + if (expr != null) { + scc_vec_push(member, expr); + continue; + } + + if (tok_ptr->type == SCC_TOK_COMMA) { + // FIXME check comma + scc_parser_next_consume(parser, null); + } else if (tok_ptr->type == SCC_TOK_R_BRACE) { + scc_parser_next_consume(parser, null); + break; + } else { + LOG_ERROR("Unexpected token in enum specifier"); + scc_parser_next_consume(parser, null); + break; + } + } + decl = scc_malloc(sizeof(scc_ast_decl_t)); + Assert(decl != null); + scc_ast_decl_enum_init(decl, name, &member); + } + + scc_ast_type_t *type = ast_type_alloc(); + scc_ast_type_enum_init(type, name, decl); + return type; +} + static scc_ast_type_t *parse_type_specifier(scc_parser_t *parser) { type_spec_info_t info = {0}; if (!scc_parse_is_type_specifier_start(parser)) @@ -550,13 +711,12 @@ static scc_ast_type_t *parse_type_specifier(scc_parser_t *parser) { break; case SCC_TOK_STRUCT: case SCC_TOK_UNION: + info.user_type = parse_record_type( + parser, tok_ptr->type == SCC_TOK_STRUCT ? SCC_AST_TYPE_STRUCT + : SCC_AST_TYPE_UNION); + goto done; case SCC_TOK_ENUM: - // // 解析 struct/union/enum 说明符(需单独实现) - // info.user_type = parse_struct_union_enum(parser, tok->type); - // if (!info.user_type) - // return null; - // // 这些类型说明符后不能再跟其他类型说明符,因此直接跳出循环 - TODO(); + info.user_type = parse_enum_type(parser); goto done; case SCC_TOK_IDENT: // // 处理 typedef 名称:查符号表获取类型节点 diff --git a/libs/parser/src/scc_parser.c b/libs/parser/src/scc_parser.c index 18450b1..35d46a7 100644 --- a/libs/parser/src/scc_parser.c +++ b/libs/parser/src/scc_parser.c @@ -8,6 +8,13 @@ static void dummy_sema_callback(void *context, scc_ast_node_type_t node_type, return; } +static scc_ast_type_t *dummy_got_type_callback(void *context, + const char *name) { + (void)context; + (void)name; + return null; +} + #define ASSIGN_PTR_OR_DEFAULT(assigned_val, value, default) \ assigned_val = value ? value : default @@ -26,12 +33,15 @@ void scc_parser_init(scc_parser_t *parser, scc_lexer_tok_ring_t *tok_ring, callbacks->on_expr, dummy_sema_callback); ASSIGN_PTR_OR_DEFAULT(parser->sema_callbacks.on_type, callbacks->on_type, dummy_sema_callback); + ASSIGN_PTR_OR_DEFAULT(parser->sema_callbacks.got_type, + callbacks->got_type, dummy_got_type_callback); parser->sema_callbacks.context = callbacks->context; } else { parser->sema_callbacks.on_decl = dummy_sema_callback; parser->sema_callbacks.on_stmt = dummy_sema_callback; parser->sema_callbacks.on_expr = dummy_sema_callback; parser->sema_callbacks.on_type = dummy_sema_callback; + parser->sema_callbacks.got_type = dummy_got_type_callback; parser->sema_callbacks.context = null; } } diff --git a/libs/parser/src/scc_sema.c b/libs/parser/src/scc_sema.c index fd26198..97affcc 100644 --- a/libs/parser/src/scc_sema.c +++ b/libs/parser/src/scc_sema.c @@ -12,4 +12,5 @@ void scc_sema_init(scc_sema_callbacks_t *callbacks) { callbacks->on_expr = null; callbacks->on_stmt = null; callbacks->on_type = null; + callbacks->got_type = null; } diff --git a/libs/parser/tests/test_parser_unit.c b/libs/parser/tests/test_parser_unit.c index 1837ad2..3fa8b8d 100644 --- a/libs/parser/tests/test_parser_unit.c +++ b/libs/parser/tests/test_parser_unit.c @@ -28,6 +28,7 @@ static scc_ast_node_t *process_input(const char *input, scc_ring_not_eof(*parser.ring, not_eof); if (not_eof == true) { // FIXME MAYBE free + LOG_ERROR("Didn't consume all tokens"); return null; } @@ -53,19 +54,23 @@ static void dump2buffer(void *_buffer, const char *fmt, ...) { va_end(args); } +static void _scc_check_ast(scc_ast_node_t *expect_node_ptr, const char *str, + scc_parse_node_func parse_func) { + scc_ast_node_t *output_node_ptr = process_input(str, parse_func); + scc_tree_dump_ctx_t ctx; + expect_buffer[0] = '\n', expect_buffer[1] = '\0'; + scc_tree_dump_ctx_init(&ctx, true, dump2buffer, expect_buffer); + scc_ast_dump_node(&ctx, expect_node_ptr); + scc_tree_dump_ctx_drop(&ctx); + output_buffer[0] = '\n', output_buffer[1] = '\0'; + scc_tree_dump_ctx_init(&ctx, true, dump2buffer, output_buffer); + scc_ast_dump_node(&ctx, output_node_ptr); + scc_tree_dump_ctx_drop(&ctx); +} + #define SCC_CHECK_AST(expect_node_ptr, str, parse_func) \ do { \ - scc_ast_node_t *output_node_ptr = \ - process_input(str, (scc_parse_node_func)parse_func); \ - scc_tree_dump_ctx_t ctx; \ - expect_buffer[0] = '\n', expect_buffer[1] = '\0'; \ - scc_tree_dump_ctx_init(&ctx, true, dump2buffer, expect_buffer); \ - scc_ast_dump_node(&ctx, expect_node_ptr); \ - scc_tree_dump_ctx_drop(&ctx); \ - output_buffer[0] = '\n', output_buffer[1] = '\0'; \ - scc_tree_dump_ctx_init(&ctx, true, dump2buffer, output_buffer); \ - scc_ast_dump_node(&ctx, output_node_ptr); \ - scc_tree_dump_ctx_drop(&ctx); \ + _scc_check_ast(expect_node_ptr, str, (scc_parse_node_func)parse_func); \ TEST_CHECK(strcmp(output_buffer, expect_buffer) == 0); \ TEST_MSG("Expected: %s", expect_buffer); \ TEST_MSG("Produced: %s", output_buffer); \ @@ -368,6 +373,21 @@ static void test_parser_unit(void) { SCC_CHECK_AST(&typedef_decl.base, "typedef int int32_t;", scc_parse_declaration); } + + { + // struct { int x; } (匿名结构体定义) + scc_ast_decl_t field; + scc_ast_decl_val_init( + &field, (scc_ast_type_t *)&scc_ast_builtin_type_int, "x", null); + scc_ast_decl_vec_t fields; + scc_vec_init(fields); + scc_vec_push(fields, &field); + + scc_ast_decl_t struct_def; + scc_ast_decl_struct_init(&struct_def, null, &fields); + SCC_CHECK_AST(&struct_def.base, "struct { int x; };", + scc_parse_declaration); + } } static void test_parser_expression(void) { @@ -696,7 +716,7 @@ static void test_parser_type(void) { scc_ast_type_t array_of_int_var; scc_ast_type_array_init(&array_of_int_var, (scc_ast_type_t *)&scc_ast_builtin_type_int, - NULL); // NULL 表示不定长数组 + null); // null 表示不定长数组 scc_ast_type_t ptr_to_array_var; scc_ast_type_pointer_init(&ptr_to_array_var, &array_of_int_var); @@ -713,7 +733,7 @@ static void test_parser_type(void) { // 函数类型,返回 int*,无参数 scc_ast_type_t func_type; - scc_ast_type_function_init(&func_type, &ptr_to_int, NULL); + scc_ast_type_function_init(&func_type, &ptr_to_int, null); SCC_CHECK_AST(&func_type.base, "int *()", _scc_parse_type); } @@ -770,7 +790,7 @@ static void test_parser_type(void) { // --- 数组,元素为上述 const 指针,大小未指定 --- scc_ast_type_t array_of_ptr; - scc_ast_type_array_init(&array_of_ptr, &ptr_to_func, NULL); + scc_ast_type_array_init(&array_of_ptr, &ptr_to_func, null); SCC_CHECK_AST(&array_of_ptr.base, "int (*const [])(unsigned int, ...)", @@ -901,7 +921,7 @@ static void test_parser_type(void) { scc_ast_type_t array_of_int_unknown; scc_ast_type_array_init(&array_of_int_unknown, (scc_ast_type_t *)&scc_ast_builtin_type_int, - NULL); + null); SCC_CHECK_AST(&array_of_int_unknown.base, "int []", _scc_parse_type); // // int [*] (变长数组原型中的不定长数组) @@ -909,11 +929,11 @@ static void test_parser_type(void) { // scc_ast_type_t array_of_int_var; // scc_ast_type_array_init(&array_of_int_var, // (scc_ast_type_t *)&scc_ast_builtin_type_int, - // NULL); - // // 注意:[*] 与 [] 在AST中目前无法区分,都使用 size=NULL + // null); + // // 注意:[*] 与 [] 在AST中目前无法区分,都使用 size=null // // 表示。如果解析器需要区分,可能需要特殊处理。 这里暂时假设解析器对 // [*] - // // 也生成 size=NULL 的数组节点。 + // // 也生成 size=null 的数组节点。 // SCC_CHECK_AST(&array_of_int_var.base, "int [*]", scc_parse_type); // int [5][3] (二维数组) @@ -1087,46 +1107,57 @@ static void test_parser_type(void) { // struct S (不完整类型) scc_ast_type_t struct_tag; scc_ast_type_struct_init(&struct_tag, "S", - NULL); // name="S", members=NULL + null); // name="S", members=null SCC_CHECK_AST(&struct_tag.base, "struct S", _scc_parse_type); // struct { int x; } (匿名结构体定义) scc_ast_decl_t field; scc_ast_decl_val_init( - &field, (scc_ast_type_t *)&scc_ast_builtin_type_int, "x", NULL); + &field, (scc_ast_type_t *)&scc_ast_builtin_type_int, "x", null); scc_ast_decl_vec_t fields; scc_vec_init(fields); scc_vec_push(fields, &field); - scc_ast_type_t struct_def; - scc_ast_type_struct_init(&struct_def, NULL, - &fields); // name=NULL, members=fields - SCC_CHECK_AST(&struct_def.base, "struct { int x; }", _scc_parse_type); + scc_ast_decl_t struct_def; + scc_ast_decl_struct_init(&struct_def, null, &fields); + scc_ast_type_t struct_type; + scc_ast_type_struct_init(&struct_type, null, &struct_def); + SCC_CHECK_AST(&struct_type.base, "struct { int x; }", _scc_parse_type); + scc_ast_decl_struct_init(&struct_def, "A", &fields); + scc_ast_type_struct_init(&struct_type, "A", &struct_def); + SCC_CHECK_AST(&struct_type.base, "struct A { int x; }", + _scc_parse_type); // union U (不完整类型) scc_ast_type_t union_tag; - scc_ast_type_union_init(&union_tag, "U", NULL); + scc_ast_type_union_init(&union_tag, "U", null); SCC_CHECK_AST(&union_tag.base, "union U", _scc_parse_type); // union { int a; float b; } (匿名联合定义) scc_ast_decl_t field_a, field_b; scc_ast_decl_val_init( - &field_a, (scc_ast_type_t *)&scc_ast_builtin_type_int, "a", NULL); + &field_a, (scc_ast_type_t *)&scc_ast_builtin_type_int, "a", null); scc_ast_decl_val_init( - &field_b, (scc_ast_type_t *)&scc_ast_builtin_type_float, "b", NULL); + &field_b, (scc_ast_type_t *)&scc_ast_builtin_type_float, "b", null); scc_ast_decl_vec_t fields_union; scc_vec_init(fields_union); scc_vec_push(fields_union, &field_a); scc_vec_push(fields_union, &field_b); - scc_ast_type_t union_def; - scc_ast_type_union_init(&union_def, NULL, &fields_union); - SCC_CHECK_AST(&union_def.base, "union { int a; float b; }", + scc_ast_decl_t union_def; + scc_ast_decl_union_init(&union_def, null, &fields_union); + scc_ast_type_t union_type; + scc_ast_type_union_init(&union_type, null, &union_def); + SCC_CHECK_AST(&union_type.base, "union { int a; float b; }", + _scc_parse_type); + scc_ast_decl_union_init(&union_def, "Union", &fields_union); + scc_ast_type_union_init(&union_type, "Union", &union_def); + SCC_CHECK_AST(&union_type.base, "union Union { int a; float b; }", _scc_parse_type); // enum E (不完整类型) scc_ast_type_t enum_tag; - scc_ast_type_enum_init(&enum_tag, "E", NULL); + scc_ast_type_enum_init(&enum_tag, "E", null); SCC_CHECK_AST(&enum_tag.base, "enum E", _scc_parse_type); // enum { RED, GREEN, BLUE } (匿名枚举定义) @@ -1140,9 +1171,15 @@ static void test_parser_type(void) { scc_vec_push(enumerators, &green); scc_vec_push(enumerators, &blue); - scc_ast_type_t enum_def; - scc_ast_type_enum_init(&enum_def, NULL, &enumerators); - SCC_CHECK_AST(&enum_def.base, "enum { RED, GREEN, BLUE }", + scc_ast_decl_t enum_def; + scc_ast_decl_enum_init(&enum_def, null, &enumerators); + scc_ast_type_t enum_type; + scc_ast_type_enum_init(&enum_type, null, &enum_def); + SCC_CHECK_AST(&enum_type.base, "enum { RED, GREEN, BLUE }", + _scc_parse_type); + scc_ast_decl_enum_init(&enum_def, "E", &enumerators); + scc_ast_type_enum_init(&enum_type, "E", &enum_def); + SCC_CHECK_AST(&enum_type.base, "enum E { RED, GREEN, BLUE }", _scc_parse_type); } @@ -1189,13 +1226,13 @@ static void test_parser_type(void) { SCC_CHECK_AST(&ptr_to_array.base, "const int * volatile (*)[10]", _scc_parse_type); - // int (*(*)(int, ...))(float) + // float (*(*)(int, ...))() // 1) float 类型作为内部函数返回类型 // 2) 构建返回 float 的函数类型,无参数(或者参数为空) scc_ast_type_t func_ret_float; scc_ast_type_function_init( &func_ret_float, (scc_ast_type_t *)&scc_ast_builtin_type_float, - NULL); + null); // 3) 指针指向该函数 scc_ast_type_t ptr_to_func_ret_float; @@ -1220,7 +1257,7 @@ static void test_parser_type(void) { // 5) 指针指向外层函数 scc_ast_type_t ptr_to_outer_func; scc_ast_type_pointer_init(&ptr_to_outer_func, &outer_func); - SCC_CHECK_AST(&ptr_to_outer_func.base, "int (*(*)(int, ...))(float)", + SCC_CHECK_AST(&ptr_to_outer_func.base, "float (*(*)(int, ...))()", _scc_parse_type); } } @@ -1233,4 +1270,4 @@ TEST_LIST = { // {"parser_declaration", test_parser_declaration}, // {"parser_translation_unit", test_parser_translation_unit}, {null, null}, -}; \ No newline at end of file +};