feat(lex_parser, pprocessor): rename identifier header check and add macro system

- Rename `scc_lex_parse_is_identifier_header` to `scc_lex_parse_is_identifier_prefix` for clarity and add a TODO comment
- Update lexer to use the renamed function for consistency
- Fix package and dependency names in `cbuild.toml` (`smcc_pprocesser` → `scc_pprocesser`, `smcc_lex_parser` → `lex_parser`)
- Introduce new macro system with header file `pp_macro.h` defining macro types, structures, and management functions
- Refactor preprocessor initialization and cleanup in `pprocessor.c` to use new macro table and stream handling
- Replace legacy `hashmap` with `scc_pp_macro_table_t` for macro storage
- Improve error handling and resource management in preprocessor lifecycle
This commit is contained in:
zzy
2025-12-13 16:09:46 +08:00
parent 874a58281f
commit 07a76d82f4
16 changed files with 970 additions and 490 deletions

View File

@@ -3,45 +3,50 @@
#include <string.h>
#include <utest/acutest.h>
static cbool process_input(const char *input, cstring_t *output) {
smcc_pp_t pp;
core_mem_stream_t mem_stream;
core_stream_t *output_stream;
static cbool process_input(const char *input, scc_cstring_t *output) {
scc_pproc_t pp;
scc_mem_probe_stream_t mem_stream;
scc_probe_stream_t *output_stream;
// 初始化预处理器
output_stream = pp_init(
&pp, core_mem_stream_init(&mem_stream, input, strlen(input), false));
output_stream =
scc_pproc_init(&pp, scc_mem_probe_stream_init(&mem_stream, input,
strlen(input), false));
// 获取输出结果
int ch;
*output = cstring_new();
*output = scc_cstring_new();
while (1) {
ch = core_stream_next_char(output_stream);
if (ch == core_stream_eof) {
ch = scc_probe_stream_consume(output_stream);
if (ch == scc_stream_eof) {
break;
}
cstring_push(output, (char)ch);
scc_cstring_append_ch(output, (char)ch);
}
// 清理资源
pp_drop(&pp);
scc_pproc_drop(&pp);
return true;
}
#define CHECK_PP_OUTPUT_EXACT(input, expect) \
do { \
cstring_t output; \
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 { \
cstring_t output; \
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_object_macro(void) {
@@ -56,6 +61,15 @@ static void test_define_complex_object_macro(void) {
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");
@@ -90,12 +104,41 @@ static void test_define_nested_macros(void) {
"((1 + 1) + 1)\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");
}
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");
}
#define TEST_LIST_CASE(func_name) {#func_name, func_name}
TEST_LIST = {
{"test_define_simple_object_macro", test_define_simple_object_macro},
{"test_define_complex_object_macro", test_define_complex_object_macro},
{"test_define_function_macro", test_define_function_macro},
{"test_define_stringify_operator", test_define_stringify_operator},
{"test_define_concat_operator", test_define_concat_operator},
{"test_define_nested_macros", test_define_nested_macros},
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),
{NULL, NULL},
};