From 07f5d9331b255c012fcece389637648386a90258 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Mon, 15 Dec 2025 20:24:39 +0800 Subject: [PATCH] feat(lexer, preprocessor): replace cstring conversion with copy and refactor macro expansion - Replace `scc_cstring_from_cstr(scc_cstring_as_cstr(...))` with `scc_cstring_copy()` in lexer to fix memory leaks - Extract macro expansion logic into separate `expand_macro.c` file - Remove `expand_stack` parameter from `scc_pp_expand_macro()` function - Add new parsing functions for macro replacement lists and arguments - Add string utility functions for whitespace trimming and string joining - Update memory stream documentation for clarity --- libs/lexer/src/lexer.c | 4 +- libs/pprocessor/include/pp_parse.h | 7 +- libs/pprocessor/src/expand_macro.c | 296 ++++++++++++++++++ libs/pprocessor/src/macro.c | 2 +- libs/pprocessor/src/parse.c | 199 +----------- libs/pprocessor/src/pprocessor.c | 13 +- runtime/libcore/include/core_str.h | 16 + runtime/libcore/include/core_stream.h | 10 +- runtime/libcore/src/stream.c | 23 +- .../include/{hashmap.h => hashtable.h} | 8 +- runtime/libutils/include/libutils.h | 4 +- runtime/libutils/include/strpool.h | 2 +- .../libutils/src/{hashmap.c => hashtable.c} | 2 +- runtime/libutils/src/vector-gdb.py | 112 ------- runtime/runtime_gdb.py | 222 +++++++++++++ 15 files changed, 574 insertions(+), 346 deletions(-) create mode 100644 libs/pprocessor/src/expand_macro.c rename runtime/libutils/include/{hashmap.h => hashtable.h} (97%) rename runtime/libutils/src/{hashmap.c => hashtable.c} (99%) delete mode 100644 runtime/libutils/src/vector-gdb.py create mode 100644 runtime/runtime_gdb.py diff --git a/libs/lexer/src/lexer.c b/libs/lexer/src/lexer.c index ca213c7..b10f98f 100644 --- a/libs/lexer/src/lexer.c +++ b/libs/lexer/src/lexer.c @@ -79,7 +79,7 @@ void scc_lexer_init(scc_lexer_t *lexer, scc_probe_stream_t *stream) { lexer->stream = stream; lexer->pos = scc_pos_init(); // FIXME - lexer->pos.name = scc_cstring_from_cstr(scc_cstring_as_cstr(&stream->name)); + lexer->pos.name = scc_cstring_copy(&stream->name); } #define set_err_token(token) ((token)->type = SCC_TOK_UNKNOWN) @@ -135,7 +135,7 @@ static void parse_line(scc_lexer_t *lexer, scc_lexer_tok_t *token) { scc_lex_parse_skip_line(lexer->stream, &lexer->pos); token->loc.line = n; // FIXME memory leak - token->loc.name = scc_cstring_from_cstr(scc_cstring_as_cstr(&str)); + token->loc.name = scc_cstring_copy(&str); scc_cstring_free(&str); return; SKIP_LINE: diff --git a/libs/pprocessor/include/pp_parse.h b/libs/pprocessor/include/pp_parse.h index 684d873..2661f03 100644 --- a/libs/pprocessor/include/pp_parse.h +++ b/libs/pprocessor/include/pp_parse.h @@ -5,9 +5,14 @@ #include void scc_pp_parse_directive(scc_probe_stream_t *stream, scc_pos_t *pos, scc_pp_macro_table_t *macros); +cbool scc_pp_parse_macro_replace_list(scc_probe_stream_t *stream, + scc_pp_macro_list_t *list); +cbool scc_pp_parse_macro_arguments(scc_probe_stream_t *stream, + scc_pp_macro_list_t *args); + +// expand cbool scc_pp_expand_macro(scc_probe_stream_t *stream, scc_pp_macro_table_t *macros, - scc_pp_macro_table_t *expand_stack, scc_probe_stream_t **out_stream, int depth); #endif /* __SCC_PP_PARSE_H__ */ diff --git a/libs/pprocessor/src/expand_macro.c b/libs/pprocessor/src/expand_macro.c new file mode 100644 index 0000000..5994306 --- /dev/null +++ b/libs/pprocessor/src/expand_macro.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include + +static inline void scc_generate_cstr(scc_cstring_t *buff) { + scc_cstring_t out_buff = scc_cstring_new(); + scc_cstring_append_ch(&out_buff, '\"'); + // TODO it is too simple + scc_cstring_append(&out_buff, buff); + scc_cstring_append_ch(&out_buff, '\"'); + + // FIXME 可能有着更好的解决方案 + scc_cstring_clear(buff); + scc_cstring_append(buff, &out_buff); + scc_cstring_free(&out_buff); +} + +#define SCC_PP_IS_LIST_BLANK(i) \ + ((i) < list->size && scc_vec_at(*list, (i)).data[0] == ' ' && \ + scc_vec_at(*list, (i)).data[1] == '\0') +#define SCC_PP_IS_LIST_TO_STRING(i) \ + ((i) < list->size && scc_vec_at(*list, (i)).data[0] == '#' && \ + scc_vec_at(*list, (i)).data[1] == '\0') +#define SCC_PP_IS_LIST_CONNECT(i) \ + ((i) < list->size && scc_vec_at(*list, (i)).data[0] == '#' && \ + scc_vec_at(*list, (i)).data[1] == '#' && \ + scc_vec_at(*list, (i)).data[2] == '\0') +#define SCC_PP_USE_CONNECT(font, rear) \ + if (rear < list->size) { \ + scc_cstring_append(out_buff, &scc_vec_at(*list, font)); \ + scc_cstring_append(out_buff, &scc_vec_at(*list, rear)); \ + } else { \ + scc_cstring_append(out_buff, &scc_vec_at(*list, font)); \ + } +// for # ## to generator string +static inline cbool scc_pp_expand_string_unsafe(scc_pp_macro_list_t *list, + scc_cstring_t *out_buff) { + for (usize i = 0; i < list->size; ++i) { + if (SCC_PP_IS_LIST_BLANK(i + 1)) { + if (SCC_PP_IS_LIST_CONNECT(i + 2)) { + SCC_PP_USE_CONNECT(i, i + 3); + i += 3; + continue; + } + } else if (SCC_PP_IS_LIST_CONNECT(i + 1)) { + SCC_PP_USE_CONNECT(i, i + 2); + i += 2; + continue; + } else if (SCC_PP_IS_LIST_TO_STRING(i)) { + i += 1; + if (i < list->size) { + scc_generate_cstr(&scc_vec_at(*list, i)); + } else { + LOG_WARN("# need a valid literator"); + break; + } + } + scc_cstring_append(out_buff, &scc_vec_at(*list, i)); + } + return true; +} + +// 展开对象宏 +cbool scc_pp_expand_object_macro(scc_pp_macro_t *macro, + scc_cstring_t *out_buff) { + Assert(macro->type == SCC_PP_MACRO_OBJECT && macro->params.size == 0); + Assert(scc_cstring_is_empty(out_buff) == true); + // 对象宏输出替换文本并进行递归展开 + scc_pp_expand_string_unsafe(¯o->replaces, out_buff); + return true; +} + +// 展开函数宏 +cbool scc_pp_expand_function_macro(scc_pp_macro_t *macro, + scc_pp_macro_list_t *origin_params, + scc_pp_macro_list_t *params, + scc_cstring_t *out_buff) { + Assert(macro->type == SCC_PP_MACRO_FUNCTION); + Assert(out_buff != null); + Assert(scc_cstring_is_empty(out_buff) == true); + Assert(params->size == macro->params.size); + + scc_pp_macro_list_t list; + scc_vec_init(list); + for (usize i = 0; i < macro->replaces.size; ++i) { + // TODO ... __VA_ARGS__ + for (usize j = 0; j < macro->params.size; ++j) { + if (scc_strcmp( + scc_cstring_as_cstr(&scc_vec_at(macro->replaces, i)), + scc_cstring_as_cstr(&scc_vec_at(macro->params, j))) == 0) { + Assert(&scc_vec_at(*params, j) != null); + scc_vec_push(list, scc_cstring_copy(&scc_vec_at(*params, j))); + goto END; + } + } + scc_vec_push(list, scc_cstring_copy(&scc_vec_at(macro->replaces, i))); + END:; + } + scc_pp_expand_string_unsafe(&list, out_buff); + for (usize i = 0; i < list.size; ++i) { + scc_cstring_free(&scc_vec_at(list, i)); + } + scc_vec_free(list); + return true; +} + +// 状态管理结构 +typedef struct { + scc_pp_macro_table_t *macros; + scc_pp_macro_table_t painted_blue; // 正在展开的宏 + int depth; +} macro_expansion_state_t; + +// 进入宏展开 +static void enter_macro_expansion(macro_expansion_state_t *state, + scc_pp_macro_t *macro) { + // 添加到活动宏集合 + scc_pp_macro_table_set(&state->painted_blue, + scc_pp_macro_new(¯o->name, macro->type)); +} + +// 离开宏展开(开始重新扫描) +static void leave_macro_expansion(macro_expansion_state_t *state, + scc_pp_macro_t *macro) { + // 从活动宏移除,添加到禁用宏 + scc_pp_macro_table_remove(&state->painted_blue, ¯o->name); +} + +// 检查是否可以展开 +static cbool can_expand_macro(macro_expansion_state_t *state, + scc_pp_macro_t *macro) { + return scc_pp_macro_table_get(&state->painted_blue, ¯o->name) == null; +} + +static cbool _scc_pp_expand_macro(scc_probe_stream_t *stream, + macro_expansion_state_t *state, + scc_probe_stream_t **out_stream); + +static cbool expanded_buffer(const scc_cstring_t *in, scc_cstring_t *out, + macro_expansion_state_t *state) { + scc_probe_stream_t *in_stream = scc_mem_probe_stream_new( + scc_cstring_as_cstr(in), scc_cstring_len(in), false); + + // rescanning + int ch; + while ((ch = scc_probe_stream_peek(in_stream)) != scc_stream_eof) { + if (scc_lex_parse_is_identifier_prefix(ch)) { + // 递归检查 + scc_probe_stream_t *out_stream; + if (_scc_pp_expand_macro(in_stream, state, &out_stream) == false) { + scc_cstring_free(out); + return false; + } + + Assert(out_stream != null); + while (scc_probe_stream_peek(out_stream) != scc_stream_eof) { + scc_cstring_append_ch(out, + scc_probe_stream_consume(out_stream)); + } + Assert(out_stream != null && out_stream->drop != null); + scc_probe_stream_drop(out_stream); + } else { + scc_cstring_append_ch(out, scc_probe_stream_consume(in_stream)); + } + } + + scc_probe_stream_drop(in_stream); + return true; +} + +/** + * 1. 参数先展开 + * 2. 替换后重扫描 + * 3. 蓝色集合中不展开 + * 4. #, ## 不展开 + * 5. 最后的括号要检查 + */ +static cbool _scc_pp_expand_macro(scc_probe_stream_t *stream, + macro_expansion_state_t *state, + scc_probe_stream_t **out_stream) { + // TODO self position and it maybe is a stack on #include ? + // 递归扫描 + if (state->depth-- <= 0) { + *out_stream = null; + return false; + } + scc_pp_macro_table_t *macros = state->macros; + scc_cstring_t identifier = scc_cstring_new(); + scc_pos_t pos = scc_pos_init(); + + cbool ret; + ret = scc_lex_parse_identifier(stream, &pos, &identifier); + Assert(ret == true); + + scc_pp_macro_t *macro = scc_pp_macro_table_get(macros, &identifier); + + // 1. 不是宏,直接输出标识符 + if (macro == null) { + // 不是宏,直接输出 + usize length = scc_cstring_len(&identifier); + *out_stream = scc_mem_probe_stream_new( + scc_cstring_move_cstr(&identifier), length, true); + return true; + } else { + scc_cstring_free(&identifier); + } + + // 收集参数(如果是函数宏) + scc_pp_macro_list_t params; + scc_vec_init(params); + if (macro->type == SCC_PP_MACRO_FUNCTION) { + // TODO when expand need check another func with () at the end + scc_lex_parse_skip_whitespace(stream, &pos); + if (scc_probe_stream_peek(stream) != '(') { + goto ORIGIN; + } + ret = scc_pp_parse_macro_arguments(stream, ¶ms); + Assert(ret == true); + } + + // 2. 检查到重复展开跳过 + // 检查是否可以展开 + if (!can_expand_macro(state, macro)) { + ORIGIN: + // 输出原始调用 + scc_cstring_t original = scc_cstring_new(); + scc_cstring_append(&original, ¯o->name); + if (macro->type == SCC_PP_MACRO_FUNCTION && params.size != 0) { + scc_cstring_append_ch(&original, '('); + for (usize i = 0; i < params.size; ++i) { + scc_cstring_append(&original, &scc_vec_at(params, i)); + if (i != params.size - 1) { + scc_cstring_append_ch(&original, ','); + scc_cstring_append_ch(&original, ' '); + } + } + scc_cstring_append_ch(&original, ')'); + } + *out_stream = scc_mem_probe_stream_new( + scc_cstring_as_cstr(&original), scc_cstring_len(&original), true); + scc_vec_free(params); + return true; + } + + // 开始展开 + scc_cstring_t expanded = scc_cstring_new(); + if (macro->type == SCC_PP_MACRO_OBJECT) { + ret = scc_pp_expand_object_macro(macro, &expanded); + Assert(ret == true); + goto RESCANNING; + } else if (macro->type != SCC_PP_MACRO_FUNCTION) { + TODO(); + } + + Assert(macro->type == SCC_PP_MACRO_FUNCTION); + + scc_pp_macro_list_t expanded_params; + scc_vec_init(expanded_params); + // expand params fisrt and recursive + for (usize i = 0; i < params.size; ++i) { + scc_cstring_t param = scc_vec_at(params, i); + scc_cstring_t out = scc_cstring_new(); + expanded_buffer(¶m, &out, state); + scc_vec_push(expanded_params, out); + } + ret = scc_pp_expand_function_macro(macro, ¶ms, &expanded_params, + &expanded); + Assert(ret == true); + +RESCANNING: + // 重新扫描展开结果 + // 将展开内容变换成stream并递归展开 + scc_cstring_t rescanned = scc_cstring_new(); + enter_macro_expansion(state, macro); + expanded_buffer(&expanded, &rescanned, state); + leave_macro_expansion(state, macro); + + scc_cstring_free(&expanded); + *out_stream = scc_mem_probe_stream_new(scc_cstring_as_cstr(&rescanned), + scc_cstring_len(&rescanned), true); + return true; +} + +cbool scc_pp_expand_macro(scc_probe_stream_t *stream, + scc_pp_macro_table_t *macros, + scc_probe_stream_t **out_stream, int depth) { + Assert(depth > 0 && stream != null && macros != null && out_stream != null); + macro_expansion_state_t state; + state.depth = depth; + scc_pp_marco_table_init(&state.painted_blue); + state.macros = macros; + cbool ret = _scc_pp_expand_macro(stream, &state, out_stream); + scc_pp_macro_table_drop(&state.painted_blue); + return ret; +} diff --git a/libs/pprocessor/src/macro.c b/libs/pprocessor/src/macro.c index d8674e3..8939709 100644 --- a/libs/pprocessor/src/macro.c +++ b/libs/pprocessor/src/macro.c @@ -9,7 +9,7 @@ scc_pp_macro_t *scc_pp_macro_new(const scc_cstring_t *name, return null; } - macro->name = scc_cstring_from_cstr(scc_cstring_as_cstr(name)); + macro->name = scc_cstring_copy(name); macro->type = type; scc_vec_init(macro->params); scc_vec_init(macro->replaces); diff --git a/libs/pprocessor/src/parse.c b/libs/pprocessor/src/parse.c index 1cb38a4..f459ceb 100644 --- a/libs/pprocessor/src/parse.c +++ b/libs/pprocessor/src/parse.c @@ -1,9 +1,7 @@ -#include #include #include #include #include -#include static const struct { const char *name; @@ -57,7 +55,7 @@ static inline void try_to_cut_list(scc_pp_macro_list_t *list, } } -static cbool parse_macro_replace_list(scc_probe_stream_t *stream, +cbool scc_pp_parse_macro_replace_list(scc_probe_stream_t *stream, scc_pp_macro_list_t *list) { Assert(stream != null && list != null); scc_probe_stream_reset(stream); @@ -114,7 +112,7 @@ static cbool parse_macro_replace_list(scc_probe_stream_t *stream, } // 解析宏参数列表 -static cbool parse_macro_arguments(scc_probe_stream_t *stream, +cbool scc_pp_parse_macro_arguments(scc_probe_stream_t *stream, scc_pp_macro_list_t *args) { Assert(stream != null && args != null); @@ -237,7 +235,7 @@ void scc_pp_parse_directive(scc_probe_stream_t *stream, scc_pos_t *pos, if (!has_whitespace && ch == '(') { // 函数宏 scc_pp_macro_list_t params; - if (!parse_macro_arguments(stream, ¶ms)) { + if (!scc_pp_parse_macro_arguments(stream, ¶ms)) { goto ERR; } @@ -250,12 +248,12 @@ void scc_pp_parse_directive(scc_probe_stream_t *stream, scc_pos_t *pos, } scc_pp_macro_list_t replacement; - parse_macro_replace_list(stream, &replacement); + scc_pp_parse_macro_replace_list(stream, &replacement); scc_pp_add_function_macro(macros, &name, ¶ms, &replacement); } else { // 对象宏 scc_pp_macro_list_t replacement; - parse_macro_replace_list(stream, &replacement); + scc_pp_parse_macro_replace_list(stream, &replacement); scc_pp_add_object_macro(macros, &name, &replacement); } scc_cstring_free(&name); @@ -296,190 +294,3 @@ FREE: scc_cstring_free(&directive); scc_cstring_free(&name); } - -static inline void scc_generate_cstr(scc_cstring_t *buff) { - scc_cstring_t out_buff = scc_cstring_new(); - scc_cstring_append_ch(&out_buff, '\"'); - // TODO it is too simple - scc_cstring_append(&out_buff, buff); - scc_cstring_append_ch(&out_buff, '\"'); - - // FIXME 可能有着更好的解决方案 - scc_cstring_clear(buff); - scc_cstring_append(buff, &out_buff); - scc_cstring_free(&out_buff); -} - -#define SCC_PP_IS_LIST_BLANK(i) \ - ((i) < list->size && scc_vec_at(*list, (i)).data[0] == ' ' && \ - scc_vec_at(*list, (i)).data[1] == '\0') -#define SCC_PP_IS_LIST_TO_STRING(i) \ - ((i) < list->size && scc_vec_at(*list, (i)).data[0] == '#' && \ - scc_vec_at(*list, (i)).data[1] == '\0') -#define SCC_PP_IS_LIST_CONNECT(i) \ - ((i) < list->size && scc_vec_at(*list, (i)).data[0] == '#' && \ - scc_vec_at(*list, (i)).data[1] == '#' && \ - scc_vec_at(*list, (i)).data[2] == '\0') -#define SCC_PP_USE_CONNECT(font, rear) \ - if (rear < list->size) { \ - scc_cstring_append(out_buff, &scc_vec_at(*list, font)); \ - scc_cstring_append(out_buff, &scc_vec_at(*list, rear)); \ - } else { \ - scc_cstring_append(out_buff, &scc_vec_at(*list, font)); \ - } -// for # ## to generator string -static inline cbool scc_pp_expand_string_unsafe(scc_pp_macro_list_t *list, - scc_cstring_t *out_buff) { - for (usize i = 0; i < list->size; ++i) { - if (SCC_PP_IS_LIST_BLANK(i + 1)) { - if (SCC_PP_IS_LIST_CONNECT(i + 2)) { - SCC_PP_USE_CONNECT(i, i + 3); - i += 3; - continue; - } - } else if (SCC_PP_IS_LIST_CONNECT(i + 1)) { - SCC_PP_USE_CONNECT(i, i + 2); - i += 2; - continue; - } else if (SCC_PP_IS_LIST_TO_STRING(i)) { - i += 1; - if (i < list->size) { - scc_generate_cstr(&scc_vec_at(*list, i)); - } else { - LOG_WARN("# need a valid literator"); - break; - } - } - scc_cstring_append(out_buff, &scc_vec_at(*list, i)); - } - return true; -} - -// 展开对象宏 -cbool scc_pp_expand_object_macro(scc_pp_macro_t *macro, - scc_cstring_t *out_buff) { - Assert(macro->type == SCC_PP_MACRO_OBJECT && macro->params.size == 0); - Assert(scc_cstring_is_empty(out_buff) == true); - // 对象宏输出替换文本并进行递归展开 - scc_pp_expand_string_unsafe(¯o->replaces, out_buff); - return true; -} - -// 展开函数宏 -cbool scc_pp_expand_function_macro(scc_pp_macro_t *macro, - scc_pp_macro_list_t *params, - scc_cstring_t *out_buff) { - Assert(macro->type == SCC_PP_MACRO_FUNCTION); - Assert(out_buff != null); - Assert(scc_cstring_is_empty(out_buff) == true); - for (usize i = 0; i < macro->replaces.size; ++i) { - // TODO ... __VA_ARGS__ - for (usize j = 0; j < macro->params.size; ++j) { - if (scc_strcmp( - scc_cstring_as_cstr(&scc_vec_at(macro->replaces, i)), - scc_cstring_as_cstr(&scc_vec_at(macro->params, j))) == 0) { - scc_cstring_free(&scc_vec_at(macro->replaces, i)); - scc_cstring_append(&scc_vec_at(macro->replaces, i), - &scc_vec_at(*params, j)); - continue; - } - } - } - scc_pp_expand_string_unsafe(¯o->replaces, out_buff); - return true; -} - -cbool scc_pp_expand_macro(scc_probe_stream_t *stream, - scc_pp_macro_table_t *macros, - scc_pp_macro_table_t *expand_stack, - scc_probe_stream_t **out_stream, int depth) { - // TODO self position and it maybe is a stack on #include ? - // 递归扫描 - if (depth <= 0) { - *out_stream = null; - return false; - } - Assert(stream != null && macros != null && out_stream != null); - - scc_cstring_t identifier = scc_cstring_new(); - scc_pos_t pos = scc_pos_init(); - - cbool ret; - ret = scc_lex_parse_identifier(stream, &pos, &identifier); - Assert(ret == true); - - scc_pp_macro_t *macro = scc_pp_macro_table_get(macros, &identifier); - // 1. 不是宏,直接输出标识符 - // 2. 检查到重复展开跳过 - if (macro == null || - scc_pp_macro_table_get(expand_stack, ¯o->name) != null) { - *out_stream = - scc_mem_probe_stream_new(scc_cstring_as_cstr(&identifier), - scc_cstring_len(&identifier), false); - return true; - } else { - scc_cstring_free(&identifier); - } - - // 根据宏类型展开 - scc_cstring_t tmp_buff = scc_cstring_new(); - if (macro->type == SCC_PP_MACRO_OBJECT) { - cbool ret = scc_pp_expand_object_macro(macro, &tmp_buff); - Assert(ret == true); - } else if (macro->type == SCC_PP_MACRO_FUNCTION) { - // FIXME 是否需要忽略空白字符? - scc_lex_parse_skip_whitespace(stream, &pos); - if (scc_probe_stream_peek(stream) != '(') { - LOG_ERROR("Not a function and skip it"); - goto ERR; - } - scc_pp_macro_list_t params; - ret = parse_macro_arguments(stream, ¶ms); - Assert(ret == true); - scc_pp_expand_function_macro(macro, ¶ms, &tmp_buff); - Assert(ret == true); - } - - // 已经展开的将被标记并入栈 - scc_pp_macro_table_set(expand_stack, - scc_pp_macro_new(¯o->name, macro->type)); - - // 将展开内容变换成stream - scc_probe_stream_t *tmp_stream = scc_mem_probe_stream_new( - scc_cstring_as_cstr(&tmp_buff), scc_cstring_len(&tmp_buff), false); - int ch; - scc_cstring_t real_buff = scc_cstring_new(); - - while ((ch = scc_probe_stream_peek(tmp_stream)) != scc_stream_eof) { - if (scc_lex_parse_is_identifier_prefix(ch)) { - // 递归检查 - scc_probe_stream_t *tmp_out_stream; - if (scc_pp_expand_macro(tmp_stream, macros, expand_stack, - &tmp_out_stream, depth - 1) == false) { - return false; - } - // scc_cstring_append_cstr(); - Assert(tmp_out_stream != null); - while (scc_probe_stream_peek(tmp_out_stream) != scc_stream_eof) { - scc_cstring_append_ch(&real_buff, - scc_probe_stream_consume(tmp_out_stream)); - } - Assert(tmp_out_stream != null && tmp_out_stream->drop != null); - scc_probe_stream_drop(tmp_out_stream); - } else { - scc_cstring_append_ch(&real_buff, - scc_probe_stream_consume(tmp_stream)); - } - } - scc_cstring_free(&tmp_buff); - scc_probe_stream_drop(tmp_stream); - *out_stream = scc_mem_probe_stream_new(scc_cstring_as_cstr(&real_buff), - scc_cstring_len(&real_buff), false); - - // 已经展开的将被标记并出栈 - scc_pp_macro_table_remove(expand_stack, ¯o->name); - return true; -ERR: - *out_stream = null; - return false; -} diff --git a/libs/pprocessor/src/pprocessor.c b/libs/pprocessor/src/pprocessor.c index 25f55ac..8ce17d9 100644 --- a/libs/pprocessor/src/pprocessor.c +++ b/libs/pprocessor/src/pprocessor.c @@ -9,7 +9,11 @@ #include #include +#ifdef TEST_MODE +#define MAX_MACRO_EXPANSION_DEPTH 16 +#else #define MAX_MACRO_EXPANSION_DEPTH 64 // 防止无限递归的最大展开深度 +#endif static int pp_stream_read_char(scc_probe_stream_t *_stream) { scc_pp_stream_t *stream = (scc_pp_stream_t *)_stream; @@ -30,12 +34,9 @@ RETRY: &stream->self->macro_table); goto RETRY; } else if (scc_lex_parse_is_identifier_prefix(ch)) { - scc_pp_macro_table_t tmp_table; - scc_pp_marco_table_init(&tmp_table); - cbool ret = scc_pp_expand_macro( - stream->input, &stream->self->macro_table, &tmp_table, - &stream->tmp_stream, MAX_MACRO_EXPANSION_DEPTH); - scc_pp_macro_table_drop(&tmp_table); + cbool ret = + scc_pp_expand_macro(stream->input, &stream->self->macro_table, + &stream->tmp_stream, MAX_MACRO_EXPANSION_DEPTH); if (ret == false) { LOG_ERROR("macro_expand_error"); } diff --git a/runtime/libcore/include/core_str.h b/runtime/libcore/include/core_str.h index ce2380f..7734ad0 100644 --- a/runtime/libcore/include/core_str.h +++ b/runtime/libcore/include/core_str.h @@ -20,6 +20,7 @@ typedef struct scc_cstring { * * @return cstring_t 初始化后的对象 */ +// FIXME need using `init` beacuse it not malloc static inline scc_cstring_t scc_cstring_new(void) { return (scc_cstring_t){.data = null, .size = 0, .cap = 0}; } @@ -48,6 +49,10 @@ static inline scc_cstring_t scc_cstring_from_cstr(const char *s) { return (scc_cstring_t){.size = len + 1, .cap = len + 1, .data = data}; } +static inline scc_cstring_t scc_cstring_copy(const scc_cstring_t *s) { + return scc_cstring_from_cstr(s->data); +} + /** * @brief 释放动态字符串占用的内存资源 * @@ -182,4 +187,15 @@ static inline char *scc_cstring_as_cstr(const scc_cstring_t *str) { return str->data; } +static inline char *scc_cstring_move_cstr(scc_cstring_t *str) { + if (str == null || str->data == null) { + return ""; + } + char *ret = str->data; + str->data = null; + str->cap = 0; + str->size = 0; + return ret; +} + #endif /* __SCC_CORE_STR_H__ */ diff --git a/runtime/libcore/include/core_stream.h b/runtime/libcore/include/core_stream.h index 8ea8a30..18afe3a 100644 --- a/runtime/libcore/include/core_stream.h +++ b/runtime/libcore/include/core_stream.h @@ -100,7 +100,7 @@ typedef struct scc_mem_probe_stream { usize data_length; usize curr_pos; // 当前读取位置 usize probe_pos; // 探针位置(用于peek) - cbool owned; // 是否拥有数据(需要释放) + cbool owned; // 是否拥有数据(如果拥有将会自动释放) } scc_mem_probe_stream_t; /** @@ -109,22 +109,22 @@ typedef struct scc_mem_probe_stream { * @param stream 流结构指针 * @param data 数据指针 * @param length 数据长度 - * @param need_copy 是否需要复制数据 + * @param owned 是否拥有数据(如果拥有将会自动释放) * @return core_probe_stream_t* 成功返回流指针,失败返回NULL */ scc_probe_stream_t *scc_mem_probe_stream_init(scc_mem_probe_stream_t *stream, const char *data, usize length, - cbool need_copy); + cbool owned); /** * @brief 构造内存探针流(其中drop会自动释放内存) * * @param data * @param length - * @param need_copy + * @param owned 是否拥有数据(如果拥有将会自动释放) * @return scc_probe_stream_t* */ scc_probe_stream_t *scc_mem_probe_stream_new(const char *data, usize length, - cbool need_copy); + cbool owned); #endif #endif /* __SMCC_CORE_PROBE_STREAM_H__ */ diff --git a/runtime/libcore/src/stream.c b/runtime/libcore/src/stream.c index 5950d2e..de4b7a3 100644 --- a/runtime/libcore/src/stream.c +++ b/runtime/libcore/src/stream.c @@ -125,7 +125,7 @@ static void mem_probe_stream_drop(scc_probe_stream_t *_stream) { scc_probe_stream_t *scc_mem_probe_stream_init(scc_mem_probe_stream_t *stream, const char *data, usize length, - cbool need_copy) { + cbool owned) { if (stream == null || data == null) { LOG_ERROR("param error"); return null; @@ -133,22 +133,11 @@ scc_probe_stream_t *scc_mem_probe_stream_init(scc_mem_probe_stream_t *stream, if (length == 0) { LOG_WARN("input memory is empty"); - need_copy = false; + owned = false; } - stream->owned = need_copy; - if (need_copy) { - char *buf = (char *)scc_malloc(length); - if (buf == null) { - LOG_ERROR("malloc error"); - return null; - } - - scc_memcpy(buf, data, length); - stream->data = buf; - } else { - stream->data = data; - } + stream->owned = owned; + stream->data = data; stream->data_length = length; stream->curr_pos = 0; stream->probe_pos = 0; @@ -176,7 +165,7 @@ static void scc_owned_mem_stream_drop(scc_probe_stream_t *_stream) { } scc_probe_stream_t *scc_mem_probe_stream_new(const char *data, usize length, - cbool need_copy) { + cbool owned) { scc_mem_probe_stream_t *stream = (scc_mem_probe_stream_t *)scc_malloc(sizeof(scc_mem_probe_stream_t)); if (stream == null) { @@ -184,7 +173,7 @@ scc_probe_stream_t *scc_mem_probe_stream_new(const char *data, usize length, } scc_probe_stream_t *ret = - scc_mem_probe_stream_init(stream, data, length, need_copy); + scc_mem_probe_stream_init(stream, data, length, owned); stream->stream.drop = scc_owned_mem_stream_drop; Assert(ret != null); return ret; diff --git a/runtime/libutils/include/hashmap.h b/runtime/libutils/include/hashtable.h similarity index 97% rename from runtime/libutils/include/hashmap.h rename to runtime/libutils/include/hashtable.h index 7701fb8..594c9ac 100644 --- a/runtime/libutils/include/hashmap.h +++ b/runtime/libutils/include/hashtable.h @@ -1,12 +1,12 @@ /** - * @file hashmap.h + * @file hashtable.h * @brief 开放寻址法哈希表实现 * * 提供基于向量容器的哈希表实现,支持动态扩容和墓碑机制 */ -#ifndef __SCC_HASHMAP_H__ -#define __SCC_HASHMAP_H__ +#ifndef __SCC_HASHTABLE_H__ +#define __SCC_HASHTABLE_H__ #include @@ -121,4 +121,4 @@ typedef int (*scc_hashtable_iter_fn)(const void *key, void *value, void scc_hashtable_foreach(scc_hashtable_t *ht, scc_hashtable_iter_fn iter_func, void *context); -#endif /* __SCC_HASHMAP_H__ */ +#endif /* __SCC_HASHTABLE_H__ */ diff --git a/runtime/libutils/include/libutils.h b/runtime/libutils/include/libutils.h index c9e0639..0ef7256 100644 --- a/runtime/libutils/include/libutils.h +++ b/runtime/libutils/include/libutils.h @@ -1,9 +1,9 @@ #ifndef __SMCC_UTILS_H__ #define __SMCC_UTILS_H__ -#include "hashmap.h" +#include "hashtable.h" #include "kllist.h" #include "strpool.h" #include -#endif // __SMCC_UTILS_H__ +#endif /* __SMCC_UTILS_H__ */ diff --git a/runtime/libutils/include/strpool.h b/runtime/libutils/include/strpool.h index 707a130..7f00555 100644 --- a/runtime/libutils/include/strpool.h +++ b/runtime/libutils/include/strpool.h @@ -8,7 +8,7 @@ #ifndef __SCC_STRPOOL_H__ #define __SCC_STRPOOL_H__ -#include "hashmap.h" +#include "hashtable.h" #include /** diff --git a/runtime/libutils/src/hashmap.c b/runtime/libutils/src/hashtable.c similarity index 99% rename from runtime/libutils/src/hashmap.c rename to runtime/libutils/src/hashtable.c index 6fbb380..bb2f0ed 100644 --- a/runtime/libutils/src/hashmap.c +++ b/runtime/libutils/src/hashtable.c @@ -1,4 +1,4 @@ -#include +#include #ifndef SCC_INIT_HASHMAP_SIZE #define SCC_INIT_HASHMAP_SIZE (32) diff --git a/runtime/libutils/src/vector-gdb.py b/runtime/libutils/src/vector-gdb.py deleted file mode 100644 index e3d6a1a..0000000 --- a/runtime/libutils/src/vector-gdb.py +++ /dev/null @@ -1,112 +0,0 @@ -# vector_gdb.py -import gdb # type: ignore -from gdb.printing import PrettyPrinter # type: ignore - -class VectorPrinter: - """兼容新旧注册方式的最终方案""" - - def __init__(self, val: gdb.Value): - self.val:gdb.Value = val - - def check_type(self) -> bool: - """类型检查(兼容匿名结构体)""" - try: - if self.val.type.code != gdb.TYPE_CODE_STRUCT: - return False - fields = self.val.type.fields() - if not fields: - return False - exp = ['size', 'cap', 'data'] - for t in fields: - if t.name in exp: - exp.remove(t.name) - else: - return False - return True - except gdb.error: - return False - - def to_string(self): - if not self.check_type(): - return "Not a vector" - - return "vector({} size={}, cap={})".format( - self.val.address, - self.val['size'], - self.val['cap'], - ) - - def display_hint(self): - return 'array' - - def children(self): - """生成数组元素(关键改进点)""" - if not self.check_type(): - return [] - - size = int(self.val['size']) - cap = int(self.val['cap']) - data_ptr = self.val['data'] - - if cap == 0 or data_ptr == 0: - return [] - - # 使用 GDB 内置数组转换 - array = data_ptr.dereference() - array = array.cast(data_ptr.type.target().array(cap - 1)) - - for i in range(size): - # state = "" if i < size else "" - try: - value = array[i] - yield (f"[{i}] {value.type} {value.address}", value) - except gdb.MemoryError: - yield (f"[{i}]", "") - -# 注册方式一:传统append方法(您之前有效的方式)self -def append_printer(): - gdb.pretty_printers.append( - lambda val: VectorPrinter(val) if VectorPrinter(val).check_type() else None - ) - -# 注册方式二:新版注册方法(备用方案) -def register_new_printer(): - class VectorPrinterLocator(PrettyPrinter): - def __init__(self): - super().__init__("vector_printer") - - def __call__(self, val): - ret = VectorPrinter(val).check_type() - print(f"ret {ret}, type {val.type}, {[(i.name, i.type) for i in val.type.fields()]}") - return None - - gdb.printing.register_pretty_printer( - gdb.current_objfile(), - VectorPrinterLocator() - ) - -# 双重注册保证兼容性 -append_printer() # 保留您原来有效的方式 -# register_new_printer() # 添加新版注册 - -class VectorInfoCommand(gdb.Command): - """保持原有命令不变""" - def __init__(self): - super().__init__("vector_info", gdb.COMMAND_USER) - - def invoke(self, argument, from_tty): - val = gdb.parse_and_eval(argument) - printer = VectorPrinter(val) - - if not printer.check_type(): - print("Invalid vector") - return - - print("=== Vector Details ===") - print("Size:", val['size']) - print("Capacity:", val['cap']) - print("Elements:") - for name, value in printer.children(): - print(f" {name}: {value}") - -VectorInfoCommand() diff --git a/runtime/runtime_gdb.py b/runtime/runtime_gdb.py new file mode 100644 index 0000000..700ae65 --- /dev/null +++ b/runtime/runtime_gdb.py @@ -0,0 +1,222 @@ +"https://sourceware.org/gdb/current/onlinedocs/gdb.html/Python-API.html#Python-API" + +import gdb # type: ignore + + +class VectorPrinter(gdb.ValuePrinter): + """兼容新旧注册方式的最终方案""" + + def __init__(self, val: gdb.Value): + self.val: gdb.Value = val + + @staticmethod + def check_type(val: gdb.Value) -> bool: + """类型检查(兼容匿名结构体)""" + try: + if val.type.code not in (gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_TYPEDEF): + return False + if val.type.name == "scc_cstring_t": + return False + fields = val.type.fields() + if not fields: + return False + exp = ["size", "cap", "data"] + for t in fields: + if t.name in exp: + exp.remove(t.name) + else: + return False + return True + except gdb.error: + return False + except ValueError: + return False + except TypeError: + return False + except Exception as e: + print(f"[DEBUG] Unknown exception type: {type(e).__name__}") + print(f"[DEBUG] Exception details: {e}") + print( + f"[DEBUG] val type: {val.type if hasattr(val, 'type') else 'no type attr'}" + ) + return False + + def to_string(self): + """ + GDB will call this method to display the string representation + of the value passed to the object's constructor. + + This is a basic method, and is optional. + + When printing from the CLI, if the to_string method exists, + then GDB will prepend its result to the values returned by children. + Exactly how this formatting is done is dependent on the display hint, + and may change as more hints are added. Also, depending on the print settings + (see Print Settings), the CLI may print just the result of to_string + in a stack trace, omitting the result of children. + + If this method returns a string, it is printed verbatim. + + Otherwise, if this method returns an instance of gdb.Value, + then GDB prints this value. This may result in a call to another pretty-printer. + + If instead the method returns a Python value which is convertible to a gdb.Value, + then GDB performs the conversion and prints the resulting value. Again, + this may result in a call to another pretty-printer. Python scalars + (integers, floats, and booleans) and strings are convertible to gdb.Value; + other types are not. + + Finally, if this method returns None then no further operations are performed + in this method and nothing is printed. + + If the result is not one of these types, an exception is raised. + + https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API + """ + return ( + f"vector({self.val.address} size={self.val['size']}, cap={self.val['cap']})" + ) + + def display_hint(self): + """ + The CLI may call this method and use its result to change the formatting of a value. + The result will also be supplied to an MI consumer as a 'displayhint' + attribute of the variable being printed. + + This is a basic method, and is optional. If it does exist, + this method must return a string or the special value None. + + Some display hints are predefined by GDB: + + 'array' + Indicate that the object being printed is “array-like”. + The CLI uses this to respect parameters such as set print elements and set print array. + + 'map' + Indicate that the object being printed is “map-like”, + and that the children of this value can be assumed to alternate between keys and values. + + 'string' + Indicate that the object being printed is “string-like”. + If the printer's to_string method returns a Python string of some kind, + then GDB will call its internal language-specific string-printing function + to format the string. For the CLI this means adding quotation marks, possibly + escaping some characters, respecting set print elements, and the like. + + The special value None causes GDB to apply the default display rules. + + https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API + """ + return "array" + + def num_children(self): + """ + This is not a basic method, so GDB will only ever call it for objects + derived from gdb.ValuePrinter. + + If available, this method should return the number of children. + + None may be returned if the number can't readily be computed. + + https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API + """ + return int(self.val["size"]) + + def children(self): + """ + This is not a basic method, so GDB will only ever call it for objects + derived from gdb.ValuePrinter. + + If available, this method should return the child item (that is, + a tuple holding the name and value of this child) indicated by n. + Indices start at zero. + + GDB provides a function which can be used to look up the default + pretty-printer for a gdb.Value: + + https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing-API.html#Pretty-Printing-API + """ + size = int(self.val["size"]) + cap = int(self.val["cap"]) + data_ptr = self.val["data"] + + if cap == 0 or data_ptr == 0: + return [] + + # 使用 GDB 内置数组转换 + array = data_ptr.dereference() + array = array.cast(data_ptr.type.target().array(cap - 1)) + + for i in range(size): + # state = "" if i < size else "" + try: + value = array[i] + yield (f"[{i}] {value.type} {value.address}", value) + except gdb.MemoryError: + yield (f"[{i}]", "") + + +class HashTablePrinter(gdb.ValuePrinter): + def __init__(self, val: gdb.Value): + self.val: gdb.Value = val + + @staticmethod + def check_type(val: gdb.Value) -> bool: + if val.type.name in ["scc_hashtable_t", "scc_hashtable"]: + return True + return False + + +def append_printer(): + "注册方式一:传统append方法(您之前有效的方式)self" + gdb.pretty_printers.append( + lambda val: VectorPrinter(val) if VectorPrinter.check_type(val) else None + ) + + +def register_new_printer(): + "注册方式二:新版注册方法(备用方案)" + + def str_lookup_function(val): + if VectorPrinter.check_type(val) is False: + return None + ret = VectorPrinter(val) + # print( + # f"ret {ret}, type {val.type.name}, {[(i.name, i.type) for i in val.type.fields()]}" + # ) + return ret + + gdb.printing.register_pretty_printer(gdb.current_objfile(), str_lookup_function) + # if gdb.current_progspace() is not None: + # pts = gdb.current_progspace().pretty_printers + # print(pts, len(pts)) + # pts.append(str_lookup_function) + + +class VectorInfoCommand(gdb.Command): + """保持原有命令不变""" + + def __init__(self): + super().__init__("vector_info", gdb.COMMAND_USER) + + def invoke(self, argument, from_tty): + val = gdb.parse_and_eval(argument) + + if not VectorPrinter.check_type(val): + print("Invalid vector") + return + + printer = VectorPrinter(val) + print("=== Vector Details ===") + print("Size:", val["size"]) + print("Capacity:", val["cap"]) + print("Elements:") + for name, value in printer.children(): + print(f" {name}: {value}") + + +if __name__ == "__main__": + # 双重注册保证兼容性 + # append_printer() # 保留您原来有效的方式 + register_new_printer() # 添加新版注册 + VectorInfoCommand()