feat(pproc): 实现预处理器条件编译和可变参数宏支持
- 添加了完整的条件编译功能,包括 #if、#elif、#else、#endif 指令 - 实现了数值常量表达式的解析和求值 - 支持嵌套条件编译和与其他指令混合使用 - 实现了可变参数宏定义和 __VA_ARGS__ 替换功能 - 改进了宏展开机制以正确处理可变参数宏 - 重构了预处理器指令处理逻辑,提高了代码可维护性 - 添加了相应的单元测试用例验证新功能
This commit is contained in:
@@ -145,20 +145,21 @@ typedef enum scc_cstd {
|
||||
// END
|
||||
/* clang-format on */
|
||||
|
||||
// 定义TokenType枚举
|
||||
typedef enum scc_tok_type {
|
||||
// must first becase the unknown token must be 0
|
||||
/* clang-format off */
|
||||
// must first becase the unknown token must be 0
|
||||
#define X(str, subtype, tok) tok,
|
||||
SCC_CTOK_TABLE
|
||||
#undef X
|
||||
|
||||
#define X(name, type, tok) tok,
|
||||
SCC_PPKEYWORD_TABLE
|
||||
SCC_PPKEYWORD_TABLE
|
||||
#undef X
|
||||
|
||||
#define X(name, subtype, tok, std) tok,
|
||||
SCC_CKEYWORD_TABLE
|
||||
SCC_CKEYWORD_TABLE
|
||||
#undef X
|
||||
/* clang-format on*/
|
||||
} scc_tok_type_t;
|
||||
|
||||
typedef enum scc_tok_subtype {
|
||||
|
||||
@@ -67,7 +67,14 @@ 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_parse_include(scc_pproc_t *pp, scc_lexer_tok_t *include_tok);
|
||||
|
||||
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,
|
||||
scc_lexer_tok_ring_t *tok_ring);
|
||||
void scc_pproc_parse_include(scc_pproc_t *pp, scc_lexer_tok_t *include_tok,
|
||||
scc_lexer_tok_ring_t *tok_ring);
|
||||
|
||||
void scc_pproc_parse_macro_arguments(scc_lexer_tok_ring_t *ring,
|
||||
scc_lexer_tok_vec_t *args, int need_full);
|
||||
void scc_pproc_parse_function_macro(scc_pproc_t *pp,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <pproc_expand.h>
|
||||
#include <scc_core_ring.h>
|
||||
#include <scc_lexer_utils.h>
|
||||
#include <scc_pproc.h>
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
scc_tok_type_t tok_type;
|
||||
@@ -148,6 +151,25 @@ void scc_pproc_parse_object_macro(scc_pproc_t *pp,
|
||||
scc_pproc_macro_table_set(&pp->macro_table, macro);
|
||||
}
|
||||
|
||||
static void scc_pproc_parse_line_and_expand(scc_pproc_t *pp,
|
||||
scc_lexer_tok_ring_t *out_ring) {
|
||||
int ok;
|
||||
scc_lexer_tok_t tok;
|
||||
scc_lexer_tok_ring_t *stream = pp->cur_ring;
|
||||
scc_lexer_tok_vec_t org_toks;
|
||||
scc_vec_init(org_toks);
|
||||
while (1) {
|
||||
scc_ring_peek(*stream, tok, ok);
|
||||
if (ok == false)
|
||||
break;
|
||||
scc_ring_next_consume(*stream, tok, ok);
|
||||
scc_vec_push(org_toks, tok);
|
||||
if (tok.type == SCC_TOK_ENDLINE)
|
||||
break;
|
||||
}
|
||||
scc_pproc_expand_by_vec(&pp->macro_table, &org_toks, out_ring);
|
||||
}
|
||||
|
||||
/*
|
||||
```txt
|
||||
6.10 Preprocessing directives
|
||||
@@ -297,121 +319,43 @@ void scc_pproc_handle_directive(scc_pproc_t *pp) {
|
||||
scc_lexer_tok_drop(&tok);
|
||||
return;
|
||||
}
|
||||
case SCC_PP_TOK_INCLUDE:
|
||||
scc_pproc_parse_include(pp, &tok);
|
||||
return;
|
||||
case SCC_PP_TOK_IFDEF:
|
||||
case SCC_PP_TOK_IFNDEF: {
|
||||
// 解析标识符
|
||||
if (!scc_lexer_next_non_blank(pp->cur_ring, &tok) ||
|
||||
tok.type != SCC_TOK_IDENT) {
|
||||
scc_lexer_tok_drop(&tok);
|
||||
LOG_ERROR("expected identifier");
|
||||
goto ERROR;
|
||||
}
|
||||
cbool defined =
|
||||
(scc_pproc_macro_table_get(&pp->macro_table, &tok.lexeme) != null);
|
||||
cbool condition = (type == SCC_PP_TOK_IFDEF) ? defined : !defined;
|
||||
scc_lexer_tok_drop(&tok);
|
||||
|
||||
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;
|
||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||
case SCC_PP_TOK_INCLUDE: {
|
||||
scc_lexer_tok_ring_t out_ring;
|
||||
scc_pproc_parse_line_and_expand(pp, &out_ring);
|
||||
scc_pproc_parse_include(pp, &tok, &out_ring);
|
||||
return;
|
||||
}
|
||||
case SCC_PP_TOK_IFDEF:
|
||||
case SCC_PP_TOK_IFNDEF:
|
||||
case SCC_PP_TOK_ELIFDEF:
|
||||
case SCC_PP_TOK_ELIFNDEF: {
|
||||
if (scc_vec_size(pp->if_stack) == 0) {
|
||||
LOG_ERROR("#elif without #if");
|
||||
goto ERROR;
|
||||
}
|
||||
scc_pproc_if_t *top =
|
||||
&scc_vec_at(pp->if_stack, scc_vec_size(pp->if_stack) - 1);
|
||||
if (top->seen_else) {
|
||||
LOG_ERROR("#elif after #else");
|
||||
goto ERROR;
|
||||
}
|
||||
// 解析标识符
|
||||
scc_lexer_tok_drop(&tok);
|
||||
if (!scc_lexer_next_non_blank(pp->cur_ring, &tok) ||
|
||||
tok.type != SCC_TOK_IDENT) {
|
||||
scc_lexer_tok_drop(&tok);
|
||||
LOG_ERROR("expected identifier");
|
||||
goto ERROR;
|
||||
}
|
||||
int defined =
|
||||
(scc_pproc_macro_table_get(&pp->macro_table, &tok.lexeme) != NULL);
|
||||
int condition = (type == SCC_PP_TOK_ELIFDEF) ? defined : !defined;
|
||||
scc_lexer_tok_drop(&tok);
|
||||
|
||||
if (top->found_true) {
|
||||
// 前面已有真分支,本 elif 不激活
|
||||
top->active = 0;
|
||||
} else {
|
||||
if (condition) {
|
||||
top->active = 1;
|
||||
top->found_true = 1;
|
||||
} else {
|
||||
top->active = 0;
|
||||
}
|
||||
scc_pproc_parse_if_defined(pp, type, &tok);
|
||||
scc_lexer_tok_drop(&tok);
|
||||
}
|
||||
|
||||
// seen_else 仍为 0
|
||||
pp->enable = top->active;
|
||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||
return;
|
||||
}
|
||||
case SCC_PP_TOK_ELSE: {
|
||||
if (scc_vec_size(pp->if_stack) == 0) {
|
||||
LOG_ERROR("#else without #if");
|
||||
goto ERROR;
|
||||
}
|
||||
scc_pproc_if_t *top =
|
||||
&scc_vec_at(pp->if_stack, scc_vec_size(pp->if_stack) - 1);
|
||||
if (top->seen_else) {
|
||||
LOG_ERROR("multiple #else");
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
if (top->found_true) {
|
||||
top->active = 0;
|
||||
} else {
|
||||
top->active = 1;
|
||||
top->found_true = 1;
|
||||
}
|
||||
|
||||
top->seen_else = 1;
|
||||
|
||||
pp->enable = top->active;
|
||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||
return;
|
||||
}
|
||||
case SCC_PP_TOK_ELSE:
|
||||
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;
|
||||
}
|
||||
scc_lexer_tok_drop(&tok);
|
||||
scc_pproc_parse_if_defined(pp, type, null);
|
||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||
return;
|
||||
}
|
||||
case SCC_PP_TOK_IF:
|
||||
case SCC_PP_TOK_ELIF:
|
||||
// parse constant expression
|
||||
// 暂不实现表达式求值
|
||||
LOG_ERROR("Expression in #if/#elif not implemented");
|
||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||
case SCC_PP_TOK_ELIF: {
|
||||
scc_lexer_tok_drop(&tok);
|
||||
scc_lexer_tok_ring_t out_ring;
|
||||
scc_pproc_parse_line_and_expand(pp, &out_ring);
|
||||
scc_pproc_parse_if_condition(pp, type, &out_ring);
|
||||
return;
|
||||
}
|
||||
case SCC_PP_TOK_LINE:
|
||||
case SCC_PP_TOK_EMBED:
|
||||
goto ERROR;
|
||||
@@ -443,7 +387,8 @@ void scc_pproc_handle_directive(scc_pproc_t *pp) {
|
||||
return;
|
||||
case SCC_PP_TOK_PRAGMA:
|
||||
LOG_WARN("Pragma ignored");
|
||||
break;
|
||||
scc_lexer_skip_until_newline(pp->cur_ring);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -123,32 +123,44 @@ void scc_pproc_expand_by_vec(scc_pproc_macro_table_t *macro_table,
|
||||
|
||||
static inline void
|
||||
split_arguments(scc_pproc_macro_extened_params_t *splited_params,
|
||||
scc_lexer_tok_vec_t *raw_args) {
|
||||
scc_lexer_tok_vec_t *raw_args, const scc_pproc_macro_t *macro) {
|
||||
scc_lexer_tok_vec_t arg;
|
||||
scc_vec_init(arg);
|
||||
|
||||
int named_count = (int)scc_vec_size(macro->params);
|
||||
cbool is_variadic =
|
||||
(named_count > 0 &&
|
||||
scc_vec_at(macro->params, named_count - 1).type == SCC_TOK_ELLIPSIS);
|
||||
|
||||
scc_vec_foreach(*raw_args, i) {
|
||||
scc_lexer_tok_t *raw_arg = &scc_vec_at(*raw_args, i);
|
||||
if (raw_arg->type == SCC_TOK_COMMA) {
|
||||
scc_lexer_tok_drop(raw_arg);
|
||||
if (scc_vec_size(arg) &&
|
||||
scc_vec_at(arg, scc_vec_size(arg) - 1).type == SCC_TOK_BLANK) {
|
||||
scc_lexer_tok_drop(&scc_vec_pop(arg));
|
||||
}
|
||||
scc_vec_push(*splited_params, arg);
|
||||
scc_vec_init(arg);
|
||||
} else {
|
||||
if (raw_arg->type != SCC_TOK_COMMA ||
|
||||
(is_variadic && scc_vec_size(*splited_params) == named_count - 1)) {
|
||||
if (scc_vec_size(arg) == 0 && raw_arg->type == SCC_TOK_BLANK) {
|
||||
scc_lexer_tok_drop(raw_arg);
|
||||
} else {
|
||||
scc_vec_push(arg, *raw_arg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
scc_lexer_tok_drop(raw_arg);
|
||||
if (scc_vec_size(arg) &&
|
||||
scc_vec_at(arg, scc_vec_size(arg) - 1).type == SCC_TOK_BLANK) {
|
||||
scc_lexer_tok_drop(&scc_vec_pop(arg));
|
||||
}
|
||||
scc_vec_push(*splited_params, arg);
|
||||
scc_vec_init(arg);
|
||||
}
|
||||
if (scc_vec_size(arg) &&
|
||||
scc_vec_at(arg, scc_vec_size(arg) - 1).type == SCC_TOK_BLANK) {
|
||||
scc_lexer_tok_drop(&scc_vec_pop(arg));
|
||||
}
|
||||
|
||||
scc_vec_push(*splited_params, arg);
|
||||
if (is_variadic && scc_vec_size(*splited_params) == named_count - 1) {
|
||||
scc_vec_init(arg);
|
||||
scc_vec_push(*splited_params, arg);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -232,7 +244,7 @@ static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
|
||||
// collect, fill and expand arg
|
||||
scc_pproc_macro_extened_params_t splited_params;
|
||||
scc_vec_init(splited_params);
|
||||
split_arguments(&splited_params, &raw_args);
|
||||
split_arguments(&splited_params, &raw_args, macro);
|
||||
|
||||
scc_pproc_macro_extened_params_t expanded_params;
|
||||
scc_vec_init(expanded_params);
|
||||
|
||||
172
libs/pproc/src/pproc_if.c
Normal file
172
libs/pproc/src/pproc_if.c
Normal file
@@ -0,0 +1,172 @@
|
||||
#include <scc_lexer_utils.h>
|
||||
#include <scc_pproc.h>
|
||||
|
||||
cbool scc_pproc_parse_if_defined(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
const scc_lexer_tok_t *tok) {
|
||||
int defined = 0;
|
||||
if (tok) {
|
||||
defined = (scc_pproc_macro_table_get(&pp->macro_table,
|
||||
&(tok->lexeme)) != null);
|
||||
}
|
||||
switch (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;
|
||||
break;
|
||||
}
|
||||
case SCC_PP_TOK_ELIFDEF:
|
||||
case SCC_PP_TOK_ELIFNDEF: {
|
||||
if (scc_vec_size(pp->if_stack) == 0) {
|
||||
LOG_ERROR("#elif without #if");
|
||||
return false;
|
||||
}
|
||||
scc_pproc_if_t *top =
|
||||
&scc_vec_at(pp->if_stack, scc_vec_size(pp->if_stack) - 1);
|
||||
if (top->seen_else) {
|
||||
LOG_ERROR("#elif after #else");
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
break;
|
||||
}
|
||||
case SCC_PP_TOK_ELSE: {
|
||||
if (scc_vec_size(pp->if_stack) == 0) {
|
||||
LOG_ERROR("#else without #if");
|
||||
return false;
|
||||
}
|
||||
scc_pproc_if_t *top =
|
||||
&scc_vec_at(pp->if_stack, scc_vec_size(pp->if_stack) - 1);
|
||||
if (top->seen_else) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG_FATAL("unexpected directive");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static cbool parse_constant_condition() { return false; }
|
||||
|
||||
cbool scc_pproc_parse_if_condition(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
scc_lexer_tok_ring_t *tok_ring) {
|
||||
// TODO
|
||||
int ok;
|
||||
scc_lexer_tok_t tok = {0};
|
||||
ok = scc_lexer_next_non_blank(tok_ring, &tok);
|
||||
if (ok == false) {
|
||||
LOG_FATAL("unexpected EOF");
|
||||
}
|
||||
int condition = 0;
|
||||
if (tok.type == SCC_TOK_INT_LITERAL) {
|
||||
condition = scc_cstring_as_cstr(&tok.lexeme)[0] == '0' ? 0 : 1;
|
||||
} else {
|
||||
LOG_ERROR("expected integer constant");
|
||||
}
|
||||
scc_lexer_tok_drop(&tok);
|
||||
|
||||
ok = scc_lexer_next_non_blank(tok_ring, &tok);
|
||||
if (ok == false) {
|
||||
LOG_FATAL("unexpected EOF");
|
||||
}
|
||||
if (tok.type != SCC_TOK_ENDLINE) {
|
||||
LOG_ERROR("expected endline");
|
||||
scc_lexer_skip_until_newline(tok_ring);
|
||||
} else {
|
||||
scc_lexer_tok_drop(&tok);
|
||||
}
|
||||
scc_ring_free(*tok_ring);
|
||||
|
||||
// 根据指令类型更新条件编译栈
|
||||
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;
|
||||
break;
|
||||
}
|
||||
case SCC_PP_TOK_ELIF: {
|
||||
if (scc_vec_size(pp->if_stack) == 0) {
|
||||
LOG_ERROR("#elif without #if");
|
||||
return false;
|
||||
}
|
||||
scc_pproc_if_t *top =
|
||||
&scc_vec_at(pp->if_stack, scc_vec_size(pp->if_stack) - 1);
|
||||
if (top->seen_else) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_FATAL("unexpected directive in parse_if_condition");
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <pproc_expand.h>
|
||||
#include <scc_core_ring.h>
|
||||
#include <scc_pproc.h>
|
||||
|
||||
static int switch_file_stack(scc_pproc_t *pp, scc_cstring_t *fname,
|
||||
@@ -56,31 +57,16 @@ FOPEN:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scc_pproc_parse_include(scc_pproc_t *pp, scc_lexer_tok_t *include_tok) {
|
||||
void scc_pproc_parse_include(scc_pproc_t *pp, scc_lexer_tok_t *include_tok,
|
||||
scc_lexer_tok_ring_t *tok_ring) {
|
||||
int ok;
|
||||
scc_lexer_tok_t tok;
|
||||
scc_pos_t pos = include_tok->loc;
|
||||
scc_lexer_tok_drop(include_tok);
|
||||
|
||||
scc_lexer_tok_ring_t *stream = pp->cur_ring;
|
||||
scc_lexer_tok_vec_t org_toks;
|
||||
scc_vec_init(org_toks);
|
||||
while (1) {
|
||||
scc_ring_peek(*stream, tok, ok);
|
||||
if (ok == false)
|
||||
break;
|
||||
scc_ring_next_consume(*stream, tok, ok);
|
||||
scc_vec_push(org_toks, tok);
|
||||
// FIXME endline needed?
|
||||
if (tok.type == SCC_TOK_ENDLINE)
|
||||
break;
|
||||
}
|
||||
|
||||
scc_lexer_tok_ring_t out_ring;
|
||||
scc_pproc_expand_by_vec(&pp->macro_table, &org_toks, &out_ring);
|
||||
scc_cstring_t line = scc_cstring_create();
|
||||
while (1) {
|
||||
scc_ring_next_consume(out_ring, tok, ok);
|
||||
scc_ring_next_consume(*tok_ring, tok, ok);
|
||||
if (!ok)
|
||||
break;
|
||||
if (scc_get_tok_subtype(tok.type) != SCC_TOK_SUBTYPE_EMPTYSPACE &&
|
||||
@@ -89,7 +75,7 @@ void scc_pproc_parse_include(scc_pproc_t *pp, scc_lexer_tok_t *include_tok) {
|
||||
}
|
||||
scc_lexer_tok_drop(&tok);
|
||||
}
|
||||
scc_ring_free(out_ring);
|
||||
scc_ring_free(*tok_ring);
|
||||
|
||||
const char *includename = scc_cstring_as_cstr(&line);
|
||||
int len = scc_cstring_len(&line);
|
||||
|
||||
@@ -350,6 +350,64 @@ static void test_conditional_ifdef(void) {
|
||||
"x defined\nY not defined\nafter inner\n");
|
||||
}
|
||||
|
||||
static void test_simple_number_conditional_if(void) {
|
||||
TEST_CASE("if and elif with one integer constants");
|
||||
|
||||
// 基本 if
|
||||
CHECK_PP_OUTPUT_EXACT("#if 1\ntrue\n#endif\n", "true\n");
|
||||
CHECK_PP_OUTPUT_EXACT("#if 0\nfalse\n#endif\n", "");
|
||||
CHECK_PP_OUTPUT_EXACT("#if 4\ntrue\n#endif\n", "true\n");
|
||||
CHECK_PP_OUTPUT_EXACT("#if 0\nfalse\n#else\nother\n#endif\n", "other\n");
|
||||
|
||||
// if + elif + else
|
||||
CHECK_PP_OUTPUT_EXACT("#if 0\nzero\n#elif 1\none\n#else\nother\n#endif\n",
|
||||
"one\n");
|
||||
CHECK_PP_OUTPUT_EXACT("#if 0\nzero\n#elif 0\none\n#else\nother\n#endif\n",
|
||||
"other\n");
|
||||
CHECK_PP_OUTPUT_EXACT("#if 1\nfirst\n#elif 1\nsecond\n#endif\n", "first\n");
|
||||
|
||||
// 嵌套
|
||||
CHECK_PP_OUTPUT_EXACT(
|
||||
"#if 1\n #if 0\n inner\n #endif\n outer\n#endif\n", " outer\n");
|
||||
CHECK_PP_OUTPUT_EXACT("#if 0\n #if 1\n inner\n #endif\n "
|
||||
"outer\n#else\n alternative\n#endif\n",
|
||||
" alternative\n");
|
||||
|
||||
// 与 #ifdef 混合
|
||||
CHECK_PP_OUTPUT_EXACT("#define FOO\n"
|
||||
"#if 1\n"
|
||||
" #ifdef FOO\n"
|
||||
" foo\n"
|
||||
" #endif\n"
|
||||
" bar\n"
|
||||
"#endif\n",
|
||||
" foo\n bar\n");
|
||||
}
|
||||
|
||||
static void test_variadic_macros(void) {
|
||||
TEST_CASE("variadic macros with __VA_ARGS__");
|
||||
|
||||
// 基本可变参数宏
|
||||
CHECK_PP_OUTPUT_EXACT("#define FOO(x, ...) x __VA_ARGS__\n"
|
||||
"FOO(1, 2, 3)\n",
|
||||
"1 2, 3\n");
|
||||
|
||||
// 多参数
|
||||
CHECK_PP_OUTPUT_EXACT("#define SUM(...) (__VA_ARGS__)\n"
|
||||
"SUM(1, 2, 3)\n",
|
||||
"(1, 2, 3)\n");
|
||||
|
||||
// 与 printf 结合
|
||||
CHECK_PP_OUTPUT_EXACT("#define DEBUG(fmt, ...) printf(fmt, __VA_ARGS__)\n"
|
||||
"DEBUG(\"hello\", 1, 2)\n",
|
||||
"printf(\"hello\", 1, 2)\n");
|
||||
|
||||
// 空可变参数
|
||||
CHECK_PP_OUTPUT_EXACT("#define FOO(x, ...) x __VA_ARGS__\n"
|
||||
"FOO(1)\n",
|
||||
"1 \n");
|
||||
}
|
||||
|
||||
#define TEST_LIST_CASE(func_name) {#func_name, func_name}
|
||||
TEST_LIST = {
|
||||
TEST_LIST_CASE(test_define_simple_no_macro),
|
||||
@@ -363,5 +421,7 @@ TEST_LIST = {
|
||||
TEST_LIST_CASE(test_undef_macros),
|
||||
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_variadic_macros),
|
||||
{NULL, NULL},
|
||||
};
|
||||
Reference in New Issue
Block a user