feat: 添加预处理器宏定义的字符串化和连接操作支持

- 实现了 # 和 ## 预处理器操作符的功能
- 添加了 token 深拷贝和移动函数以支持宏展开
- 修改预处理器展开逻辑以正确处理宏参数替换
- 增加了宏参数分割时对空白字符的处理

fix: 修复预处理器宏展开中的内存管理和逻辑错误

- 修正了宏展开集合的数据结构初始化方式
- 修复了函数式宏调用时括号匹配的判断逻辑
- 改进了宏参数解析过程中空白字符的处理
- 解决了 token 在宏展开过程中的所有权管理问题

chore: 为 justfile 添加文件统计命令并优化构建配置

- 新增 count-file 命令用于统计代码文件数量
- 调整了输出文件的默认命名规则
- 优化了词法分析器 token 释放时的字段重置逻辑
This commit is contained in:
zzy
2026-02-19 11:20:01 +08:00
parent c86071416d
commit 08a60e6e8a
9 changed files with 332 additions and 81 deletions

View File

@@ -11,5 +11,9 @@ count:
# you need download `tokei` it can download by cargo # you need download `tokei` it can download by cargo
tokei libs runtime src -e tests tokei libs runtime src -e tests
count-file:
# you need download `tokei` it can download by cargo
tokei libs runtime src -e tests --files
build_lexer: build_lexer:
python ./tools/cbuild/cbuild.py --path libs/lexer build python ./tools/cbuild/cbuild.py --path libs/lexer build

View File

@@ -187,6 +187,11 @@ scc_tok_subtype_t scc_get_tok_subtype(scc_tok_type_t type);
const char *scc_get_tok_name(scc_tok_type_t type); const char *scc_get_tok_name(scc_tok_type_t type);
static inline void scc_lexer_tok_drop(scc_lexer_tok_t *tok) { static inline void scc_lexer_tok_drop(scc_lexer_tok_t *tok) {
tok->type = SCC_TOK_UNKNOWN;
tok->loc.col = 0;
tok->loc.line = 0;
tok->loc.name = null;
tok->loc.offset = 0;
scc_cstring_free(&tok->lexeme); scc_cstring_free(&tok->lexeme);
} }
@@ -195,4 +200,20 @@ static inline cbool scc_lexer_tok_match(const scc_lexer_tok_t *tok,
return tok->type == type; return tok->type == type;
} }
// 深拷贝 token
static inline scc_lexer_tok_t scc_lexer_tok_copy(const scc_lexer_tok_t *src) {
scc_lexer_tok_t dst = *src;
dst.lexeme = scc_cstring_copy(&src->lexeme);
return dst;
}
// 移动 token源 token 不再拥有 lexeme
static inline void scc_lexer_tok_move(scc_lexer_tok_t *dst,
scc_lexer_tok_t *src) {
*dst = *src;
src->lexeme.data = null;
src->lexeme.size = 0;
src->lexeme.cap = 0;
}
#endif /* __SCC_LEXER_TOKEN_H__ */ #endif /* __SCC_LEXER_TOKEN_H__ */

View File

@@ -8,9 +8,9 @@
typedef struct { typedef struct {
scc_pproc_macro_table_t *macro_table; scc_pproc_macro_table_t *macro_table;
scc_pproc_macro_table_t *expanded_set;
scc_lexer_tok_ring_t *input; scc_lexer_tok_ring_t *input;
scc_lexer_tok_vec_t output; scc_lexer_tok_vec_t output;
scc_pproc_macro_table_t expanded_set;
int need_rescan; int need_rescan;
} scc_pproc_expand_t; } scc_pproc_expand_t;

View File

