From bc0b1d23e32df58e1e9eb3c508f448ceacb10c28 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Thu, 19 Feb 2026 19:30:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(pproc):=20=E6=B7=BB=E5=8A=A0=E9=A2=84?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=99=A8=E5=8C=85=E5=90=AB=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=92=8C=E6=94=B9=E8=BF=9B=E5=A4=B4=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=9F=A5=E6=89=BE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加了新的类型定义 scc_pproc_cstr_vec_t 用于存储包含路径, 并在 scc_pproc 结构中添加 include_paths 字段。实现改进的 switch_file_stack 函数,支持从当前目录、父目录和系统包含路径 中查找头文件,提供更完整的 #include 指令处理能力。 fix(core): 重命名环形缓冲区内联宏避免命名冲突 将 scc_ring_phys 宏重命名为 _scc_ring_phys,并添加其他相关 内部宏如 _scc_ring_cap、_scc_ring_head 等,以避免与外部接口 的命名冲突并提高代码清晰度。 refactor(main): 添加命令行包含路径选项并清理标准库引用 在命令行参数解析中添加 -I/--include 选项支持,允许用户指定 额外的头文件搜索路径。同时移除不必要的 stdio.h 引用并清理 一些调试相关的缓冲区设置。 --- libs/pproc/include/scc_pproc.h | 2 ++ libs/pproc/src/pproc_include.c | 43 +++++++++++++++++++++--- libs/pproc/src/scc_pproc.c | 1 + runtime/scc_core/include/scc_core_ring.h | 20 +++++++---- src/main.c | 10 ++++-- 5 files changed, 62 insertions(+), 14 deletions(-) diff --git a/libs/pproc/include/scc_pproc.h b/libs/pproc/include/scc_pproc.h index 579caad..7711f3b 100644 --- a/libs/pproc/include/scc_pproc.h +++ b/libs/pproc/include/scc_pproc.h @@ -28,6 +28,7 @@ typedef struct { } scc_pproc_file_state_t; typedef SCC_VEC(scc_pproc_file_state_t *) scc_pproc_file_stack_t; typedef SCC_VEC(scc_lexer_tok_ring_t *) scc_pproc_ring_vec_t; +typedef SCC_VEC(scc_cstring_t) scc_pproc_cstr_vec_t; typedef struct scc_pproc { scc_lexer_tok_ring_t *org_ring; @@ -36,6 +37,7 @@ typedef struct scc_pproc { scc_strpool_t strpool; int at_line_start; + scc_pproc_cstr_vec_t include_paths; scc_pproc_macro_table_t macro_table; scc_pproc_if_stack_t if_stack; scc_pproc_file_stack_t file_stack; diff --git a/libs/pproc/src/pproc_include.c b/libs/pproc/src/pproc_include.c index 0655d8a..01647ec 100644 --- a/libs/pproc/src/pproc_include.c +++ b/libs/pproc/src/pproc_include.c @@ -1,11 +1,45 @@ #include #include -static int switch_file_stack(scc_pproc_t *pp, scc_cstring_t fname, +static int switch_file_stack(scc_pproc_t *pp, scc_cstring_t *fname, int is_system) { + scc_cstring_t fpath = scc_cstring_create(); + int ret = 0; + + if (!is_system) { + const char parent[] = "/../"; + // FIXME maybe it can eazy + const char *org_fname = + (((scc_sstream_t *)(((scc_lexer_t *)pp->org_ring->userdata) + ->stream_ref->userdata)) + ->fname); + scc_cstring_append_cstr(&fpath, org_fname, scc_strlen(org_fname)); + scc_cstring_append_cstr(&fpath, parent, scc_strlen(parent)); + scc_cstring_append(&fpath, fname); + ret = scc_fexists(scc_cstring_as_cstr(&fpath)); + if (ret == true) { + goto FOPEN; + } + } + + /* system default path and -I includes path */ + scc_vec_foreach(pp->include_paths, i) { + scc_cstring_free(&fpath); + scc_cstring_t *syspath = &scc_vec_at(pp->include_paths, i); + scc_cstring_append(&fpath, syspath); + scc_cstring_append(&fpath, fname); + ret = scc_fexists(scc_cstring_as_cstr(&fpath)); + if (ret == true) { + goto FOPEN; + } + } + LOG_ERROR("Include File %c%s%c Not Found", is_system ? '<' : '\"', + scc_cstring_as_cstr(fname), is_system ? '>' : '\"'); + return -1; +FOPEN: scc_pproc_file_state_t *file = scc_malloc(sizeof(scc_pproc_file_state_t)); Assert(file != null); - if (scc_sstream_init(&(file->sstream), fname.data, 1024)) { + if (scc_sstream_init(&(file->sstream), scc_cstring_as_cstr(&fpath), 1024)) { return -1; } scc_lexer_init(&(file->lexer), scc_sstream_to_ring(&(file->sstream))); @@ -74,9 +108,10 @@ void scc_pproc_parse_include(scc_pproc_t *pp) { } scc_cstring_free(&line); int is_system = includename[0] == '<'; - if (switch_file_stack(pp, fname, is_system)) { - goto ERROR; + if (switch_file_stack(pp, &fname, is_system)) { + // LOG_ERROR() } + scc_cstring_free(&fname); return; ERROR: LOG_ERROR("Invalid include filename need \"FILENAME\" or "); diff --git a/libs/pproc/src/scc_pproc.c b/libs/pproc/src/scc_pproc.c index ceac03c..7a0dc53 100644 --- a/libs/pproc/src/scc_pproc.c +++ b/libs/pproc/src/scc_pproc.c @@ -84,6 +84,7 @@ void scc_pproc_init(scc_pproc_t *pp, scc_lexer_tok_ring_t *input) { pp->cur_ring = pp->org_ring; scc_ring_init(pp->expanded_ring, 0, 0, 0); scc_pproc_marco_table_init(&pp->macro_table); + scc_vec_init(pp->include_paths); scc_vec_init(pp->if_stack); scc_vec_init(pp->file_stack); pp->at_line_start = true; diff --git a/runtime/scc_core/include/scc_core_ring.h b/runtime/scc_core/include/scc_core_ring.h index 4dc1511..44fe57f 100644 --- a/runtime/scc_core/include/scc_core_ring.h +++ b/runtime/scc_core/include/scc_core_ring.h @@ -29,14 +29,20 @@ // ==================== 内部辅助宏 (不直接使用) ==================== -#define scc_ring_phys(ring, idx) ((idx) % (ring).cap) +#define _scc_ring_phys(ring, idx) ((idx) % (ring).cap) +#define _scc_ring_cap(ring) ((ring).cap) +#define _scc_ring_head(ring) ((ring).head) +#define _scc_ring_probe(ring) ((ring).probe) +#define _scc_ring_tail(ring) ((ring).tail) +#define _scc_ring_size(ring) ((ring).tail - (ring).head) +#define _scc_ring_empty(ring) ((ring).head == (ring).tail) /** * @brief 确保 probe 位置有数据可用 (尝试填充) * @param ring 环形缓冲区变量 * @param ok 变量名 (如 int ok_flag) ,宏会将其设置为 true 或 false */ -#define scc_ring_ensure(ring, ok) \ +#define _scc_ring_ensure(ring, ok) \ do { \ ok = 1; \ if ((ring).probe < (ring).tail) \ @@ -50,7 +56,7 @@ ok = 0; /* 缓冲区满,无法填充 */ \ break; \ } \ - usize phys_tail = scc_ring_phys(ring, (ring).tail); \ + usize phys_tail = _scc_ring_phys(ring, (ring).tail); \ if ((ring).fill == null || \ !(ring).fill(&(ring).data[phys_tail], (ring).userdata)) { \ ok = 0; \ @@ -110,14 +116,14 @@ */ #define scc_ring_peek(ring, val, ok) \ do { \ - scc_ring_ensure(ring, ok); \ + _scc_ring_ensure(ring, ok); \ if (!(ok)) \ break; \ if ((ring).probe >= (ring).tail) { \ ok = 0; \ break; \ } \ - usize _phys = scc_ring_phys(ring, (ring).probe); \ + usize _phys = _scc_ring_phys(ring, (ring).probe); \ val = (ring).data[_phys]; \ } while (0) @@ -129,14 +135,14 @@ */ #define scc_ring_next(ring, val, ok) \ do { \ - scc_ring_ensure(ring, ok); \ + _scc_ring_ensure(ring, ok); \ if (!(ok)) \ break; \ if ((ring).probe >= (ring).tail) { \ ok = 0; \ break; \ } \ - usize _phys = scc_ring_phys(ring, (ring).probe); \ + usize _phys = _scc_ring_phys(ring, (ring).probe); \ val = (ring).data[_phys]; \ (ring).probe++; \ } while (0) diff --git a/src/main.c b/src/main.c index 5401b61..a124432 100644 --- a/src/main.c +++ b/src/main.c @@ -7,8 +7,6 @@ // #include // #include -#include - typedef struct { const char *input_file; const char *output_file; @@ -26,6 +24,7 @@ static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, SCC_HINT_DESCRIPTION, SCC_HINT_OUTPUT_FILE, SCC_HINT_INPUT_FILE, + SCC_HINT_INCLUDE_PATH, SCC_HINT_VERBOSE, SCC_HINT_EMIT_LEX, @@ -38,6 +37,7 @@ static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, [SCC_HINT_DESCRIPTION] = "A simple C compiler", [SCC_HINT_OUTPUT_FILE] = "Output file", [SCC_HINT_INPUT_FILE] = "Input source file", + [SCC_HINT_INCLUDE_PATH] = "SCC_HINT_INCLUDE_PATH", [SCC_HINT_VERBOSE] = "Increase verbosity (can be used multiple times)", [SCC_HINT_EMIT_LEX] = "Generate lexer sources tokens and exit", [SCC_HINT_EMIT_PP] = "Generate preprocessed tokens and exit", @@ -49,6 +49,7 @@ static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, [SCC_HINT_DESCRIPTION] = "一个简单的C编译器", [SCC_HINT_OUTPUT_FILE] = "输出文件", [SCC_HINT_INPUT_FILE] = "输入源文件", + [SCC_HINT_INCLUDE_PATH] = "SCC_HINT_INCLUDE_PATH", [SCC_HINT_VERBOSE] = "增加详细输出(可多次使用)", [SCC_HINT_EMIT_LEX] = "生成`源代码的词法单元`并退出", [SCC_HINT_EMIT_PP] = "生成`预处理后的词法单元`并退出", @@ -88,6 +89,10 @@ static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config, scc_argparse_spec_set_required(&arg_input.spec, true); scc_argparse_cmd_add_arg(root, &arg_input); + scc_argparse_opt_t opt_include; + scc_argparse_opt_init(&opt_include, 0, "include", + scc_hints[SCC_HINT_INCLUDE_PATH]); + // -v, --verbose (计数) scc_argparse_opt_t opt_verbose; scc_argparse_opt_init(&opt_verbose, 'V', "verbose", @@ -175,7 +180,6 @@ int main(int argc, const char **argv, const char **envp) { SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); #endif - setbuf(stdout, NULL); #ifdef _WIN32 #define OUTPUT_DEFAULT_FILE "a.exe"