Compare commits
3 Commits
30ac2de73b
...
2d1032c363
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d1032c363 | |||
| c46578736a | |||
| b00a42a539 |
@@ -39,18 +39,19 @@ typedef enum {
|
||||
scc_ast_stmt_t_END, // 结束语句
|
||||
|
||||
// 表达式
|
||||
scc_ast_expr_t_BEGIN, // 表达式开始
|
||||
SCC_AST_EXPR_BINARY, // 二元运算
|
||||
SCC_AST_EXPR_UNARY, // 一元运算
|
||||
SCC_AST_EXPR_COND, // 条件表达式 ?:
|
||||
SCC_AST_EXPR_CALL, // 函数调用
|
||||
SCC_AST_EXPR_ARRAY_SUBSCRIPT, // 数组下标
|
||||
SCC_AST_EXPR_MEMBER, // 成员访问 .
|
||||
SCC_AST_EXPR_PTR_MEMBER, // 指针成员访问 ->
|
||||
SCC_AST_EXPR_CAST, // 类型转换
|
||||
SCC_AST_EXPR_SIZE_OF, // sizeof
|
||||
SCC_AST_EXPR_ALIGN_OF, // _Alignof
|
||||
SCC_AST_EXPR_COMPOUND_LITERAL, // 复合字面量
|
||||
scc_ast_expr_t_BEGIN, // 表达式开始
|
||||
SCC_AST_EXPR_BINARY, // 二元运算
|
||||
SCC_AST_EXPR_UNARY, // 一元运算
|
||||
SCC_AST_EXPR_COND, // 条件表达式 ?:
|
||||
SCC_AST_EXPR_CALL, // 函数调用
|
||||
SCC_AST_EXPR_ARRAY_SUBSCRIPT, // 数组下标
|
||||
SCC_AST_EXPR_MEMBER, // 成员访问 .
|
||||
SCC_AST_EXPR_PTR_MEMBER, // 指针成员访问 ->
|
||||
SCC_AST_EXPR_CAST, // 类型转换
|
||||
SCC_AST_EXPR_SIZE_OF, // sizeof
|
||||
SCC_AST_EXPR_ALIGN_OF, // _Alignof
|
||||
SCC_AST_EXPR_COMPOUND, // 复合字面量
|
||||
SCC_AST_EXPR_LVALUE, // 右值
|
||||
// 字面量
|
||||
SCC_AST_EXPR_INT_LITERAL, // 整数字面量
|
||||
SCC_AST_EXPR_FLOAT_LITERAL, // 浮点字面量
|
||||
@@ -189,7 +190,7 @@ struct scc_ast_type {
|
||||
} enumeration;
|
||||
struct {
|
||||
const char *name;
|
||||
scc_ast_type_t *underlying;
|
||||
scc_ast_decl_t *decl;
|
||||
} typedef_type;
|
||||
};
|
||||
};
|
||||
@@ -310,9 +311,10 @@ struct scc_ast_expr {
|
||||
} attr_of;
|
||||
// 复合字面量
|
||||
struct {
|
||||
scc_ast_type_t *type;
|
||||
scc_ast_expr_vec_t init_list;
|
||||
} compound_literal;
|
||||
scc_ast_expr_t *base;
|
||||
scc_ast_expr_vec_t lhs_exprs;
|
||||
scc_ast_expr_vec_t rhs_exprs;
|
||||
} compound;
|
||||
// 字面量
|
||||
struct {
|
||||
const char *lexme;
|
||||
@@ -323,6 +325,9 @@ struct scc_ast_expr {
|
||||
const char *name;
|
||||
scc_ast_decl_t *_target;
|
||||
} identifier;
|
||||
struct {
|
||||
scc_ast_type_t *type;
|
||||
} lvalue;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -341,24 +341,56 @@ static inline void scc_ast_expr_ptr_member_init(scc_ast_expr_t *expr,
|
||||
_scc_ast_expr_member_init(expr, SCC_AST_EXPR_PTR_MEMBER, object, member);
|
||||
}
|
||||
|
||||
// TODO
|
||||
// SCC_AST_EXPR_CAST, // 类型转换
|
||||
// SCC_AST_EXPR_SIZE_OF, // sizeof
|
||||
// SCC_AST_EXPR_ALIGN_OF, // _Alignof
|
||||
static inline void scc_ast_expr_cast_init(scc_ast_expr_t *expr,
|
||||
scc_ast_type_t *type,
|
||||
scc_ast_expr_t *operand) {
|
||||
Assert(expr != null && type != null && operand != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.type = SCC_AST_EXPR_CAST;
|
||||
expr->cast.type = type;
|
||||
expr->cast.expr = operand;
|
||||
}
|
||||
|
||||
// init can be null
|
||||
static inline void
|
||||
scc_ast_expr_compound_literal_init(scc_ast_expr_t *expr, scc_ast_type_t *type,
|
||||
scc_ast_expr_vec_t *init) {
|
||||
static inline void scc_ast_expr_sizeof_init(scc_ast_expr_t *expr,
|
||||
scc_ast_type_t *type) {
|
||||
Assert(expr != null && type != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.type = SCC_AST_EXPR_COMPOUND_LITERAL;
|
||||
expr->compound_literal.type = type;
|
||||
if (init == null) {
|
||||
scc_vec_init(expr->compound_literal.init_list);
|
||||
expr->base.type = SCC_AST_EXPR_SIZE_OF;
|
||||
expr->attr_of.type = type;
|
||||
expr->attr_of.expr = null;
|
||||
}
|
||||
|
||||
static inline void scc_ast_expr_alignof_init(scc_ast_expr_t *expr,
|
||||
scc_ast_type_t *type) {
|
||||
Assert(expr != null && type != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.type = SCC_AST_EXPR_SIZE_OF;
|
||||
expr->attr_of.type = type;
|
||||
expr->attr_of.expr = null;
|
||||
}
|
||||
|
||||
// lhs_exprs and rhs_exprs can be null
|
||||
static inline void scc_ast_expr_compound_init(scc_ast_expr_t *expr,
|
||||
scc_ast_expr_t *base,
|
||||
scc_ast_expr_vec_t *lhs_exprs,
|
||||
scc_ast_expr_vec_t *rhs_exprs) {
|
||||
Assert(expr != null && base != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.type = SCC_AST_EXPR_COMPOUND;
|
||||
expr->compound.base = base;
|
||||
|
||||
if (lhs_exprs == null) {
|
||||
scc_vec_init(expr->compound.lhs_exprs);
|
||||
} else {
|
||||
expr->compound_literal.init_list = *init;
|
||||
scc_vec_init(*init);
|
||||
expr->compound.lhs_exprs = *lhs_exprs;
|
||||
scc_vec_init(*lhs_exprs);
|
||||
}
|
||||
|
||||
if (rhs_exprs == null) {
|
||||
scc_vec_init(expr->compound.rhs_exprs);
|
||||
} else {
|
||||
expr->compound.rhs_exprs = *rhs_exprs;
|
||||
scc_vec_init(*rhs_exprs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,6 +435,14 @@ static inline void scc_ast_expr_identifier_init(scc_ast_expr_t *expr,
|
||||
expr->identifier._target = null;
|
||||
}
|
||||
|
||||
static inline void scc_ast_expr_lvalue_init(scc_ast_expr_t *expr,
|
||||
scc_ast_type_t *type) {
|
||||
Assert(expr != null && type != null);
|
||||
expr->base.loc = scc_pos_create();
|
||||
expr->base.type = SCC_AST_EXPR_LVALUE;
|
||||
expr->lvalue.type = type;
|
||||
}
|
||||
|
||||
// have defined builtin type
|
||||
static inline void _scc_ast_type_builtin_init(scc_ast_type_t *type,
|
||||
scc_ast_builtin_type_t builtin) {
|
||||
@@ -486,18 +526,18 @@ static inline void scc_ast_type_enum_init(scc_ast_type_t *type,
|
||||
type->base.type = SCC_AST_TYPE_ENUM;
|
||||
type->quals = (scc_ast_decl_specifier_t){0}; // FIXME
|
||||
type->enumeration.name = name;
|
||||
type->enumeration.decl = null;
|
||||
type->enumeration.decl = decl;
|
||||
}
|
||||
|
||||
static inline void scc_ast_type_typedef_init(scc_ast_type_t *type,
|
||||
const char *name,
|
||||
scc_ast_type_t *target) {
|
||||
scc_ast_decl_t *target) {
|
||||
Assert(type != null && target != null);
|
||||
type->base.loc = scc_pos_create();
|
||||
type->base.type = SCC_AST_TYPE_TYPEDEF;
|
||||
type->quals = (scc_ast_decl_specifier_t){0}; // FIXME
|
||||
type->typedef_type.name = name;
|
||||
type->typedef_type.underlying = target;
|
||||
type->typedef_type.decl = target;
|
||||
}
|
||||
|
||||
#endif /* __SCC_AST_H__ */
|
||||
|
||||
@@ -52,7 +52,8 @@ static const char *node_type_names[] = {
|
||||
[SCC_AST_EXPR_CAST] = "CastExpr",
|
||||
[SCC_AST_EXPR_SIZE_OF] = "SizeofExpr",
|
||||
[SCC_AST_EXPR_ALIGN_OF] = "AlignofExpr",
|
||||
[SCC_AST_EXPR_COMPOUND_LITERAL] = "CompoundLiteralExpr",
|
||||
[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",
|
||||
@@ -461,14 +462,25 @@ static void dump_expr_impl(scc_ast_expr_t *expr, scc_tree_dump_ctx_t *ctx) {
|
||||
}
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_COMPOUND_LITERAL:
|
||||
dump_child_node((scc_ast_node_t *)expr->compound_literal.type, ctx,
|
||||
false);
|
||||
// 初始化列表
|
||||
for (size_t i = 0; i < expr->compound_literal.init_list.size; i++) {
|
||||
case SCC_AST_EXPR_LVALUE:
|
||||
dump_child_node((scc_ast_node_t *)expr->lvalue.type, ctx, true);
|
||||
break;
|
||||
|
||||
case SCC_AST_EXPR_COMPOUND:;
|
||||
dump_child_node((scc_ast_node_t *)expr->compound.base, ctx, false);
|
||||
if (scc_vec_size(expr->compound.lhs_exprs) !=
|
||||
scc_vec_size(expr->compound.rhs_exprs)) {
|
||||
LOG_ERROR("compound expr lhs and rhs size not equal");
|
||||
break;
|
||||
}
|
||||
usize size = scc_vec_size(expr->compound.lhs_exprs);
|
||||
for (usize i = 0; i < size; i++) {
|
||||
dump_child_node(
|
||||
(scc_ast_node_t *)expr->compound_literal.init_list.data[i], ctx,
|
||||
i == expr->compound_literal.init_list.size - 1);
|
||||
(scc_ast_node_t *)scc_vec_at(expr->compound.lhs_exprs, i), ctx,
|
||||
false);
|
||||
dump_child_node(
|
||||
(scc_ast_node_t *)scc_vec_at(expr->compound.rhs_exprs, i), ctx,
|
||||
i + 1 == size);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -567,6 +579,10 @@ static void dump_stmt_impl(scc_ast_stmt_t *stmt, scc_tree_dump_ctx_t *ctx) {
|
||||
dump_child_node((scc_ast_node_t *)stmt->case_stmt.stmt, ctx, true);
|
||||
break;
|
||||
|
||||
case SCC_AST_STMT_BREAK:
|
||||
case SCC_AST_STMT_CONTINUE:
|
||||
break;
|
||||
|
||||
case SCC_AST_STMT_DEFAULT:
|
||||
end_node_dump(ctx);
|
||||
dump_child_node((scc_ast_node_t *)stmt->default_stmt.stmt, ctx, true);
|
||||
|
||||
@@ -71,4 +71,13 @@ static inline void scc_parser_reset(scc_parser_t *parser) {
|
||||
scc_ring_reset(*parser->ring);
|
||||
}
|
||||
|
||||
#include <scc_pos_log.h>
|
||||
static inline scc_pos_t scc_parser_got_current_pos(scc_parser_t *parser) {
|
||||
const scc_lexer_tok_t *tok = scc_parser_peek(parser);
|
||||
scc_pos_t pos = scc_pos_create();
|
||||
if (tok != null)
|
||||
pos = tok->loc;
|
||||
return pos;
|
||||
}
|
||||
|
||||
#endif /* __SCC_PARSER_UTILS_H__ */
|
||||
|
||||
@@ -51,6 +51,8 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser);
|
||||
* @return 声明 AST 节点
|
||||
*/
|
||||
scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser);
|
||||
scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
scc_ast_expr_t *base);
|
||||
|
||||
/**
|
||||
* @brief 解析语句
|
||||
@@ -58,6 +60,8 @@ scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser);
|
||||
* @return 语句 AST 节点
|
||||
*/
|
||||
scc_ast_stmt_t *scc_parse_statement(scc_parser_t *parser);
|
||||
scc_ast_expr_t *scc_parse_assignment_expression(scc_parser_t *parser);
|
||||
scc_ast_expr_t *scc_parser_constant_expression(scc_parser_t *parser);
|
||||
|
||||
/**
|
||||
* @brief 解析表达式
|
||||
@@ -75,4 +79,24 @@ scc_ast_node_t *_scc_parse_type(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,
|
||||
scc_ast_decl_t *decl) {
|
||||
parser->sema_callbacks.on_decl(parser->sema_callbacks.context,
|
||||
decl ? decl->base.type : SCC_AST_UNKNOWN,
|
||||
decl);
|
||||
}
|
||||
|
||||
static inline void scc_parse_type_sema(scc_parser_t *parser,
|
||||
scc_ast_type_t *type) {
|
||||
parser->sema_callbacks.on_type(parser->sema_callbacks.context,
|
||||
type ? type->base.type : SCC_AST_UNKNOWN,
|
||||
type);
|
||||
}
|
||||
|
||||
static inline scc_ast_type_t *scc_parse_got_type(scc_parser_t *parser,
|
||||
const char *name) {
|
||||
return parser->sema_callbacks.got_type(parser->sema_callbacks.context,
|
||||
name);
|
||||
}
|
||||
|
||||
#endif /* __SCC_PARSER_H__ */
|
||||
|
||||
@@ -154,10 +154,95 @@ A.2.4 External definitions
|
||||
#include <parser_utils.h>
|
||||
#include <scc_parser.h>
|
||||
|
||||
scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
||||
cbool ok;
|
||||
scc_lexer_tok_t tok;
|
||||
scc_ast_expr_t *scc_parse_initializer(scc_parser_t *parser,
|
||||
scc_ast_expr_t *base) {
|
||||
/*
|
||||
initializer:
|
||||
assignment-expression
|
||||
{ initializer-list }
|
||||
{ initializer-list , }
|
||||
initializer-list:
|
||||
designation(opt) initializer
|
||||
initializer-list , designation(opt) initializer
|
||||
designation:
|
||||
designator-list =
|
||||
designator-list:
|
||||
designator
|
||||
designator-list designator
|
||||
designator:
|
||||
[ constant-expression ]
|
||||
. identifier
|
||||
*/
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
scc_ast_expr_t *init = null;
|
||||
if (!(tok_ptr && tok_ptr->type == SCC_TOK_L_BRACE)) {
|
||||
// TODO int a = 1, b = 1;
|
||||
init = scc_parse_assignment_expression(parser);
|
||||
return init;
|
||||
}
|
||||
scc_parser_next_consume(parser, null);
|
||||
|
||||
init = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(init != null);
|
||||
scc_ast_expr_vec_t lhs_exprs;
|
||||
scc_vec_init(lhs_exprs);
|
||||
scc_ast_expr_vec_t rhs_exprs;
|
||||
scc_vec_init(rhs_exprs);
|
||||
scc_ast_expr_t *lhs = null;
|
||||
scc_ast_expr_t *rhs = null;
|
||||
|
||||
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) {
|
||||
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));
|
||||
|
||||
rhs = scc_parse_initializer(parser, lhs);
|
||||
Assert(rhs != null);
|
||||
scc_vec_push(lhs_exprs, lhs);
|
||||
scc_vec_push(rhs_exprs, rhs);
|
||||
} else {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected 'identifier' after '.'");
|
||||
}
|
||||
} else if (tok_ptr->type == SCC_TOK_L_BRACKET) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
scc_ast_expr_t *idx = scc_parser_constant_expression(parser);
|
||||
Assert(idx != null);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_BRACKET)) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Expected ']'");
|
||||
}
|
||||
lhs = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(lhs != null);
|
||||
scc_ast_expr_array_subscript_init(lhs, base, idx);
|
||||
|
||||
rhs = scc_parse_initializer(parser, lhs);
|
||||
Assert(rhs != null);
|
||||
scc_vec_push(lhs_exprs, lhs);
|
||||
scc_vec_push(rhs_exprs, rhs);
|
||||
} else if (tok_ptr->type == SCC_TOK_R_BRACE) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
break;
|
||||
} else if (tok_ptr->type == SCC_TOK_COMMA) {
|
||||
continue;
|
||||
} else {
|
||||
// FIXME
|
||||
scc_ast_expr_t *expr = scc_parse_initializer(parser, base);
|
||||
scc_vec_push(lhs_exprs, null);
|
||||
scc_vec_push(rhs_exprs, expr);
|
||||
}
|
||||
}
|
||||
scc_ast_expr_compound_init(init, base, &lhs_exprs, &rhs_exprs);
|
||||
return init;
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -182,7 +267,7 @@ scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
||||
} 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 {
|
||||
LOG_ERROR("invalid declaration");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "invalid declaration");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -192,10 +277,12 @@ scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
||||
goto RETURN;
|
||||
} else if (tok_ptr->type == SCC_TOK_ASSIGN) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
scc_ast_expr_t *init = scc_parse_expression(parser);
|
||||
decl->var.init = init;
|
||||
// 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)) {
|
||||
LOG_ERROR("expect semicolon");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "expect semicolon");
|
||||
}
|
||||
goto RETURN;
|
||||
} else if (tok_ptr->type == SCC_TOK_L_BRACE) {
|
||||
@@ -211,9 +298,6 @@ scc_ast_decl_t *scc_parse_declaration(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
RETURN:
|
||||
if (decl) {
|
||||
parser->sema_callbacks.on_decl(parser->sema_callbacks.context,
|
||||
decl->base.type, decl);
|
||||
}
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
@@ -132,43 +132,12 @@ typedef enum {
|
||||
PREC_PRIMARY = 17, // 最高优先级
|
||||
} scc_precedence_t;
|
||||
|
||||
static inline scc_ast_expr_t *expr_create(scc_parser_t *parser,
|
||||
scc_ast_node_type_t type) {
|
||||
scc_ast_expr_t *expr = (scc_ast_expr_t *)scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
expr->base.type = type;
|
||||
expr->base.loc = scc_pos_create();
|
||||
return expr;
|
||||
}
|
||||
|
||||
/* ---------------------------- 函数前向声明 ---------------------------- */
|
||||
static scc_ast_expr_t *expr_create(scc_parser_t *parser,
|
||||
scc_ast_node_type_t type);
|
||||
static scc_ast_expr_t *parse_expression_with_precedence(scc_parser_t *parser,
|
||||
int min_prec);
|
||||
|
||||
// 通用二元解析器(用于左结合各层)
|
||||
typedef scc_ast_expr_t *(*parse_sub_expr_func)(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *parse_binary_expression(scc_parser_t *parser,
|
||||
parse_sub_expr_func parse_sub,
|
||||
int this_prec);
|
||||
|
||||
// 各优先级层(除特殊的外,均调用通用解析器)
|
||||
static scc_ast_expr_t *parse_multiplicative_expression(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *parse_additive_expression(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *parse_shift_expression(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *parse_relational_expression(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *parse_equality_expression(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *parse_bitwise_and_expression(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *parse_bitwise_xor_expression(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *parse_bitwise_or_expression(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *parse_logical_and_expression(scc_parser_t *parser);
|
||||
static scc_ast_expr_t *parse_logical_or_expression(scc_parser_t *parser);
|
||||
|
||||
// 特殊结构:独立解析(右结合、条件、一元、后缀、基本)
|
||||
static scc_ast_expr_t *
|
||||
parse_assignment_expression(scc_parser_t *parser); // 右结合
|
||||
static scc_ast_expr_t *
|
||||
parse_conditional_expression(scc_parser_t *parser); // 右结合
|
||||
static scc_ast_expr_t *parse_cast_expression(scc_parser_t *parser); // 类型转换
|
||||
static scc_ast_expr_t *
|
||||
@@ -357,9 +326,9 @@ static scc_ast_expr_op_t map_token_to_assign_op(scc_tok_type_t type) {
|
||||
/* ---------------------------- 错误恢复辅助 ---------------------------- */
|
||||
// 跳过直到遇到同步 token(分号、右括号、逗号、EOF)
|
||||
static void parser_sync(scc_parser_t *parser) {
|
||||
const scc_lexer_tok_t *tok;
|
||||
while ((tok = scc_parser_peek(parser)) != null) {
|
||||
scc_tok_type_t type = tok->type;
|
||||
const scc_lexer_tok_t *tok_ptr;
|
||||
while ((tok_ptr = scc_parser_peek(parser)) != null) {
|
||||
scc_tok_type_t type = tok_ptr->type;
|
||||
if (type == SCC_TOK_SEMICOLON || type == SCC_TOK_R_PAREN ||
|
||||
type == SCC_TOK_R_BRACE || type == SCC_TOK_COMMA ||
|
||||
type == SCC_TOK_EOF) {
|
||||
@@ -373,154 +342,47 @@ static void parser_sync(scc_parser_t *parser) {
|
||||
}
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *create_binary_expr(scc_parser_t *parser,
|
||||
scc_ast_expr_t *left,
|
||||
scc_ast_expr_t *right,
|
||||
scc_ast_expr_op_t op) {
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_BINARY);
|
||||
if (!expr)
|
||||
return null;
|
||||
expr->binary.op = op;
|
||||
expr->binary.lhs = left;
|
||||
expr->binary.rhs = right;
|
||||
return expr;
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *create_unary_expr(scc_parser_t *parser,
|
||||
scc_ast_expr_op_t op,
|
||||
scc_ast_expr_t *operand) {
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_UNARY);
|
||||
if (!expr)
|
||||
return null;
|
||||
expr->unary.op = op;
|
||||
expr->unary.operand = operand;
|
||||
return expr;
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *create_conditional_expr(scc_parser_t *parser,
|
||||
scc_ast_expr_t *cond,
|
||||
scc_ast_expr_t *then_expr,
|
||||
scc_ast_expr_t *else_expr) {
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_COND);
|
||||
if (!expr)
|
||||
return null;
|
||||
expr->cond.cond = cond;
|
||||
expr->cond.then_expr = then_expr;
|
||||
expr->cond.else_expr = else_expr;
|
||||
return expr;
|
||||
}
|
||||
|
||||
// 其他创建函数根据需要添加(如 call、subscript、member 等)
|
||||
|
||||
/* ---------------------------- 通用二元解析器 ---------------------------- */
|
||||
/**
|
||||
* 解析左结合的二元表达式
|
||||
* @param parser 解析器
|
||||
* @param parse_sub 解析下一级(优先级更低)的函数
|
||||
* @param this_prec 当前层的优先级
|
||||
* @return 表达式节点
|
||||
*/
|
||||
static scc_ast_expr_t *parse_binary_expression(scc_parser_t *parser,
|
||||
parse_sub_expr_func parse_sub,
|
||||
int this_prec) {
|
||||
scc_ast_expr_t *left = parse_sub(parser);
|
||||
if (!left) {
|
||||
// 左侧解析失败,尝试同步后返回 null
|
||||
parser_sync(parser);
|
||||
static scc_ast_expr_t *parse_expression_with_precedence(scc_parser_t *parser,
|
||||
int min_prec) {
|
||||
// 从最底层(cast-expression)开始
|
||||
scc_ast_expr_t *left = parse_cast_expression(parser);
|
||||
if (!left)
|
||||
return null;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
const scc_lexer_tok_t *tok = scc_parser_peek(parser);
|
||||
if (!tok)
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (!tok_ptr)
|
||||
break;
|
||||
int prec = get_token_precedence(tok->type);
|
||||
if (prec < this_prec)
|
||||
break;
|
||||
// 必须是二元运算符(但赋值和条件除外,它们已在高层处理,这里不会出现)
|
||||
if (!is_binary_operator(tok->type))
|
||||
int prec = get_token_precedence(tok_ptr->type);
|
||||
// 只处理优先级 >= min_prec 的普通二元运算符
|
||||
if (prec < min_prec || !is_binary_operator(tok_ptr->type))
|
||||
break;
|
||||
|
||||
// 消费运算符
|
||||
scc_lexer_tok_t op_tok;
|
||||
if (!scc_parser_next_consume(parser, &op_tok)) {
|
||||
// 消费失败,可能是流结束,退出循环
|
||||
if (!scc_parser_next_consume(parser, &op_tok))
|
||||
break;
|
||||
}
|
||||
scc_ast_expr_op_t op = map_token_to_binary_op(op_tok.type);
|
||||
scc_lexer_tok_drop(&op_tok);
|
||||
|
||||
// 解析右侧(注意左结合:传入
|
||||
// this_prec+1,确保优先级相同的不再结合,避免右结合)
|
||||
// 解析右操作数(优先级 +1,确保左结合)
|
||||
scc_ast_expr_t *right =
|
||||
parse_binary_expression(parser, parse_sub, this_prec + 1);
|
||||
parse_expression_with_precedence(parser, prec + 1);
|
||||
if (!right) {
|
||||
// 右侧解析失败,尝试恢复
|
||||
parser_sync(parser);
|
||||
// 释放已构建的 left?这里 left 可能已被使用,简单的做法是向上返回
|
||||
// null
|
||||
return null;
|
||||
}
|
||||
|
||||
left = create_binary_expr(parser, left, right, op);
|
||||
if (!left)
|
||||
return null;
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_binary_init(expr, op, left, right);
|
||||
left = expr;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_multiplicative_expression(scc_parser_t *parser) {
|
||||
return parse_binary_expression(parser, parse_cast_expression,
|
||||
PREC_MULTIPLICATIVE);
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_additive_expression(scc_parser_t *parser) {
|
||||
return parse_binary_expression(parser, parse_multiplicative_expression,
|
||||
PREC_ADDITIVE);
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_shift_expression(scc_parser_t *parser) {
|
||||
return parse_binary_expression(parser, parse_additive_expression,
|
||||
PREC_SHIFT);
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_relational_expression(scc_parser_t *parser) {
|
||||
return parse_binary_expression(parser, parse_shift_expression,
|
||||
PREC_RELATIONAL);
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_equality_expression(scc_parser_t *parser) {
|
||||
return parse_binary_expression(parser, parse_relational_expression,
|
||||
PREC_EQUALITY);
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_bitwise_and_expression(scc_parser_t *parser) {
|
||||
return parse_binary_expression(parser, parse_equality_expression,
|
||||
PREC_BITWISE_AND);
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_bitwise_xor_expression(scc_parser_t *parser) {
|
||||
return parse_binary_expression(parser, parse_bitwise_and_expression,
|
||||
PREC_BITWISE_XOR);
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_bitwise_or_expression(scc_parser_t *parser) {
|
||||
return parse_binary_expression(parser, parse_bitwise_xor_expression,
|
||||
PREC_BITWISE_OR);
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_logical_and_expression(scc_parser_t *parser) {
|
||||
return parse_binary_expression(parser, parse_bitwise_or_expression,
|
||||
PREC_LOGICAL_AND);
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_logical_or_expression(scc_parser_t *parser) {
|
||||
return parse_binary_expression(parser, parse_logical_and_expression,
|
||||
PREC_LOGICAL_OR);
|
||||
}
|
||||
|
||||
// 赋值表达式(右结合)
|
||||
static scc_ast_expr_t *parse_assignment_expression(scc_parser_t *parser) {
|
||||
scc_ast_expr_t *scc_parse_assignment_expression(scc_parser_t *parser) {
|
||||
// 先解析左侧的 unary-expression(C 标准规定赋值左边必须是
|
||||
// unary-expression)
|
||||
scc_ast_expr_t *left = null;
|
||||
@@ -528,12 +390,12 @@ static scc_ast_expr_t *parse_assignment_expression(scc_parser_t *parser) {
|
||||
if (!left)
|
||||
return null;
|
||||
|
||||
const scc_lexer_tok_t *tok = scc_parser_peek(parser);
|
||||
if (!tok)
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (!tok_ptr)
|
||||
return left;
|
||||
|
||||
int prec = get_token_precedence(tok->type);
|
||||
if (prec == PREC_ASSIGNMENT && is_binary_operator(tok->type)) {
|
||||
int prec = get_token_precedence(tok_ptr->type);
|
||||
if (prec == PREC_ASSIGNMENT && is_binary_operator(tok_ptr->type)) {
|
||||
// 消费赋值运算符
|
||||
scc_lexer_tok_t op_tok;
|
||||
if (!scc_parser_next_consume(parser, &op_tok))
|
||||
@@ -542,30 +404,34 @@ static scc_ast_expr_t *parse_assignment_expression(scc_parser_t *parser) {
|
||||
scc_lexer_tok_drop(&op_tok);
|
||||
|
||||
// 解析右侧(右结合:继续调用 parse_assignment_expression)
|
||||
scc_ast_expr_t *right = parse_assignment_expression(parser);
|
||||
scc_ast_expr_t *right = scc_parse_assignment_expression(parser);
|
||||
if (!right) {
|
||||
// 错误恢复
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
|
||||
left = create_binary_expr(parser, left, right, op);
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_binary_init(expr, op, left, right);
|
||||
left = expr;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
// 条件表达式(右结合)
|
||||
static scc_ast_expr_t *parse_conditional_expression(scc_parser_t *parser) {
|
||||
scc_ast_expr_t *cond = parse_logical_or_expression(parser);
|
||||
if (!cond)
|
||||
scc_ast_expr_t *cond_expr =
|
||||
parse_expression_with_precedence(parser, PREC_LOGICAL_OR);
|
||||
if (!cond_expr)
|
||||
return null;
|
||||
|
||||
const scc_lexer_tok_t *tok = scc_parser_peek(parser);
|
||||
if (tok && tok->type == SCC_TOK_COND) {
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr && tok_ptr->type == SCC_TOK_COND) {
|
||||
// 消耗 '?'
|
||||
scc_lexer_tok_t q_tok;
|
||||
if (!scc_parser_next_consume(parser, &q_tok))
|
||||
return cond;
|
||||
return cond_expr;
|
||||
scc_lexer_tok_drop(&q_tok);
|
||||
|
||||
// 解析中间表达式(可以是任何表达式,包括逗号)
|
||||
@@ -577,7 +443,8 @@ static scc_ast_expr_t *parse_conditional_expression(scc_parser_t *parser) {
|
||||
|
||||
// 消耗 ':'
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_COLON)) {
|
||||
LOG_ERROR("Expected ':' after '?'");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected ':' after '?'");
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
@@ -589,18 +456,23 @@ static scc_ast_expr_t *parse_conditional_expression(scc_parser_t *parser) {
|
||||
return null;
|
||||
}
|
||||
|
||||
cond = create_conditional_expr(parser, cond, then_expr, else_expr);
|
||||
scc_ast_expr_t *cond = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(cond != null);
|
||||
scc_ast_expr_cond_init(cond, cond_expr, then_expr, else_expr);
|
||||
cond_expr = cond;
|
||||
}
|
||||
return cond;
|
||||
return cond_expr;
|
||||
}
|
||||
|
||||
// 类型转换表达式 (type-name) cast-expression
|
||||
static scc_ast_expr_t *parse_cast_expression(scc_parser_t *parser) {
|
||||
const scc_lexer_tok_t *tok = scc_parser_peek(parser);
|
||||
if (tok && tok->type == SCC_TOK_L_PAREN) {
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
scc_ast_type_t *type = null;
|
||||
if (tok_ptr && tok_ptr->type == SCC_TOK_L_PAREN) {
|
||||
// 尝试解析类型名
|
||||
scc_parser_store(parser);
|
||||
scc_ast_type_t *type = scc_parse_type_name(parser); // 需要外部实现
|
||||
scc_parser_next(parser);
|
||||
type = scc_parse_type_name(parser); // 需要外部实现
|
||||
if (type) {
|
||||
// 消耗了类型名后,下一个应该是 ')'
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
@@ -612,19 +484,19 @@ static scc_ast_expr_t *parse_cast_expression(scc_parser_t *parser) {
|
||||
// TODO: 需要 scc_ast_type_drop(type);
|
||||
return null;
|
||||
}
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_CAST);
|
||||
expr->cast.type = type;
|
||||
expr->cast.expr = 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 {
|
||||
// 不是类型转换,回退
|
||||
scc_parser_restore(parser);
|
||||
// 释放 type(假设 scc_parse_type_name 分配了)
|
||||
// TODO: scc_ast_type_drop(type);
|
||||
scc_parser_restore(parser);
|
||||
}
|
||||
} else {
|
||||
// 解析类型名失败,回退
|
||||
scc_parser_restore(parser);
|
||||
// 解析类型名失败,回退
|
||||
}
|
||||
}
|
||||
// 否则作为一元表达式
|
||||
@@ -633,12 +505,12 @@ static scc_ast_expr_t *parse_cast_expression(scc_parser_t *parser) {
|
||||
|
||||
// 一元表达式
|
||||
static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) {
|
||||
const scc_lexer_tok_t *tok = scc_parser_peek(parser);
|
||||
if (!tok)
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (!tok_ptr)
|
||||
return null;
|
||||
|
||||
// 处理一元运算符
|
||||
switch (tok->type) {
|
||||
switch (tok_ptr->type) {
|
||||
case SCC_TOK_ADD_ADD: // ++x
|
||||
case SCC_TOK_SUB_SUB: // --x
|
||||
case SCC_TOK_AND: // &x
|
||||
@@ -660,7 +532,11 @@ static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) {
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
return create_unary_expr(parser, op, operand);
|
||||
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_unary_init(expr, op, operand);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_SIZEOF:
|
||||
return parse_sizeof_expression(parser);
|
||||
@@ -671,19 +547,21 @@ static scc_ast_expr_t *parse_unary_expression(scc_parser_t *parser) {
|
||||
|
||||
// sizeof 表达式(特殊处理两种形式)
|
||||
static scc_ast_expr_t *parse_sizeof_expression(scc_parser_t *parser) {
|
||||
scc_lexer_tok_t tok;
|
||||
if (!scc_parser_next_consume(parser, &tok) || tok.type != SCC_TOK_SIZEOF) {
|
||||
scc_lexer_tok_t tok_ptr;
|
||||
if (!scc_parser_next_consume(parser, &tok_ptr) ||
|
||||
tok_ptr.type != SCC_TOK_SIZEOF) {
|
||||
return null;
|
||||
}
|
||||
scc_lexer_tok_drop(&tok);
|
||||
scc_lexer_tok_drop(&tok_ptr);
|
||||
|
||||
const scc_lexer_tok_t *next = scc_parser_peek(parser);
|
||||
if (!next) {
|
||||
LOG_ERROR("Unexpected end after sizeof");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Unexpected end after sizeof");
|
||||
return null;
|
||||
}
|
||||
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_SIZE_OF);
|
||||
scc_ast_expr_t *expr = null;
|
||||
|
||||
// 尝试解析 sizeof(type-name)
|
||||
if (next->type == SCC_TOK_L_PAREN) {
|
||||
@@ -691,17 +569,14 @@ static scc_ast_expr_t *parse_sizeof_expression(scc_parser_t *parser) {
|
||||
scc_ast_type_t *type = scc_parse_type_name(parser);
|
||||
if (type) {
|
||||
// 消耗 ')'
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
expr->attr_of.type = type;
|
||||
return expr;
|
||||
} else {
|
||||
// 不是有效的 sizeof(type-name),回退
|
||||
scc_parser_restore(parser);
|
||||
// 释放 type
|
||||
// TODO: scc_ast_type_drop(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_parser_restore(parser);
|
||||
TODO();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,29 +586,50 @@ static scc_ast_expr_t *parse_sizeof_expression(scc_parser_t *parser) {
|
||||
scc_free(expr);
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
} else {
|
||||
scc_ast_expr_sizeof_init(operand, null);
|
||||
}
|
||||
expr->attr_of.expr = operand;
|
||||
return expr;
|
||||
}
|
||||
|
||||
// 后缀表达式
|
||||
static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
scc_ast_expr_t *left = parse_primary_expression(parser);
|
||||
if (!left)
|
||||
return null;
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
if (!left) {
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (!(tok_ptr && tok_ptr->type == SCC_TOK_L_PAREN)) {
|
||||
return null;
|
||||
}
|
||||
scc_parser_store(parser);
|
||||
scc_parser_next(parser);
|
||||
scc_ast_type_t *type = scc_parse_type_name(parser);
|
||||
if (!type) {
|
||||
scc_parser_restore(parser);
|
||||
return null;
|
||||
}
|
||||
scc_parser_commit(parser);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Expected ')'");
|
||||
}
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_L_BRACKET)) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Expected '{");
|
||||
}
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
scc_ast_expr_lvalue_init(expr, type);
|
||||
return scc_parse_initializer(parser, expr);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
const scc_lexer_tok_t *tok = scc_parser_peek(parser);
|
||||
if (!tok)
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (!tok_ptr)
|
||||
break;
|
||||
|
||||
switch (tok->type) {
|
||||
switch (tok_ptr->type) {
|
||||
case SCC_TOK_L_BRACKET: // left[expr]
|
||||
{
|
||||
scc_lexer_tok_t lb;
|
||||
if (!scc_parser_next_consume(parser, &lb))
|
||||
if (!scc_parser_next_consume(parser, null))
|
||||
return left;
|
||||
scc_lexer_tok_drop(&lb);
|
||||
|
||||
scc_ast_expr_t *index = scc_parse_expression(parser);
|
||||
if (!index) {
|
||||
@@ -741,54 +637,50 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
return null;
|
||||
}
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_BRACKET)) {
|
||||
LOG_ERROR("Expected ']' after subscript");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected ']' after subscript");
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
scc_ast_expr_t *subscript =
|
||||
expr_create(parser, SCC_AST_EXPR_ARRAY_SUBSCRIPT);
|
||||
subscript->subscript.array = left;
|
||||
subscript->subscript.index = index;
|
||||
scc_ast_expr_t *subscript = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(subscript != null);
|
||||
scc_ast_expr_array_subscript_init(subscript, left, index);
|
||||
left = subscript;
|
||||
break;
|
||||
}
|
||||
case SCC_TOK_L_PAREN: // left(args)
|
||||
{
|
||||
scc_lexer_tok_t lp;
|
||||
if (!scc_parser_next_consume(parser, &lp))
|
||||
if (!scc_parser_next_consume(parser, null))
|
||||
return left;
|
||||
scc_lexer_tok_drop(&lp);
|
||||
scc_ast_expr_vec_t args;
|
||||
scc_vec_init(args);
|
||||
|
||||
scc_ast_expr_t *call = expr_create(parser, SCC_AST_EXPR_CALL);
|
||||
call->call.callee = left;
|
||||
scc_vec_init(call->call.args);
|
||||
while (1) {
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_R_PAREN))
|
||||
break;
|
||||
scc_ast_expr_t *arg = scc_parse_assignment_expression(parser);
|
||||
if (!arg) {
|
||||
parser_sync(parser);
|
||||
break;
|
||||
}
|
||||
scc_vec_push(args, arg);
|
||||
|
||||
// 解析参数列表
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
while (1) {
|
||||
scc_ast_expr_t *arg = parse_assignment_expression(parser);
|
||||
if (!arg) {
|
||||
parser_sync(parser);
|
||||
// 释放已解析的参数
|
||||
// TODO: 释放 call->call.args 中的表达式
|
||||
scc_free(call);
|
||||
return null;
|
||||
}
|
||||
scc_vec_push(call->call.args, arg);
|
||||
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_COMMA)) {
|
||||
continue;
|
||||
} else if (scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
break;
|
||||
} else {
|
||||
LOG_ERROR("Expected ',' or ')' in function call");
|
||||
parser_sync(parser);
|
||||
// 释放资源
|
||||
scc_free(call);
|
||||
return null;
|
||||
}
|
||||
if (scc_parser_consume_if(parser, SCC_TOK_COMMA)) {
|
||||
continue;
|
||||
} else if (scc_parser_consume_if(parser, SCC_TOK_R_PAREN))
|
||||
break;
|
||||
else {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected ',' or ')' in function call");
|
||||
// 释放已解析的参数
|
||||
// TODO: 释放 args 中的表达式
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
scc_ast_expr_t *call = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(call != null);
|
||||
scc_ast_expr_call_init(call, left, &args);
|
||||
left = call;
|
||||
break;
|
||||
}
|
||||
@@ -800,17 +692,21 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
scc_lexer_tok_t ident_tok;
|
||||
if (!scc_parser_next_consume(parser, &ident_tok) ||
|
||||
ident_tok.type != SCC_TOK_IDENT) {
|
||||
LOG_ERROR("Expected identifier after member access");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected identifier after member access");
|
||||
scc_lexer_tok_drop(&op_tok);
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
const char *name = scc_cstring_as_cstr(&ident_tok.lexeme);
|
||||
scc_ast_expr_t *member = expr_create(
|
||||
parser, op_tok.type == SCC_TOK_DOT ? SCC_AST_EXPR_MEMBER
|
||||
: SCC_AST_EXPR_PTR_MEMBER);
|
||||
member->member.base = left;
|
||||
member->member.name = name;
|
||||
|
||||
scc_ast_expr_t *member = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(member != null);
|
||||
if (op_tok.type == SCC_TOK_DOT) {
|
||||
scc_ast_expr_member_init(member, left, name);
|
||||
} else {
|
||||
scc_ast_expr_ptr_member_init(member, left, name);
|
||||
}
|
||||
|
||||
scc_lexer_tok_drop(&op_tok);
|
||||
left = member;
|
||||
@@ -824,7 +720,10 @@ static scc_ast_expr_t *parse_postfix_expression(scc_parser_t *parser) {
|
||||
return left;
|
||||
scc_ast_expr_op_t op = map_token_to_unary_op(op_tok.type, false);
|
||||
scc_lexer_tok_drop(&op_tok);
|
||||
left = create_unary_expr(parser, op, left);
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_unary_init(expr, op, left);
|
||||
left = expr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -837,70 +736,65 @@ done:
|
||||
|
||||
// 基本表达式
|
||||
static scc_ast_expr_t *parse_primary_expression(scc_parser_t *parser) {
|
||||
const scc_lexer_tok_t *tok = scc_parser_peek(parser);
|
||||
if (!tok)
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (!tok_ptr)
|
||||
return null;
|
||||
|
||||
switch (tok->type) {
|
||||
scc_lexer_tok_t tok = {0};
|
||||
scc_ast_expr_t *expr = null;
|
||||
switch (tok_ptr->type) {
|
||||
case SCC_TOK_IDENT: {
|
||||
scc_lexer_tok_t ident;
|
||||
if (!scc_parser_next_consume(parser, &ident))
|
||||
if (!scc_parser_next_consume(parser, &tok))
|
||||
return null;
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_IDENTIFIER);
|
||||
expr->identifier.name = scc_cstring_as_cstr(&ident.lexeme);
|
||||
ident.lexeme.data = null;
|
||||
scc_lexer_tok_drop(&ident);
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_identifier_init(expr, scc_cstring_as_cstr(&tok.lexeme));
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_INT_LITERAL: {
|
||||
scc_lexer_tok_t lit;
|
||||
if (!scc_parser_next_consume(parser, &lit))
|
||||
if (!scc_parser_next_consume(parser, &tok))
|
||||
return null;
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_INT_LITERAL);
|
||||
expr->literal.lexme = scc_cstring_as_cstr(&lit.lexeme);
|
||||
lit.lexeme.data = null; // 转移所有权
|
||||
scc_lexer_tok_drop(&lit);
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_literal_int_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
false);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_FLOAT_LITERAL: {
|
||||
scc_lexer_tok_t lit;
|
||||
if (!scc_parser_next_consume(parser, &lit))
|
||||
if (!scc_parser_next_consume(parser, &tok))
|
||||
return null;
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_FLOAT_LITERAL);
|
||||
expr->literal.lexme = scc_cstring_as_cstr(&lit.lexeme);
|
||||
lit.lexeme.data = null;
|
||||
scc_lexer_tok_drop(&lit);
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_literal_float_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
false);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_CHAR_LITERAL: {
|
||||
scc_lexer_tok_t lit;
|
||||
if (!scc_parser_next_consume(parser, &lit))
|
||||
if (!scc_parser_next_consume(parser, &tok))
|
||||
return null;
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_CHAR_LITERAL);
|
||||
expr->literal.lexme = scc_cstring_as_cstr(&lit.lexeme);
|
||||
lit.lexeme.data = null;
|
||||
scc_lexer_tok_drop(&lit);
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_literal_char_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
false);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_STRING_LITERAL: {
|
||||
scc_lexer_tok_t lit;
|
||||
if (!scc_parser_next_consume(parser, &lit))
|
||||
if (!scc_parser_next_consume(parser, &tok))
|
||||
return null;
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_STRING_LITERAL);
|
||||
expr->literal.lexme = scc_cstring_as_cstr(&lit.lexeme);
|
||||
lit.lexeme.data = null;
|
||||
scc_lexer_tok_drop(&lit);
|
||||
expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_literal_string_init(expr, scc_cstring_as_cstr(&tok.lexeme),
|
||||
false);
|
||||
return expr;
|
||||
}
|
||||
case SCC_TOK_L_PAREN:
|
||||
return parse_paren_expression(parser);
|
||||
default:
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理括号表达式、类型转换、复合字面量(目前只实现括号表达式和类型转换)
|
||||
// 处理括号表达式、类型转换、复合字面量
|
||||
static scc_ast_expr_t *parse_paren_expression(scc_parser_t *parser) {
|
||||
// 保存位置以便回退
|
||||
scc_parser_store(parser);
|
||||
@@ -917,9 +811,9 @@ static scc_ast_expr_t *parse_paren_expression(scc_parser_t *parser) {
|
||||
// TODO: scc_ast_type_drop(type);
|
||||
return null;
|
||||
}
|
||||
scc_ast_expr_t *expr = expr_create(parser, SCC_AST_EXPR_CAST);
|
||||
expr->cast.type = type;
|
||||
expr->cast.expr = 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
|
||||
@@ -944,7 +838,8 @@ static scc_ast_expr_t *parse_paren_expression(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
LOG_ERROR("Expected ')' after expression");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected ')' after expression");
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
@@ -952,17 +847,25 @@ static scc_ast_expr_t *parse_paren_expression(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
scc_ast_expr_t *scc_parse_expression(scc_parser_t *parser) {
|
||||
scc_ast_expr_t *left = parse_assignment_expression(parser);
|
||||
scc_ast_expr_t *left = scc_parse_assignment_expression(parser);
|
||||
if (!left)
|
||||
return null;
|
||||
|
||||
while (scc_parser_consume_if(parser, SCC_TOK_COMMA)) {
|
||||
scc_ast_expr_t *right = parse_assignment_expression(parser);
|
||||
scc_ast_expr_t *right = scc_parse_assignment_expression(parser);
|
||||
if (!right) {
|
||||
parser_sync(parser);
|
||||
return null;
|
||||
}
|
||||
left = create_binary_expr(parser, left, right, SCC_AST_OP_COMMA);
|
||||
scc_ast_expr_t *expr = scc_malloc(sizeof(scc_ast_expr_t));
|
||||
Assert(expr != null);
|
||||
scc_ast_expr_binary_init(expr, SCC_AST_OP_COMMA, left, right);
|
||||
left = expr;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
scc_ast_expr_t *scc_parser_constant_expression(scc_parser_t *parser) {
|
||||
// TODO check constant
|
||||
return parse_conditional_expression(parser);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ A.2.3 Statements
|
||||
|
||||
#include <parser_utils.h>
|
||||
#include <scc_parser.h>
|
||||
|
||||
static inline scc_ast_stmt_t *ast_stmt_alloc() {
|
||||
scc_ast_stmt_t *stmt = (scc_ast_stmt_t *)scc_malloc(sizeof(scc_ast_stmt_t));
|
||||
if (stmt == null) {
|
||||
@@ -59,13 +60,15 @@ static inline scc_ast_stmt_t *ast_stmt_alloc() {
|
||||
|
||||
static inline scc_ast_expr_t *ast_parse_paren_expression(scc_parser_t *parser) {
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_L_PAREN)) {
|
||||
LOG_ERROR("Expected '(' before like `( expression )` .");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected '(' before like `( expression )` .");
|
||||
}
|
||||
|
||||
scc_ast_expr_t *ret = scc_parse_expression(parser);
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
LOG_ERROR("Expected ')' before like `( expression )` .");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected ')' before like `( expression )` .");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -97,10 +100,16 @@ static scc_ast_stmt_t *parse_case_statement(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
scc_ast_expr_t *expr = null;
|
||||
// TODO = scc_parser_constant_expression();
|
||||
expr = scc_parser_constant_expression(parser);
|
||||
if (expr == null) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected constant expression after case.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_COLON)) {
|
||||
LOG_ERROR("Expected constant expression after case.");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected `:` after case.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -120,7 +129,8 @@ static scc_ast_stmt_t *parse_default_statement(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_COLON)) {
|
||||
LOG_ERROR("Expected constant expression after case.");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected constant expression after case.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -150,7 +160,7 @@ static scc_ast_stmt_t *parse_compound_statement(scc_parser_t *parser) {
|
||||
ret = (scc_ast_node_t *)scc_parse_statement(parser);
|
||||
}
|
||||
if (ret == null) {
|
||||
LOG_ERROR("Invalid statement");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Invalid statement");
|
||||
// TODO free
|
||||
parser->errcode = 1;
|
||||
return null;
|
||||
@@ -217,7 +227,8 @@ static scc_ast_stmt_t *parse_do_while_statement(scc_parser_t *parser) {
|
||||
scc_ast_stmt_t *statement = scc_parse_statement(parser);
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_WHILE)) {
|
||||
LOG_ERROR("Expected 'while' after do.");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected 'while' after do.");
|
||||
// TODO 使用更好的错误处理,未来应当采用更好的内存管理器
|
||||
scc_free(statement);
|
||||
return null;
|
||||
@@ -240,7 +251,8 @@ static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser) {
|
||||
*/
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_L_PAREN)) {
|
||||
LOG_ERROR("Expected '(' before like `( expression )` .");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected '(' before like `( expression )` .");
|
||||
}
|
||||
|
||||
scc_ast_type_t *init = null;
|
||||
@@ -253,20 +265,23 @@ static scc_ast_stmt_t *parse_for_statement(scc_parser_t *parser) {
|
||||
if (init == null) {
|
||||
init = (scc_ast_type_t *)scc_parse_expression(parser);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||
LOG_ERROR("Expected semicolon in for statement.");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected semicolon in for statement.");
|
||||
}
|
||||
}
|
||||
|
||||
cond = scc_parse_expression(parser);
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||
LOG_ERROR("Expected semicolon in for statement.");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected semicolon in for statement.");
|
||||
}
|
||||
|
||||
incr = scc_parse_expression(parser);
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
LOG_ERROR("Expected ')' after like `( expression )` .");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected ')' after like `( expression )` .");
|
||||
}
|
||||
|
||||
body = scc_parse_statement(parser);
|
||||
@@ -284,7 +299,8 @@ static scc_ast_stmt_t *parse_jump_statement(scc_parser_t *parser) {
|
||||
if (scc_parser_next_consume(parser, &tok)) {
|
||||
scc_ast_stmt_goto_init(stmt, scc_cstring_as_cstr(&tok.lexeme));
|
||||
} else {
|
||||
LOG_ERROR("Expected label after goto.");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected label after goto.");
|
||||
}
|
||||
} else if (scc_parser_consume_if(parser, SCC_TOK_CONTINUE)) {
|
||||
scc_ast_stmt_continue_init(stmt);
|
||||
@@ -297,7 +313,8 @@ static scc_ast_stmt_t *parse_jump_statement(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||
LOG_ERROR("Expected semicolon after jump statement.");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected semicolon after jump statement.");
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
@@ -319,7 +336,8 @@ static scc_ast_stmt_t *parse_expression_statement(scc_parser_t *parser) {
|
||||
scc_ast_stmt_expr_init(stmt, expr);
|
||||
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_SEMICOLON)) {
|
||||
LOG_ERROR("Expected semicolon after expression.");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected semicolon after expression.");
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
|
||||
@@ -212,15 +212,10 @@ cbool scc_parse_is_decl_specifier_start(scc_parser_t *parser) {
|
||||
// 函数说明符
|
||||
case SCC_TOK_INLINE:
|
||||
return true;
|
||||
|
||||
// typedef 名称(标识符也可能是类型说明符)
|
||||
// typedef 名称(标识符也可能是类型说明符)
|
||||
case SCC_TOK_IDENT:
|
||||
// 需要检查标识符是否在符号表中定义为 typedef
|
||||
// 这里简化处理:假设所有标识符都可能是 typedef
|
||||
// 在实际解析器中,需要查询符号表
|
||||
// TODO
|
||||
return false;
|
||||
|
||||
return scc_parse_got_type(
|
||||
parser, scc_cstring_as_cstr(&tok_ptr->lexeme)) != null;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -250,7 +245,8 @@ cbool scc_parse_is_type_specifier_start(scc_parser_t *parser) {
|
||||
// typedef 名称
|
||||
case SCC_TOK_IDENT:
|
||||
// 需要检查标识符是否在符号表中定义为 typedef
|
||||
return true;
|
||||
return scc_parse_got_type(
|
||||
parser, scc_cstring_as_cstr(&tok_ptr->lexeme)) != null;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -289,8 +285,15 @@ cbool scc_parse_is_storage_class_start(scc_parser_t *parser) {
|
||||
}
|
||||
}
|
||||
|
||||
#define DUP_CHECK(expr) \
|
||||
do { \
|
||||
if (expr) \
|
||||
goto duplicate_error; \
|
||||
expr = true; \
|
||||
} while (0)
|
||||
static scc_ast_decl_specifier_t
|
||||
parse_type_qualifier_list(scc_parser_t *parser) {
|
||||
parse_type_qualifier_list(scc_parser_t *parser,
|
||||
scc_ast_decl_specifier_t quals) {
|
||||
/*
|
||||
(6.7.3)
|
||||
type-qualifier:
|
||||
@@ -302,7 +305,6 @@ parse_type_qualifier_list(scc_parser_t *parser) {
|
||||
type-qualifier
|
||||
type-qualifier-list type-qualifier
|
||||
*/
|
||||
scc_ast_decl_specifier_t quals = {0};
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
CONTINUE:
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
@@ -311,21 +313,68 @@ CONTINUE:
|
||||
}
|
||||
switch (tok_ptr->type) {
|
||||
case SCC_TOK_CONST:
|
||||
scc_parser_next_consume(parser, null);
|
||||
quals.is_const = true;
|
||||
DUP_CHECK(quals.is_const);
|
||||
break;
|
||||
case SCC_TOK_RESTRICT:
|
||||
scc_parser_next_consume(parser, null);
|
||||
DUP_CHECK(quals.is_restrict);
|
||||
quals.is_restrict = true;
|
||||
break;
|
||||
case SCC_TOK_VOLATILE:
|
||||
scc_parser_next_consume(parser, null);
|
||||
quals.is_volatile = true;
|
||||
DUP_CHECK(quals.is_volatile);
|
||||
break;
|
||||
default:
|
||||
return quals;
|
||||
}
|
||||
scc_parser_next_consume(parser, null);
|
||||
goto CONTINUE;
|
||||
duplicate_error:
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Duplicate type specifier");
|
||||
return quals;
|
||||
}
|
||||
|
||||
static scc_ast_decl_specifier_t
|
||||
parse_declaration_specifiers_list(scc_parser_t *parser,
|
||||
scc_ast_decl_specifier_t quals) {
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
CONTINUE:
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr == null) {
|
||||
return quals;
|
||||
}
|
||||
switch (tok_ptr->type) {
|
||||
case SCC_TOK_CONST:
|
||||
DUP_CHECK(quals.is_const);
|
||||
break;
|
||||
case SCC_TOK_RESTRICT:
|
||||
DUP_CHECK(quals.is_restrict);
|
||||
quals.is_restrict = true;
|
||||
break;
|
||||
case SCC_TOK_VOLATILE:
|
||||
DUP_CHECK(quals.is_volatile);
|
||||
break;
|
||||
case SCC_TOK_EXTERN:
|
||||
DUP_CHECK(quals.is_extern);
|
||||
break;
|
||||
case SCC_TOK_STATIC:
|
||||
DUP_CHECK(quals.is_static);
|
||||
break;
|
||||
case SCC_TOK_AUTO:
|
||||
DUP_CHECK(quals.is_auto);
|
||||
break;
|
||||
case SCC_TOK_REGISTER:
|
||||
DUP_CHECK(quals.is_register);
|
||||
break;
|
||||
case SCC_TOK_INLINE:
|
||||
DUP_CHECK(quals.is_inline);
|
||||
break;
|
||||
default:
|
||||
return quals;
|
||||
}
|
||||
scc_parser_next_consume(parser, null);
|
||||
goto CONTINUE;
|
||||
duplicate_error:
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Duplicate type specifier");
|
||||
return quals;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@@ -346,50 +395,59 @@ typedef struct {
|
||||
scc_ast_type_t *user_type; // 如果是用户定义类型,直接存储解析结果
|
||||
} type_spec_info_t;
|
||||
|
||||
static cbool check_type_combinations(type_spec_info_t *info) {
|
||||
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;
|
||||
if (basic_count > 1) {
|
||||
LOG_ERROR("Multiple basic type specifiers");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Multiple basic type specifiers");
|
||||
return false;
|
||||
}
|
||||
|
||||
// long 不能与 void/char/float/bool 组合(但可以和 double 组合为 long
|
||||
// double)
|
||||
if (info->is_long && info->is_float) {
|
||||
LOG_ERROR("'long' and 'float' cannot be combined");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"'long' and 'float' cannot be combined");
|
||||
return false;
|
||||
}
|
||||
if (info->is_long && info->is_char) {
|
||||
LOG_ERROR("'long' and 'char' cannot be combined");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"'long' and 'char' cannot be combined");
|
||||
return false;
|
||||
}
|
||||
if (info->is_long && info->is_bool) {
|
||||
LOG_ERROR("'long' and 'bool' cannot be combined");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"'long' and 'bool' cannot be combined");
|
||||
return false;
|
||||
}
|
||||
// long 与 double 可以组合为 long double
|
||||
if (info->is_long_long && info->is_double) {
|
||||
LOG_ERROR("'long long' and 'double' cannot be combined");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"'long long' and 'double' cannot be combined");
|
||||
return false;
|
||||
}
|
||||
// short 只能与 int 组合(默认 int),不能与 double/float 等
|
||||
if (info->is_short &&
|
||||
(info->is_double || info->is_float || info->is_bool || info->is_void)) {
|
||||
LOG_ERROR("'short' cannot be combined with this type");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"'short' cannot be combined with this type");
|
||||
return false;
|
||||
}
|
||||
// _Complex 只能与 float/double/long double 组合(或单独出现?C99 中
|
||||
// _Complex 本身不是类型,必须跟浮点类型)
|
||||
if (info->is_complex && !info->is_float && !info->is_double) {
|
||||
LOG_ERROR("'complex' must be combined with a floating type");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"'complex' must be combined with a floating type");
|
||||
return false;
|
||||
}
|
||||
// 如果用户定义了类型(struct/typedef),不能与任何其他类型说明符混合
|
||||
if (info->user_type != null && basic_count > 0) {
|
||||
LOG_ERROR(
|
||||
SCC_ERROR(
|
||||
scc_parser_got_current_pos(parser),
|
||||
"Cannot combine user-defined type with basic type specifiers");
|
||||
return false;
|
||||
}
|
||||
@@ -511,7 +569,8 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
while (1) {
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr == null) {
|
||||
LOG_ERROR("Unexpected EOF in enum specifier");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Unexpected EOF in enum specifier");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -532,7 +591,8 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
scc_parser_next_consume(parser, null);
|
||||
break;
|
||||
} else {
|
||||
LOG_ERROR("Unexpected token in enum specifier");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Unexpected token in enum specifier");
|
||||
scc_parser_next_consume(parser, null);
|
||||
break;
|
||||
}
|
||||
@@ -545,6 +605,7 @@ static scc_ast_type_t *parse_record_type(scc_parser_t *parser,
|
||||
} else {
|
||||
scc_ast_decl_union_init(decl, name, &member);
|
||||
}
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
}
|
||||
|
||||
scc_ast_type_t *type = ast_type_alloc();
|
||||
@@ -568,7 +629,7 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
enumeration-constant = constant-expression
|
||||
*/
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_ENUM)) {
|
||||
LOG_ERROR("Expected 'enum'");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Expected 'enum'");
|
||||
return null;
|
||||
}
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
@@ -589,11 +650,12 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
while (1) {
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr == null) {
|
||||
LOG_ERROR("Unexpected EOF in enum specifier");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Unexpected EOF in enum specifier");
|
||||
break;
|
||||
}
|
||||
|
||||
scc_ast_expr_t *expr = scc_parse_expression(parser);
|
||||
scc_ast_expr_t *expr = scc_parse_assignment_expression(parser);
|
||||
if (expr != null) {
|
||||
scc_vec_push(member, expr);
|
||||
continue;
|
||||
@@ -606,7 +668,8 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
scc_parser_next_consume(parser, null);
|
||||
break;
|
||||
} else {
|
||||
LOG_ERROR("Unexpected token in enum specifier");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Unexpected token in enum specifier");
|
||||
scc_parser_next_consume(parser, null);
|
||||
break;
|
||||
}
|
||||
@@ -614,6 +677,7 @@ static scc_ast_type_t *parse_enum_type(scc_parser_t *parser) {
|
||||
decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl != null);
|
||||
scc_ast_decl_enum_init(decl, name, &member);
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
}
|
||||
|
||||
scc_ast_type_t *type = ast_type_alloc();
|
||||
@@ -625,8 +689,36 @@ 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))
|
||||
return null;
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
|
||||
switch (tok_ptr->type) {
|
||||
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:
|
||||
info.user_type = parse_enum_type(parser);
|
||||
goto done;
|
||||
case SCC_TOK_IDENT:
|
||||
info.user_type =
|
||||
scc_parse_got_type(parser, scc_cstring_as_cstr(&tok_ptr->lexeme));
|
||||
if (info.user_type == null) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Expected type specifier %s",
|
||||
scc_cstring_as_cstr(&tok_ptr->lexeme));
|
||||
}
|
||||
scc_parser_next_consume(parser, null);
|
||||
Assert(info.user_type != null);
|
||||
goto done;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr == null) {
|
||||
break;
|
||||
}
|
||||
@@ -658,7 +750,8 @@ static scc_ast_type_t *parse_type_specifier(scc_parser_t *parser) {
|
||||
case SCC_TOK_LONG:
|
||||
// long 可以出现两次
|
||||
if (info.is_long_long) {
|
||||
LOG_ERROR("Three 'long's in type specifier");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Three 'long's in type specifier");
|
||||
return null;
|
||||
}
|
||||
if (info.is_long) {
|
||||
@@ -689,7 +782,8 @@ static scc_ast_type_t *parse_type_specifier(scc_parser_t *parser) {
|
||||
break;
|
||||
case SCC_TOK_SIGNED:
|
||||
if (info.is_unsigned || info.is_signed) {
|
||||
LOG_ERROR("Both 'signed' and 'unsigned' in type specifier");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Both 'signed' and 'unsigned' in type specifier");
|
||||
return null;
|
||||
}
|
||||
info.is_signed = true;
|
||||
@@ -697,7 +791,8 @@ static scc_ast_type_t *parse_type_specifier(scc_parser_t *parser) {
|
||||
break;
|
||||
case SCC_TOK_UNSIGNED:
|
||||
if (info.is_unsigned || info.is_signed) {
|
||||
LOG_ERROR("Both 'signed' and 'unsigned' in type specifier");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Both 'signed' and 'unsigned' in type specifier");
|
||||
return null;
|
||||
}
|
||||
info.is_unsigned = true;
|
||||
@@ -709,41 +804,28 @@ static scc_ast_type_t *parse_type_specifier(scc_parser_t *parser) {
|
||||
info.is_complex = true;
|
||||
scc_parser_next_consume(parser, null);
|
||||
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:
|
||||
info.user_type = parse_enum_type(parser);
|
||||
goto done;
|
||||
case SCC_TOK_IDENT:
|
||||
// // 处理 typedef 名称:查符号表获取类型节点
|
||||
// info.user_type = parse_typedef_name(parser);
|
||||
// if (!info.user_type)
|
||||
// return null;
|
||||
goto done;
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (!check_type_combinations(&info)) {
|
||||
if (!check_type_combinations(parser, &info)) {
|
||||
return null;
|
||||
}
|
||||
return build_type_from_info(&info);
|
||||
duplicate_error:
|
||||
LOG_ERROR("Duplicate type specifier");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Duplicate type specifier");
|
||||
return null;
|
||||
}
|
||||
|
||||
static scc_ast_node_t *parse_declarator(scc_parser_t *parser,
|
||||
static scc_ast_type_t *parse_declarator(scc_parser_t *parser,
|
||||
scc_ast_type_t *base,
|
||||
scc_ast_type_t **delay_pointee_ptr);
|
||||
static scc_ast_node_t *
|
||||
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_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);
|
||||
@@ -772,7 +854,7 @@ static scc_ast_type_t *parse_pointer(scc_parser_t *parser,
|
||||
pointee = pointer;
|
||||
}
|
||||
scc_ast_type_pointer_init(pointer, pointee);
|
||||
pointer->quals = parse_type_qualifier_list(parser);
|
||||
pointer->quals = parse_type_qualifier_list(parser, pointer->quals);
|
||||
|
||||
return parse_pointer(parser, pointer, delay_pointee_ptr);
|
||||
}
|
||||
@@ -793,18 +875,15 @@ static void parse_parameter_type_list(scc_parser_t *parser,
|
||||
scc_ast_decl_t *param = null;
|
||||
while (1) {
|
||||
// FIXME
|
||||
scc_ast_decl_specifier_t spec = parse_type_qualifier_list(parser);
|
||||
scc_ast_type_t *type = parse_type_specifier(parser);
|
||||
if (type == null) {
|
||||
break;
|
||||
scc_ast_node_t *node = _scc_parse_type(parser);
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
type->quals = spec;
|
||||
|
||||
scc_ast_node_t *node = parse_declarator(parser, type, null);
|
||||
|
||||
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));
|
||||
@@ -828,28 +907,43 @@ static void parse_parameter_type_list(scc_parser_t *parser,
|
||||
}
|
||||
}
|
||||
|
||||
static inline cbool parse_function_parameters_start(scc_parser_t *parser) {
|
||||
const scc_lexer_tok_t *tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr == null) {
|
||||
return false;
|
||||
}
|
||||
if (scc_parse_is_decl_specifier_start(parser)) {
|
||||
return true;
|
||||
}
|
||||
if (tok_ptr->type == SCC_TOK_R_PAREN) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void parse_function_parameters(scc_parser_t *parser,
|
||||
scc_ast_decl_vec_t *params) {
|
||||
// FIXME ?
|
||||
// if (!scc_parser_consume_if(parser, SCC_TOK_L_PAREN)) {
|
||||
// LOG_ERROR("Expect '('");
|
||||
// SCC_ERROR(scc_parser_got_current_pos(parser),"Expect '('");
|
||||
// }
|
||||
scc_vec_init(*params);
|
||||
parse_parameter_type_list(parser, params);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
LOG_ERROR("expect ')'");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "expect ')'");
|
||||
}
|
||||
}
|
||||
|
||||
static scc_ast_expr_t *parse_array_size_type(scc_parser_t *parser) {
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_L_BRACKET)) {
|
||||
LOG_ERROR("Expect '['");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "Expect '['");
|
||||
parser->errcode = 1;
|
||||
return null;
|
||||
}
|
||||
|
||||
scc_ast_expr_t *size = null;
|
||||
scc_ast_decl_specifier_t quals = {0};
|
||||
if (scc_parse_is_type_qualifier_start(parser)) {
|
||||
// static assignment-expression
|
||||
// assignment-expression(opt)
|
||||
@@ -864,7 +958,7 @@ static scc_ast_expr_t *parse_array_size_type(scc_parser_t *parser) {
|
||||
// [ * ]
|
||||
} else if (scc_parser_consume_if(parser, SCC_TOK_STATIC)) {
|
||||
// type-qualifier-list(opt) assignment-expression
|
||||
parse_type_qualifier_list(parser);
|
||||
parse_type_qualifier_list(parser, quals);
|
||||
size = scc_parse_expression(parser);
|
||||
} else {
|
||||
// assignment-expression(opt)
|
||||
@@ -874,16 +968,17 @@ static scc_ast_expr_t *parse_array_size_type(scc_parser_t *parser) {
|
||||
}
|
||||
}
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_BRACKET)) {
|
||||
LOG_ERROR("expect ']'");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "expect ']'");
|
||||
parser->errcode = 1;
|
||||
return null;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static scc_ast_node_t *parse_declarator(scc_parser_t *parser,
|
||||
static scc_ast_type_t *parse_declarator(scc_parser_t *parser,
|
||||
scc_ast_type_t *base,
|
||||
scc_ast_type_t **delay_pointee_ptr) {
|
||||
scc_ast_type_t **delay_pointee_ptr,
|
||||
scc_lexer_tok_t *tok_ident) {
|
||||
/*
|
||||
(6.7.5) declarator:
|
||||
pointer(opt) direct-declarator
|
||||
@@ -901,72 +996,66 @@ static scc_ast_node_t *parse_declarator(scc_parser_t *parser,
|
||||
direct-declarator ( identifier-list(opt) )
|
||||
*/
|
||||
scc_ast_type_t *ret = parse_pointer(parser, base, delay_pointee_ptr);
|
||||
return parse_direct_declarator(parser, ret, delay_pointee_ptr);
|
||||
return parse_direct_declarator(parser, ret, delay_pointee_ptr, tok_ident);
|
||||
}
|
||||
|
||||
static scc_ast_node_t *
|
||||
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_ast_type_t **delay_pointee_ptr,
|
||||
scc_lexer_tok_t *tok_ident) {
|
||||
const scc_lexer_tok_t *tok_ptr = null;
|
||||
scc_ast_type_t *ret = null;
|
||||
// direct-abstract-declarator
|
||||
tok_ptr = scc_parser_peek(parser);
|
||||
if (tok_ptr == null) {
|
||||
return (scc_ast_node_t *)base;
|
||||
return base;
|
||||
}
|
||||
|
||||
if (tok_ptr->type == SCC_TOK_IDENT) {
|
||||
scc_lexer_tok_t tok = {0};
|
||||
scc_parser_next_consume(parser, &tok);
|
||||
|
||||
scc_ast_node_t *type =
|
||||
parse_direct_declarator(parser, base, delay_pointee_ptr);
|
||||
Assert(SCC_AST_IS_A(scc_ast_type_t, type));
|
||||
scc_ast_decl_t *decl = scc_malloc(sizeof(scc_ast_decl_t));
|
||||
Assert(decl != null);
|
||||
|
||||
if (type->type == SCC_AST_TYPE_FUNCTION) {
|
||||
scc_ast_decl_func_init(decl, SCC_AST_CAST_TO(scc_ast_type_t, type),
|
||||
scc_cstring_as_cstr(&tok.lexeme), null);
|
||||
} else {
|
||||
scc_ast_decl_val_init(decl, SCC_AST_CAST_TO(scc_ast_type_t, type),
|
||||
scc_cstring_as_cstr(&tok.lexeme), null);
|
||||
Assert(tok_ident != null);
|
||||
if (tok_ident->type != SCC_TOK_UNKNOWN) {
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser),
|
||||
"Got double identifier in declarator");
|
||||
return base;
|
||||
}
|
||||
return (scc_ast_node_t *)decl;
|
||||
scc_parser_next_consume(parser, tok_ident);
|
||||
|
||||
return parse_direct_declarator(parser, base, delay_pointee_ptr,
|
||||
tok_ident);
|
||||
} else if (tok_ptr->type == SCC_TOK_L_PAREN) {
|
||||
// () SCC_TOK_L_PAREN
|
||||
scc_parser_next_consume(parser, null);
|
||||
scc_ast_type_t *delay_pointee = null;
|
||||
ret = parse_abstract_declarator(parser, null, &delay_pointee);
|
||||
if (ret == null) {
|
||||
if (parse_function_parameters_start(parser)) {
|
||||
scc_ast_decl_vec_t params;
|
||||
parse_function_parameters(parser, ¶ms);
|
||||
ret = ast_type_alloc();
|
||||
scc_ast_type_function_init(ret, base, ¶ms);
|
||||
return (scc_ast_node_t *)parse_direct_declarator(parser, ret,
|
||||
delay_pointee_ptr);
|
||||
return parse_direct_declarator(parser, ret, delay_pointee_ptr,
|
||||
tok_ident);
|
||||
} else {
|
||||
ret = parse_declarator(parser, null, &delay_pointee, tok_ident);
|
||||
Assert(ret != null);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
LOG_ERROR("expect ')'");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "expect ')'");
|
||||
}
|
||||
base = (scc_ast_type_t *)parse_direct_declarator(parser, base,
|
||||
delay_pointee_ptr);
|
||||
base = parse_direct_declarator(parser, base, delay_pointee_ptr,
|
||||
tok_ident);
|
||||
Assert(SCC_AST_IS_A(scc_ast_type_t, base));
|
||||
Assert(delay_pointee != null);
|
||||
delay_pointee->pointer.pointee = base;
|
||||
return ret;
|
||||
}
|
||||
return (scc_ast_node_t *)ret;
|
||||
} else if (tok_ptr->type == SCC_TOK_L_BRACKET) {
|
||||
// [] SCC_TOK_L_BRACKET
|
||||
scc_ast_expr_t *size = parse_array_size_type(parser);
|
||||
scc_ast_type_t *ret = ast_type_alloc();
|
||||
base = (scc_ast_type_t *)parse_direct_declarator(parser, base,
|
||||
delay_pointee_ptr);
|
||||
Assert(SCC_AST_IS_A(scc_ast_type_t, base));
|
||||
base =
|
||||
parse_direct_declarator(parser, base, delay_pointee_ptr, tok_ident);
|
||||
scc_ast_type_array_init(ret, base, size);
|
||||
return (scc_ast_node_t *)ret;
|
||||
return ret;
|
||||
} else {
|
||||
return (scc_ast_node_t *)base;
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1008,8 +1097,7 @@ parse_direct_abstract_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
// () SCC_TOK_L_PAREN
|
||||
scc_parser_next_consume(parser, null);
|
||||
scc_ast_type_t *delay_pointee = null;
|
||||
ret = parse_abstract_declarator(parser, null, &delay_pointee);
|
||||
if (ret == null) {
|
||||
if (parse_function_parameters_start(parser)) {
|
||||
scc_ast_decl_vec_t params;
|
||||
parse_function_parameters(parser, ¶ms);
|
||||
ret = ast_type_alloc();
|
||||
@@ -1017,8 +1105,10 @@ parse_direct_abstract_declarator(scc_parser_t *parser, scc_ast_type_t *base,
|
||||
return parse_direct_abstract_declarator(parser, ret,
|
||||
delay_pointee_ptr);
|
||||
} else {
|
||||
ret = parse_abstract_declarator(parser, null, &delay_pointee);
|
||||
Assert(ret != null);
|
||||
if (!scc_parser_consume_if(parser, SCC_TOK_R_PAREN)) {
|
||||
LOG_ERROR("expect ')'");
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "expect ')'");
|
||||
}
|
||||
base = parse_direct_abstract_declarator(parser, base,
|
||||
delay_pointee_ptr);
|
||||
@@ -1050,17 +1140,44 @@ scc_ast_node_t *_scc_parse_type(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
scc_ast_type_t *ret = null;
|
||||
scc_ast_decl_specifier_t spec = parse_type_qualifier_list(parser);
|
||||
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_ast_node_t *node = parse_declarator(parser, ret, null);
|
||||
|
||||
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) {
|
||||
Assert(node->type == SCC_AST_DECL_VAR);
|
||||
node->type = SCC_AST_DECL_TYPEDEF;
|
||||
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);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
|
||||
return decl != null ? &decl->base : &type->base;
|
||||
}
|
||||
|
||||
scc_ast_type_t *scc_parse_type_name(scc_parser_t *parser) {
|
||||
@@ -1070,7 +1187,8 @@ scc_ast_type_t *scc_parse_type_name(scc_parser_t *parser) {
|
||||
}
|
||||
|
||||
scc_ast_type_t *ret = null;
|
||||
scc_ast_decl_specifier_t spec = parse_type_qualifier_list(parser);
|
||||
scc_ast_decl_specifier_t spec = {0};
|
||||
spec = parse_type_qualifier_list(parser, spec);
|
||||
ret = parse_type_specifier(parser);
|
||||
if (ret != null) {
|
||||
ret->quals = spec;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <parser_utils.h>
|
||||
#include <scc_parser.h>
|
||||
|
||||
static void dummy_sema_callback(void *context, scc_ast_node_type_t node_type,
|
||||
void *node) {
|
||||
(void)context;
|
||||
@@ -70,9 +71,10 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
|
||||
scc_vec_push(unit->declarations, decl);
|
||||
} else {
|
||||
break;
|
||||
// MAYBE return or next
|
||||
}
|
||||
if (parser->errcode != 0) { // FIXME errcode
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "parser error: %d",
|
||||
parser->errcode);
|
||||
break;
|
||||
}
|
||||
const scc_lexer_tok_t *tok = scc_parser_peek(parser);
|
||||
@@ -83,6 +85,8 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
|
||||
|
||||
if (parser->errcode) {
|
||||
// TODO: 清理
|
||||
SCC_ERROR(scc_parser_got_current_pos(parser), "parser error: %d",
|
||||
parser->errcode);
|
||||
scc_free(unit);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,55 @@
|
||||
#include <scc_sema.h>
|
||||
#include <sema_symtab.h>
|
||||
|
||||
static void type_callback(void *context, scc_ast_node_type_t node_type,
|
||||
void *node) {
|
||||
scc_sema_symtab_t *sema_symtab = context;
|
||||
(void)context;
|
||||
(void)node_type;
|
||||
(void)node;
|
||||
return;
|
||||
}
|
||||
|
||||
static void decl_callback(void *context, scc_ast_node_type_t node_type,
|
||||
void *node) {
|
||||
if (node_type == SCC_AST_UNKNOWN || node == null) {
|
||||
return;
|
||||
}
|
||||
scc_sema_symtab_t *sema_symtab = context;
|
||||
scc_ast_decl_t *decl = SCC_AST_CAST_TO(scc_ast_decl_t, node);
|
||||
|
||||
scc_ast_type_t *type = scc_malloc(sizeof(scc_ast_type_t));
|
||||
Assert(type != null);
|
||||
if (decl->name == null) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
} 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);
|
||||
} 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);
|
||||
} 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);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static scc_ast_type_t *got_type_callback(void *context, const char *name) {
|
||||
scc_sema_symtab_t *sema_symtab = context;
|
||||
scc_ast_node_t *node = scc_sema_symtab_lookup_symbol(sema_symtab, name);
|
||||
if (SCC_AST_IS_A(scc_ast_type_t, node)) {
|
||||
scc_ast_type_t *type = scc_malloc(sizeof(scc_ast_type_t));
|
||||
*type = *(scc_ast_type_t *)node;
|
||||
return type;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void scc_sema_init(scc_sema_callbacks_t *callbacks) {
|
||||
scc_sema_symtab_t *sema_symtab = scc_malloc(sizeof(scc_sema_symtab_t));
|
||||
if (sema_symtab == null) {
|
||||
@@ -8,11 +57,19 @@ void scc_sema_init(scc_sema_callbacks_t *callbacks) {
|
||||
return;
|
||||
}
|
||||
callbacks->context = sema_symtab;
|
||||
callbacks->on_decl = null;
|
||||
callbacks->on_decl = decl_callback;
|
||||
callbacks->on_expr = null;
|
||||
callbacks->on_stmt = null;
|
||||
callbacks->on_type = null;
|
||||
callbacks->got_type = null;
|
||||
callbacks->on_type = type_callback;
|
||||
callbacks->got_type = got_type_callback;
|
||||
|
||||
scc_sema_symtab_init(sema_symtab);
|
||||
scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_va_list",
|
||||
&scc_ast_builtin_type_va_list.base);
|
||||
scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_size_t",
|
||||
&scc_ast_builtin_type_long_long.base);
|
||||
scc_sema_symtab_add_symbol(sema_symtab, "__scc_builtin_ptrdiff_t",
|
||||
&scc_ast_builtin_type_long_long.base);
|
||||
}
|
||||
|
||||
void scc_sema_drop(scc_sema_callbacks_t *callbacks) {}
|
||||
|
||||
@@ -4,8 +4,8 @@ void scc_sema_symtab_init(scc_sema_symtab_t *symtab) {
|
||||
symtab->root_scope.parent = null;
|
||||
|
||||
scc_hashtable_init(&symtab->root_scope.symbols,
|
||||
(scc_hashtable_hash_func_t)scc_strcmp,
|
||||
(scc_hashtable_equal_func_t)scc_strhash32);
|
||||
(scc_hashtable_hash_func_t)scc_strhash32,
|
||||
(scc_hashtable_equal_func_t)scc_strcmp);
|
||||
symtab->current_scope = &symtab->root_scope;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
typedef scc_ast_node_t *(*scc_parse_node_func)(scc_parser_t *parser);
|
||||
|
||||
static scc_ast_node_t *process_input(const char *input,
|
||||
scc_parse_node_func parse_func) {
|
||||
scc_parse_node_func parse_func,
|
||||
cbool need_sema) {
|
||||
int res = 0;
|
||||
scc_sstream_t mem_stream;
|
||||
res = scc_sstream_init_by_buffer(&mem_stream, input, strlen(input), false,
|
||||
@@ -20,7 +21,13 @@ static scc_ast_node_t *process_input(const char *input,
|
||||
scc_lexer_tok_ring_t *tok_ring = scc_lexer_to_ring(&lexer, 64, false);
|
||||
|
||||
scc_parser_t parser;
|
||||
scc_parser_init(&parser, tok_ring, null);
|
||||
if (need_sema) {
|
||||
scc_sema_callbacks_t sema_callbacks;
|
||||
scc_sema_init(&sema_callbacks);
|
||||
scc_parser_init(&parser, tok_ring, &sema_callbacks);
|
||||
} else {
|
||||
scc_parser_init(&parser, tok_ring, null);
|
||||
}
|
||||
|
||||
scc_ast_node_t *ret = parse_func(&parser);
|
||||
|
||||
@@ -55,8 +62,8 @@ static void dump2buffer(void *_buffer, const char *fmt, ...) {
|
||||
}
|
||||
|
||||
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_parse_node_func parse_func, cbool need_sema) {
|
||||
scc_ast_node_t *output_node_ptr = process_input(str, parse_func, need_sema);
|
||||
scc_tree_dump_ctx_t ctx;
|
||||
expect_buffer[0] = '\n', expect_buffer[1] = '\0';
|
||||
scc_tree_dump_ctx_init(&ctx, true, dump2buffer, expect_buffer);
|
||||
@@ -68,9 +75,19 @@ static void _scc_check_ast(scc_ast_node_t *expect_node_ptr, const char *str,
|
||||
scc_tree_dump_ctx_drop(&ctx);
|
||||
}
|
||||
|
||||
#define SCC_CHECK_AST_WITH_SEMA(expect_node_ptr, str, parse_func) \
|
||||
do { \
|
||||
_scc_check_ast(expect_node_ptr, str, (scc_parse_node_func)parse_func, \
|
||||
true); \
|
||||
TEST_CHECK(strcmp(output_buffer, expect_buffer) == 0); \
|
||||
TEST_MSG("Expected: %s", expect_buffer); \
|
||||
TEST_MSG("Produced: %s", output_buffer); \
|
||||
} while (0);
|
||||
|
||||
#define SCC_CHECK_AST(expect_node_ptr, str, parse_func) \
|
||||
do { \
|
||||
_scc_check_ast(expect_node_ptr, str, (scc_parse_node_func)parse_func); \
|
||||
_scc_check_ast(expect_node_ptr, str, (scc_parse_node_func)parse_func, \
|
||||
false); \
|
||||
TEST_CHECK(strcmp(output_buffer, expect_buffer) == 0); \
|
||||
TEST_MSG("Expected: %s", expect_buffer); \
|
||||
TEST_MSG("Produced: %s", output_buffer); \
|
||||
@@ -370,8 +387,38 @@ static void test_parser_unit(void) {
|
||||
scc_ast_decl_t typedef_decl;
|
||||
scc_ast_decl_typedef_init(&typedef_decl, "int32_t",
|
||||
&scc_ast_builtin_type_int);
|
||||
SCC_CHECK_AST(&typedef_decl.base, "typedef int int32_t;",
|
||||
scc_parse_declaration);
|
||||
scc_ast_type_t typedef_type;
|
||||
scc_ast_type_typedef_init(&typedef_type, "int32_t", &typedef_decl);
|
||||
|
||||
scc_ast_decl_t i32a_decl;
|
||||
scc_ast_decl_val_init(&i32a_decl, &typedef_type, "a", null);
|
||||
|
||||
scc_ast_node_t *array[] = {&typedef_decl.base, &i32a_decl.base};
|
||||
scc_ast_stmt_t stmt;
|
||||
scc_ast_block_item_vec_t items;
|
||||
scc_vec_unsafe_from_array(items, array);
|
||||
scc_ast_stmt_compound_init(&stmt, &items);
|
||||
SCC_CHECK_AST_WITH_SEMA(&stmt.base, "{typedef int int32_t;int32_t a;}",
|
||||
scc_parse_statement);
|
||||
|
||||
scc_ast_type_t void_ptr;
|
||||
scc_ast_type_pointer_init(&void_ptr, &scc_ast_builtin_type_void);
|
||||
scc_ast_decl_t void_ptr_decl;
|
||||
scc_ast_decl_typedef_init(&void_ptr_decl, "void_ptr", &void_ptr);
|
||||
scc_ast_type_t void_ptr_type;
|
||||
scc_ast_type_typedef_init(&void_ptr_type, "void_ptr", &void_ptr_decl);
|
||||
|
||||
scc_ast_decl_t void_ptr_a_decl;
|
||||
scc_ast_decl_val_init(&void_ptr_a_decl, &void_ptr_type, "a", null);
|
||||
|
||||
scc_ast_node_t *array2[] = {&void_ptr_decl.base, &void_ptr_a_decl.base};
|
||||
scc_vec_unsafe_from_array(items, array2);
|
||||
scc_ast_stmt_compound_init(&stmt, &items);
|
||||
SCC_CHECK_AST_WITH_SEMA(&stmt.base,
|
||||
"{typedef void* void_ptr; void_ptr a;}",
|
||||
scc_parse_statement);
|
||||
SCC_CHECK_AST_WITH_SEMA(&void_ptr_decl.base, "typedef void *void_ptr;",
|
||||
scc_parse_declaration);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -387,6 +434,229 @@ static void test_parser_unit(void) {
|
||||
scc_ast_decl_struct_init(&struct_def, null, &fields);
|
||||
SCC_CHECK_AST(&struct_def.base, "struct { int x; };",
|
||||
scc_parse_declaration);
|
||||
|
||||
scc_ast_type_t struct_type;
|
||||
scc_ast_type_struct_init(&struct_type, null, &struct_def);
|
||||
scc_ast_type_t typedef_type;
|
||||
scc_ast_type_typedef_init(&typedef_type, "struct_t", &struct_def);
|
||||
scc_ast_decl_t typedef_decl;
|
||||
scc_ast_decl_typedef_init(&typedef_decl, "struct_t", &struct_type);
|
||||
SCC_CHECK_AST_WITH_SEMA(&typedef_decl.base,
|
||||
"typedef struct { int x; } struct_t;",
|
||||
scc_parse_declaration);
|
||||
|
||||
scc_ast_decl_t typedef_impl_decl;
|
||||
scc_ast_decl_val_init(&typedef_impl_decl, &typedef_type, "a", null);
|
||||
scc_ast_node_t *array[] = {&typedef_decl.base, &typedef_impl_decl.base};
|
||||
scc_ast_stmt_t stmt;
|
||||
scc_ast_block_item_vec_t items;
|
||||
scc_vec_unsafe_from_array(items, array);
|
||||
scc_ast_stmt_compound_init(&stmt, &items);
|
||||
SCC_CHECK_AST_WITH_SEMA(
|
||||
&stmt.base, "{typedef struct { int x; } struct_t; struct_t a;}",
|
||||
scc_parse_statement);
|
||||
}
|
||||
|
||||
{
|
||||
scc_ast_decl_t type_decl;
|
||||
scc_ast_decl_typedef_init(&type_decl, "size_t",
|
||||
&scc_ast_builtin_type_long_long);
|
||||
scc_ast_type_t type_type;
|
||||
scc_ast_type_typedef_init(&type_type, "size_t", &type_decl);
|
||||
|
||||
scc_ast_decl_t param1;
|
||||
scc_ast_decl_param_init(¶m1, &type_type, "a");
|
||||
scc_ast_decl_t param2;
|
||||
scc_ast_decl_param_init(¶m2, &scc_ast_builtin_type_int, "b");
|
||||
scc_ast_decl_t param3;
|
||||
scc_ast_decl_param_init(¶m3, &scc_ast_builtin_type_va_list, null);
|
||||
scc_ast_decl_t *params_array[] = {¶m1, ¶m2, ¶m3};
|
||||
scc_ast_decl_vec_t func_params;
|
||||
scc_vec_unsafe_from_array(func_params, params_array);
|
||||
scc_ast_type_t func_type;
|
||||
|
||||
scc_ast_type_t return_type;
|
||||
|
||||
scc_ast_type_pointer_init(&return_type, &scc_ast_builtin_type_void);
|
||||
scc_ast_type_function_init(&func_type, &return_type, &func_params);
|
||||
scc_ast_decl_t func_decl;
|
||||
scc_ast_decl_func_init(&func_decl, &func_type, "func", null);
|
||||
|
||||
scc_ast_decl_t *decls_array[] = {&type_decl, &func_decl};
|
||||
scc_ast_translation_unit_t tu;
|
||||
scc_ast_decl_vec_t decls;
|
||||
scc_vec_unsafe_from_array(decls, decls_array);
|
||||
scc_ast_translation_unit_init(&tu, &decls);
|
||||
SCC_CHECK_AST_WITH_SEMA(&tu.base,
|
||||
"typedef long long size_t;"
|
||||
"void *func(size_t a, int b, ...);",
|
||||
scc_parse_translation_unit);
|
||||
|
||||
scc_ast_type_t type_func_ptr_type;
|
||||
scc_ast_type_pointer_init(&type_func_ptr_type, &func_type);
|
||||
scc_ast_decl_t type_func_ptr_decl;
|
||||
scc_ast_decl_typedef_init(&type_func_ptr_decl, "func_t",
|
||||
&type_func_ptr_type);
|
||||
scc_ast_decl_t *decls_array2[] = {&type_decl, &type_func_ptr_decl};
|
||||
scc_vec_unsafe_from_array(decls, decls_array2);
|
||||
scc_ast_translation_unit_init(&tu, &decls);
|
||||
SCC_CHECK_AST_WITH_SEMA(
|
||||
&tu.base,
|
||||
"typedef long long size_t;"
|
||||
"typedef void *(*func_t)(size_t a, int b, ...);",
|
||||
scc_parse_translation_unit);
|
||||
}
|
||||
|
||||
{
|
||||
// 1. 构造参数类型:volatile const char *restrict,并附加 register
|
||||
// 存储类
|
||||
scc_ast_type_t char_type;
|
||||
_scc_ast_type_builtin_init(&char_type, SCC_AST_BUILTIN_TYPE_CHAR);
|
||||
char_type.quals.is_const = true; // const
|
||||
char_type.quals.is_volatile = true; // volatile
|
||||
|
||||
scc_ast_type_t ptr_to_char;
|
||||
scc_ast_type_pointer_init(&ptr_to_char, &char_type);
|
||||
ptr_to_char.quals.is_restrict = true; // restrict 限定指针
|
||||
ptr_to_char.quals.is_register = true; // register 存储类(作用于参数)
|
||||
|
||||
// 2. 参数声明
|
||||
scc_ast_decl_t param_decl;
|
||||
scc_ast_decl_param_init(¶m_decl, &ptr_to_char, "fmt");
|
||||
|
||||
// 3. 返回类型:void *
|
||||
scc_ast_type_t void_type;
|
||||
_scc_ast_type_builtin_init(&void_type, SCC_AST_BUILTIN_TYPE_VOID);
|
||||
scc_ast_type_t ptr_to_void;
|
||||
scc_ast_type_pointer_init(&ptr_to_void, &void_type);
|
||||
|
||||
// 4. 参数列表
|
||||
scc_ast_decl_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_push(params, ¶m_decl);
|
||||
|
||||
// 5. 函数类型(包含 static 和 inline)
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_type_function_init(&func_type, &ptr_to_void, ¶ms);
|
||||
func_type.quals.is_static = true;
|
||||
func_type.quals.is_inline = true;
|
||||
|
||||
// 6. 函数声明
|
||||
scc_ast_decl_t decl;
|
||||
scc_ast_decl_func_init(&decl, &func_type, "call", NULL);
|
||||
|
||||
// 7. 与解析结果比较
|
||||
SCC_CHECK_AST_WITH_SEMA(&decl.base,
|
||||
"static inline void *call(volatile register "
|
||||
"const char *restrict fmt);",
|
||||
scc_parse_declaration);
|
||||
}
|
||||
|
||||
{
|
||||
scc_ast_expr_t lvalue;
|
||||
scc_ast_expr_lvalue_init(&lvalue, &scc_ast_builtin_type_void);
|
||||
|
||||
scc_ast_expr_t lhs1;
|
||||
scc_ast_expr_member_init(&lhs1, &lvalue, "data");
|
||||
scc_ast_expr_t lhs2;
|
||||
scc_ast_expr_member_init(&lhs2, &lvalue, "size");
|
||||
scc_ast_expr_t lhs3;
|
||||
scc_ast_expr_member_init(&lhs3, &lvalue, "cap");
|
||||
|
||||
scc_ast_expr_t rl0;
|
||||
scc_ast_expr_literal_int_init(&rl0, "0", false);
|
||||
scc_ast_type_t void_ptr;
|
||||
scc_ast_type_pointer_init(&void_ptr, &scc_ast_builtin_type_void);
|
||||
scc_ast_expr_t rhs1;
|
||||
scc_ast_expr_cast_init(&rhs1, &void_ptr, &rl0);
|
||||
scc_ast_expr_t rhs2;
|
||||
scc_ast_expr_literal_int_init(&rhs2, "0", false);
|
||||
scc_ast_expr_t rhs3;
|
||||
scc_ast_expr_literal_int_init(&rhs3, "0", false);
|
||||
|
||||
scc_ast_expr_vec_t lhs_exprs;
|
||||
scc_ast_expr_t *lhs_array[] = {&lhs1, &lhs2, &lhs3};
|
||||
scc_vec_unsafe_from_array(lhs_exprs, lhs_array);
|
||||
|
||||
scc_ast_expr_vec_t rhs_exprs;
|
||||
scc_ast_expr_t *rhs_array[] = {&rhs1, &rhs2, &rhs3};
|
||||
scc_vec_unsafe_from_array(rhs_exprs, rhs_array);
|
||||
|
||||
scc_ast_expr_t expr;
|
||||
scc_ast_expr_compound_init(&expr, &lvalue, &lhs_exprs, &rhs_exprs);
|
||||
|
||||
// FIXME use real records type
|
||||
SCC_CHECK_AST(&expr.base,
|
||||
"(void){.data = ((void *)0), .size = 0, .cap = 0}",
|
||||
scc_parse_expression);
|
||||
}
|
||||
|
||||
{
|
||||
// int (*(*)(void))[5] (指向函数的指针,该函数返回指向数组的指针)
|
||||
// 步骤:
|
||||
// 1) 数组类型:int [5]
|
||||
scc_ast_expr_t size_5;
|
||||
scc_ast_expr_literal_int_init(&size_5, "5", false);
|
||||
scc_ast_type_t array_of_5_int;
|
||||
scc_ast_type_array_init(&array_of_5_int,
|
||||
(scc_ast_type_t *)&scc_ast_builtin_type_int,
|
||||
&size_5);
|
||||
|
||||
// 2) 函数类型:返回指向数组的指针,无参数
|
||||
scc_ast_type_t ptr_to_array;
|
||||
scc_ast_type_pointer_init(&ptr_to_array, &array_of_5_int);
|
||||
scc_ast_type_t func_type;
|
||||
scc_ast_decl_vec_t func_params;
|
||||
scc_ast_decl_t void_decl;
|
||||
scc_ast_decl_param_init(&void_decl, &scc_ast_builtin_type_void, null);
|
||||
scc_ast_decl_t *array[] = {&void_decl};
|
||||
scc_vec_unsafe_from_array(func_params, array);
|
||||
scc_ast_type_function_init(&func_type, &ptr_to_array,
|
||||
&func_params); // 无参数
|
||||
|
||||
// 3) 指向该函数的指针
|
||||
scc_ast_type_t ptr_to_func;
|
||||
scc_ast_type_pointer_init(&ptr_to_func, &func_type);
|
||||
|
||||
scc_ast_decl_t ptr_to_func_decl;
|
||||
scc_ast_decl_val_init(&ptr_to_func_decl, &ptr_to_func, "foo", null);
|
||||
SCC_CHECK_AST(&ptr_to_func_decl.base, "int (*(*foo)(void))[5];",
|
||||
scc_parse_declaration);
|
||||
|
||||
scc_ast_decl_t typedef_func_decl;
|
||||
scc_ast_decl_typedef_init(&typedef_func_decl, "func_t", &ptr_to_func);
|
||||
scc_ast_type_t typedef_func_type;
|
||||
scc_ast_type_typedef_init(&typedef_func_type, "func_t",
|
||||
&typedef_func_decl);
|
||||
scc_ast_decl_t func_hard_decl;
|
||||
scc_ast_type_t func_hard_type;
|
||||
|
||||
scc_ast_decl_t param1;
|
||||
scc_ast_decl_param_init(¶m1, &ptr_to_func, "bar");
|
||||
scc_ast_decl_t param2;
|
||||
scc_ast_decl_param_init(¶m2, &typedef_func_type, "a");
|
||||
scc_ast_decl_t param3;
|
||||
scc_ast_decl_param_init(¶m1, &scc_ast_builtin_type_va_list, null);
|
||||
scc_ast_decl_t *func_hard_array[] = {¶m1, ¶m2, ¶m3};
|
||||
scc_ast_decl_vec_t func_hard_params;
|
||||
scc_vec_unsafe_from_array(func_hard_params, func_hard_array);
|
||||
scc_ast_type_function_init(&func_hard_type, &ptr_to_array,
|
||||
&func_hard_params);
|
||||
scc_ast_decl_func_init(&func_hard_decl, &func_hard_type, "bar", null);
|
||||
|
||||
scc_ast_decl_vec_t decls;
|
||||
scc_ast_decl_t *decls_array[] = {
|
||||
&typedef_func_decl,
|
||||
&func_hard_decl,
|
||||
};
|
||||
scc_vec_unsafe_from_array(decls, decls_array);
|
||||
scc_ast_translation_unit_t tu;
|
||||
scc_ast_translation_unit_init(&tu, &decls);
|
||||
// SCC_CHECK_AST_WITH_SEMA(
|
||||
// &tu.base,
|
||||
// "typedef int (*(*func_t)(void))[5];"
|
||||
// "int (*(*(bar)(int(*(*foo)(void))[5], func_t a,
|
||||
// ...))(void))[5];", scc_parse_translation_unit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,18 +783,12 @@ static void test_parser_expression(void) {
|
||||
|
||||
// 4. 类型转换(示例: (int)x )
|
||||
{
|
||||
// scc_ast_type_t
|
||||
// int_type; // 使用内置类型全局变量即可,但类型转换需要一个类型节点
|
||||
// //
|
||||
// 我们可以直接使用全局内置类型的地址,但类型转换节点需要一个类型节点,直接引用全局即可
|
||||
// // TODO
|
||||
// scc_ast_expr_t x;
|
||||
// scc_ast_expr_identifier_init(&x, "x");
|
||||
// scc_ast_expr_t cast;
|
||||
// scc_ast_expr_cast_init(&cast,
|
||||
// (scc_ast_type_t *)&scc_ast_builtin_type_int,
|
||||
// &x);
|
||||
// SCC_CHECK_AST(&cast.base, "(int)x", scc_parse_expression);
|
||||
scc_ast_expr_t x;
|
||||
scc_ast_expr_identifier_init(&x, "x");
|
||||
scc_ast_expr_t cast;
|
||||
scc_ast_expr_cast_init(&cast,
|
||||
(scc_ast_type_t *)&scc_ast_builtin_type_int, &x);
|
||||
SCC_CHECK_AST(&cast.base, "(int)x", scc_parse_expression);
|
||||
}
|
||||
|
||||
// 5. 二元运算符优先级
|
||||
@@ -838,7 +1102,7 @@ static void test_parser_type(void) {
|
||||
|
||||
// _Complex double
|
||||
SCC_CHECK_AST((scc_ast_node_t *)&scc_ast_builtin_type_complex_double,
|
||||
"complex double", _scc_parse_type);
|
||||
"double complex", _scc_parse_type);
|
||||
}
|
||||
|
||||
// 2. 带类型限定符的基本类型 (const, volatile)
|
||||
@@ -1168,10 +1432,8 @@ static void test_parser_type(void) {
|
||||
scc_ast_expr_identifier_init(&green, "GREEN");
|
||||
scc_ast_expr_identifier_init(&blue, "BLUE");
|
||||
scc_ast_expr_vec_t enumerators;
|
||||
scc_vec_init(enumerators);
|
||||
scc_vec_push(enumerators, &red);
|
||||
scc_vec_push(enumerators, &green);
|
||||
scc_vec_push(enumerators, &blue);
|
||||
scc_ast_expr_t *array[] = {&red, &green, &blue};
|
||||
scc_vec_unsafe_from_array(enumerators, array);
|
||||
|
||||
scc_ast_decl_t enum_def;
|
||||
scc_ast_decl_enum_init(&enum_def, null, &enumerators);
|
||||
@@ -1179,9 +1441,11 @@ static void test_parser_type(void) {
|
||||
scc_ast_type_enum_init(&enum_type, null, &enum_def);
|
||||
SCC_CHECK_AST(&enum_type.base, "enum { RED, GREEN, BLUE }",
|
||||
_scc_parse_type);
|
||||
|
||||
scc_vec_unsafe_from_array(enumerators, array);
|
||||
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_CHECK_AST(&enum_type.base, "enum E { RED, GREEN, BLUE, }",
|
||||
_scc_parse_type);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,10 @@ typedef struct {
|
||||
scc_pproc_macro_table_t *expanded_set;
|
||||
scc_lexer_tok_ring_t *input;
|
||||
scc_lexer_tok_vec_t output;
|
||||
scc_pos_t call_pos;
|
||||
cbool need_rescan;
|
||||
cbool need_parse_defined;
|
||||
cbool need_keep_org_pos;
|
||||
} scc_pproc_expand_t;
|
||||
|
||||
static inline scc_lexer_tok_ring_t
|
||||
@@ -27,10 +29,11 @@ void scc_pproc_expand_macro(scc_pproc_expand_t *expand_ctx);
|
||||
void scc_pproc_expand_by_src(scc_pproc_macro_table_t *macro_table,
|
||||
scc_lexer_tok_ring_t *input,
|
||||
scc_lexer_tok_ring_t *output,
|
||||
const scc_pproc_macro_t *macro);
|
||||
const scc_pproc_macro_t *macro,
|
||||
cbool need_keep_org_pos);
|
||||
void scc_pproc_expand_by_vec(scc_pproc_macro_table_t *macro_table,
|
||||
scc_lexer_tok_vec_t *input,
|
||||
scc_lexer_tok_vec_t *output,
|
||||
cbool need_parse_defined);
|
||||
cbool need_parse_defined, cbool need_keep_org_pos);
|
||||
|
||||
#endif /* __SCC_PPROC_EXPAND_H__ */
|
||||
|
||||
@@ -51,6 +51,7 @@ typedef struct scc_pproc {
|
||||
|
||||
struct {
|
||||
int max_include_depth;
|
||||
cbool keep_original_pos;
|
||||
} config;
|
||||
} scc_pproc_t;
|
||||
|
||||
|
||||
@@ -90,6 +90,10 @@ static inline void fill_replacements(scc_pproc_t *pp,
|
||||
scc_ring_next_consume(*pp->cur_ring, tok, ok);
|
||||
if (!ok)
|
||||
break;
|
||||
if (scc_get_tok_subtype(tok.type) == SCC_TOK_SUBTYPE_COMMENT) {
|
||||
scc_lexer_tok_drop(&tok);
|
||||
continue;
|
||||
}
|
||||
if (tok.type == SCC_TOK_EOF || tok.type == SCC_TOK_ENDLINE) {
|
||||
scc_lexer_tok_drop(&tok);
|
||||
break;
|
||||
@@ -172,7 +176,7 @@ static void scc_pproc_parse_line_and_expand(scc_pproc_t *pp,
|
||||
}
|
||||
scc_lexer_tok_vec_t out_vec;
|
||||
scc_pproc_expand_by_vec(&pp->macro_table, &org_toks, &out_vec,
|
||||
need_parse_defined);
|
||||
need_parse_defined, pp->config.keep_original_pos);
|
||||
*out_ring = scc_lexer_array_to_ring(&out_vec);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ static void rescan(scc_pproc_expand_t *expand_ctx,
|
||||
const scc_pproc_macro_t *macro,
|
||||
scc_lexer_tok_vec_t *tok_buffer);
|
||||
|
||||
static scc_lexer_tok_t stringify_argument(scc_lexer_tok_vec_t *arg_tokens) {
|
||||
static scc_lexer_tok_t stringify_argument(scc_pproc_expand_t *ctx,
|
||||
scc_lexer_tok_vec_t *arg_tokens) {
|
||||
// WRITE BY AI
|
||||
scc_cstring_t str = scc_cstring_create();
|
||||
scc_cstring_append_ch(&str, '\"'); // 左引号
|
||||
@@ -38,10 +39,13 @@ static scc_lexer_tok_t stringify_argument(scc_lexer_tok_vec_t *arg_tokens) {
|
||||
scc_lexer_tok_t result;
|
||||
result.type = SCC_TOK_STRING_LITERAL;
|
||||
result.lexeme = str;
|
||||
if (ctx->need_keep_org_pos)
|
||||
result.loc = ctx->call_pos;
|
||||
return result;
|
||||
}
|
||||
|
||||
static scc_lexer_tok_t concatenate_tokens(const scc_lexer_tok_t *left,
|
||||
static scc_lexer_tok_t concatenate_tokens(scc_pproc_expand_t *ctx,
|
||||
const scc_lexer_tok_t *left,
|
||||
const scc_lexer_tok_t *right) {
|
||||
scc_cstring_t new_lex = scc_cstring_from_cstr("");
|
||||
if (left != null) {
|
||||
@@ -84,6 +88,8 @@ RETURN:
|
||||
scc_lexer_drop_ring(ring);
|
||||
scc_lexer_drop(&lexer);
|
||||
scc_sstream_drop(&sstream);
|
||||
if (ctx->need_keep_org_pos)
|
||||
result.loc = ctx->call_pos;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -102,7 +108,8 @@ static inline void scc_copy_expand(scc_pproc_expand_t *expand_ctx,
|
||||
void scc_pproc_expand_by_src(scc_pproc_macro_table_t *macro_table,
|
||||
scc_lexer_tok_ring_t *input,
|
||||
scc_lexer_tok_ring_t *output,
|
||||
const scc_pproc_macro_t *macro) {
|
||||
const scc_pproc_macro_t *macro,
|
||||
cbool need_keep_org_pos) {
|
||||
scc_lexer_tok_vec_t expaned_buffer;
|
||||
scc_vec_init(expaned_buffer);
|
||||
|
||||
@@ -130,7 +137,8 @@ void scc_pproc_expand_by_src(scc_pproc_macro_table_t *macro_table,
|
||||
}
|
||||
|
||||
scc_lexer_tok_vec_t output_vec;
|
||||
scc_pproc_expand_by_vec(macro_table, &expaned_buffer, &output_vec, false);
|
||||
scc_pproc_expand_by_vec(macro_table, &expaned_buffer, &output_vec, false,
|
||||
need_keep_org_pos);
|
||||
Assert(output->cap == 0 && output->data == null); // FIXME hack it
|
||||
*output = scc_lexer_array_to_ring(&output_vec);
|
||||
}
|
||||
@@ -138,13 +146,16 @@ void scc_pproc_expand_by_src(scc_pproc_macro_table_t *macro_table,
|
||||
void scc_pproc_expand_by_vec(scc_pproc_macro_table_t *macro_table,
|
||||
scc_lexer_tok_vec_t *input,
|
||||
scc_lexer_tok_vec_t *output,
|
||||
cbool need_parse_defined) {
|
||||
cbool need_parse_defined,
|
||||
cbool need_keep_org_pos) {
|
||||
scc_pproc_expand_t ctx;
|
||||
scc_lexer_tok_ring_t ring = scc_lexer_array_to_ring(input);
|
||||
ctx.input = ˚
|
||||
ctx.macro_table = macro_table;
|
||||
ctx.need_rescan = false;
|
||||
ctx.need_parse_defined = need_parse_defined;
|
||||
ctx.need_keep_org_pos = need_keep_org_pos;
|
||||
ctx.call_pos = scc_pos_create();
|
||||
scc_vec_init(ctx.output);
|
||||
scc_pproc_macro_table_t expanded_set;
|
||||
ctx.expanded_set = &expanded_set;
|
||||
@@ -311,7 +322,8 @@ static void rescan(scc_pproc_expand_t *expand_ctx,
|
||||
true);
|
||||
scc_lexer_tok_vec_t output = {0};
|
||||
scc_pproc_expand_by_vec(expand_ctx->macro_table, &expaned_buffer,
|
||||
&output, expand_ctx->need_parse_defined);
|
||||
&output, expand_ctx->need_parse_defined,
|
||||
expand_ctx->need_keep_org_pos);
|
||||
scc_vec_foreach(output, i) {
|
||||
scc_vec_push(expand_ctx->output, scc_vec_at(output, i));
|
||||
}
|
||||
@@ -352,8 +364,8 @@ static inline int got_right_non_blank(int i,
|
||||
return right_idx;
|
||||
}
|
||||
|
||||
static void concact(scc_lexer_tok_vec_t *tok_buffer, scc_lexer_tok_t *right,
|
||||
cbool gnu_va_arg_extend) {
|
||||
static void concact(scc_pproc_expand_t *ctx, scc_lexer_tok_vec_t *tok_buffer,
|
||||
scc_lexer_tok_t *right, cbool gnu_va_arg_extend) {
|
||||
// ## contact
|
||||
int tok_buf_size = (int)scc_vec_size(*tok_buffer);
|
||||
int left_idx = got_left_non_blank(tok_buf_size, tok_buffer);
|
||||
@@ -369,7 +381,7 @@ static void concact(scc_lexer_tok_vec_t *tok_buffer, scc_lexer_tok_t *right,
|
||||
}
|
||||
}
|
||||
|
||||
scc_lexer_tok_t concate_tok = concatenate_tokens(left, right);
|
||||
scc_lexer_tok_t concate_tok = concatenate_tokens(ctx, left, right);
|
||||
|
||||
while (left_idx++ < tok_buf_size) {
|
||||
scc_lexer_tok_drop(&scc_vec_pop(*tok_buffer));
|
||||
@@ -409,6 +421,8 @@ static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
|
||||
scc_vec_foreach(macro->replaces, i) {
|
||||
scc_lexer_tok_t tok =
|
||||
scc_lexer_tok_copy(&scc_vec_at(macro->replaces, i));
|
||||
if (expand_ctx->need_keep_org_pos)
|
||||
tok.loc = expand_ctx->call_pos;
|
||||
if (tok.type == SCC_TOK_BLANK) {
|
||||
scc_cstring_free(&tok.lexeme);
|
||||
tok.lexeme = scc_cstring_from_cstr(" ");
|
||||
@@ -430,7 +444,8 @@ static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
|
||||
int j = find_params(&scc_vec_at(macro->replaces, right_idx), macro);
|
||||
Assert(j != -1 && j < (int)scc_vec_size(splited_params));
|
||||
|
||||
tok = stringify_argument(&scc_vec_at(splited_params, j));
|
||||
tok =
|
||||
stringify_argument(expand_ctx, &scc_vec_at(splited_params, j));
|
||||
scc_vec_push(tok_buffer, tok);
|
||||
i = right_idx;
|
||||
continue;
|
||||
@@ -467,12 +482,12 @@ static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
|
||||
if (scc_strcmp(scc_cstring_as_cstr(&(right_tok->lexeme)),
|
||||
"__VA_ARGS__") == 0) {
|
||||
if (scc_vec_size(right_vec) == 0) {
|
||||
concact(&tok_buffer, right, true);
|
||||
concact(expand_ctx, &tok_buffer, right, true);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
concact(&tok_buffer, right, false);
|
||||
concact(expand_ctx, &tok_buffer, right, false);
|
||||
}
|
||||
|
||||
scc_vec_foreach(right_vec, j) {
|
||||
@@ -520,6 +535,8 @@ static inline void expand_object_macro(scc_pproc_expand_t *expand_ctx,
|
||||
scc_vec_foreach(macro->replaces, i) {
|
||||
scc_lexer_tok_t tok =
|
||||
scc_lexer_tok_copy(&scc_vec_at(macro->replaces, i));
|
||||
if (expand_ctx->need_keep_org_pos)
|
||||
tok.loc = expand_ctx->call_pos;
|
||||
if (tok.type == SCC_TOK_BLANK) {
|
||||
// FIXME using function to warpper it
|
||||
scc_cstring_free(&tok.lexeme);
|
||||
@@ -536,7 +553,7 @@ static inline void expand_object_macro(scc_pproc_expand_t *expand_ctx,
|
||||
right = &scc_vec_at(macro->replaces, right_idx);
|
||||
}
|
||||
|
||||
concact(&tok_buffer, right, false);
|
||||
concact(expand_ctx, &tok_buffer, right, false);
|
||||
i = right_idx;
|
||||
continue;
|
||||
}
|
||||
@@ -630,6 +647,7 @@ void scc_pproc_expand_macro(scc_pproc_expand_t *expand_ctx) {
|
||||
}
|
||||
expand_ctx->need_rescan = true;
|
||||
|
||||
expand_ctx->call_pos = tok.loc;
|
||||
if (macro->type == SCC_PP_MACRO_OBJECT) {
|
||||
scc_lexer_tok_drop(&tok);
|
||||
expand_object_macro(expand_ctx, macro);
|
||||
|
||||
@@ -96,10 +96,10 @@ cbool scc_pproc_add_function_macro(scc_pproc_macro_table_t *macros,
|
||||
|
||||
scc_pproc_macro_t *scc_pproc_macro_table_set(scc_pproc_macro_table_t *pp,
|
||||
scc_pproc_macro_t *macro) {
|
||||
Assert(pp != null && macro != null);
|
||||
Assert(pp != null && macro != null && scc_cstring_len(¯o->name) != 0);
|
||||
scc_pproc_macro_t *old = scc_hashtable_set(&pp->table, ¯o->name, macro);
|
||||
if (old && old != macro) {
|
||||
LOG_WARN("same macro name");
|
||||
LOG_WARN("same macro name `%s`", scc_cstring_as_cstr(¯o->name));
|
||||
scc_pproc_macro_drop(old);
|
||||
}
|
||||
return macro;
|
||||
|
||||
@@ -62,7 +62,8 @@ CONTINUE:
|
||||
return ok;
|
||||
}
|
||||
scc_pproc_expand_by_src(&pp->macro_table, pp->cur_ring,
|
||||
&pp->expanded_ring, macro);
|
||||
&pp->expanded_ring, macro,
|
||||
pp->config.keep_original_pos);
|
||||
goto CONTINUE;
|
||||
} else {
|
||||
// continue
|
||||
@@ -113,6 +114,7 @@ void scc_pproc_init(scc_pproc_t *pp, scc_lexer_tok_ring_t *input) {
|
||||
pp->enable = true;
|
||||
|
||||
pp->config.max_include_depth = 32;
|
||||
pp->config.keep_original_pos = true;
|
||||
}
|
||||
|
||||
void scc_pproc_add_builtin_macros() {
|
||||
|
||||
41
libs/pproc/tests/test_pproc_pos.c
Normal file
41
libs/pproc/tests/test_pproc_pos.c
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <assert.h>
|
||||
#include <scc_pproc.h>
|
||||
#include <string.h>
|
||||
#include <utest/acutest.h>
|
||||
|
||||
static void test_define_pos(void) {
|
||||
int ret = 0;
|
||||
scc_sstream_t mem_stream;
|
||||
const char *input = "#define OBJ 1\nOBJ";
|
||||
ret = scc_sstream_init_by_buffer(&mem_stream, input, strlen(input), false,
|
||||
16);
|
||||
Assert(ret == 0);
|
||||
|
||||
scc_lexer_t lexer;
|
||||
scc_lexer_init(&lexer, scc_sstream_to_ring(&mem_stream));
|
||||
|
||||
scc_pproc_t pp;
|
||||
scc_pproc_init(&pp, scc_lexer_to_ring(&lexer, 8, true));
|
||||
|
||||
scc_lexer_tok_ring_t *tok_ring = scc_pproc_to_ring(&pp, 8, true, true);
|
||||
scc_lexer_tok_t tok = {0};
|
||||
|
||||
scc_ring_next_consume(*tok_ring, tok, ret);
|
||||
Assert(ret == true);
|
||||
TEST_CHECK(tok.loc.line == 2 && tok.loc.col == 1 &&
|
||||
scc_strcmp(tok.lexeme.data, "1") == 0);
|
||||
TEST_MSG("Expected: %d:%d:%s", 2, 1, "1");
|
||||
TEST_MSG("Produced: %zu:%zu:%s", tok.loc.line, tok.loc.col,
|
||||
tok.lexeme.data);
|
||||
|
||||
scc_ring_free(*tok_ring);
|
||||
scc_pproc_drop(&pp);
|
||||
scc_lexer_drop(&lexer);
|
||||
scc_sstream_drop(&mem_stream);
|
||||
}
|
||||
|
||||
#define TEST_LIST_CASE(func_name) {#func_name, func_name}
|
||||
TEST_LIST = {
|
||||
TEST_LIST_CASE(test_define_pos),
|
||||
{NULL, NULL},
|
||||
};
|
||||
@@ -194,6 +194,11 @@ static void test_define_nested_macros(void) {
|
||||
CHECK_PP_OUTPUT_EXACT("#define default a\n"
|
||||
"default\n",
|
||||
"a\n");
|
||||
|
||||
TEST_CASE("test_macro_end_by_comment");
|
||||
CHECK_PP_OUTPUT_EXACT("#define MAX_SIZE 128///! COMMENT\n"
|
||||
"MAX_SIZE\n",
|
||||
"128\n");
|
||||
}
|
||||
|
||||
static void test_undef_macros(void) {
|
||||
|
||||
@@ -15,10 +15,10 @@ int scc_memcmp(const void *s1, const void *s2, usize n);
|
||||
* @return u32
|
||||
*/
|
||||
static inline u32 scc_strhash32(const char *s) {
|
||||
u32 hash = 2166136261u; // FNV-1a偏移基础值
|
||||
u32 hash = 2166136261; // FNV-1a偏移基础值
|
||||
while (*s) {
|
||||
hash ^= *s++;
|
||||
hash *= 16777619u;
|
||||
hash *= 16777619;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -34,25 +34,29 @@ static_assert(sizeof(cbool) == 1, "cbool size must 1");
|
||||
|
||||
#else
|
||||
/* clang-format off */
|
||||
typedef __scc_i8 i8;
|
||||
typedef __scc_i16 i16;
|
||||
typedef __scc_i32 i32;
|
||||
typedef __scc_i64 i64;
|
||||
typedef __scc_u8 u8;
|
||||
typedef __scc_u16 u16;
|
||||
typedef __scc_u32 u32;
|
||||
typedef __scc_u64 u64;
|
||||
|
||||
typedef __scc_isize isize;
|
||||
typedef __scc_usize usize;
|
||||
typedef __scc_isize pdiff;
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef __scc_f32 f32;
|
||||
typedef __scc_f64 f64;
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef __scc_bool cbool;
|
||||
/// void / null
|
||||
#define null __scc_null
|
||||
typedef intptr_t isize;
|
||||
typedef uintptr_t usize;
|
||||
typedef ptrdiff_t pdiff;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
typedef bool cbool;
|
||||
|
||||
/* clang-format on */
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __SCC__ // FIXME it will be remove
|
||||
typedef void *FILE;
|
||||
#endif
|
||||
|
||||
void *scc_pal_malloc(size_t size) { return malloc(size); }
|
||||
|
||||
void *scc_pal_calloc(size_t count, size_t size) { return calloc(count, size); }
|
||||
|
||||
Reference in New Issue
Block a user