feat(parser): 添加声明列表支持并重构解析逻辑
- 添加 SCC_AST_DECL_LIST 节点类型用于表示声明列表 - 实现 scc_ast_decl_list_init 函数来初始化声明列表节点 - 重构 scc_parse_declaration 函数以支持逗号分隔的多个变量声明 - 分离类型说明符解析到独立的 scc_parse_declaration_specifiers 函数 - 支持 typedef 和多变量声明如 'int a, b;' 和 'int a = 1, b = 2;' - 在 ast_dump 中添加对声明列表节点的打印支持 refactor(ast): 统一使用 scc_vec_foreach 宏替换手动循环 - 将 ast_dump.c 中的多个手动索引循环改为使用 scc_vec_foreach - 提高代码可读性和安全性 - 避免索引越界错误 fix(parser): 修复语义分析中结构体符号表冲突 - 为结构体、联合体和枚举符号名添加前缀避免命名冲突 - 使用 '$S_'、'$U_'、'$E_' 前缀分别标识结构体、联合体和枚举 refactor(log): 统一终止处理方式 - 将 log_exit 替换为 log_abort 以更准确反映行为 - 更新相关依赖模块的实现 style(parser): 移除未使用的参数和清理代码 - 在 argparse.c 中添加 (void) 参数注释处理未使用的参数 - 清理 parse_expr.c 中未使用的函数声明 - 优化 parse_type.c 中的错误处理流程
This commit is contained in:
@@ -75,7 +75,9 @@ scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser);
|
||||
* @param parser 解析器实例
|
||||
* @return 类型 AST 节点
|
||||
*/
|
||||
scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser);
|
||||
scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser,
|
||||
scc_ast_type_t *type);
|
||||
scc_ast_type_t *scc_parse_declaration_specifiers(scc_parser_t *parser);
|
||||
scc_ast_type_t *scc_parse_type_name(scc_parser_t *parser);
|
||||
|
||||
static inline void scc_parse_decl_sema(scc_parser_t *parser,
|
||||
|
||||
@@ -258,25 +258,33 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
}
|
||||
|
||||
scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
||||
scc_ast_decl_t *decl = scc_parse_declarator(parser);
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
|
||||
scc_ast_decl_t *decl_list = null;
|
||||
scc_ast_decl_vec_t decl_list_vec;
|
||||
scc_vec_init(decl_list_vec);
|
||||
|
||||
scc_ast_type_t *type = scc_parse_declaration_specifiers(parser);
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
scc_ast_decl_specifier_t spec = type->quals;
|
||||
// FIXME drop typedef inline and ...
|
||||
type->quals.is_typedef = false;
|
||||
|
||||
scc_ast_decl_t *decl = null;
|
||||
CONTINUE:
|
||||
decl = scc_parse_declarator(parser, type);
|
||||
if (decl == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr->type == SCC_TOK_SEMICOLON) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
goto RETURN;
|
||||
} else if (tok_ptr->type == SCC_TOK_ASSIGN) {
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr->type == SCC_TOK_ASSIGN) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
// TODO maybe memory leak
|
||||
scc_ast_expr_t *lvalue = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
scc_ast_expr_lvalue_init(lvalue, decl->var.type);
|
||||
decl->var.init = scc_parse_initializer(parser, lvalue);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "expect semicolon");
|
||||
}
|
||||
goto RETURN;
|
||||
} else if (tok_ptr->type == SCC_TOK_L_BRACE) {
|
||||
scc_ast_stmt_t *body = scc_parse_statement(parser);
|
||||
Assert(decl->base.type == SCC_AST_DECL_FUNC);
|
||||
@@ -285,13 +293,56 @@ scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
||||
Assert(decl->func.type->base.type == SCC_AST_TYPE_FUNCTION);
|
||||
Assert(decl->func.body != null);
|
||||
Assert(decl->func.body->base.type == SCC_AST_STMT_COMPOUND);
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr->type == SCC_TOK_SEMICOLON) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
scc_ast_decl_list_init(decl_list, &decl_list_vec);
|
||||
decl = decl_list;
|
||||
} else {
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
}
|
||||
goto RETURN;
|
||||
} else if (tok_ptr->type == SCC_TOK_COMMA) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
if (decl_list == null) {
|
||||
decl_list = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl_list != null);
|
||||
scc_vec_push(decl_list_vec, decl);
|
||||
} else {
|
||||
Assert(scc_vec_size(decl_list_vec) != 0);
|
||||
decl->var.type = scc_vec_at(decl_list_vec, 0)->var.type;
|
||||
scc_vec_push(decl_list_vec, decl);
|
||||
}
|
||||
goto CONTINUE;
|
||||
} else {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected ';' or '=' or '{'");
|
||||
UNREACHABLE();
|
||||
// FIXME memory leak
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
RETURN:
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
return decl;
|
||||
ERROR:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -149,8 +149,6 @@ parse_primary_expression(scc_parser_t *parser); // 基本表达式
|
||||
|
||||
// 特殊结构的内部辅助函数
|
||||
static scc_ast_expr_t *parse_sizeof_expression(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *
|
||||
parse_paren_expression(scc_parser_t *parser); // 处理括号的三种情况
|
||||
|
||||
/* ---------------------------- 工具函数 ---------------------------- */
|
||||
// 获取 token 的优先级(用于二元运算符)
|
||||
@@ -537,11 +535,10 @@ static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) {
|
||||
case SCC_TOK_BIT_NOT: // ~x
|
||||
case SCC_TOK_NOT: // !x
|
||||
{
|
||||
scc_lexer_tok_t op_tok;
|
||||
if (!scc_parser_next_consume(parser, &op_tok))
|
||||
if (!scc_parser_next_consume(parser, &tok))
|
||||
return null;
|
||||
scc_ast_expr_op_t op = map_token_to_unary_op(op_tok.type, true);
|
||||
scc_lexer_tok_drop(&op_tok);
|
||||
scc_ast_expr_op_t op = map_token_to_unary_op(tok.type, true);
|
||||
scc_lexer_tok_drop(&tok);
|
||||
|
||||
// 一元运算符右结合,递归调用 parse_unary_expression
|
||||
|
||||
|
||||
@@ -588,10 +588,13 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
break;
|
||||
}
|
||||
|
||||
decl = scc_parse_declarator(parser);
|
||||
if (decl != null) {
|
||||
scc_vec_push(member, decl);
|
||||
continue;
|
||||
scc_ast_type_t *type = scc_parse_declaration_specifiers(parser);
|
||||
if (type != null) {
|
||||
decl = scc_parse_declarator(parser, type);
|
||||
if (decl != null) {
|
||||
scc_vec_push(member, decl);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (tok_ptr->type == SCC_TOK_SEMICOLON) {
|
||||
@@ -893,11 +896,16 @@ static void parse_parameter_type_list(scc_parser_t *parser,
|
||||
declaration-specifiers abstract-declarator(opt)
|
||||
*/
|
||||
scc_ast_decl_t *param = null;
|
||||
scc_ast_decl_t *decl = null;
|
||||
while (1) {
|
||||
// FIXME
|
||||
scc_ast_decl_t *decl = scc_parse_declarator(parser);
|
||||
scc_ast_type_t *type = scc_parse_declaration_specifiers(parser);
|
||||
if (type == null) {
|
||||
break;
|
||||
}
|
||||
decl = scc_parse_declarator(parser, type);
|
||||
if (decl == null) {
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO Check validation
|
||||
@@ -1142,87 +1150,142 @@ parse_direct_abstract_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
}
|
||||
}
|
||||
|
||||
scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser) {
|
||||
if (!scc_parse_is_decl_specifier_start(parser)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
cbool is_typedef_decl = false;
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_TYPEDEF)) {
|
||||
is_typedef_decl = true;
|
||||
}
|
||||
|
||||
scc_ast_type_t *ret = null;
|
||||
scc_ast_decl_specifier_t spec = {0};
|
||||
spec = parse_declaration_specifiers_list(parser, spec);
|
||||
ret = parse_type_specifier(parser);
|
||||
if (ret != null) {
|
||||
ret->quals = spec;
|
||||
ret->quals.is_inline = false;
|
||||
}
|
||||
|
||||
scc_lexer_tok_t tok_ident = {0};
|
||||
scc_ast_type_t *type = parse_declarator(parser, ret, null, &tok_ident);
|
||||
|
||||
scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser,
|
||||
scc_ast_type_t *type) {
|
||||
scc_lexer_tok_t decl_name_tok = {0};
|
||||
scc_ast_type_t *decl_type =
|
||||
parse_declarator(parser, type, null, &decl_name_tok);
|
||||
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;
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl != null);
|
||||
Assert(decl_name_tok.type == SCC_TOK_IDENT ||
|
||||
decl_name_tok.type == SCC_TOK_UNKNOWN);
|
||||
|
||||
// FIXME memory leak
|
||||
const char *name = decl_name_tok.type == SCC_TOK_IDENT
|
||||
? scc_cstring_as_cstr(&decl_name_tok.lexeme)
|
||||
: null;
|
||||
|
||||
if (decl_type->base.type == SCC_AST_TYPE_FUNCTION) {
|
||||
scc_ast_decl_func_init(decl, decl_type, name, null);
|
||||
// TODO using sema to change it
|
||||
if (type->quals.is_inline) {
|
||||
decl_type->quals.is_inline = true;
|
||||
} 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);
|
||||
type->quals.is_inline = false;
|
||||
}
|
||||
} else {
|
||||
scc_ast_decl_unsafe_val_init(decl, 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) {
|
||||
if (decl_name_tok.type != SCC_TOK_IDENT) {
|
||||
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 = type->record.decl;
|
||||
scc_free(type_or_decl); // FIXME
|
||||
} else if (type->base.type == SCC_AST_TYPE_ENUM) {
|
||||
if (type->enumeration.decl == null) {
|
||||
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 = type->enumeration.decl;
|
||||
scc_free(type_or_decl); // FIXME
|
||||
scc_free(decl_type); // 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_declaration_specifiers(scc_parser_t *parser) {
|
||||
if (!scc_parse_is_decl_specifier_start(parser)) {
|
||||
return null;
|
||||
}
|
||||
scc_ast_decl_specifier_t spec = {0};
|
||||
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_TYPEDEF)) {
|
||||
spec.is_typedef = true;
|
||||
}
|
||||
|
||||
spec = parse_declaration_specifiers_list(parser, spec);
|
||||
scc_ast_type_t *specifier = parse_type_specifier(parser);
|
||||
if (specifier == null) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"declaration specifier can't have type specifier");
|
||||
return null;
|
||||
}
|
||||
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) {
|
||||
if (!(scc_parse_is_type_specifier_start(parser) ||
|
||||
scc_parse_is_type_qualifier_start(parser))) {
|
||||
|
||||
@@ -64,7 +64,6 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
|
||||
* same as
|
||||
* Program := Declaration* Definition*
|
||||
*/
|
||||
cbool matched = false;
|
||||
while (1) {
|
||||
scc_ast_decl_t *decl = scc_parse_declaration(parser);
|
||||
if (decl != null) {
|
||||
|
||||
@@ -25,13 +25,22 @@ static void decl_callback(void *context, scc_ast_node_type_t node_type,
|
||||
}
|
||||
if (decl->base.type == SCC_AST_DECL_STRUCT) {
|
||||
scc_ast_type_struct_init(type, decl->name, decl);
|
||||
scc_sema_symtab_add_symbol(sema_symtab, decl->name, &type->base);
|
||||
scc_cstring_t name = scc_cstring_from_cstr("$S_");
|
||||
scc_cstring_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_cstring_as_cstr(&name),
|
||||
&type->base);
|
||||
} else if (decl->base.type == SCC_AST_DECL_UNION) {
|
||||
scc_ast_type_union_init(type, decl->name, decl);
|
||||
scc_sema_symtab_add_symbol(sema_symtab, decl->name, &type->base);
|
||||
scc_cstring_t name = scc_cstring_from_cstr("$U_");
|
||||
scc_cstring_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_cstring_as_cstr(&name),
|
||||
&type->base);
|
||||
} else if (decl->base.type == SCC_AST_DECL_ENUM) {
|
||||
scc_ast_type_enum_init(type, decl->name, decl);
|
||||
scc_sema_symtab_add_symbol(sema_symtab, decl->name, &type->base);
|
||||
scc_cstring_t name = scc_cstring_from_cstr("$E_");
|
||||
scc_cstring_append_cstr(&name, decl->name, scc_strlen(decl->name));
|
||||
scc_sema_symtab_add_symbol(sema_symtab, scc_cstring_as_cstr(&name),
|
||||
&type->base);
|
||||
} else if (decl->base.type == SCC_AST_DECL_TYPEDEF) {
|
||||
scc_ast_type_typedef_init(type, decl->name, decl);
|
||||
scc_sema_symtab_add_symbol(sema_symtab, decl->name, &type->base);
|
||||
|
||||
@@ -23,8 +23,9 @@ void scc_sema_symtab_enter_scope(scc_sema_symtab_t *symtab) {
|
||||
return;
|
||||
}
|
||||
scope->parent = symtab->current_scope;
|
||||
scc_hashtable_init(&scope->symbols, (scc_hashtable_hash_func_t)scc_strcmp,
|
||||
(scc_hashtable_equal_func_t)scc_strhash32);
|
||||
scc_hashtable_init(&scope->symbols,
|
||||
(scc_hashtable_hash_func_t)scc_strhash32,
|
||||
(scc_hashtable_equal_func_t)scc_strcmp);
|
||||
symtab->current_scope = scope;
|
||||
}
|
||||
|
||||
|
||||
@@ -689,55 +689,57 @@ static void test_parser_unit(void) {
|
||||
scc_parse_declaration);
|
||||
}
|
||||
|
||||
// // 测试 int a, b;
|
||||
// {
|
||||
// scc_ast_decl_t decl_a, decl_b;
|
||||
// scc_ast_decl_val_init(&decl_a,
|
||||
// (scc_ast_type_t
|
||||
// *)&scc_ast_builtin_type_int, "a", null);
|
||||
// scc_ast_decl_val_init(&decl_b,
|
||||
// (scc_ast_type_t
|
||||
// *)&scc_ast_builtin_type_int, "b", null);
|
||||
// 测试 int a, b;
|
||||
{
|
||||
scc_ast_decl_t decl_a, decl_b;
|
||||
scc_ast_decl_val_init(&decl_a,
|
||||
(scc_ast_type_t *)&scc_ast_builtin_type_int,
|
||||
"a", null);
|
||||
scc_ast_decl_val_init(&decl_b,
|
||||
(scc_ast_type_t *)&scc_ast_builtin_type_int,
|
||||
"b", null);
|
||||
|
||||
// scc_ast_decl_vec_t decl_vec;
|
||||
// scc_vec_init(decl_vec);
|
||||
// scc_vec_push(decl_vec, &decl_a);
|
||||
// scc_vec_push(decl_vec, &decl_b);
|
||||
scc_ast_decl_vec_t decl_vec;
|
||||
scc_vec_init(decl_vec);
|
||||
scc_vec_push(decl_vec, &decl_a);
|
||||
scc_vec_push(decl_vec, &decl_b);
|
||||
|
||||
// scc_ast_decl_t decl_list;
|
||||
// scc_ast_decl_list_init(&decl_list, &decl_vec); // 假设存在该函数
|
||||
scc_ast_decl_t decl_list;
|
||||
scc_ast_decl_list_init(&decl_list, &decl_vec); // 假设存在该函数
|
||||
|
||||
// SCC_CHECK_AST(&decl_list.base, "int a, b;",
|
||||
// scc_parse_declaration);
|
||||
// }
|
||||
SCC_CHECK_AST(&decl_list.base, "int a, b;", scc_parse_declaration);
|
||||
}
|
||||
|
||||
// // 测试 int a = 1, b = 2;
|
||||
// {
|
||||
// scc_ast_expr_t lit1, lit2;
|
||||
// scc_ast_expr_literal_int_init(&lit1, "1", false);
|
||||
// scc_ast_expr_literal_int_init(&lit2, "2", false);
|
||||
// 测试 int a = 1, b = 2;
|
||||
{
|
||||
scc_ast_expr_t lit1, lit2;
|
||||
scc_ast_expr_literal_int_init(&lit1, "1", false);
|
||||
scc_ast_expr_literal_int_init(&lit2, "2", false);
|
||||
|
||||
// scc_ast_decl_t decl_a, decl_b;
|
||||
// scc_ast_decl_val_init(&decl_a,
|
||||
// (scc_ast_type_t
|
||||
// *)&scc_ast_builtin_type_int, "a", &lit1);
|
||||
// scc_ast_decl_val_init(&decl_b,
|
||||
// (scc_ast_type_t
|
||||
// *)&scc_ast_builtin_type_int, "b", &lit2);
|
||||
scc_ast_decl_t decl_a, decl_b;
|
||||
scc_ast_decl_val_init(&decl_a,
|
||||
(scc_ast_type_t *)&scc_ast_builtin_type_int,
|
||||
"a", &lit1);
|
||||
scc_ast_decl_val_init(&decl_b,
|
||||
(scc_ast_type_t *)&scc_ast_builtin_type_int,
|
||||
"b", &lit2);
|
||||
|
||||
// scc_ast_decl_vec_t decl_vec;
|
||||
// scc_vec_init(decl_vec);
|
||||
// scc_vec_push(decl_vec, &decl_a);
|
||||
// scc_vec_push(decl_vec, &decl_b);
|
||||
scc_ast_decl_vec_t decl_vec;
|
||||
scc_vec_init(decl_vec);
|
||||
scc_vec_push(decl_vec, &decl_a);
|
||||
scc_vec_push(decl_vec, &decl_b);
|
||||
|
||||
// scc_ast_decl_t decl_list;
|
||||
// scc_ast_decl_list_init(&decl_list, &decl_vec); // 假设存在该函数
|
||||
scc_ast_decl_t decl_list;
|
||||
scc_ast_decl_list_init(&decl_list, &decl_vec); // 假设存在该函数
|
||||
|
||||
// SCC_CHECK_AST(&decl_list.base, "int a = 1, b = 2;",
|
||||
// scc_parse_declaration);
|
||||
// }
|
||||
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;";
|
||||
"__scc_builtin_va_arg(ag, int)";
|
||||
"__scc_builtin_va_arg(ag, long long)";
|
||||
"typedef struct a;int a;struct a b;";
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user