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);
|
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,
|
cbool scc_pproc_parse_if_defined(scc_pproc_t *pp, scc_tok_type_t type,
|
||||||
const scc_lexer_tok_t *tok);
|
const scc_lexer_tok_t *tok);
|
||||||
cbool scc_pproc_parse_if_condition(scc_pproc_t *pp, scc_tok_type_t type,
|
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;
|
scc_tok_type_t type = keywords[ret].tok_type;
|
||||||
|
|
||||||
if (scc_vec_size(pp->if_stack) != 0) {
|
if (scc_pproc_parse_if_need_skip(pp, type)) {
|
||||||
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) {
|
|
||||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -361,34 +340,30 @@ void scc_pproc_handle_directive(scc_pproc_t *pp) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case SCC_PP_TOK_LINE:
|
case SCC_PP_TOK_LINE:
|
||||||
|
goto ERROR;
|
||||||
case SCC_PP_TOK_EMBED:
|
case SCC_PP_TOK_EMBED:
|
||||||
goto ERROR;
|
goto ERROR;
|
||||||
case SCC_PP_TOK_ERROR:
|
#define __SCC_PPROC_LOG_PNT(func_name) \
|
||||||
scc_lexer_tok_drop(&tok);
|
do { \
|
||||||
while (1) {
|
scc_lexer_tok_drop(&tok); \
|
||||||
ok = scc_lexer_next_non_blank(pp->cur_ring, &tok);
|
while (1) { \
|
||||||
if (tok.type == SCC_TOK_ENDLINE || ok == false) {
|
ok = scc_lexer_next_non_blank(pp->cur_ring, &tok); \
|
||||||
return;
|
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));
|
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);
|
} \
|
||||||
}
|
scc_lexer_tok_drop(&tok); \
|
||||||
return;
|
} \
|
||||||
case SCC_PP_TOK_WARNING:
|
return; \
|
||||||
scc_lexer_tok_drop(&tok);
|
} while (0)
|
||||||
while (1) {
|
case SCC_PP_TOK_ERROR: {
|
||||||
ok = scc_lexer_next_non_blank(pp->cur_ring, &tok);
|
__SCC_PPROC_LOG_PNT(SCC_ERROR);
|
||||||
if (tok.type == SCC_TOK_ENDLINE || ok == false) {
|
}
|
||||||
return;
|
case SCC_PP_TOK_WARNING: {
|
||||||
}
|
__SCC_PPROC_LOG_PNT(SCC_WARN);
|
||||||
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;
|
|
||||||
case SCC_PP_TOK_PRAGMA:
|
case SCC_PP_TOK_PRAGMA:
|
||||||
SCC_WARN(tok.loc, "pragma ignored");
|
SCC_WARN(tok.loc, "pragma ignored");
|
||||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||||
|
|||||||
@@ -1,6 +1,83 @@
|
|||||||
#include <scc_lexer_utils.h>
|
#include <scc_lexer_utils.h>
|
||||||
#include <scc_pproc.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,
|
cbool scc_pproc_parse_if_defined(scc_pproc_t *pp, scc_tok_type_t type,
|
||||||
const scc_lexer_tok_t *tok) {
|
const scc_lexer_tok_t *tok) {
|
||||||
int defined = 0;
|
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_IFDEF:
|
||||||
case SCC_PP_TOK_IFNDEF: {
|
case SCC_PP_TOK_IFNDEF: {
|
||||||
cbool condition = (type == SCC_PP_TOK_IFDEF) ? defined : !defined;
|
cbool condition = (type == SCC_PP_TOK_IFDEF) ? defined : !defined;
|
||||||
|
in_if(pp, condition);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCC_PP_TOK_ELIFDEF:
|
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;
|
int condition = (type == SCC_PP_TOK_ELIFDEF) ? defined : !defined;
|
||||||
|
in_elif(pp, top, condition);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCC_PP_TOK_ELSE: {
|
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");
|
LOG_ERROR("multiple #else");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
in_else(pp, top);
|
||||||
if (top->found_true) {
|
|
||||||
top->active = 0;
|
|
||||||
} else {
|
|
||||||
top->active = 1;
|
|
||||||
top->found_true = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
top->seen_else = 1;
|
|
||||||
|
|
||||||
pp->enable = top->active;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCC_PP_TOK_ENDIF: {
|
case SCC_PP_TOK_ENDIF: {
|
||||||
if (scc_vec_size(pp->if_stack) == 0) {
|
in_endif(pp);
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@@ -129,12 +165,7 @@ cbool scc_pproc_parse_if_condition(scc_pproc_t *pp, scc_tok_type_t type,
|
|||||||
// 根据指令类型更新条件编译栈
|
// 根据指令类型更新条件编译栈
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SCC_PP_TOK_IF: {
|
case SCC_PP_TOK_IF: {
|
||||||
scc_pproc_if_t new_if;
|
in_if(pp, condition);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCC_PP_TOK_ELIF: {
|
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");
|
LOG_ERROR("#elif after #else");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (top->found_true) {
|
in_elif(pp, top, condition);
|
||||||
top->active = 0;
|
|
||||||
} else {
|
|
||||||
if (condition) {
|
|
||||||
top->active = 1;
|
|
||||||
top->found_true = 1;
|
|
||||||
} else {
|
|
||||||
top->active = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pp->enable = top->active;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -417,6 +417,50 @@ static void test_simple_number_conditional_if(void) {
|
|||||||
" foo\n bar\n");
|
" 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) {
|
static void test_variadic_macros(void) {
|
||||||
TEST_CASE("variadic macros with __VA_ARGS__");
|
TEST_CASE("variadic macros with __VA_ARGS__");
|
||||||
|
|
||||||
@@ -560,6 +604,7 @@ TEST_LIST = {
|
|||||||
TEST_LIST_CASE(hard_test_define_func_macros),
|
TEST_LIST_CASE(hard_test_define_func_macros),
|
||||||
TEST_LIST_CASE(test_conditional_ifdef),
|
TEST_LIST_CASE(test_conditional_ifdef),
|
||||||
TEST_LIST_CASE(test_simple_number_conditional_if),
|
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_variadic_macros),
|
||||||
TEST_LIST_CASE(test_gnu_comma_variadic_deletion),
|
TEST_LIST_CASE(test_gnu_comma_variadic_deletion),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user