refactor(pproc): 重构预处理器条件编译逻辑
- 提取条件判断逻辑到独立函数 scc_pproc_parse_if_need_skip - 使用辅助函数 in_if, in_elif, in_else, in_endif 简化条件处理 - 添加宏 __SCC_PPROC_LOG_PNT 统一错误和警告处理逻辑 - 增加嵌套条件测试用例验证非活动状态下的正确行为
This commit is contained in:
@@ -68,6 +68,7 @@ static inline void scc_pproc_add_include_path_cstr(scc_pproc_t *pp,
|
||||
|
||||
void scc_pproc_handle_directive(scc_pproc_t *pp);
|
||||
|
||||
cbool scc_pproc_parse_if_need_skip(scc_pproc_t *pp, scc_tok_type_t type);
|
||||
cbool scc_pproc_parse_if_defined(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
const scc_lexer_tok_t *tok);
|
||||
cbool scc_pproc_parse_if_condition(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
|
||||
@@ -251,28 +251,7 @@ void scc_pproc_handle_directive(scc_pproc_t *pp) {
|
||||
}
|
||||
scc_tok_type_t type = keywords[ret].tok_type;
|
||||
|
||||
if (scc_vec_size(pp->if_stack) != 0) {
|
||||
scc_pproc_if_t *top =
|
||||
&scc_vec_at(pp->if_stack, scc_vec_size(pp->if_stack) - 1);
|
||||
pp->enable = top->active;
|
||||
}
|
||||
// 非条件指令,且当前不活动时直接跳过整行
|
||||
int is_conditional = 0;
|
||||
switch (type) {
|
||||
case SCC_PP_TOK_IFDEF:
|
||||
case SCC_PP_TOK_IFNDEF:
|
||||
case SCC_PP_TOK_ELIFDEF:
|
||||
case SCC_PP_TOK_ELIFNDEF:
|
||||
case SCC_PP_TOK_ELSE:
|
||||
case SCC_PP_TOK_ENDIF:
|
||||
case SCC_PP_TOK_IF:
|
||||
case SCC_PP_TOK_ELIF:
|
||||
is_conditional = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!is_conditional && !pp->enable) {
|
||||
if (scc_pproc_parse_if_need_skip(pp, type)) {
|
||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||
return;
|
||||
}
|
||||
@@ -361,34 +340,30 @@ void scc_pproc_handle_directive(scc_pproc_t *pp) {
|
||||
return;
|
||||
}
|
||||
case SCC_PP_TOK_LINE:
|
||||
goto ERROR;
|
||||
case SCC_PP_TOK_EMBED:
|
||||
goto ERROR;
|
||||
case SCC_PP_TOK_ERROR:
|
||||
scc_lexer_tok_drop(&tok);
|
||||
while (1) {
|
||||
ok = scc_lexer_next_non_blank(pp->cur_ring, &tok);
|
||||
if (tok.type == SCC_TOK_ENDLINE || ok == false) {
|
||||
return;
|
||||
}
|
||||
if (scc_get_tok_subtype(tok.type) == SCC_TOK_SUBTYPE_LITERAL) {
|
||||
SCC_ERROR(tok.loc, "%s", scc_cstring_as_cstr(&tok.lexeme));
|
||||
}
|
||||
scc_lexer_tok_drop(&tok);
|
||||
}
|
||||
return;
|
||||
case SCC_PP_TOK_WARNING:
|
||||
scc_lexer_tok_drop(&tok);
|
||||
while (1) {
|
||||
ok = scc_lexer_next_non_blank(pp->cur_ring, &tok);
|
||||
if (tok.type == SCC_TOK_ENDLINE || ok == false) {
|
||||
return;
|
||||
}
|
||||
if (scc_get_tok_subtype(tok.type) == SCC_TOK_SUBTYPE_LITERAL) {
|
||||
SCC_WARN(tok.loc, "%s", scc_cstring_as_cstr(&tok.lexeme));
|
||||
}
|
||||
scc_lexer_tok_drop(&tok);
|
||||
}
|
||||
return;
|
||||
#define __SCC_PPROC_LOG_PNT(func_name) \
|
||||
do { \
|
||||
scc_lexer_tok_drop(&tok); \
|
||||
while (1) { \
|
||||
ok = scc_lexer_next_non_blank(pp->cur_ring, &tok); \
|
||||
if (tok.type == SCC_TOK_ENDLINE || ok == false) { \
|
||||
return; \
|
||||
} \
|
||||
if (scc_get_tok_subtype(tok.type) == SCC_TOK_SUBTYPE_LITERAL) { \
|
||||
func_name(tok.loc, "%s", scc_cstring_as_cstr(&tok.lexeme)); \
|
||||
} \
|
||||
scc_lexer_tok_drop(&tok); \
|
||||
} \
|
||||
return; \
|
||||
} while (0)
|
||||
case SCC_PP_TOK_ERROR: {
|
||||
__SCC_PPROC_LOG_PNT(SCC_ERROR);
|
||||
}
|
||||
case SCC_PP_TOK_WARNING: {
|
||||
__SCC_PPROC_LOG_PNT(SCC_WARN);
|
||||
}
|
||||
case SCC_PP_TOK_PRAGMA:
|
||||
SCC_WARN(tok.loc, "pragma ignored");
|
||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||
|
||||
@@ -1,6 +1,83 @@
|
||||
#include <scc_lexer_utils.h>
|
||||
#include <scc_pproc.h>
|
||||
|
||||
cbool scc_pproc_parse_if_need_skip(scc_pproc_t *pp, scc_tok_type_t type) {
|
||||
if (pp->enable == true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (scc_vec_size(pp->if_stack) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
scc_pproc_if_t *top =
|
||||
&scc_vec_at(pp->if_stack, scc_vec_size(pp->if_stack) - 1);
|
||||
pp->enable = top->active;
|
||||
|
||||
if ((type == SCC_PP_TOK_IF || type == SCC_PP_TOK_IFDEF ||
|
||||
type == SCC_PP_TOK_IFNDEF || type == SCC_PP_TOK_ELIFDEF ||
|
||||
type == SCC_PP_TOK_ELIFNDEF || type == SCC_PP_TOK_ELSE ||
|
||||
type == SCC_PP_TOK_ELIF || type == SCC_PP_TOK_ENDIF)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void in_if(scc_pproc_t *pp, cbool enable) {
|
||||
scc_pproc_if_t new_if;
|
||||
|
||||
if (pp->enable) {
|
||||
new_if.active = enable;
|
||||
new_if.found_true = enable;
|
||||
new_if.seen_else = false;
|
||||
pp->enable = enable;
|
||||
} else {
|
||||
// to disable hole stack if we are in disabled state
|
||||
new_if.active = false;
|
||||
new_if.found_true = true;
|
||||
new_if.seen_else = false;
|
||||
}
|
||||
scc_vec_push(pp->if_stack, new_if);
|
||||
}
|
||||
|
||||
static void in_elif(scc_pproc_t *pp, scc_pproc_if_t *top, cbool enable) {
|
||||
if (top->found_true) {
|
||||
top->active = false;
|
||||
} else {
|
||||
if (enable) {
|
||||
top->found_true = true;
|
||||
}
|
||||
top->active = enable;
|
||||
}
|
||||
pp->enable = top->active;
|
||||
}
|
||||
|
||||
static void in_else(scc_pproc_t *pp, scc_pproc_if_t *top) {
|
||||
if (top->found_true) {
|
||||
top->active = false;
|
||||
} else {
|
||||
top->active = true;
|
||||
top->found_true = true;
|
||||
}
|
||||
|
||||
top->seen_else = true;
|
||||
pp->enable = top->active;
|
||||
}
|
||||
|
||||
static void in_endif(scc_pproc_t *pp) {
|
||||
if (scc_vec_size(pp->if_stack) == 0) {
|
||||
LOG_ERROR("#endif without #if");
|
||||
} else {
|
||||
scc_vec_pop(pp->if_stack);
|
||||
}
|
||||
if (scc_vec_size(pp->if_stack) == 0) {
|
||||
pp->enable = true;
|
||||
} else {
|
||||
pp->enable =
|
||||
scc_vec_at(pp->if_stack, scc_vec_size(pp->if_stack) - 1).active;
|
||||
}
|
||||
}
|
||||
|
||||
cbool scc_pproc_parse_if_defined(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
const scc_lexer_tok_t *tok) {
|
||||
int defined = 0;
|
||||
@@ -12,14 +89,7 @@ cbool scc_pproc_parse_if_defined(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
case SCC_PP_TOK_IFDEF:
|
||||
case SCC_PP_TOK_IFNDEF: {
|
||||
cbool condition = (type == SCC_PP_TOK_IFDEF) ? defined : !defined;
|
||||
|
||||
scc_pproc_if_t new_if;
|
||||
new_if.found_true = condition;
|
||||
new_if.seen_else = 0;
|
||||
new_if.active = pp->enable ? condition : 0;
|
||||
scc_vec_push(pp->if_stack, new_if);
|
||||
|
||||
pp->enable = new_if.active;
|
||||
in_if(pp, condition);
|
||||
break;
|
||||
}
|
||||
case SCC_PP_TOK_ELIFDEF:
|
||||
@@ -36,21 +106,7 @@ cbool scc_pproc_parse_if_defined(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
}
|
||||
|
||||
int condition = (type == SCC_PP_TOK_ELIFDEF) ? defined : !defined;
|
||||
|
||||
if (top->found_true) {
|
||||
// 前面已有真分支,本 elif 不激活
|
||||
top->active = 0;
|
||||
} else {
|
||||
if (condition) {
|
||||
top->active = 1;
|
||||
top->found_true = 1;
|
||||
} else {
|
||||
top->active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// seen_else 仍为 0
|
||||
pp->enable = top->active;
|
||||
in_elif(pp, top, condition);
|
||||
break;
|
||||
}
|
||||
case SCC_PP_TOK_ELSE: {
|
||||
@@ -64,31 +120,11 @@ cbool scc_pproc_parse_if_defined(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
LOG_ERROR("multiple #else");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (top->found_true) {
|
||||
top->active = 0;
|
||||
} else {
|
||||
top->active = 1;
|
||||
top->found_true = 1;
|
||||
}
|
||||
|
||||
top->seen_else = 1;
|
||||
|
||||
pp->enable = top->active;
|
||||
in_else(pp, top);
|
||||
break;
|
||||
}
|
||||
case SCC_PP_TOK_ENDIF: {
|
||||
if (scc_vec_size(pp->if_stack) == 0) {
|
||||
LOG_ERROR("#endif without #if");
|
||||
} else {
|
||||
scc_vec_pop(pp->if_stack);
|
||||
}
|
||||
if (scc_vec_size(pp->if_stack) == 0) {
|
||||
pp->enable = 1;
|
||||
} else {
|
||||
pp->enable =
|
||||
scc_vec_at(pp->if_stack, scc_vec_size(pp->if_stack) - 1).active;
|
||||
}
|
||||
in_endif(pp);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -129,12 +165,7 @@ cbool scc_pproc_parse_if_condition(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
// 根据指令类型更新条件编译栈
|
||||
switch (type) {
|
||||
case SCC_PP_TOK_IF: {
|
||||
scc_pproc_if_t new_if;
|
||||
new_if.found_true = condition;
|
||||
new_if.seen_else = 0;
|
||||
new_if.active = pp->enable ? condition : 0;
|
||||
scc_vec_push(pp->if_stack, new_if);
|
||||
pp->enable = new_if.active;
|
||||
in_if(pp, condition);
|
||||
break;
|
||||
}
|
||||
case SCC_PP_TOK_ELIF: {
|
||||
@@ -149,17 +180,7 @@ cbool scc_pproc_parse_if_condition(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
LOG_ERROR("#elif after #else");
|
||||
return false;
|
||||
}
|
||||
if (top->found_true) {
|
||||
top->active = 0;
|
||||
} else {
|
||||
if (condition) {
|
||||
top->active = 1;
|
||||
top->found_true = 1;
|
||||
} else {
|
||||
top->active = 0;
|
||||
}
|
||||
}
|
||||
pp->enable = top->active;
|
||||
in_elif(pp, top, condition);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -417,6 +417,50 @@ static void test_simple_number_conditional_if(void) {
|
||||
" foo\n bar\n");
|
||||
}
|
||||
|
||||
static void test_conditional_nested_inactive(void) {
|
||||
TEST_CASE("nested conditional when outer inactive");
|
||||
CHECK_PP_OUTPUT_EXACT("#ifdef NOT_DEFINED\n"
|
||||
"#if 1\n"
|
||||
"should not appear\n"
|
||||
"#endif\n"
|
||||
"#endif\n"
|
||||
"after\n",
|
||||
"after\n");
|
||||
CHECK_PP_OUTPUT_EXACT("#define A\n"
|
||||
"#ifdef A\n"
|
||||
" #ifdef B\n"
|
||||
" B defined\n"
|
||||
" #else\n"
|
||||
" B not defined\n"
|
||||
" #endif\n"
|
||||
"#else\n"
|
||||
" A not defined\n"
|
||||
"#endif\n",
|
||||
" B not defined\n");
|
||||
CHECK_PP_OUTPUT_EXACT("#undef A\n"
|
||||
"#ifdef A\n"
|
||||
" #ifdef B\n"
|
||||
" B defined\n"
|
||||
" #else\n"
|
||||
" B not defined\n"
|
||||
" #endif\n"
|
||||
"#else\n"
|
||||
" A not defined\n"
|
||||
"#endif\n",
|
||||
" A not defined\n");
|
||||
CHECK_PP_OUTPUT_EXACT("#if 0\n"
|
||||
"#ifdef X\n"
|
||||
"X defined\n"
|
||||
"#elifdef Y\n"
|
||||
"Y defined\n"
|
||||
"#else\n"
|
||||
"none\n"
|
||||
"#endif\n"
|
||||
"#endif\n"
|
||||
"end\n",
|
||||
"end\n");
|
||||
}
|
||||
|
||||
static void test_variadic_macros(void) {
|
||||
TEST_CASE("variadic macros with __VA_ARGS__");
|
||||
|
||||
@@ -560,6 +604,7 @@ TEST_LIST = {
|
||||
TEST_LIST_CASE(hard_test_define_func_macros),
|
||||
TEST_LIST_CASE(test_conditional_ifdef),
|
||||
TEST_LIST_CASE(test_simple_number_conditional_if),
|
||||
TEST_LIST_CASE(test_conditional_nested_inactive),
|
||||
TEST_LIST_CASE(test_variadic_macros),
|
||||
TEST_LIST_CASE(test_gnu_comma_variadic_deletion),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user