- 实现了括号深度跟踪来正确分割带括号的宏参数 - 添加了对 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 测试中的未初始化变量 - 为测试函数中的字符变量添加初始化值避免未定义行为
551 lines
21 KiB
C
551 lines
21 KiB
C
#include <assert.h>
|
|
#include <scc_pproc.h>
|
|
#include <string.h>
|
|
#include <utest/acutest.h>
|
|
|
|
static cbool process_input(const char *input, scc_cstring_t *output) {
|
|
int ret = 0;
|
|
scc_sstream_t mem_stream;
|
|
ret = scc_sstream_init_by_buffer(&mem_stream, input, strlen(input), false,
|
|
16);
|
|
Assert(ret == 0);
|
|
|
|
scc_lexer_t lexer;
|
|
scc_lexer_init(&lexer, scc_sstream_to_ring(&mem_stream));
|
|
|
|
scc_pproc_t pp;
|
|
scc_pproc_init(&pp, scc_lexer_to_ring(&lexer, 8, true));
|
|
|
|
scc_lexer_tok_ring_t *tok_ring = scc_pproc_to_ring(&pp, 8);
|
|
*output = scc_cstring_from_cstr("");
|
|
scc_lexer_tok_t tok;
|
|
while (1) {
|
|
scc_ring_next_consume(*tok_ring, tok, ret);
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
scc_cstring_append(output, &tok.lexeme);
|
|
scc_lexer_tok_drop(&tok);
|
|
}
|
|
|
|
scc_pproc_drop(&pp);
|
|
scc_lexer_drop(&lexer);
|
|
scc_sstream_drop(&mem_stream);
|
|
return true;
|
|
}
|
|
|
|
#define CHECK_PP_OUTPUT_EXACT(input, expect) \
|
|
do { \
|
|
scc_cstring_t output; \
|
|
process_input(input, &output); \
|
|
assert(output.data != NULL); \
|
|
TEST_CHECK(strcmp(output.data, expect) == 0); \
|
|
TEST_MSG("Expected: %s", expect); \
|
|
TEST_MSG("Produced: %s", output.data); \
|
|
} while (0)
|
|
|
|
#define CHECK_PP_OUTPUT_CONTAIN(input, expect) \
|
|
do { \
|
|
scc_cstring_t output; \
|
|
process_input(input, &output); \
|
|
assert(output.data != NULL); \
|
|
TEST_CHECK(strstr(output.data, expect) != NULL); \
|
|
TEST_MSG("Expected: %s", expect); \
|
|
TEST_MSG("Produced: %s", output.data); \
|
|
} while (0)
|
|
|
|
static void test_define_simple_no_macro(void) {
|
|
TEST_CASE("simple no macro");
|
|
CHECK_PP_OUTPUT_EXACT("a", "a");
|
|
CHECK_PP_OUTPUT_EXACT("a()", "a()");
|
|
CHECK_PP_OUTPUT_EXACT("a(b)", "a(b)");
|
|
CHECK_PP_OUTPUT_EXACT("a(b, c)", "a(b, c)");
|
|
CHECK_PP_OUTPUT_EXACT("a(b, c, d)", "a(b, c, d)");
|
|
}
|
|
|
|
static void test_define_simple_object_macro(void) {
|
|
TEST_CASE("simple object-like macro");
|
|
CHECK_PP_OUTPUT_EXACT("#define MAX 100\nMAX\n", "100\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define NAME test\r\nNAME\n", "test\n");
|
|
}
|
|
|
|
static void test_define_complex_object_macro(void) {
|
|
TEST_CASE("complex object-like macro");
|
|
CHECK_PP_OUTPUT_EXACT("#define VALUE (100 + 50)\nVALUE\n", "(100 + 50)\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define PI 3.14159\nPI\n", "3.14159\n");
|
|
}
|
|
|
|
static void test_define_object_macro_backspace(void) {
|
|
TEST_CASE("object-like macro check backspace");
|
|
CHECK_PP_OUTPUT_EXACT("#define MAX 100\nMAX\n", "100\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define NAME \ttest\r\nNAME\n", "test\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define \tVALUE (100 \t+ 50)\nVALUE\n",
|
|
"(100 + 50)\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define \tPI \t 3.14159\nPI\n", "3.14159\n");
|
|
}
|
|
|
|
static void test_define_function_macro(void) {
|
|
TEST_CASE("function-like macro");
|
|
CHECK_PP_OUTPUT_EXACT("#define ADD(a,b) a + b\nADD(1, 2)\n", "1 + 2\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define ADD( a , b ) a + b\nADD(1, 2)\n", "1 + 2\n");
|
|
CHECK_PP_OUTPUT_EXACT(
|
|
"#define MAX(a,b) ((a) > (b) ? (a) : (b))\nMAX(10, 20)\n",
|
|
"((10) > (20) ? (10) : (20))\n");
|
|
}
|
|
|
|
static void test_define_stringify_operator(void) {
|
|
TEST_CASE("stringify operator (#)");
|
|
CHECK_PP_OUTPUT_EXACT("#define STRINGIFY(x) #x\nSTRINGIFY(hello)\n",
|
|
"\"hello\"\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define STR(x) #x\nSTR(test value)\n",
|
|
"\"test value\"\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define STR(x) #x\nSTR(A B \"ab\")\n",
|
|
"\"A B \"ab\"\"\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define STR(x) # x\nSTR(A B \"ab\")\n",
|
|
"\"A B \"ab\"\"\n");
|
|
}
|
|
|
|
static void test_define_concat_operator(void) {
|
|
TEST_CASE("concatenation operator (##)");
|
|
CHECK_PP_OUTPUT_EXACT("#define CONCAT a##b\nCONCAT\n", "ab\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define CONCAT a ## b\nCONCAT\n", "ab\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define CONCAT(a,b) a##b\nCONCAT(hello,world)\n",
|
|
"helloworld\n");
|
|
CHECK_PP_OUTPUT_EXACT(
|
|
"#define CONCAT( a , b ) a ## b\nCONCAT( hello , world )\n",
|
|
"helloworld\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define JOIN(pre,suf) pre ## suf\nJOIN(var, 123)\n",
|
|
"var123\n");
|
|
}
|
|
|
|
static void test_define_nested_macros(void) {
|
|
TEST_CASE("nested macros");
|
|
CHECK_PP_OUTPUT_EXACT(
|
|
"#define MAX 100\n#define TWICE_MAX (MAX * 2)\nTWICE_MAX\n",
|
|
"(100 * 2)\n");
|
|
CHECK_PP_OUTPUT_EXACT(
|
|
"#define A 1\n#define B (A + 1)\n#define C (B + 1)\nC\n",
|
|
"((1 + 1) + 1)\n");
|
|
|
|
CHECK_PP_OUTPUT_EXACT("#define A\n", "");
|
|
CHECK_PP_OUTPUT_EXACT("#undef A\n", "");
|
|
|
|
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) {
|
|
TEST_CASE("test_undef_macros");
|
|
CHECK_PP_OUTPUT_EXACT("#define x 1\n"
|
|
"x\n"
|
|
"#undef x\n"
|
|
"x\n"
|
|
"#define x 2\n"
|
|
"x\n",
|
|
"1\nx\n2\n");
|
|
}
|
|
|
|
static void hard_test_define_func_macros(void) {
|
|
TEST_CASE("func_macros_hard with pp_01");
|
|
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");
|
|
|
|
TEST_CASE("func_macros_hard with recursive define");
|
|
CHECK_PP_OUTPUT_EXACT("#define M1(x) M2(x + 1)\n"
|
|
"#define M2(x) M1(x * 2)\n"
|
|
"M1(5)\n",
|
|
"M1(5 + 1 * 2)\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define A B\n"
|
|
"#define B C\n"
|
|
"#define C 1\n"
|
|
"A\n",
|
|
"1\n");
|
|
|
|
TEST_CASE("func_macros_hard with self recursive call");
|
|
CHECK_PP_OUTPUT_EXACT("#define M(x) x\n"
|
|
"M(M(10))\n",
|
|
"10\n");
|
|
CHECK_PP_OUTPUT_EXACT("#define M(x) M(x)\n"
|
|
"#define N(x) x\n"
|
|
"N(M(1))\n",
|
|
"M(1)\n");
|
|
|
|
TEST_CASE("func_macros_hard with define by macro");
|
|
CHECK_PP_OUTPUT_EXACT("#define M1(x) M1(x + 1)\n"
|
|
"#define M2 M1\n"
|
|
"#define M3(x) x\n"
|
|
"M3(M3(M2)(0))\n",
|
|
"M1(0 + 1)\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("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) {
|
|
TEST_CASE("macro redefinition");
|
|
// 应检测到警告或错误
|
|
// CHECK_PP_OUTPUT_CONTAIN("#define A 1\n#define A 2\n", "warning");
|
|
|
|
TEST_CASE("undefined macro");
|
|
CHECK_PP_OUTPUT_EXACT("UNDEFINED_MACRO\n", "UNDEFINED_MACRO\n");
|
|
}
|
|
|
|
static void test_edge_cases(void) {
|
|
TEST_CASE("empty macro");
|
|
CHECK_PP_OUTPUT_EXACT("#define EMPTY()\nEMPTY()\n", "\n");
|
|
|
|
TEST_CASE("macro with only spaces");
|
|
CHECK_PP_OUTPUT_EXACT("#define SPACE \nSPACE\n", "\n");
|
|
|
|
TEST_CASE("deep nesting");
|
|
CHECK_PP_OUTPUT_EXACT("#define A B\n#define B C\n#define C 1\nA\n", "1\n");
|
|
}
|
|
|
|
static void test_conditional_ifdef(void) {
|
|
TEST_CASE("ifdef and ifndef");
|
|
|
|
// 基本 ifdef / ifndef
|
|
CHECK_PP_OUTPUT_EXACT("#define FOO\n"
|
|
"#ifdef FOO\n"
|
|
"foo\n"
|
|
"#endif\n",
|
|
"foo\n");
|
|
|
|
CHECK_PP_OUTPUT_EXACT("#define FOO\n"
|
|
"#ifndef FOO\n"
|
|
"foo\n"
|
|
"#endif\n",
|
|
"");
|
|
|
|
CHECK_PP_OUTPUT_EXACT("#undef FOO\n"
|
|
"#ifdef FOO\n"
|
|
"foo\n"
|
|
"#endif\n",
|
|
"");
|
|
|
|
CHECK_PP_OUTPUT_EXACT("#undef FOO\n"
|
|
"#ifndef FOO\n"
|
|
"foo\n"
|
|
"#endif\n",
|
|
"foo\n");
|
|
|
|
// ifdef + else
|
|
CHECK_PP_OUTPUT_EXACT("#define FOO\n"
|
|
"#ifdef FOO\n"
|
|
"foo\n"
|
|
"#else\n"
|
|
"bar\n"
|
|
"#endif\n",
|
|
"foo\n");
|
|
|
|
CHECK_PP_OUTPUT_EXACT("#undef FOO\n"
|
|
"#ifdef FOO\n"
|
|
"foo\n"
|
|
"#else\n"
|
|
"bar\n"
|
|
"#endif\n",
|
|
"bar\n");
|
|
|
|
// ifdef + elifdef (C23)
|
|
CHECK_PP_OUTPUT_EXACT("#define FOO\n"
|
|
"#ifdef FOO\n"
|
|
"foo\n"
|
|
"#elifdef FOO\n"
|
|
"foo2\n"
|
|
"#endif\n",
|
|
"foo\n");
|
|
|
|
CHECK_PP_OUTPUT_EXACT("#undef FOO\n"
|
|
"#define BAR\n"
|
|
"#ifdef FOO\n"
|
|
"foo\n"
|
|
"#elifdef BAR\n"
|
|
"bar\n"
|
|
"#else\n"
|
|
"none\n"
|
|
"#endif\n",
|
|
"bar\n");
|
|
|
|
CHECK_PP_OUTPUT_EXACT("#undef FOO\n"
|
|
"#undef BAR\n"
|
|
"#ifdef FOO\n"
|
|
"foo\n"
|
|
"#elifdef BAR\n"
|
|
"bar\n"
|
|
"#else\n"
|
|
"none\n"
|
|
"#endif\n",
|
|
"none\n");
|
|
|
|
// 嵌套
|
|
CHECK_PP_OUTPUT_EXACT("#define A\n"
|
|
"#ifdef A\n"
|
|
" #ifdef B\n"
|
|
" inner\n"
|
|
" #endif\n"
|
|
" outer\n"
|
|
"#endif\n",
|
|
" outer\n");
|
|
|
|
CHECK_PP_OUTPUT_EXACT("#define B\n"
|
|
"#ifndef A\n"
|
|
" #ifdef B\n"
|
|
" inner\n"
|
|
" #endif\n"
|
|
" outer\n"
|
|
"#endif\n",
|
|
" inner\n outer\n");
|
|
|
|
// 外层假,内层真
|
|
CHECK_PP_OUTPUT_EXACT("#ifdef __NONE\n"
|
|
"#define OUTER\n"
|
|
"#endif\n"
|
|
"#ifdef OUTER\n"
|
|
"should not appear\n"
|
|
"#endif\n",
|
|
""); // 期望为空
|
|
|
|
// 更复杂的嵌套条件
|
|
CHECK_PP_OUTPUT_EXACT("#define X\n"
|
|
"#ifdef X\n"
|
|
"x defined\n"
|
|
"#ifdef Y\n"
|
|
"Y defined\n"
|
|
"#else\n"
|
|
"Y not defined\n"
|
|
"#endif\n"
|
|
"after inner\n"
|
|
"#else\n"
|
|
"X not defined\n"
|
|
"#endif\n",
|
|
"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");
|
|
|
|
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}
|
|
TEST_LIST = {
|
|
TEST_LIST_CASE(test_define_simple_no_macro),
|
|
TEST_LIST_CASE(test_define_simple_object_macro),
|
|
TEST_LIST_CASE(test_define_complex_object_macro),
|
|
TEST_LIST_CASE(test_define_object_macro_backspace),
|
|
TEST_LIST_CASE(test_define_function_macro),
|
|
TEST_LIST_CASE(test_define_stringify_operator),
|
|
TEST_LIST_CASE(test_define_concat_operator),
|
|
TEST_LIST_CASE(test_define_nested_macros),
|
|
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),
|
|
TEST_LIST_CASE(test_gnu_comma_variadic_deletion),
|
|
|
|
TEST_LIST_CASE(test_c99_docs),
|
|
{NULL, NULL},
|
|
};
|