diff --git a/libs/lexer/include/scc_lexer_token.h b/libs/lexer/include/scc_lexer_token.h index b4df6c9..c6dd8f9 100644 --- a/libs/lexer/include/scc_lexer_token.h +++ b/libs/lexer/include/scc_lexer_token.h @@ -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 { diff --git a/libs/pproc/include/scc_pproc.h b/libs/pproc/include/scc_pproc.h index 657b133..a186121 100644 --- a/libs/pproc/include/scc_pproc.h +++ b/libs/pproc/include/scc_pproc.h @@ -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, diff --git a/libs/pproc/src/pproc_directive.c b/libs/pproc/src/pproc_directive.c index 952493e..30ab77d 100644 --- a/libs/pproc/src/pproc_directive.c +++ b/libs/pproc/src/pproc_directive.c @@ -1,5 +1,8 @@ +#include +#include #include #include + 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,11 +387,12 @@ 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; } ERROR: LOG_WARN("Unhandled directive: %s", scc_cstring_as_cstr(&tok.lexeme)); scc_lexer_skip_until_newline(pp->cur_ring); -} \ No newline at end of file +} diff --git a/libs/pproc/src/pproc_expand.c b/libs/pproc/src/pproc_expand.c index 909ca40..1de31d1 100644 --- a/libs/pproc/src/pproc_expand.c +++ b/libs/pproc/src/pproc_expand.c @@ -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); diff --git a/libs/pproc/src/pproc_if.c b/libs/pproc/src/pproc_if.c new file mode 100644 index 0000000..d78258a --- /dev/null +++ b/libs/pproc/src/pproc_if.c @@ -0,0 +1,172 @@ +#include +#include + +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; +} diff --git a/libs/pproc/src/pproc_include.c b/libs/pproc/src/pproc_include.c index a361e23..d11b734 100644 --- a/libs/pproc/src/pproc_include.c +++ b/libs/pproc/src/pproc_include.c @@ -1,4 +1,5 @@ #include +#include #include 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); diff --git a/libs/pproc/tests/test_unit.c b/libs/pproc/tests/test_unit.c index a0aadbb..44426b9 100644 --- a/libs/pproc/tests/test_unit.c +++ b/libs/pproc/tests/test_unit.c @@ -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}, -}; \ No newline at end of file +};