feat(pproc): 实现预处理器宏连接操作符功能
- 修改concatenate_tokens函数以支持null参数检查,避免空指针访问 - 添加concact辅助函数来处理##连接操作的逻辑 - 重构expand_function_macro中##操作符的实现,支持GNU扩展特性 - 实现对可变参数宏中##操作的正确处理,包括逗号删除逻辑 - 改进object宏中的##连接操作处理 - 添加多个单元测试用例验证连接操作符的正确性 - 修复字符串连接时的边界条件处理 refactor(tests): 重命名预处理器单元测试文件 - 将test_unit.c重命名为test_pproc_unit.c以更明确标识测试范围
This commit is contained in:
@@ -39,10 +39,13 @@ static scc_lexer_tok_t stringify_argument(scc_lexer_tok_vec_t *arg_tokens) {
|
||||
|
||||
static scc_lexer_tok_t concatenate_tokens(const scc_lexer_tok_t *left,
|
||||
const scc_lexer_tok_t *right) {
|
||||
Assert(left != null && right != null);
|
||||
scc_cstring_t new_lex = scc_cstring_create();
|
||||
scc_cstring_append(&new_lex, &left->lexeme);
|
||||
scc_cstring_append(&new_lex, &right->lexeme);
|
||||
scc_cstring_t new_lex = scc_cstring_from_cstr("");
|
||||
if (left != null) {
|
||||
scc_cstring_append(&new_lex, &left->lexeme);
|
||||
}
|
||||
if (right != null) {
|
||||
scc_cstring_append(&new_lex, &right->lexeme);
|
||||
}
|
||||
|
||||
scc_lexer_t lexer;
|
||||
scc_sstream_t sstream;
|
||||
@@ -56,7 +59,7 @@ static scc_lexer_tok_t concatenate_tokens(const scc_lexer_tok_t *left,
|
||||
int ok;
|
||||
scc_ring_next_consume(*ring, result, ok);
|
||||
if (!ok) {
|
||||
scc_lexer_tok_drop(&result);
|
||||
result.type = SCC_TOK_EOF;
|
||||
return result;
|
||||
}
|
||||
scc_ring_next_consume(*ring, result, ok);
|
||||
@@ -263,6 +266,36 @@ 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) {
|
||||
// ## contact
|
||||
int tok_buf_size = (int)scc_vec_size(*tok_buffer);
|
||||
int left_idx = got_left_non_blank(tok_buf_size, tok_buffer);
|
||||
|
||||
scc_lexer_tok_t *left;
|
||||
if (left_idx < 0) {
|
||||
left = null;
|
||||
left_idx = 0; // FIXME for free tok_buffer
|
||||
} else {
|
||||
left = &scc_vec_at(*tok_buffer, left_idx);
|
||||
if (gnu_va_arg_extend && left->type == SCC_TOK_COMMA) {
|
||||
left = null;
|
||||
}
|
||||
}
|
||||
|
||||
scc_lexer_tok_t concate_tok = concatenate_tokens(left, right);
|
||||
|
||||
while (left_idx++ < tok_buf_size) {
|
||||
scc_lexer_tok_drop(&scc_vec_pop(*tok_buffer));
|
||||
}
|
||||
if (concate_tok.type == SCC_TOK_UNKNOWN) {
|
||||
LOG_FATAL("Invalid ## token");
|
||||
}
|
||||
if (concate_tok.type != SCC_TOK_EOF) {
|
||||
scc_vec_push(*tok_buffer, concate_tok);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
|
||||
const scc_pproc_macro_t *macro) {
|
||||
scc_lexer_tok_vec_t tok_buffer;
|
||||
@@ -316,55 +349,16 @@ static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
|
||||
} else if (tok.type == SCC_TOK_SHARP_SHARP) {
|
||||
// ## contact
|
||||
scc_lexer_tok_drop(&tok);
|
||||
int left_idx = got_left_non_blank(i, ¯o->replaces);
|
||||
int right_idx = got_right_non_blank(i, ¯o->replaces);
|
||||
|
||||
if (left_idx < 0 ||
|
||||
right_idx >= (int)scc_vec_size(macro->replaces)) {
|
||||
LOG_FATAL("Invalid ## operator");
|
||||
}
|
||||
while ((int)i++ < right_idx) {
|
||||
scc_lexer_tok_drop(&scc_vec_pop(tok_buffer));
|
||||
}
|
||||
|
||||
scc_lexer_tok_t *left_tok = &scc_vec_at(macro->replaces, left_idx);
|
||||
scc_lexer_tok_t *right_tok =
|
||||
&scc_vec_at(macro->replaces, right_idx);
|
||||
|
||||
if (left_tok->type == SCC_TOK_COMMA &&
|
||||
scc_strcmp(scc_cstring_as_cstr(&(right_tok->lexeme)),
|
||||
"__VA_ARGS__") == 0) {
|
||||
// GNU 扩展:处理逗号删除
|
||||
int right_param_idx = find_params(right_tok, macro);
|
||||
Assert(right_param_idx != -1);
|
||||
scc_lexer_tok_vec_t right_vec =
|
||||
scc_vec_at(expanded_params, right_param_idx);
|
||||
if (scc_vec_size(right_vec) != 0) {
|
||||
// 可变参数非空:输出逗号副本,然后输出右侧参数的展开
|
||||
scc_lexer_tok_t comma_tok = scc_lexer_tok_copy(left_tok);
|
||||
scc_vec_push(tok_buffer, comma_tok);
|
||||
}
|
||||
scc_vec_foreach(right_vec, k) {
|
||||
scc_lexer_tok_t tok =
|
||||
scc_lexer_tok_copy(&scc_vec_at(right_vec, k));
|
||||
scc_vec_push(tok_buffer, tok);
|
||||
}
|
||||
i = right_idx;
|
||||
continue;
|
||||
}
|
||||
|
||||
int idx;
|
||||
idx = find_params(left_tok, macro);
|
||||
scc_lexer_tok_vec_t left_vec;
|
||||
if (idx != -1) {
|
||||
Assert(idx < (int)scc_vec_size(splited_params));
|
||||
left_vec = scc_vec_at(splited_params, idx);
|
||||
scc_lexer_tok_t *right_tok;
|
||||
if (right_idx >= (int)scc_vec_size(macro->replaces)) {
|
||||
right_tok = null;
|
||||
} else {
|
||||
scc_vec_init(left_vec);
|
||||
scc_vec_push(left_vec, scc_lexer_tok_copy(left_tok));
|
||||
right_tok = &scc_vec_at(macro->replaces, right_idx);
|
||||
}
|
||||
|
||||
idx = find_params(right_tok, macro);
|
||||
int idx = find_params(right_tok, macro);
|
||||
scc_lexer_tok_vec_t right_vec;
|
||||
if (idx != -1) {
|
||||
Assert(idx < (int)scc_vec_size(splited_params));
|
||||
@@ -374,26 +368,21 @@ static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
|
||||
scc_vec_push(right_vec, scc_lexer_tok_copy(right_tok));
|
||||
}
|
||||
|
||||
scc_lexer_tok_t *left =
|
||||
scc_vec_size(left_vec)
|
||||
? &scc_vec_at(left_vec, scc_vec_size(left_vec) - 1)
|
||||
: null;
|
||||
scc_lexer_tok_t *right =
|
||||
scc_vec_size(right_vec) ? &scc_vec_at(right_vec, 0) : null;
|
||||
|
||||
scc_vec_foreach(left_vec, k) {
|
||||
if (k + 1 >= scc_vec_size(left_vec)) {
|
||||
// GNU ## extention
|
||||
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);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
scc_lexer_tok_t tok =
|
||||
scc_lexer_tok_copy(&scc_vec_at(left_vec, k));
|
||||
scc_vec_push(tok_buffer, tok);
|
||||
} else {
|
||||
concact(&tok_buffer, right, false);
|
||||
}
|
||||
scc_lexer_tok_t concate_tok = concatenate_tokens(left, right);
|
||||
if (concate_tok.type == SCC_TOK_UNKNOWN) {
|
||||
LOG_FATAL("Invalid ## token");
|
||||
}
|
||||
scc_vec_push(tok_buffer, concate_tok);
|
||||
|
||||
scc_vec_foreach(right_vec, k) {
|
||||
if (k == 0) {
|
||||
continue;
|
||||
@@ -439,24 +428,16 @@ static inline void expand_object_macro(scc_pproc_expand_t *expand_ctx,
|
||||
tok.lexeme = scc_cstring_from_cstr(" ");
|
||||
} else if (tok.type == SCC_TOK_SHARP_SHARP) {
|
||||
// ## contact
|
||||
int left_idx = got_left_non_blank(i, ¯o->replaces);
|
||||
int right_idx = got_right_non_blank(i, ¯o->replaces);
|
||||
|
||||
if (left_idx < 0 ||
|
||||
right_idx >= (int)scc_vec_size(macro->replaces)) {
|
||||
LOG_FATAL("Invalid ## operator");
|
||||
scc_lexer_tok_t *right;
|
||||
if (right_idx >= (int)scc_vec_size(macro->replaces)) {
|
||||
right = null;
|
||||
} else {
|
||||
right = &scc_vec_at(macro->replaces, right_idx);
|
||||
}
|
||||
scc_lexer_tok_t *left = &scc_vec_at(macro->replaces, left_idx);
|
||||
scc_lexer_tok_t *right = &scc_vec_at(macro->replaces, right_idx);
|
||||
|
||||
scc_lexer_tok_t concate_tok = concatenate_tokens(left, right);
|
||||
while ((int)i++ < right_idx) {
|
||||
scc_lexer_tok_drop(&scc_vec_pop(tok_buffer));
|
||||
}
|
||||
if (concate_tok.type == SCC_TOK_UNKNOWN) {
|
||||
LOG_FATAL("Invalid ## token");
|
||||
}
|
||||
scc_vec_push(tok_buffer, concate_tok);
|
||||
concact(&tok_buffer, right, false);
|
||||
i = right_idx;
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user