feat(compiler): 添加对裸机环境的支持并改进构建配置

- 更新README描述为C语言裸机环境的自举编译器
- 修改justfile中的构建命令,添加--dev参数并将输出文件名从scc.exe改为scc
- 在AST定义中添加SCC_AST_UNKNOWN节点类型
- 修复位置日志格式化中的类型错误
- 实现标准输出流支持,当输出文件为'-'时输出到控制台
- 支持基于环境变量LANG的语言本地化选择

fix(lexer): 改进标记打印功能

- 修复换行符的显示,将实际换行符显示为"\n"
- 改进文件输出逻辑,支持标准输出流

refactor(build): 更新cbuild工具的包含路径

- 将包含路径从"scc_libs"更改为"scc_include"

test: 添加简单的包含测试用例

- 新增测试文件tests/simple/12_include.c用于测试头文件包含功能
This commit is contained in:
zzy
2026-02-26 16:07:19 +08:00
parent 13de9d713b
commit 4e2176b7f0
8 changed files with 54 additions and 21 deletions

View File

@@ -36,7 +36,8 @@ static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
static const char *scc_hints_en[] = {
[SCC_HINT_PROG_NAME] = "scc",
[SCC_HINT_DESCRIPTION] = "A simple C compiler",
[SCC_HINT_OUTPUT_FILE] = "Output file",
[SCC_HINT_OUTPUT_FILE] =
"Output file (`-` means standard output stream file)",
[SCC_HINT_INPUT_FILE] = "Input source file",
[SCC_HINT_INCLUDE_PATH] = "Add directory to the include search paths",
[SCC_HINT_VERBOSE] = "Increase verbosity (can be used multiple times)",
@@ -48,7 +49,7 @@ static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
static const char *scc_hints_zh[] = {
[SCC_HINT_PROG_NAME] = "scc",
[SCC_HINT_DESCRIPTION] = "一个简单的C编译器",
[SCC_HINT_OUTPUT_FILE] = "输出文件",
[SCC_HINT_OUTPUT_FILE] = "输出文件(`-`表示标准输出流文件)",
[SCC_HINT_INPUT_FILE] = "输入源文件",
[SCC_HINT_INCLUDE_PATH] = "添加系统头文件到搜索路径",
[SCC_HINT_VERBOSE] = "增加详细输出(可多次使用)",
@@ -147,10 +148,11 @@ static void print_ring(scc_lexer_tok_ring_t *ring, int verbose) {
if (verbose == 0) {
scc_printf("%s ", scc_get_tok_name(tok.type));
} else if (verbose >= 1) {
scc_printf("token [%-8s] `%s` at %s:%d:%d\n",
scc_get_tok_name(tok.type),
scc_cstring_as_cstr(&tok.lexeme), tok.loc.name,
tok.loc.line, tok.loc.col);
scc_printf(
"token [%-8s] `%s` at %s:%d:%d\n", scc_get_tok_name(tok.type),
tok.type != SCC_TOK_ENDLINE ? scc_cstring_as_cstr(&tok.lexeme)
: "\\n",
tok.loc.name, tok.loc.line, tok.loc.col);
}
scc_lexer_tok_drop(&tok);
}
@@ -159,20 +161,28 @@ static void print_ring(scc_lexer_tok_ring_t *ring, int verbose) {
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;
scc_file_t fp = null;
cbool is_stdout = scc_strcmp(file_name, "-") == 0;
if (!is_stdout) {
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);
if (is_stdout) {
scc_printf("%s", scc_cstring_as_cstr(&tok.lexeme));
} else {
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);
}
@@ -190,6 +200,13 @@ int main(int argc, const char **argv, const char **envp) {
#else
#define OUTPUT_DEFAULT_FILE "a.out"
#endif
scc_argparse_lang_t argparse_lang = SCC_ARGPARSE_LANG_EN;
for (const char **env = envp; *env != null; env++) {
const char *env_str = *env;
if (scc_strcmp(env_str, "LANG=zh_CN.UTF-8") == 0) {
argparse_lang = SCC_ARGPARSE_LANG_ZH;
}
}
scc_config_t config = {
.input_file = null,
@@ -201,11 +218,11 @@ int main(int argc, const char **argv, const char **envp) {
scc_vec_init(config.include_paths);
scc_argparse_t argparse;
setup_argparse(&argparse, &config, SCC_ARGPARSE_LANG_ZH);
setup_argparse(&argparse, &config, argparse_lang);
int ret = scc_argparse_parse(&argparse, argc, argv);
if (ret != 0) {
scc_argparse_drop(&argparse);
return ret;
return 0;
}
scc_argparse_drop(&argparse);