fix(ast): 修复AST转储中逗号分隔符逻辑错误
在dump_decl_impl函数中,修正了列表元素间逗号分隔符的判断逻辑, 将条件从"不是最后一个元素"改为"是最后一个元素",确保正确的 分隔符输出。 BREAKING CHANGE: 逗号分隔符的逻辑被反转,影响AST转储输出格式。 --- fix(parser): 修复声明列表处理中的内存泄漏问题 调整了typedef声明的处理顺序,在解析完成前添加声明到列表, 避免了重复添加导致的内存泄漏。同时移除了不必要的错误检查。 --- refactor(parser): 重构记录类型和枚举类型的声明初始化逻辑 移除了重复的声明创建代码,统一了结构体、联合体和枚举类型的 声明初始化流程,消除了之前存在的Panic错误路径。 --- test(parser): 增加复杂声明的单元测试覆盖 添加了对结构体指针声明和typedef复合声明的测试用例, 提高了测试覆盖率并验证了解析器的正确性。 --- feat(preprocessor): 添加预定义宏支持 增加了__SCC__、_WIN64和__x86_64__等预定义宏的定义, 为不同平台提供更好的编译支持。
This commit is contained in:
@@ -608,7 +608,6 @@ static void dump_decl_impl(scc_ast_decl_t *decl, scc_tree_dump_ctx_t *ctx) {
|
||||
if (decl->name) {
|
||||
PRINT_QUOTED_VALUE(ctx, decl->name);
|
||||
}
|
||||
|
||||
end_node_dump(ctx);
|
||||
|
||||
// 递归转储子节点
|
||||
@@ -616,7 +615,7 @@ static void dump_decl_impl(scc_ast_decl_t *decl, scc_tree_dump_ctx_t *ctx) {
|
||||
case SCC_AST_DECL_LIST:
|
||||
scc_vec_foreach(decl->list.vars, i) {
|
||||
dump_child_node((scc_ast_node_t *)scc_vec_at(decl->list.vars, i),
|
||||
ctx, i + 1 != scc_vec_size(decl->list.vars));
|
||||
ctx, i + 1 == scc_vec_size(decl->list.vars));
|
||||
}
|
||||
break;
|
||||
case SCC_AST_DECL_VAR:
|
||||
@@ -650,7 +649,7 @@ static void dump_decl_impl(scc_ast_decl_t *decl, scc_tree_dump_ctx_t *ctx) {
|
||||
scc_vec_foreach(decl->record.fields, i) {
|
||||
dump_child_node(
|
||||
(scc_ast_node_t *)scc_vec_at(decl->record.fields, i), ctx,
|
||||
i + 1 != scc_vec_size(decl->record.fields));
|
||||
i + 1 == scc_vec_size(decl->record.fields));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -658,7 +657,7 @@ static void dump_decl_impl(scc_ast_decl_t *decl, scc_tree_dump_ctx_t *ctx) {
|
||||
scc_vec_foreach(decl->enumeration.enumerators, i) {
|
||||
dump_child_node(
|
||||
(scc_ast_node_t *)scc_vec_at(decl->enumeration.enumerators, i),
|
||||
ctx, i + 1 != scc_vec_size(decl->enumeration.enumerators));
|
||||
ctx, i + 1 == scc_vec_size(decl->enumeration.enumerators));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -684,7 +683,7 @@ static void dump_unit_impl(scc_ast_translation_unit_t *unit,
|
||||
end_node_dump(ctx);
|
||||
scc_vec_foreach(unit->declarations, i) {
|
||||
dump_child_node((scc_ast_node_t *)scc_vec_at(unit->declarations, i),
|
||||
ctx, i + 1 != scc_vec_size(unit->declarations));
|
||||
ctx, i + 1 == scc_vec_size(unit->declarations));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -299,19 +299,19 @@ CONTINUE:
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr->type == SCC_TOK_SEMICOLON) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
if (decl_list)
|
||||
scc_vec_push(decl_list_vec, decl);
|
||||
if (spec.is_typedef) {
|
||||
if (decl_list) {
|
||||
scc_vec_foreach(decl_list_vec, i) {
|
||||
decl = scc_vec_at(decl_list_vec, i);
|
||||
scc_ast_decl_typedef_init(decl, decl->name, type);
|
||||
scc_ast_decl_typedef_init(decl, decl->name, decl->var.type);
|
||||
}
|
||||
} else {
|
||||
scc_ast_decl_typedef_init(decl, decl->name, decl->var.type);
|
||||
}
|
||||
}
|
||||
if (decl_list != null) {
|
||||
scc_vec_push(decl_list_vec, decl);
|
||||
|
||||
scc_vec_foreach(decl_list_vec, i) {
|
||||
decl = scc_vec_at(decl_list_vec, i);
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
|
||||
@@ -626,20 +626,13 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
// FIXME memory leak
|
||||
return null;
|
||||
}
|
||||
|
||||
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, null);
|
||||
} else {
|
||||
scc_ast_decl_union_init(decl, name, null);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -713,9 +706,6 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
// FIXME memory leak
|
||||
return null;
|
||||
}
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl != null);
|
||||
scc_ast_decl_enum_init(decl, name, null);
|
||||
}
|
||||
|
||||
scc_ast_type_t *type = ast_type_alloc();
|
||||
@@ -1182,20 +1172,27 @@ scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser,
|
||||
if (decl_type->base.type == SCC_AST_TYPE_STRUCT ||
|
||||
decl_type->base.type == SCC_AST_TYPE_UNION) {
|
||||
if (decl_type->record.decl == null) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"record don't have a decl");
|
||||
Panic();
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl != null);
|
||||
if (decl_type->base.type == SCC_AST_TYPE_STRUCT) {
|
||||
scc_ast_decl_struct_init(decl, decl_type->record.name,
|
||||
null);
|
||||
} else {
|
||||
scc_ast_decl_union_init(decl, decl_type->record.name, null);
|
||||
}
|
||||
} else {
|
||||
decl = decl_type->record.decl;
|
||||
scc_free(decl_type); // FIXME
|
||||
}
|
||||
decl = decl_type->record.decl;
|
||||
scc_free(decl_type); // FIXME
|
||||
} else if (decl_type->base.type == SCC_AST_TYPE_ENUM) {
|
||||
if (decl_type->enumeration.decl == null) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"enum don't have a decl");
|
||||
Panic();
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl != null);
|
||||
scc_ast_decl_enum_init(decl, type->enumeration.name, null);
|
||||
} else {
|
||||
decl = type->enumeration.decl;
|
||||
scc_free(decl_type); // FIXME
|
||||
}
|
||||
decl = type->enumeration.decl;
|
||||
scc_free(decl_type); // FIXME
|
||||
} else {
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
scc_ast_decl_unsafe_val_init(decl, type, null, null);
|
||||
@@ -1224,66 +1221,6 @@ scc_ast_type_t *scc_parse_declaration_specifiers(scc_parser_t *parser) {
|
||||
specifier->quals = spec;
|
||||
|
||||
return specifier;
|
||||
// scc_lexer_tok_t tok_ident = {0};
|
||||
// scc_ast_type_t *type = parse_declarator(parser, ret, null, &tok_ident);
|
||||
|
||||
// scc_ast_decl_t *decl = null;
|
||||
// if (tok_ident.type == SCC_TOK_IDENT) {
|
||||
// decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
// Assert(decl != null);
|
||||
// }
|
||||
// const char *name = decl ? scc_cstring_as_cstr(&tok_ident.lexeme) : null;
|
||||
// if (is_typedef_decl) {
|
||||
// if (decl == null) {
|
||||
// SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
// "typedef don't have a ident");
|
||||
// parser->errcode = 1;
|
||||
// } else {
|
||||
// scc_ast_decl_typedef_init(decl, name, type);
|
||||
// }
|
||||
// } else if (decl) {
|
||||
// if (type->base.type == SCC_AST_TYPE_FUNCTION) {
|
||||
// scc_ast_decl_func_init(decl, type, name, null);
|
||||
// // TODO using sema to change it
|
||||
// if (spec.is_inline) {
|
||||
// type->quals.is_inline = true;
|
||||
// }
|
||||
// } else {
|
||||
// scc_ast_decl_val_init(decl, type, name, null);
|
||||
// }
|
||||
// }
|
||||
|
||||
// scc_ast_node_t *type_or_decl = decl != null ? &decl->base : &type->base;
|
||||
// if (SCC_AST_IS_A(scc_ast_type_t, type_or_decl)) {
|
||||
// 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) {
|
||||
// if (type->record.decl == null) {
|
||||
// SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
// "record don't have a decl");
|
||||
// Panic();
|
||||
// }
|
||||
// decl = type->record.decl;
|
||||
// scc_free(type_or_decl); // FIXME
|
||||
// } else if (type->base.type == SCC_AST_TYPE_ENUM) {
|
||||
// if (type->enumeration.decl == null) {
|
||||
// SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
// "enum don't have a decl");
|
||||
// Panic();
|
||||
// }
|
||||
// decl = type->enumeration.decl;
|
||||
// scc_free(type_or_decl); // FIXME
|
||||
// } else {
|
||||
// decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
// scc_ast_decl_unsafe_val_init(decl, type, null, 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 {
|
||||
// SCC_ERROR(scc_parser_got_current_pos(parser), "invalid declaration");
|
||||
// return null;
|
||||
// }
|
||||
// return decl;
|
||||
}
|
||||
|
||||
scc_ast_type_t *scc_parse_type_name(scc_parser_t *parser) {
|
||||
|
||||
@@ -545,7 +545,7 @@ static void test_parser_unit(void) {
|
||||
|
||||
// 6. 函数声明
|
||||
scc_ast_decl_t decl;
|
||||
scc_ast_decl_func_init(&decl, &func_type, "call", NULL);
|
||||
scc_ast_decl_func_init(&decl, &func_type, "call", null);
|
||||
|
||||
// 7. 与解析结果比较
|
||||
SCC_CHECK_AST_WITH_SEMA(&decl.base,
|
||||
@@ -735,8 +735,81 @@ static void test_parser_unit(void) {
|
||||
SCC_CHECK_AST(&decl_list.base, "int a = 1, b = 2;",
|
||||
scc_parse_declaration);
|
||||
}
|
||||
"struct list_head *next, *prev;";
|
||||
"typedef struct { int a; } struct_t, *struct_ptr_t;";
|
||||
// 测试 "struct list_head *next, *prev;"
|
||||
{
|
||||
// 构造 struct list_head 类型(不完整)
|
||||
scc_ast_type_t struct_list_head;
|
||||
scc_ast_type_struct_init(&struct_list_head, "list_head", null);
|
||||
|
||||
// 构造两个指针类型(分别用于 next 和 prev,指向同一结构体)
|
||||
scc_ast_type_t ptr_to_struct1, ptr_to_struct2;
|
||||
scc_ast_type_pointer_init(&ptr_to_struct1, &struct_list_head);
|
||||
scc_ast_type_pointer_init(&ptr_to_struct2, &struct_list_head);
|
||||
|
||||
// 构造变量声明 next 和 prev
|
||||
scc_ast_decl_t next_decl, prev_decl;
|
||||
scc_ast_decl_val_init(&next_decl, &ptr_to_struct1, "next", null);
|
||||
scc_ast_decl_val_init(&prev_decl, &ptr_to_struct2, "prev", null);
|
||||
|
||||
// 构造声明列表
|
||||
scc_ast_decl_vec_t decl_vec;
|
||||
scc_vec_init(decl_vec);
|
||||
scc_vec_push(decl_vec, &next_decl);
|
||||
scc_vec_push(decl_vec, &prev_decl);
|
||||
scc_ast_decl_t decl_list;
|
||||
scc_ast_decl_list_init(&decl_list, &decl_vec);
|
||||
|
||||
SCC_CHECK_AST(&decl_list.base, "struct list_head *next, *prev;",
|
||||
scc_parse_declaration);
|
||||
}
|
||||
|
||||
// 测试 "typedef struct { int a; } struct_t, *struct_ptr_t;"
|
||||
{
|
||||
// 构造字段 int a;
|
||||
scc_ast_decl_t field_a;
|
||||
scc_ast_decl_val_init(&field_a,
|
||||
(scc_ast_type_t *)&scc_ast_builtin_type_int,
|
||||
"a", null);
|
||||
|
||||
scc_ast_decl_vec_t fields;
|
||||
scc_vec_init(fields);
|
||||
scc_vec_push(fields, &field_a);
|
||||
|
||||
// 构造匿名结构体定义声明
|
||||
scc_ast_decl_t struct_def;
|
||||
scc_ast_decl_struct_init(&struct_def, null,
|
||||
&fields); // fields 被移动
|
||||
|
||||
// 构造匿名结构体类型
|
||||
scc_ast_type_t anon_struct_type;
|
||||
scc_ast_type_struct_init(&anon_struct_type, null, &struct_def);
|
||||
|
||||
// 构造指针类型指向该匿名结构体
|
||||
scc_ast_type_t ptr_to_anon;
|
||||
scc_ast_type_pointer_init(&ptr_to_anon, &anon_struct_type);
|
||||
|
||||
// 构造 typedef 声明 struct_t
|
||||
scc_ast_decl_t typedef_struct_t;
|
||||
scc_ast_decl_typedef_init(&typedef_struct_t, "struct_t",
|
||||
&anon_struct_type);
|
||||
|
||||
// 构造 typedef 声明 struct_ptr_t
|
||||
scc_ast_decl_t typedef_struct_ptr_t;
|
||||
scc_ast_decl_typedef_init(&typedef_struct_ptr_t, "struct_ptr_t",
|
||||
&ptr_to_anon);
|
||||
|
||||
// 构造声明列表
|
||||
scc_ast_decl_vec_t typedef_vec;
|
||||
scc_vec_init(typedef_vec);
|
||||
scc_vec_push(typedef_vec, &typedef_struct_t);
|
||||
scc_vec_push(typedef_vec, &typedef_struct_ptr_t);
|
||||
scc_ast_decl_t decl_list;
|
||||
scc_ast_decl_list_init(&decl_list, &typedef_vec);
|
||||
|
||||
SCC_CHECK_AST(&decl_list.base,
|
||||
"typedef struct { int a; } struct_t, *struct_ptr_t;",
|
||||
scc_parse_declaration);
|
||||
}
|
||||
"__scc_builtin_va_arg(ag, int)";
|
||||
"__scc_builtin_va_arg(ag, long long)";
|
||||
"typedef struct a;int a;struct a b;";
|
||||
|
||||
24
src/main.c
24
src/main.c
@@ -264,9 +264,27 @@ int main(int argc, const char **argv, const char **envp) {
|
||||
}
|
||||
scc_lexer_tok_vec_t pproc_tok_vec;
|
||||
scc_vec_init(pproc_tok_vec);
|
||||
scc_cstring_t pproc_macro_name = scc_cstring_from_cstr("__SCC__");
|
||||
scc_pproc_add_object_macro(&(pproc.macro_table), &pproc_macro_name,
|
||||
&pproc_tok_vec);
|
||||
scc_lexer_tok_t tok = {
|
||||
.lexeme = scc_cstring_from_cstr("1"),
|
||||
.type = SCC_TOK_INT_LITERAL,
|
||||
.loc.name = "<internal>",
|
||||
.loc.line = 0,
|
||||
.loc.col = 0,
|
||||
.loc.offset = 0,
|
||||
};
|
||||
scc_vec_push(pproc_tok_vec, tok);
|
||||
scc_cstring_t pproc_predefined_macros[] = {
|
||||
scc_cstring_from_cstr("__SCC__"),
|
||||
scc_cstring_from_cstr("_WIN64"),
|
||||
scc_cstring_from_cstr("__x86_64__"),
|
||||
};
|
||||
for (usize i = 0; i < SCC_ARRLEN(pproc_predefined_macros); i += 1) {
|
||||
scc_vec_init(pproc_tok_vec);
|
||||
scc_lexer_tok_t coped_tok = scc_lexer_tok_copy(&tok);
|
||||
scc_vec_push(pproc_tok_vec, coped_tok);
|
||||
scc_pproc_add_object_macro(&pproc.macro_table,
|
||||
&pproc_predefined_macros[i], &pproc_tok_vec);
|
||||
}
|
||||
if (config.emit_pp) {
|
||||
scc_lexer_tok_ring_t *tok_ring =
|
||||
scc_pproc_to_ring(&pproc, 8, true, true);
|
||||
|
||||
Reference in New Issue
Block a user