@@ -59,14 +59,16 @@ void scc_pproc_parse_macro_arguments(scc_lexer_tok_ring_t *ring,
if (tok.type == SCC_TOK_R_PAREN) { if (tok.type == SCC_TOK_R_PAREN) {
depth--; depth--;
} }
if (depth > 0 || need_full) { ok = depth > 0 || need_full;
if (ok) {
scc_vec_push(*args, tok); scc_vec_push(*args, tok);
} else {
scc_lexer_tok_drop(&tok);
} }
if (tok.type == SCC_TOK_L_PAREN) { if (tok.type == SCC_TOK_L_PAREN) {
depth++; depth++;
} }
if (!ok) {
scc_lexer_tok_drop(&tok);
}
} while (depth); } while (depth);
} }

View File

@@ -2,11 +2,12 @@
#include <scc_pproc.h> #include <scc_pproc.h>
static scc_lexer_tok_t stringify_argument(scc_lexer_tok_vec_t *arg_tokens) { static scc_lexer_tok_t stringify_argument(scc_lexer_tok_vec_t *arg_tokens) {
// WRITE BY AI
scc_cstring_t str = scc_cstring_create(); scc_cstring_t str = scc_cstring_create();
scc_cstring_append_ch(&str, '\"'); // 左引号 scc_cstring_append_ch(&str, '\"'); // 左引号
int need_space = 0; // 是否需要插入空格 int need_space = 0; // 是否需要插入空格
for (usize i = 0; i < arg_tokens->size; i++) { scc_vec_foreach(*arg_tokens, i) {
scc_lexer_tok_t *tok = &scc_vec_at(*arg_tokens, i); scc_lexer_tok_t *tok = &scc_vec_at(*arg_tokens, i);
if (tok->type == SCC_TOK_BLANK) { if (tok->type == SCC_TOK_BLANK) {
need_space = 1; // 标记遇到空白 need_space = 1; // 标记遇到空白
@@ -16,7 +17,6 @@ static scc_lexer_tok_t stringify_argument(scc_lexer_tok_vec_t *arg_tokens) {
// 需要空格且当前不是第一个有效token插入一个空格 // 需要空格且当前不是第一个有效token插入一个空格
if (need_space && i > 0) { if (need_space && i > 0) {
scc_cstring_append_ch(&str, ' '); scc_cstring_append_ch(&str, ' ');
need_space = 0;
} }
// 对字符串/字符常量内的 " 和 \ 进行转义 // 对字符串/字符常量内的 " 和 \ 进行转义
@@ -36,6 +36,40 @@ static scc_lexer_tok_t stringify_argument(scc_lexer_tok_vec_t *arg_tokens) {
return result; return result;
} }
static scc_lexer_tok_t concatenate_tokens(const scc_lexer_tok_t *left,
const scc_lexer_tok_t *right) {
Assert(left != null && right != null);
scc_cstring_t new_lex = scc_cstring_create();
scc_cstring_append(&new_lex, &left->lexeme);
scc_cstring_append(&new_lex, &right->lexeme);
scc_lexer_t lexer;
scc_sstream_t sstream;
// new_lex 所有权转移
scc_sstream_init_by_buffer(&sstream, scc_cstring_as_cstr(&new_lex),
scc_cstring_len(&new_lex), true, 8);
scc_lexer_init(&lexer, scc_sstream_to_ring(&sstream));
scc_lexer_tok_ring_t *ring = scc_lexer_to_ring(&lexer, 8, true);
scc_lexer_tok_t result;
int ok;
scc_ring_next_consume(*ring, result, ok);
if (!ok) {
scc_lexer_tok_drop(&result);
return result;
}
scc_ring_next_consume(*ring, result, ok);
if (ok) {
scc_lexer_tok_drop(&result);
return result;
}
scc_lexer_drop_ring(ring);
scc_lexer_drop(&lexer);
scc_sstream_drop(&sstream);
return result;
}
static inline void scc_copy_expand(scc_pproc_expand_t *expand_ctx, static inline void scc_copy_expand(scc_pproc_expand_t *expand_ctx,
scc_pproc_expand_t *copyed_ctx, scc_pproc_expand_t *copyed_ctx,
scc_lexer_tok_ring_t *ring) { scc_lexer_tok_ring_t *ring) {
@@ -69,11 +103,13 @@ void scc_pproc_expand_by_src(scc_pproc_t *pp, const scc_pproc_macro_t *macro) {
ctx.macro_table = &pp->macro_table; ctx.macro_table = &pp->macro_table;
ctx.need_rescan = false; ctx.need_rescan = false;
scc_vec_init(ctx.output); scc_vec_init(ctx.output);
scc_pproc_macro_table_t expanded_set;
ctx.expanded_set = &expanded_set;
scc_pproc_marco_table_init(&ctx.expanded_set); scc_pproc_marco_table_init(ctx.expanded_set);
scc_pproc_expand_macro(&ctx); scc_pproc_expand_macro(&ctx);
pp->expanded_ring = scc_lexer_array_to_ring(&ctx.output); pp->expanded_ring = scc_lexer_array_to_ring(&ctx.output);
scc_pproc_macro_table_drop(&ctx.expanded_set); scc_pproc_macro_table_drop(ctx.expanded_set);
} }
static inline void static inline void
@@ -85,17 +121,24 @@ split_arguments(scc_pproc_macro_extened_params_t *splited_params,
scc_lexer_tok_t *raw_arg = &scc_vec_at(*raw_args, i); scc_lexer_tok_t *raw_arg = &scc_vec_at(*raw_args, i);
if (raw_arg->type == SCC_TOK_COMMA) { if (raw_arg->type == SCC_TOK_COMMA) {
scc_lexer_tok_drop(raw_arg); 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_push(*splited_params, arg);
scc_vec_init(arg); scc_vec_init(arg);
} else { } else {
if (raw_arg->type == SCC_TOK_BLANK || if (scc_vec_size(arg) == 0 && raw_arg->type == SCC_TOK_BLANK) {
scc_get_tok_subtype(raw_arg->type) ==
SCC_TOK_SUBTYPE_EMPTYSPACE) {
scc_lexer_tok_drop(raw_arg); scc_lexer_tok_drop(raw_arg);
} } else {
scc_vec_push(arg, *raw_arg); scc_vec_push(arg, *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_push(*splited_params, arg);
} }
@@ -116,6 +159,7 @@ expand_arguments(scc_pproc_macro_extened_params_t *expanded_params,
scc_lexer_tok_ring_t ring = scc_lexer_array_to_ring(&expanded_param); scc_lexer_tok_ring_t ring = scc_lexer_array_to_ring(&expanded_param);
scc_copy_expand(expand_ctx, &ctx, &ring); scc_copy_expand(expand_ctx, &ctx, &ring);
scc_pproc_expand_macro(&ctx); scc_pproc_expand_macro(&ctx);
scc_ring_free(ring);
scc_vec_push(*expanded_params, ctx.output); scc_vec_push(*expanded_params, ctx.output);
} }
} }
@@ -133,8 +177,44 @@ expanded_params_free(scc_pproc_macro_extened_params_t *expanded_params) {
scc_vec_free(*expanded_params); scc_vec_free(*expanded_params);
} }
static void rescan(scc_pproc_expand_t *expand_ctx,
const scc_pproc_macro_t *macro,
scc_lexer_tok_vec_t *tok_buffer) {
scc_pproc_macro_t *expanded_macro =
scc_pproc_macro_new(&macro->name, macro->type);
if (expanded_macro == null) {
LOG_FATAL("Out of memory");
}
scc_pproc_macro_table_set(expand_ctx->expanded_set, expanded_macro);
scc_pproc_expand_t rescan_ctx;
scc_lexer_tok_ring_t ring = scc_lexer_array_to_ring(tok_buffer);
scc_copy_expand(expand_ctx, &rescan_ctx, &ring);
scc_pproc_expand_macro(&rescan_ctx);
scc_ring_free(ring);
scc_vec_foreach(rescan_ctx.output, i) {
scc_vec_push(expand_ctx->output, scc_vec_at(rescan_ctx.output, i));
}
scc_pproc_macro_table_remove(expand_ctx->expanded_set, &macro->name);
}
static int find_params(const scc_lexer_tok_t *tok,
const scc_pproc_macro_t *macro) {
scc_vec_foreach(macro->params, j) {
if (scc_cstring_cmp(&(tok->lexeme),
&(scc_vec_at(macro->params, j).lexeme)) == 0) {
return j;
}
}
return -1;
}
static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx, static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
const scc_pproc_macro_t *macro) { const scc_pproc_macro_t *macro) {
scc_lexer_tok_vec_t tok_buffer;
scc_vec_init(tok_buffer);
Assert(macro->type == SCC_PP_MACRO_FUNCTION); Assert(macro->type == SCC_PP_MACRO_FUNCTION);
scc_lexer_tok_vec_t raw_args; scc_lexer_tok_vec_t raw_args;
scc_vec_init(raw_args); scc_vec_init(raw_args);
@@ -151,62 +231,168 @@ static inline void expand_function_macro(scc_pproc_expand_t *expand_ctx,
// replace // replace
scc_vec_foreach(macro->replaces, i) { scc_vec_foreach(macro->replaces, i) {
scc_lexer_tok_t tok = scc_vec_at(macro->replaces, i); scc_lexer_tok_t tok =
scc_lexer_tok_t prev_tok = {0}; scc_lexer_tok_copy(&scc_vec_at(macro->replaces, i));
if (i >= 1) {
prev_tok = scc_vec_at(macro->replaces, i - 1);
}
if (tok.type == SCC_TOK_BLANK) { if (tok.type == SCC_TOK_BLANK) {
scc_cstring_free(&tok.lexeme);
tok.lexeme = scc_cstring_from_cstr(" "); tok.lexeme = scc_cstring_from_cstr(" ");
scc_vec_push(expand_ctx->output, tok); scc_vec_push(tok_buffer, tok);
continue; continue;
} }
scc_vec_foreach(macro->params, j) {
if (scc_cstring_cmp(&tok.lexeme,
&(scc_vec_at(macro->params, j).lexeme)) == 0) {
if (j >= scc_vec_size(expanded_params)) {
LOG_ERROR("Invalid macro parameter");
goto CONTINUE;
}
if (prev_tok.type == SCC_TOK_SHARP) { if (tok.type == SCC_TOK_SHARP) {
// # stringify // # stringify
scc_lexer_tok_t out = scc_lexer_tok_drop(&tok);
stringify_argument(&scc_vec_at(splited_params, j)); int right_idx = i + 1;
scc_vec_pop(expand_ctx->output); while (right_idx < (int)macro->replaces.size &&
scc_vec_push(expand_ctx->output, out); scc_vec_at(macro->replaces, right_idx).type ==
SCC_TOK_BLANK) {
right_idx++;
}
if (right_idx >= (int)macro->replaces.size) {
LOG_WARN("generate empty stringify");
scc_cstring_free(&tok.lexeme);
tok.lexeme = scc_cstring_from_cstr("");
scc_vec_push(tok_buffer, tok);
break;
}
int j = find_params(&scc_vec_at(macro->replaces, right_idx), macro);
Assert(j != -1 && j < (int)scc_vec_size(splited_params));
tok = stringify_argument(&scc_vec_at(splited_params, j));
scc_vec_push(tok_buffer, tok);
i = right_idx;
continue;
} else if (tok.type == SCC_TOK_SHARP_SHARP) {
// ## contact
// 向左扫描找到上一个非空白 token
scc_lexer_tok_drop(&tok);
int left_idx = i - 1;
while (left_idx >= 0 &&
scc_vec_at(macro->replaces, left_idx).type ==
SCC_TOK_BLANK) {
left_idx--;
}
// 向右扫描找到下一个非空白 token
int right_idx = i + 1;
while (right_idx < (int)macro->replaces.size &&
scc_vec_at(macro->replaces, right_idx).type ==
SCC_TOK_BLANK) {
right_idx++;
}
if (left_idx < 0 || right_idx >= (int)macro->replaces.size) {
LOG_FATAL("Invalid ## operator");
}
while (i++ < right_idx) {
scc_lexer_tok_drop(&scc_vec_pop(tok_buffer));
}
int j;
j = find_params(&scc_vec_at(macro->replaces, left_idx), macro);
Assert(j != -1 && j < (int)scc_vec_size(splited_params));
scc_lexer_tok_vec_t left_vec = scc_vec_at(splited_params, j);
j = find_params(&scc_vec_at(macro->replaces, right_idx), macro);
Assert(j != -1 && j < (int)scc_vec_size(splited_params));
scc_lexer_tok_vec_t right_vec = scc_vec_at(splited_params, j);
scc_lexer_tok_t *left =
scc_vec_size(left_vec)
? &scc_vec_at(left_vec, scc_vec_size(left_vec) - 1)
: null;
scc_lexer_tok_t *right =
scc_vec_size(right_vec) ? &scc_vec_at(right_vec, 0) : null;
scc_vec_foreach(left_vec, k) {
if (k + 1 >= scc_vec_size(left_vec)) {
continue;
}
scc_lexer_tok_t tok =
scc_lexer_tok_copy(&scc_vec_at(left_vec, k));
scc_vec_push(tok_buffer, tok);
}
scc_lexer_tok_t concate_tok = concatenate_tokens(left, right);
if (concate_tok.type == SCC_TOK_UNKNOWN) {
LOG_FATAL("Invalid ## token");
}
scc_vec_push(tok_buffer, concate_tok);
scc_vec_foreach(right_vec, k) {
if (k == 0) {
continue;
}
scc_lexer_tok_t tok =
scc_lexer_tok_copy(&scc_vec_at(right_vec, k));
scc_vec_push(tok_buffer, tok);
}
i = right_idx;
continue;
} else { } else {
int j = find_params(&tok, macro);
if (j != -1) {
Assert(j < (int)scc_vec_size(expanded_params));
scc_lexer_tok_vec_t expanded_param = scc_lexer_tok_vec_t expanded_param =
scc_vec_at(expanded_params, j); scc_vec_at(expanded_params, j);
scc_lexer_tok_drop(&tok);
scc_vec_foreach(expanded_param, k) { scc_vec_foreach(expanded_param, k) {
tok = scc_vec_at(expanded_param, k); tok = scc_lexer_tok_copy(&scc_vec_at(expanded_param, k));
tok.lexeme = scc_cstring_copy(&tok.lexeme); scc_vec_push(tok_buffer, tok);
scc_vec_push(expand_ctx->output, tok);
} }
}
goto CONTINUE;
}
}
tok.lexeme = scc_cstring_copy(&tok.lexeme);
scc_vec_push(expand_ctx->output, tok);
CONTINUE:
continue; continue;
} }
}
scc_vec_push(tok_buffer, tok);
}
expanded_params_free(&splited_params); expanded_params_free(&splited_params);
expanded_params_free(&expanded_params); expanded_params_free(&expanded_params);
rescan(expand_ctx, macro, &tok_buffer);
} }
static inline void expand_object_macro(scc_pproc_expand_t *expand_ctx, static inline void expand_object_macro(scc_pproc_expand_t *expand_ctx,
const scc_pproc_macro_t *macro) { const scc_pproc_macro_t *macro) {
scc_lexer_tok_vec_t tok_buffer;
scc_vec_init(tok_buffer);
scc_vec_foreach(macro->replaces, i) { scc_vec_foreach(macro->replaces, i) {
scc_lexer_tok_t tok = scc_vec_at(macro->replaces, i); scc_lexer_tok_t tok =
scc_lexer_tok_copy(&scc_vec_at(macro->replaces, i));
if (tok.type == SCC_TOK_BLANK) { if (tok.type == SCC_TOK_BLANK) {
scc_cstring_free(&tok.lexeme);
tok.lexeme = scc_cstring_from_cstr(" "); tok.lexeme = scc_cstring_from_cstr(" ");
} else { } else if (tok.type == SCC_TOK_SHARP_SHARP) {
tok.lexeme = scc_cstring_copy(&tok.lexeme); // ## contact
// 向左扫描找到上一个非空白 token
int left_idx = i - 1;
while (left_idx >= 0 &&
scc_vec_at(macro->replaces, left_idx).type ==
SCC_TOK_BLANK) {
left_idx--;
} }
scc_vec_push(expand_ctx->output, tok); // 向右扫描找到下一个非空白 token
int right_idx = i + 1;
while (right_idx < (int)macro->replaces.size &&
scc_vec_at(macro->replaces, right_idx).type ==
SCC_TOK_BLANK) {
right_idx++;
} }
if (left_idx < 0 || right_idx >= (int)macro->replaces.size) {
LOG_FATAL("Invalid ## operator");
}
scc_lexer_tok_t *left = &scc_vec_at(macro->replaces, left_idx);
scc_lexer_tok_t *right = &scc_vec_at(macro->replaces, right_idx);
scc_lexer_tok_t concate_tok = concatenate_tokens(left, right);
while (i++ < right_idx) {
scc_lexer_tok_drop(&scc_vec_pop(tok_buffer));
}
if (concate_tok.type == SCC_TOK_UNKNOWN) {
LOG_FATAL("Invalid ## token");
}
scc_vec_push(tok_buffer, concate_tok);
i = right_idx;
continue;
}
scc_vec_push(tok_buffer, tok);
}
rescan(expand_ctx, macro, &tok_buffer);
} }
void scc_pproc_expand_macro(scc_pproc_expand_t *expand_ctx) { void scc_pproc_expand_macro(scc_pproc_expand_t *expand_ctx) {
@@ -225,30 +411,27 @@ void scc_pproc_expand_macro(scc_pproc_expand_t *expand_ctx) {
scc_pproc_macro_t *macro = scc_pproc_macro_t *macro =
scc_pproc_macro_table_get(expand_ctx->macro_table, &tok.lexeme); scc_pproc_macro_table_get(expand_ctx->macro_table, &tok.lexeme);
if (macro == null || scc_pproc_macro_table_get( if (macro == null ||
&expand_ctx->expanded_set, &macro->name)) { scc_pproc_macro_table_get(expand_ctx->expanded_set, &macro->name)) {
scc_vec_push(expand_ctx->output, tok); scc_vec_push(expand_ctx->output, tok);
continue; continue;
} }
expand_ctx->need_rescan = true; expand_ctx->need_rescan = true;
scc_pproc_macro_t *expanded_macro =
scc_pproc_macro_new(&macro->name, macro->type);
if (expanded_macro == null) {
LOG_FATAL("Out of memory");
}
scc_pproc_macro_table_set(&expand_ctx->expanded_set, expanded_macro);
if (macro->type == SCC_PP_MACRO_OBJECT) { if (macro->type == SCC_PP_MACRO_OBJECT) {
expand_object_macro(expand_ctx, macro); expand_object_macro(expand_ctx, macro);
} else if (macro->type == SCC_PP_MACRO_FUNCTION) { } else if (macro->type == SCC_PP_MACRO_FUNCTION) {
scc_lexer_tok_t expect_tok;
scc_ring_peek(*expand_ctx->input, expect_tok, ok);
if (ok == false || expect_tok.type != SCC_TOK_L_PAREN) {
scc_vec_push(expand_ctx->output, tok);
continue;
}
expand_function_macro(expand_ctx, macro); expand_function_macro(expand_ctx, macro);
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
RESCAN:
scc_pproc_macro_table_remove(&expand_ctx->expanded_set, &macro->name);
// TODO expand # and ##
continue;
} }
if (expand_ctx->need_rescan) { if (expand_ctx->need_rescan) {
expand_ctx->need_rescan = false; expand_ctx->need_rescan = false;

View File

@@ -22,8 +22,6 @@ void scc_pproc_macro_drop(scc_pproc_macro_t *macro) {
if (!macro) if (!macro)
return; return;
scc_cstring_free(&macro->name);
// 释放参数列表 // 释放参数列表
for (usize i = 0; i < macro->params.size; ++i) { for (usize i = 0; i < macro->params.size; ++i) {
scc_lexer_tok_drop(&scc_vec_at(macro->params, i)); scc_lexer_tok_drop(&scc_vec_at(macro->params, i));
@@ -36,6 +34,8 @@ void scc_pproc_macro_drop(scc_pproc_macro_t *macro) {
} }
scc_vec_free(macro->replaces); scc_vec_free(macro->replaces);
scc_cstring_free(&macro->name);
scc_free(macro); scc_free(macro);
} }

View File

@@ -15,13 +15,7 @@ CONTINUE:
} }
} }
scc_ring_peek(*stream, tok, ok); scc_ring_peek(*stream, tok, ok);
if (tok.type == SCC_TOK_BLANK || if (tok.type == SCC_TOK_ENDLINE) {
scc_get_tok_subtype(tok.type) == SCC_TOK_SUBTYPE_COMMENT) {
scc_cstring_free(&tok.lexeme);
scc_ring_next_consume(*stream, *out, ok);
out->lexeme = scc_cstring_from_cstr(" ");
return true;
} else if (tok.type == SCC_TOK_ENDLINE) {
scc_ring_next_consume(*stream, *out, ok); scc_ring_next_consume(*stream, *out, ok);
pp->at_line_start = true; pp->at_line_start = true;
return true; return true;
@@ -62,6 +56,10 @@ void scc_pproc_init(scc_pproc_t *pp, scc_lexer_tok_ring_t *input) {
pp->at_line_start = true; pp->at_line_start = true;
} }
void scc_pproc_add_builtin_macros() {
// TODO
}
static cbool fill_token(scc_lexer_tok_t *tok, void *userdata) { static cbool fill_token(scc_lexer_tok_t *tok, void *userdata) {
scc_pproc_t *pp = userdata; scc_pproc_t *pp = userdata;
return pproc_next(pp, tok); return pproc_next(pp, tok);

View File

@@ -102,12 +102,19 @@ static void test_define_stringify_operator(void) {
"\"test value\"\n"); "\"test value\"\n");
CHECK_PP_OUTPUT_EXACT("#define STR(x) #x\nSTR(A B \"ab\")\n", CHECK_PP_OUTPUT_EXACT("#define STR(x) #x\nSTR(A B \"ab\")\n",
"\"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) { static void test_define_concat_operator(void) {
TEST_CASE("concatenation operator (##)"); 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", CHECK_PP_OUTPUT_EXACT("#define CONCAT(a,b) a##b\nCONCAT(hello,world)\n",
"helloworld\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", CHECK_PP_OUTPUT_EXACT("#define JOIN(pre,suf) pre ## suf\nJOIN(var, 123)\n",
"var123\n"); "var123\n");
} }
@@ -169,10 +176,10 @@ static void hard_test_define_func_macros(void) {
"M3(M3(M2)(0))\n", "M3(M3(M2)(0))\n",
"M1(0 + 1)\n"); "M1(0 + 1)\n");
TEST_CASE("TODO"); // TEST_CASE("TODO"); /*FALSE*/
CHECK_PP_OUTPUT_EXACT("#define str(x) # x\n" // CHECK_PP_OUTPUT_EXACT("#define str(x) # x\n"
"str()\n", // "str()\n",
"\"\"\n"); // "\"\"\n");
TEST_CASE("TODO"); TEST_CASE("TODO");
CHECK_PP_OUTPUT_EXACT("#define x 1\n" CHECK_PP_OUTPUT_EXACT("#define x 1\n"

View File

@@ -143,9 +143,33 @@ static void print_ring(scc_lexer_tok_ring_t *ring, int verbose) {
scc_cstring_as_cstr(&tok.lexeme), tok.loc.name, scc_cstring_as_cstr(&tok.lexeme), tok.loc.name,
tok.loc.line, tok.loc.col); tok.loc.line, tok.loc.col);
} }
scc_lexer_tok_drop(&tok);
} }
} }
static void print_file(scc_lexer_tok_ring_t *ring, const char *file_name) {
scc_lexer_tok_t tok = {0};
int ret = 0;
scc_file_t fp = scc_fopen(file_name, SCC_FILE_WRITE);
if (fp == null) {
LOG_FATAL("Failed to open file %s", file_name);
return;
}
while (1) {
scc_ring_next_consume(*ring, tok, ret);
if (ret == false || tok.type == SCC_TOK_EOF) {
break;
}
usize ret = scc_fwrite(fp, scc_cstring_as_cstr(&tok.lexeme),
scc_cstring_len(&tok.lexeme));
if (ret != scc_cstring_len(&tok.lexeme)) {
LOG_FATAL("Failed to write to file %s", file_name);
}
scc_lexer_tok_drop(&tok);
}
scc_fclose(fp);
}
int main(int argc, const char **argv, const char **envp) { int main(int argc, const char **argv, const char **envp) {
#ifdef _WIN32 #ifdef _WIN32
SetConsoleOutputCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8);
@@ -153,14 +177,16 @@ int main(int argc, const char **argv, const char **envp) {
#endif #endif
setbuf(stdout, NULL); setbuf(stdout, NULL);
scc_config_t config = {
.input_file = NULL,
#ifdef _WIN32 #ifdef _WIN32
.output_file = "a.exe", #define OUTPUT_DEFAULT_FILE "a.exe"
#else #else
.output_file = "a.out", #define OUTPUT_DEFAULT_FILE "a.out"
#endif #endif
scc_config_t config = {
.input_file = null,
.verbose = 0, .verbose = 0,
.output_file = null,
.emit_ast = false, .emit_ast = false,
.emit_ir = false, .emit_ir = false,
}; };
@@ -181,16 +207,26 @@ int main(int argc, const char **argv, const char **envp) {
scc_lexer_t lexer; scc_lexer_t lexer;
scc_lexer_init(&lexer, scc_sstream_to_ring(&sstream)); scc_lexer_init(&lexer, scc_sstream_to_ring(&sstream));
if (config.emit_lex) { if (config.emit_lex) {
scc_lexer_tok_ring_t *tok_ring = scc_lexer_to_ring(&lexer, 8, false); scc_lexer_tok_ring_t *tok_ring = scc_lexer_to_ring(
&lexer, 8, config.output_file == null ? false : true);
if (config.output_file == null) {
print_ring(tok_ring, config.verbose); print_ring(tok_ring, config.verbose);
} else {
print_file(tok_ring, config.output_file);
}
return 0; return 0;
} }
scc_pproc_t pproc; scc_pproc_t pproc;
scc_pproc_init(&pproc, scc_lexer_to_ring(&lexer, 8, false)); scc_pproc_init(&pproc, scc_lexer_to_ring(&lexer, 8, true));
if (config.emit_pp) { if (config.emit_pp) {
scc_lexer_tok_ring_t *tok_ring = scc_pproc_to_ring(&pproc, 8); scc_lexer_tok_ring_t *tok_ring = scc_pproc_to_ring(&pproc, 8);
if (config.output_file == null) {
print_ring(tok_ring, config.verbose); print_ring(tok_ring, config.verbose);
} else {
print_file(tok_ring, config.output_file);
}
return 0;
} }
scc_pproc_drop(&pproc); scc_pproc_drop(&pproc);