feat(ast): 添加内置表达式支持并完善解析器功能
- 添加SCC_AST_EXPR_BUILTIN枚举值用于表示内置表达式 - 定义scc_ast_builtin_expr_type_t枚举包含va_start、va_end、va_copy、va_arg等内置函数类型 - 在AST表达式结构中添加builtin字段以支持内置表达式存储 - 实现scc_ast_decl_unsafe_val_init内联函数用于不安全的声明初始化 - 修改sizeof和alignof表达式初始化函数以支持类型或表达式参数 - 修复默认语句的字段引用错误(default_stmt而非case_stmt) - 改进词法分析器对整数字面量后缀(U、L、LL等)的处理逻辑 - 重构解析器中的声明解析逻辑,统一使用scc_parse_declarator函数 - 完善结构体、联合体和枚举类型的声明解析,支持仅有名称的前向声明 - 优化初始化列表解析,支持复合字面量的成员访问语法 - 更新参数类型列表解析以正确处理参数声明 - 修复括号表达式的解析逻辑,区分类型转换和普通括号表达式
This commit is contained in:
@@ -174,6 +174,7 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
. identifier
|
||||
*/
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
scc_lexer_tok_t tok = {0};
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
scc_ast_expr_t *init = null;
|
||||
if (!(tok_ptr && tok_ptr->type == SCC_TOK_L_BRACE)) {
|
||||
@@ -191,21 +192,21 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
scc_vec_init(rhs_exprs);
|
||||
scc_ast_expr_t *lhs = null;
|
||||
scc_ast_expr_t *rhs = null;
|
||||
|
||||
scc_ast_expr_t *ptr = base;
|
||||
while (1) {
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr->type == SCC_TOK_DOT) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr && tok_ptr->type == SCC_TOK_IDENT) {
|
||||
scc_parser_next(parser);
|
||||
scc_parser_next_consume(parser, &tok);
|
||||
lhs = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(lhs != null);
|
||||
scc_ast_expr_member_init(lhs, base,
|
||||
scc_cstring_as_cstr(&tok_ptr->lexeme));
|
||||
scc_ast_expr_member_init(lhs, ptr,
|
||||
scc_cstring_as_cstr(&tok.lexeme));
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_ASSIGN)) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected '='");
|
||||
ptr = lhs;
|
||||
continue;
|
||||
}
|
||||
rhs = scc_parse_initializer(parser, lhs);
|
||||
if (rhs == null) {
|
||||
@@ -215,6 +216,7 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
}
|
||||
scc_vec_push(lhs_exprs, lhs);
|
||||
scc_vec_push(rhs_exprs, rhs);
|
||||
ptr = base;
|
||||
} else {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected 'identifier' after '.'");
|
||||
@@ -228,14 +230,16 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
}
|
||||
lhs = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(lhs != null);
|
||||
scc_ast_expr_array_subscript_init(lhs, base, idx);
|
||||
scc_ast_expr_array_subscript_init(lhs, ptr, idx);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_ASSIGN)) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Expected '='");
|
||||
ptr = lhs;
|
||||
continue;
|
||||
}
|
||||
rhs = scc_parse_initializer(parser, lhs);
|
||||
Assert(rhs != null);
|
||||
scc_vec_push(lhs_exprs, lhs);
|
||||
scc_vec_push(rhs_exprs, rhs);
|
||||
ptr = base;
|
||||
} else if (tok_ptr->type == SCC_TOK_R_BRACE) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
break;
|
||||
@@ -254,31 +258,8 @@ scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
}
|
||||
|
||||
scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
||||
scc_ast_node_t *type_or_decl = _scc_parse_type(parser);
|
||||
scc_ast_decl_t *decl = null;
|
||||
if (type_or_decl == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
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) {
|
||||
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 {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "invalid declaration");
|
||||
scc_ast_decl_t *decl = scc_parse_declarator(parser);
|
||||
if (decl == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -305,6 +286,8 @@ scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
||||
Assert(decl->func.body != null);
|
||||
Assert(decl->func.body->base.type == SCC_AST_STMT_COMPOUND);
|
||||
} else {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected ';' or '=' or '{'");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
@@ -507,10 +507,25 @@ static scc_ast_expr_t *parse_cast_expression(scc_parser_t *parser) {
|
||||
|
||||
// 一元表达式
|
||||
static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) {
|
||||
/*
|
||||
(6.5.3)
|
||||
unary-expression:
|
||||
postfix-expression
|
||||
++ unary-expression
|
||||
-- unary-expression
|
||||
unary-operator cast-expression
|
||||
sizeof unary-expression
|
||||
sizeof ( type-name )
|
||||
(6.5.3)
|
||||
unary-operator: one of
|
||||
& * + - ~ !
|
||||
*/
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (!tok_ptr)
|
||||
return null;
|
||||
|
||||
scc_lexer_tok_t tok = {0};
|
||||
|
||||
// 处理一元运算符
|
||||
switch (tok_ptr->type) {
|
||||
case SCC_TOK_ADD_ADD: // ++x
|
||||
@@ -529,7 +544,14 @@ static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) {
|
||||
scc_lexer_tok_drop(&op_tok);
|
||||
|
||||
// 一元运算符右结合,递归调用 parse_unary_expression
|
||||
scc_ast_expr_t *operand = parse_unary_expression(parser);
|
||||
|
||||
scc_ast_expr_t *operand = null;
|
||||
if (tok_ptr->type == SCC_TOK_ADD_ADD ||
|
||||
tok_ptr->type == SCC_TOK_SUB_SUB) {
|
||||
operand = parse_unary_expression(parser);
|
||||
} else {
|
||||
operand = parse_cast_expression(parser);
|
||||
}
|
||||
if (!operand) {
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
@@ -563,35 +585,35 @@ static scc_ast_expr_t *parse_sizeof_expression(scc_parser_t *parser) {
|
||||
return null;
|
||||
}
|
||||
|
||||
scc_ast_expr_t *expr = null;
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
|
||||
// 尝试解析 sizeof(type-name)
|
||||
if (next->type == SCC_TOK_L_PAREN) {
|
||||
scc_parser_store(parser);
|
||||
scc_ast_type_t *type = scc_parse_type_name(parser);
|
||||
if (type) {
|
||||
// 消耗 ')'
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"expected ')' after type-name in sizeof expression");
|
||||
}
|
||||
scc_ast_expr_sizeof_init(null, type);
|
||||
return expr;
|
||||
} else {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected type-name after sizeof");
|
||||
TODO();
|
||||
scc_parser_next(parser);
|
||||
scc_ast_type_t *type_name = scc_parse_type_name(parser);
|
||||
if (type_name == null) {
|
||||
scc_parser_restore(parser);
|
||||
goto next;
|
||||
}
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
// 消耗 ')'
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"expected ')' after type-name in sizeof expression");
|
||||
}
|
||||
|
||||
Assert(type_name != null);
|
||||
scc_ast_expr_sizeof_init(expr, type_name, null);
|
||||
return expr;
|
||||
}
|
||||
// 否则作为 sizeof unary-expression
|
||||
next:
|
||||
// 尝试解析 sizeof unary-expression
|
||||
scc_ast_expr_t *operand = parse_unary_expression(parser);
|
||||
if (!operand) {
|
||||
scc_free(expr);
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
} else {
|
||||
scc_ast_expr_sizeof_init(operand, null);
|
||||
if (operand != null) {
|
||||
scc_ast_expr_sizeof_init(expr, null, operand);
|
||||
return expr;
|
||||
}
|
||||
|
||||
// 否则作为 sizeof(type-name)
|
||||
return expr;
|
||||
}
|
||||
|
||||
@@ -737,6 +759,14 @@ done:
|
||||
|
||||
// 基本表达式
|
||||
static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
/*
|
||||
(6.5.1)
|
||||
primary-expression:
|
||||
identifier
|
||||
constant
|
||||
string-literal
|
||||
( expression )
|
||||
*/
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (!tok_ptr)
|
||||
return null;
|
||||
@@ -803,66 +833,18 @@ static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_L_PAREN:
|
||||
return parse_paren_expression(parser);
|
||||
scc_parser_next_consume(parser, null);
|
||||
expr = scc_parse_expression(parser);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected ')' after expression");
|
||||
}
|
||||
return expr;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理括号表达式、类型转换、复合字面量
|
||||
static scc_ast_expr_t *parse_paren_expression(scc_parser_t *parser) {
|
||||
// 保存位置以便回退
|
||||
scc_parser_store(parser);
|
||||
|
||||
// 尝试解析类型名
|
||||
scc_ast_type_t *type = scc_parse_type_name(parser);
|
||||
if (type) {
|
||||
// 如果成功,下一个应该是 ')'
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
// 是类型转换,解析后面的 cast-expression
|
||||
scc_ast_expr_t *operand = parse_cast_expression(parser);
|
||||
if (!operand) {
|
||||
// FIXME postfix-expression
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
scc_ast_expr_lvalue_init(expr, type);
|
||||
operand = scc_parse_initializer(parser, expr);
|
||||
return operand;
|
||||
}
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_cast_init(expr, type, operand);
|
||||
return expr;
|
||||
} else {
|
||||
// 不是类型转换,回退并释放 type
|
||||
scc_parser_restore(parser);
|
||||
// TODO: scc_ast_type_drop(type);
|
||||
}
|
||||
} else {
|
||||
scc_parser_restore(parser);
|
||||
}
|
||||
|
||||
// 否则作为括号表达式
|
||||
scc_lexer_tok_t lp;
|
||||
if (!scc_parser_next_consume(parser, &lp) || lp.type != SCC_TOK_L_PAREN) {
|
||||
return null;
|
||||
}
|
||||
scc_lexer_tok_drop(&lp);
|
||||
|
||||
scc_ast_expr_t *inner = scc_parse_expression(parser);
|
||||
if (!inner) {
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected ')' after expression");
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
return inner;
|
||||
}
|
||||
|
||||
scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser) {
|
||||
scc_ast_expr_t *left = scc_parse_assignment_expression(parser);
|
||||
if (!left)
|
||||
|
||||
@@ -159,6 +159,21 @@ EXAMPLE The constructions
|
||||
#include <parser_utils.h>
|
||||
#include <scc_parser.h>
|
||||
|
||||
static scc_ast_type_t *parse_declarator(scc_parser_t *parser,
|
||||
scc_ast_type_t *base,
|
||||
scc_ast_type_t **delay_pointee_ptr,
|
||||
scc_lexer_tok_t *tok_ident);
|
||||
static scc_ast_type_t *
|
||||
parse_direct_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
scc_ast_type_t **delay_pointee_ptr,
|
||||
scc_lexer_tok_t *tok_ident);
|
||||
static scc_ast_type_t *
|
||||
parse_abstract_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
scc_ast_type_t **delay_pointee_ptr);
|
||||
static scc_ast_type_t *
|
||||
parse_direct_abstract_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
scc_ast_type_t **delay_pointee_ptr);
|
||||
|
||||
static inline scc_ast_type_t *ast_type_alloc() {
|
||||
scc_ast_type_t *ast_type = scc_malloc(sizeof(scc_ast_type_t));
|
||||
ast_type->base.type = SCC_AST_UNKNOWN;
|
||||
@@ -398,9 +413,8 @@ typedef struct {
|
||||
static cbool check_type_combinations(scc_parser_t *parser,
|
||||
type_spec_info_t *info) {
|
||||
// 基本类型不能同时出现多个(void, char, int, float, double, bool 互斥)
|
||||
int basic_count = info->is_void + info->is_char + info->is_short +
|
||||
info->is_int + info->is_float + info->is_double +
|
||||
info->is_bool;
|
||||
int basic_count = info->is_void + info->is_char + info->is_int +
|
||||
info->is_float + info->is_double + info->is_bool;
|
||||
if (basic_count > 1) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Multiple basic type specifiers");
|
||||
@@ -574,11 +588,7 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
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);
|
||||
}
|
||||
decl = scc_parse_declarator(parser);
|
||||
if (decl != null) {
|
||||
scc_vec_push(member, decl);
|
||||
continue;
|
||||
@@ -606,6 +616,21 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
scc_ast_decl_union_init(decl, name, &member);
|
||||
}
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
} else {
|
||||
if (name == null) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected name in struct/union specifier");
|
||||
// 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();
|
||||
@@ -678,6 +703,16 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
Assert(decl != null);
|
||||
scc_ast_decl_enum_init(decl, name, &member);
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
} else {
|
||||
if (name == null) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected name in enum specifier");
|
||||
// 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();
|
||||
@@ -818,21 +853,6 @@ duplicate_error:
|
||||
return null;
|
||||
}
|
||||
|
||||
static scc_ast_type_t *parse_declarator(scc_parser_t *parser,
|
||||
scc_ast_type_t *base,
|
||||
scc_ast_type_t **delay_pointee_ptr,
|
||||
scc_lexer_tok_t *tok_ident);
|
||||
static scc_ast_type_t *
|
||||
parse_direct_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
scc_ast_type_t **delay_pointee_ptr,
|
||||
scc_lexer_tok_t *tok_ident);
|
||||
static scc_ast_type_t *
|
||||
parse_abstract_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
scc_ast_type_t **delay_pointee_ptr);
|
||||
static scc_ast_type_t *
|
||||
parse_direct_abstract_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
scc_ast_type_t **delay_pointee_ptr);
|
||||
|
||||
static scc_ast_type_t *parse_pointer(scc_parser_t *parser,
|
||||
scc_ast_type_t *pointee,
|
||||
scc_ast_type_t **delay_pointee_ptr) {
|
||||
@@ -875,22 +895,15 @@ static void parse_parameter_type_list(scc_parser_t *parser,
|
||||
scc_ast_decl_t *param = null;
|
||||
while (1) {
|
||||
// FIXME
|
||||
scc_ast_node_t *node = _scc_parse_type(parser);
|
||||
if (node == null) {
|
||||
scc_ast_decl_t *decl = scc_parse_declarator(parser);
|
||||
if (decl == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SCC_AST_IS_A(scc_ast_decl_t, node)) {
|
||||
param = SCC_AST_CAST_TO(scc_ast_decl_t, node);
|
||||
// TODO Check validation
|
||||
Assert(param->base.type = SCC_AST_DECL_VAR);
|
||||
param->base.type = SCC_AST_DECL_PARAM;
|
||||
} else if (SCC_AST_IS_A(scc_ast_type_t, node)) {
|
||||
param = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(param != null);
|
||||
scc_ast_decl_param_init(
|
||||
param, SCC_AST_CAST_TO(scc_ast_type_t, node), null);
|
||||
}
|
||||
// TODO Check validation
|
||||
param = SCC_AST_CAST_TO(scc_ast_decl_t, decl);
|
||||
Assert(param->base.type = SCC_AST_DECL_VAR);
|
||||
param->base.type = SCC_AST_DECL_PARAM;
|
||||
|
||||
scc_vec_push(*params, param);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_COMMA)) {
|
||||
@@ -1129,7 +1142,7 @@ parse_direct_abstract_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
}
|
||||
}
|
||||
|
||||
scc_ast_node_t *_scc_parse_type(scc_parser_t *parser) {
|
||||
scc_ast_decl_t *scc_parse_declarator(scc_parser_t *parser) {
|
||||
if (!scc_parse_is_decl_specifier_start(parser)) {
|
||||
return null;
|
||||
}
|
||||
@@ -1177,7 +1190,37 @@ scc_ast_node_t *_scc_parse_type(scc_parser_t *parser) {
|
||||
}
|
||||
}
|
||||
|
||||
return decl != null ? &decl->base : &type->base;
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user