feat(pproc): 改进宏处理器以支持括号嵌套和GNU扩展
- 实现了括号深度跟踪来正确分割带括号的宏参数 - 添加了对 GNU 扩展中 `##` 操作符逗号删除的支持 - 新增辅助函数 `got_left_non_blank` 和 `got_right_non_blank` 来优化查找非空白 token 的逻辑 - 改进了错误消息以显示预期但得到的实际值类型 fix(pproc): 修复条件编译和包含文件路径的错误消息 - 在 `scc_pproc_parse_if_condition` 中改进错误消息格式 - 修复 `switch_file_stack` 函数中的日志字符串格式问题 test(pproc): 添加宏处理相关的单元测试 - 增加了连接操作符、嵌套宏、括号处理等测试用例 - 添加了 C99 标准示例和 GNU 变参宏删除逗号的测试 - 包含了复杂的宏展开场景测试 chore(justfile): 更新构建脚本添加调试目标 - 为 `test-scc` 目标添加了 `debug-scc` 调试版本 - 更新构建命令以支持开发模式 feat(cbuild): 添加 dry-run 模式和改进编译器参数 - 为编译器类添加 dry-run 功能,只打印命令不执行 - 改进 scc 编译器的包含路径处理逻辑 - 为命令行解析器添加 dry-run 参数选项 refactor(log): 重命名 static_assert 为 StaticAssert 避免冲突 - 为了避免与标准库冲突,将自定义 static_assert 重命名为 StaticAssert style(scc_core): 移除未使用的预定义宏定义 - 删除了不再需要的基础类型前缀宏定义 fix(scc_core): 初始化 ring 测试中的未初始化变量 - 为测试函数中的字符变量添加初始化值避免未定义行为
This commit is contained in:
@@ -132,9 +132,16 @@ split_arguments(scc_pproc_macro_extened_params_t *splited_params,
|
||||
(named_count > 0 &&
|
||||
scc_vec_at(macro->params, named_count - 1).type == SCC_TOK_ELLIPSIS);
|
||||
|
||||
int depth = 0;
|
||||
|
||||
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 ||
|
||||
if (raw_arg->type == SCC_TOK_L_PAREN) {
|
||||
depth++;
|
||||
} else if (raw_arg->type == SCC_TOK_R_PAREN) {
|
||||
depth--;
|
||||
}
|
||||
if (depth != 0 || 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);
|
||||
@@ -142,14 +149,15 @@ split_arguments(scc_pproc_macro_extened_params_t *splited_params,
|
||||
scc_vec_push(arg, *raw_arg);
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
@@ -231,6 +239,25 @@ static int find_params(const scc_lexer_tok_t *tok,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int got_left_non_blank(int i,
|
||||
const scc_lexer_tok_vec_t *replaces) {
|
||||
int left_idx = i - 1;
|
||||
while (left_idx >= 0 &&
|
||||
scc_vec_at(*replaces, left_idx).type == SCC_TOK_BLANK) {
|
||||
left_idx--;
|
||||
}
|
||||
return left_idx;
|
||||
}
|
||||
static inline int got_right_non_blank(int i,
|
||||
const scc_lexer_tok_vec_t *replaces) {
|
||||
int right_idx = i + 1;
|
||||
while (right_idx < (int)scc_vec_size(*replaces) &&
|
||||
scc_vec_at(*replaces, right_idx).type == SCC_TOK_BLANK) {
|
||||
right_idx++;
|
||||
}
|
||||
return right_idx;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -264,12 +291,7 @@ static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
|
||||
if (tok.type == SCC_TOK_SHARP) {
|
||||
// # stringify
|
||||
scc_lexer_tok_drop(&tok);
|
||||
int right_idx = i + 1;
|
||||
while (right_idx < (int)macro->replaces.size &&
|
||||
scc_vec_at(macro->replaces, right_idx).type ==
|
||||
SCC_TOK_BLANK) {
|
||||
right_idx++;
|
||||
}
|
||||
int right_idx = got_right_non_blank(i, ¯o->replaces);
|
||||
if (right_idx >= (int)macro->replaces.size) {
|
||||
LOG_WARN("generate empty stringify");
|
||||
scc_cstring_free(&tok.lexeme);
|
||||
@@ -286,21 +308,10 @@ static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
|
||||
continue;
|
||||
} else if (tok.type == SCC_TOK_SHARP_SHARP) {
|
||||
// ## contact
|
||||
// 向左扫描找到上一个非空白 token
|
||||
scc_lexer_tok_drop(&tok);
|
||||
int left_idx = i - 1;
|
||||
while (left_idx >= 0 &&
|
||||
scc_vec_at(macro->replaces, left_idx).type ==
|
||||
SCC_TOK_BLANK) {
|
||||
left_idx--;
|
||||
}
|
||||
// 向右扫描找到下一个非空白 token
|
||||
int right_idx = i + 1;
|
||||
while (right_idx < (int)macro->replaces.size &&
|
||||
scc_vec_at(macro->replaces, right_idx).type ==
|
||||
SCC_TOK_BLANK) {
|
||||
right_idx++;
|
||||
}
|
||||
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)macro->replaces.size) {
|
||||
LOG_FATAL("Invalid ## operator");
|
||||
}
|
||||
@@ -308,13 +319,53 @@ static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
|
||||
scc_lexer_tok_drop(&scc_vec_pop(tok_buffer));
|
||||
}
|
||||
|
||||
int j;
|
||||
j = find_params(&scc_vec_at(macro->replaces, left_idx), macro);
|
||||
Assert(j != -1 && j < (int)scc_vec_size(splited_params));
|
||||
scc_lexer_tok_vec_t left_vec = scc_vec_at(splited_params, j);
|
||||
j = find_params(&scc_vec_at(macro->replaces, right_idx), macro);
|
||||
Assert(j != -1 && j < (int)scc_vec_size(splited_params));
|
||||
scc_lexer_tok_vec_t right_vec = scc_vec_at(splited_params, j);
|
||||
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);
|
||||
} else {
|
||||
scc_vec_init(left_vec);
|
||||
scc_vec_push(left_vec, scc_lexer_tok_copy(left_tok));
|
||||
}
|
||||
|
||||
idx = find_params(right_tok, macro);
|
||||
scc_lexer_tok_vec_t right_vec;
|
||||
if (idx != -1) {
|
||||
Assert(idx < (int)scc_vec_size(splited_params));
|
||||
right_vec = scc_vec_at(splited_params, idx);
|
||||
} else {
|
||||
scc_vec_init(right_vec);
|
||||
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)
|
||||
@@ -380,25 +431,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
|
||||
// 向左扫描找到上一个非空白 token
|
||||
int left_idx = i - 1;
|
||||
while (left_idx >= 0 &&
|
||||
scc_vec_at(macro->replaces, left_idx).type ==
|
||||
SCC_TOK_BLANK) {
|
||||
left_idx--;
|
||||
}
|
||||
// 向右扫描找到下一个非空白 token
|
||||
int right_idx = i + 1;
|
||||
while (right_idx < (int)macro->replaces.size &&
|
||||
scc_vec_at(macro->replaces, right_idx).type ==
|
||||
SCC_TOK_BLANK) {
|
||||
right_idx++;
|
||||
}
|
||||
if (left_idx < 0 || right_idx >= (int)macro->replaces.size) {
|
||||
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 *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 (i++ < right_idx) {
|
||||
scc_lexer_tok_drop(&scc_vec_pop(tok_buffer));
|
||||
|
||||
@@ -113,7 +113,8 @@ cbool scc_pproc_parse_if_condition(scc_pproc_t *pp, scc_tok_type_t type,
|
||||
if (tok.type == SCC_TOK_INT_LITERAL) {
|
||||
condition = scc_cstring_as_cstr(&tok.lexeme)[0] == '0' ? 0 : 1;
|
||||
} else {
|
||||
LOG_ERROR("expected integer constant");
|
||||
LOG_ERROR("expected integer constant but got %s",
|
||||
scc_cstring_as_cstr(&tok.lexeme));
|
||||
}
|
||||
scc_lexer_tok_drop(&tok);
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ static int switch_file_stack(scc_pproc_t *pp, scc_cstring_t *fname,
|
||||
goto FOPEN;
|
||||
}
|
||||
}
|
||||
LOG_ERROR("In %s:%d:%d include %c%s%c , the file is not found", org_fname,
|
||||
LOG_ERROR("In %s:%d:%d include %c%s%c, the file is not found", org_fname,
|
||||
pos->line, pos->col, is_system ? '<' : '\"',
|
||||
scc_cstring_as_cstr(fname), is_system ? '>' : '\"');
|
||||
return -1;
|
||||
|
||||
@@ -132,6 +132,35 @@ static void test_define_nested_macros(void) {
|
||||
|
||||
CHECK_PP_OUTPUT_EXACT(" # define A 1\nA", "1");
|
||||
// CHECK_PP_OUTPUT_EXACT(" # define A 1 \nA", "1"); // TODO
|
||||
|
||||
CHECK_PP_OUTPUT_EXACT("#define CONCAT(str) __scc_##str\nCONCAT(int)",
|
||||
"__scc_int");
|
||||
CHECK_PP_OUTPUT_EXACT("#define CONCAT(str) str##_scc__\nCONCAT(int)",
|
||||
"int_scc__");
|
||||
|
||||
CHECK_PP_OUTPUT_EXACT("#define CONCAT(str) __scc_ ## str\nCONCAT(int)",
|
||||
"__scc_int");
|
||||
|
||||
// TEST_CASE("TODO"); /*FALSE*/
|
||||
// CHECK_PP_OUTPUT_EXACT("#define str(x) # x\n"
|
||||
// "str()\n",
|
||||
// "\"\"\n");
|
||||
|
||||
TEST_CASE("TODO");
|
||||
CHECK_PP_OUTPUT_EXACT("#define x 1\n"
|
||||
"#define f(a) f(x * (a))\n"
|
||||
"f(0)\n"
|
||||
"f(x)",
|
||||
"f(1 * (0))\n"
|
||||
"f(1 * (1))");
|
||||
CHECK_PP_OUTPUT_EXACT("#define x x(0)\n"
|
||||
"#define f(a) f(x * (a))\n"
|
||||
"f(f(0))\n"
|
||||
"f(f(x))\n"
|
||||
"f(f(a))\n",
|
||||
"f(x(0) * (f(x(0) * (0))))\n"
|
||||
"f(x(0) * (f(x(0) * (x(0)))))\n"
|
||||
"f(x(0) * (f(x(0) * (a))))\n");
|
||||
}
|
||||
|
||||
static void test_undef_macros(void) {
|
||||
@@ -181,33 +210,19 @@ static void hard_test_define_func_macros(void) {
|
||||
"M3(M3(M2)(0))\n",
|
||||
"M1(0 + 1)\n");
|
||||
|
||||
// TEST_CASE("TODO"); /*FALSE*/
|
||||
// CHECK_PP_OUTPUT_EXACT("#define str(x) # x\n"
|
||||
// "str()\n",
|
||||
// "\"\"\n");
|
||||
TEST_CASE("mulit braces");
|
||||
CHECK_PP_OUTPUT_EXACT("#define MACRO(a, b, c) a, b, c\n"
|
||||
"MACRO(1, (2,3), 4)\n",
|
||||
"1, (2,3), 4\n");
|
||||
|
||||
TEST_CASE("TODO");
|
||||
CHECK_PP_OUTPUT_EXACT("#define x 1\n"
|
||||
"#define f(a) f(x * (a))\n"
|
||||
"f(0)\n"
|
||||
"f(x)",
|
||||
"f(1 * (0))\n"
|
||||
"f(1 * (1))");
|
||||
CHECK_PP_OUTPUT_EXACT("#define x x(0)\n"
|
||||
"#define f(a) f(x * (a))\n"
|
||||
"f(f(0))\n"
|
||||
"f(f(x))\n"
|
||||
"f(f(a))\n",
|
||||
"f(x(0) * (f(x(0) * (0))))\n"
|
||||
"f(x(0) * (f(x(0) * (x(0)))))\n"
|
||||
"f(x(0) * (f(x(0) * (a))))\n");
|
||||
}
|
||||
|
||||
static void test_conditional_compilation(void) {
|
||||
TEST_CASE("conditional compilation");
|
||||
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("#define FLAG 1\n#if FLAG\ntrue\n#endif\n", "true\n");
|
||||
TEST_CASE("max_macro hard");
|
||||
CHECK_PP_OUTPUT_EXACT("#define max(a, b) ((a) > (b) ? (a) : (b))\n"
|
||||
"max(1, 2)\n",
|
||||
"((1) > (2) ? (1) : (2))\n");
|
||||
CHECK_PP_OUTPUT_EXACT("#define max(a, b) ((a) > (b) ? (a) : (b))\n"
|
||||
"max(max(x, y), z)\n",
|
||||
"((((x) > (y) ? (x) : (y))) > (z) ? (((x) > (y) ? "
|
||||
"(x) : (y))) : (z))\n");
|
||||
}
|
||||
|
||||
static void test_error_cases(void) {
|
||||
@@ -406,6 +421,111 @@ static void test_variadic_macros(void) {
|
||||
CHECK_PP_OUTPUT_EXACT("#define FOO(x, ...) x __VA_ARGS__\n"
|
||||
"FOO(1)\n",
|
||||
"1 \n");
|
||||
|
||||
CHECK_PP_OUTPUT_EXACT("#define FOO(x, ...) #__VA_ARGS__\nFOO(1);", "\"\";");
|
||||
}
|
||||
|
||||
static void test_gnu_comma_variadic_deletion(void) {
|
||||
TEST_CASE("GNU comma deletion with ## and __VA_ARGS__");
|
||||
// 可变参数为空,逗号被删除
|
||||
CHECK_PP_OUTPUT_EXACT("#define FOO(fmt, ...) printf(fmt, ## __VA_ARGS__)\n"
|
||||
"FOO(\"hello\")\n",
|
||||
"printf(\"hello\")\n");
|
||||
// 可变参数非空,逗号保留
|
||||
CHECK_PP_OUTPUT_EXACT("#define FOO(fmt, ...) printf(fmt, ## __VA_ARGS__)\n"
|
||||
"FOO(\"%d\", 42)\n",
|
||||
"printf(\"%d\",42)\n");
|
||||
// 带空白变体
|
||||
CHECK_PP_OUTPUT_EXACT("#define FOO(fmt,...) printf(fmt,##__VA_ARGS__)\n"
|
||||
"FOO(\"%d\", 42)\n",
|
||||
"printf(\"%d\",42)\n");
|
||||
}
|
||||
|
||||
static void test_c99_docs(void) {
|
||||
TEST_CASE("6.10.3.3 The ## operator EXAMPLE");
|
||||
CHECK_PP_OUTPUT_EXACT("#define hash_hash # ## #\n"
|
||||
"#define mkstr(a) # a\n"
|
||||
"#define in_between(a) mkstr(a)\n"
|
||||
"#define join(c, d) in_between(c hash_hash d)\n"
|
||||
"char p[] = join(x, y);\n",
|
||||
"char p[] = \"x ## y\";\n");
|
||||
|
||||
// 6.10.3.5 Scope of macrodefinitions
|
||||
TEST_CASE("EXAMPLE 3 To illustrate the rules for redefinition and "
|
||||
"reexamination, the sequence");
|
||||
/*
|
||||
CHECK_PP_OUTPUT_EXACT(
|
||||
"#define x 3\n"
|
||||
"#define f(a) f(x * (a))\n"
|
||||
"#undef x\n"
|
||||
"#define x 2\n"
|
||||
"#define g f\n"
|
||||
"#define z z[0]\n"
|
||||
"#define h g(~\n"
|
||||
"#define m(a) a(w)\n"
|
||||
"#define w 0,1\n"
|
||||
"#define t(a) a\n"
|
||||
"#define p() int\n"
|
||||
"#define q(x) x\n"
|
||||
"#define r(x,y) x ## y\n"
|
||||
"#define str(x) # x\n"
|
||||
"f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);\n"
|
||||
"g(x+(3,4)-w) | h 5) & m\n"
|
||||
" (f)^m(m);\n"
|
||||
"p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };\n"
|
||||
"char c[2][6] = { str(hello), str() };\n",
|
||||
"f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);\n"
|
||||
"f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);\n"
|
||||
"int i[] = { 1, 23, 4, 5, };\n"
|
||||
"char c[2][6] = { \"hello\", \"\" };\n");
|
||||
*/
|
||||
|
||||
TEST_CASE("EXAMPLE 4 To illustrate the rules for creating character string "
|
||||
"literals and concatenating tokens, the sequence");
|
||||
|
||||
TEST_CASE("EXAMPLE 5 To illustrate the rules for placemarker preprocessing "
|
||||
"tokens, the sequence");
|
||||
/*
|
||||
CHECK_PP_OUTPUT_EXACT("#define t(x,y,z) x ## y ## z\n"
|
||||
"int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),\n"
|
||||
"\t\t\tt(10,,), t(,11,), t(,,12), t(,,) };\n",
|
||||
"int j[] = { 123, 45, 67, 89,\n"
|
||||
"\t\t\t10, 11, 12, };\n");
|
||||
*/
|
||||
|
||||
TEST_CASE("EXAMPLE 6 To demonstrate the redefinition rules, the following "
|
||||
"sequence is valid.");
|
||||
CHECK_PP_OUTPUT_EXACT(
|
||||
"#define OBJ_LIKE (1-1)\n"
|
||||
"#define OBJ_LIKE /* white space */ (1-1) /* other */\n"
|
||||
"#define FUNC_LIKE(a) (a)\n"
|
||||
"#define FUNC_LIKE( a )( /* note the white space */ \\\n"
|
||||
" a /* other stuffonthis line\n"
|
||||
" */ )\n",
|
||||
"");
|
||||
// INVALID
|
||||
// CHECK_PP_OUTPUT_EXACT(
|
||||
// "#define OBJ_LIKE (0) // different token sequence\n"
|
||||
// "#define OBJ_LIKE (1 - 1) // different white space\n"
|
||||
// "#define FUNC_LIKE(b) ( a ) // different parameter usage\n"
|
||||
// "#define FUNC_LIKE(b) ( b ) // different parameter spelling\n");
|
||||
|
||||
TEST_CASE("EXAMPLE 7 Finally,to show the variable argument list macro "
|
||||
"facilities:");
|
||||
CHECK_PP_OUTPUT_EXACT(
|
||||
"#define debug(...) fprintf(stderr, __VA_ARGS__)\n"
|
||||
"#define showlist(...) puts(#__VA_ARGS__)\n"
|
||||
"#define report(test, ...) ((test)?puts(#test): \\\n"
|
||||
" printf(__VA_ARGS__))\n"
|
||||
"debug(\"Flag\");\n"
|
||||
"debug(\"X = %d\\n\", x);\n"
|
||||
"showlist(The first, second, and third items.);\n"
|
||||
"report(x>y, \"x is %d but y is %d\", x, y);\n",
|
||||
|
||||
"fprintf(stderr, \"Flag\");\n"
|
||||
"fprintf(stderr, \"X = %d\\n\", x);\n"
|
||||
"puts(\"The first, second, and third items.\");\n"
|
||||
"((x>y)?puts(\"x>y\"): printf(\"x is %d but y is %d\", x, y));\n");
|
||||
}
|
||||
|
||||
#define TEST_LIST_CASE(func_name) {#func_name, func_name}
|
||||
@@ -423,5 +543,8 @@ TEST_LIST = {
|
||||
TEST_LIST_CASE(test_conditional_ifdef),
|
||||
TEST_LIST_CASE(test_simple_number_conditional_if),
|
||||
TEST_LIST_CASE(test_variadic_macros),
|
||||
TEST_LIST_CASE(test_gnu_comma_variadic_deletion),
|
||||
|
||||
TEST_LIST_CASE(test_c99_docs),
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user