stage1 大量重构
This commit is contained in:
1 parent
e4347cc3ea
commit
2a84b61e3d
18 files changed
+1831
-1354
No files matched your search
+209
-78
@@ -1,7 +1,7 @@
|
||||
/* splc0.c - SPL compiler CLI (stage 1, 引导用)
|
||||
*
|
||||
* splc0 --dump tokens|ast|all <file> dump 前端产物
|
||||
* splc0 <in> <out> 编译 (阶段 B 实现)
|
||||
* splc0 --dump tokens|ast|sema|ir|vm <file> dump 前端产物
|
||||
* splc0 <in> <out> 编译
|
||||
*/
|
||||
#define __SCC_LOG_IMPL_IMPORT_SRC__
|
||||
#include "../stage0/include/utils.h"
|
||||
@@ -27,6 +27,24 @@ typedef enum {
|
||||
DUMP_VM,
|
||||
} dump_t;
|
||||
|
||||
typedef struct {
|
||||
spl_ast_t *ast;
|
||||
char *abs_path;
|
||||
char *src;
|
||||
} spl_driver_module_t;
|
||||
typedef VEC(spl_driver_module_t) spl_driver_module_vec_t;
|
||||
|
||||
typedef struct {
|
||||
spl_ast_t main_ast;
|
||||
spl_tok_vec_t main_toks;
|
||||
char *main_path;
|
||||
|
||||
spl_driver_module_vec_t modules;
|
||||
MAP(const char *, usize) path_to_idx;
|
||||
|
||||
spl_diag_t *diag;
|
||||
} spl_driver_t;
|
||||
|
||||
static char *read_file(const char *path, long *out_len) {
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f) {
|
||||
@@ -42,132 +60,245 @@ static char *read_file(const char *path, long *out_len) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
fread(buf, 1, (size_t)len, f);
|
||||
size_t nread = fread(buf, 1, (size_t)len, f);
|
||||
fclose(f);
|
||||
buf[len] = '\0';
|
||||
*out_len = len;
|
||||
buf[nread] = '\0';
|
||||
if (out_len)
|
||||
*out_len = (long)nread;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char *const tok_type_names[] = {
|
||||
#define X(name, enum_name, dummy) #enum_name,
|
||||
KEYWORD_TABLE
|
||||
#undef X
|
||||
#define X(name, enum_name, dummy) #enum_name,
|
||||
TOKEN_TABLE
|
||||
#undef X
|
||||
};
|
||||
|
||||
/* 注意:按值接收,内部 vec_free 释放与调用方共享的 data 指针。
|
||||
调用后原 vec 视为已消费,不要再使用。 */
|
||||
static void dump_tokens(spl_tok_vec_t toks) {
|
||||
printf("tokens got (%zu)\n", toks.size);
|
||||
for (usize i = 0; i < toks.size; i++) {
|
||||
const spl_tok_t *t = &toks.data[i];
|
||||
printf("[%s] %.*s (%zu:%zu)\n", tok_type_names[t->type], (int)t->len, t->lexeme, t->line,
|
||||
printf("[%s] %.*s (%zu:%zu)\n", spl_tok_type_name(t->type), (int)t->len, t->lexeme, t->line,
|
||||
t->col);
|
||||
}
|
||||
vec_free(toks);
|
||||
}
|
||||
|
||||
/* 把 import_path 拼接到 importing_file 所在目录。
|
||||
from_fname 为空时按相对 cwd 处理。绝对路径直接透传。 */
|
||||
static void resolve_relative(const char *from, const char *path, char *out, usize cap) {
|
||||
if (!from || !path) {
|
||||
if (cap)
|
||||
out[0] = 0;
|
||||
return;
|
||||
}
|
||||
if (path[0] == '/' || path[0] == '\\' || (path[0] && path[1] == ':')) {
|
||||
snprintf(out, cap, "%s", path);
|
||||
return;
|
||||
}
|
||||
const char *last_sep = NULL;
|
||||
for (const char *p = from; *p; ++p)
|
||||
if (*p == '/' || *p == '\\')
|
||||
last_sep = p;
|
||||
if (!last_sep) {
|
||||
snprintf(out, cap, "%s", path);
|
||||
return;
|
||||
}
|
||||
usize dir_len = (usize)(last_sep - from) + 1;
|
||||
snprintf(out, cap, "%.*s%s", (int)dir_len, from, path);
|
||||
}
|
||||
|
||||
static spl_ast_t *driver_load(void *user, const char *from_fname, const char *path,
|
||||
spl_diag_t *diag) {
|
||||
spl_driver_t *d = user;
|
||||
char abs[1024];
|
||||
resolve_relative(from_fname, path, abs, sizeof abs);
|
||||
|
||||
usize idx;
|
||||
if (map_get(d->path_to_idx, abs, &idx)) {
|
||||
spl_ast_t *a = vec_at(d->modules, idx).ast;
|
||||
if (!a) {
|
||||
spl_diag_error(diag, SPL_DIAG_KIND_CIRCULAR_DEP, NULL, "circular import: `%s`", abs);
|
||||
return NULL;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/* 先登记 ast=NULL 占位:若后续解析过程中又有 @import 指回本路径,
|
||||
会命中这里,判定为环。 */
|
||||
char *key = strdup(abs);
|
||||
idx = vec_size(d->modules);
|
||||
spl_driver_module_t placeholder = {.ast = NULL, .abs_path = key, .src = NULL};
|
||||
vec_push(d->modules, placeholder);
|
||||
map_put(d->path_to_idx, key, idx);
|
||||
|
||||
long len = 0;
|
||||
char *src = read_file(abs, &len);
|
||||
if (!src) {
|
||||
spl_diag_error(diag, SPL_DIAG_KIND_LEX_UNEXPECTED, NULL, "@import: cannot open `%s`", abs);
|
||||
return NULL;
|
||||
}
|
||||
(void)len;
|
||||
|
||||
/* key 同时用作 lexer 的 fname:token.fname 与 map key 共享一份 strdup,
|
||||
减少一次分配;cleanup 时只 free module.abs_path */
|
||||
spl_tok_vec_t toks = spl_lex(src, key);
|
||||
spl_ast_t *ast = malloc(sizeof *ast);
|
||||
spl_ast_init(ast, &toks);
|
||||
ast->diag = diag;
|
||||
spl_ast_parse(ast);
|
||||
|
||||
vec_at(d->modules, idx).ast = ast;
|
||||
vec_at(d->modules, idx).src = src;
|
||||
return ast;
|
||||
}
|
||||
|
||||
static int compile_spl(const char *src, const char *fname, const char *outpath, int gen_debug,
|
||||
dump_t dump) {
|
||||
(void)gen_debug;
|
||||
|
||||
spl_tok_vec_t toks = spl_lex(src, fname);
|
||||
if (dump == DUMP_TOKEN) {
|
||||
dump_tokens(toks);
|
||||
// memory leak
|
||||
return 0;
|
||||
}
|
||||
|
||||
spl_diag_t diag;
|
||||
spl_diag_init(&diag, stderr);
|
||||
|
||||
spl_ast_t ast;
|
||||
spl_ast_init(&ast, &toks);
|
||||
spl_diag_set_stage(&diag, SPL_STAGE_PARSE);
|
||||
ast.diag = &diag;
|
||||
spl_ast_parse(&ast);
|
||||
if (spl_diag_has_error(&diag) || spl_diag_has_fatal(&diag)) {
|
||||
spl_diag_summary(&diag);
|
||||
// memory leak
|
||||
return 1;
|
||||
}
|
||||
// spl_ast_valid(&ast); TODO
|
||||
if (dump == DUMP_AST) {
|
||||
spl_ast_dump(&ast, ast.root);
|
||||
// memory leak
|
||||
spl_driver_t drv = {0};
|
||||
drv.diag = &diag;
|
||||
drv.main_path = strdup(fname);
|
||||
drv.main_toks = spl_lex(src, drv.main_path);
|
||||
spl_ast_init(&drv.main_ast, &drv.main_toks);
|
||||
drv.main_ast.diag = &diag;
|
||||
map_init(drv.path_to_idx, MAP_HASH_STR, MAP_CMP_STR);
|
||||
vec_init(drv.modules);
|
||||
|
||||
int rc = 0;
|
||||
|
||||
/* dump_tokens 消费 drv.main_toks(共享 data),之后 main_ast.input 悬空,
|
||||
所以这条分支必须在 spl_ast_parse 之前、且不能再 drop main_ast。 */
|
||||
if (dump == DUMP_TOKEN) {
|
||||
dump_tokens(drv.main_toks);
|
||||
free(drv.main_path);
|
||||
map_free(drv.path_to_idx);
|
||||
spl_diag_drop(&diag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spl_attr_t attr;
|
||||
spl_attr_init(&attr);
|
||||
spl_sema_t sema;
|
||||
spl_type_t type;
|
||||
spl_lang_type_t lang_type;
|
||||
spl_scope_t scope;
|
||||
spl_type_init(&type);
|
||||
spl_sema_t sema;
|
||||
spl_ast2ir_t a2ir;
|
||||
spl_ir_builder_t ir_builder;
|
||||
spl_ir2vm_t ir2vm;
|
||||
spl_ast_ptr_vec_t all_asts;
|
||||
|
||||
int attr_ok = 0, lang_type_ok = 0, scope_ok = 0;
|
||||
int sema_ok = 0, a2ir_ok = 0, irb_ok = 0, ir2vm_ok = 0;
|
||||
|
||||
spl_diag_set_stage(&diag, SPL_STAGE_PARSE);
|
||||
spl_ast_parse(&drv.main_ast);
|
||||
if (spl_diag_has_error(&diag) || spl_diag_has_fatal(&diag)) {
|
||||
spl_diag_summary(&diag);
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (dump == DUMP_AST) {
|
||||
spl_ast_dump(&drv.main_ast, drv.main_ast.root);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
spl_attr_init(&attr);
|
||||
attr_ok = 1;
|
||||
spl_lang_type_init(&lang_type);
|
||||
lang_type_ok = 1;
|
||||
spl_scope_init(&scope);
|
||||
spl_sema_init(&sema, &ast, &type, &scope, &attr);
|
||||
sema.ast = *
|
||||
scope_ok = 1;
|
||||
|
||||
spl_sema_init(&sema, &drv.main_ast, &lang_type, &scope, &attr);
|
||||
sema_ok = 1;
|
||||
spl_module_loader_t loader = {.load = driver_load, .user = &drv};
|
||||
sema.loader = &loader;
|
||||
spl_diag_set_stage(&diag, SPL_STAGE_SEMA);
|
||||
sema.diag = &diag;
|
||||
spl_sema_run(&sema);
|
||||
if (spl_diag_has_error(&diag) || spl_diag_has_fatal(&diag)) {
|
||||
// memory leak
|
||||
spl_diag_summary(&diag);
|
||||
return 1;
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (dump == DUMP_SEMA) {
|
||||
spl_sema_dump(&sema);
|
||||
spl_ast_dump(&ast, ast.root);
|
||||
// memory leak
|
||||
return 0;
|
||||
spl_ast_dump(&drv.main_ast, drv.main_ast.root);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
spl_ast2ir_t a2ir;
|
||||
spl_ir_builder_t ir_builder;
|
||||
/* 收集所有 ast:主文件在前,被 import 的文件按加载顺序在后。
|
||||
ast2ir 内部会 vec_free(all_asts)。 */
|
||||
vec_init(all_asts);
|
||||
vec_push(all_asts, &drv.main_ast);
|
||||
for (usize i = 0; i < vec_size(drv.modules); ++i)
|
||||
vec_push(all_asts, vec_at(drv.modules, i).ast);
|
||||
|
||||
spl_ir_builder_init(&ir_builder);
|
||||
irb_ok = 1;
|
||||
spl_ast2ir_init(&a2ir, &ir_builder, &sema);
|
||||
a2ir_ok = 1;
|
||||
spl_diag_set_stage(&diag, SPL_STAGE_AST2IR);
|
||||
a2ir.diag = &diag;
|
||||
spl_ast2ir_run(&a2ir);
|
||||
spl_ast2ir_run(&a2ir, all_asts);
|
||||
if (spl_diag_has_error(&diag) || spl_diag_has_fatal(&diag)) {
|
||||
spl_diag_summary(&diag);
|
||||
// memory leak
|
||||
spl_ast2ir_drop(&a2ir);
|
||||
spl_sema_drop(&sema);
|
||||
spl_ast_drop(&ast);
|
||||
return 1;
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (dump == DUMP_IR) {
|
||||
spl_ir_dump(&ir_builder.ir, &type, &attr);
|
||||
// memory leak
|
||||
return 0;
|
||||
spl_ir_dump(&ir_builder.ir, &lang_type.ir, &attr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
spl_ir2vm_t ir2vm;
|
||||
spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, &type, &attr);
|
||||
// ir2vm.diag = &diag;
|
||||
spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, &lang_type.ir, &attr);
|
||||
ir2vm_ok = 1;
|
||||
spl_diag_set_stage(&diag, SPL_STAGE_IR2VM);
|
||||
ir2vm.diag = &diag;
|
||||
int rc = spl_ir2vm_run(&ir2vm);
|
||||
rc = spl_ir2vm_run(&ir2vm);
|
||||
if (spl_diag_has_error(&diag) || spl_diag_has_fatal(&diag)) {
|
||||
spl_diag_summary(&diag);
|
||||
return rc;
|
||||
goto cleanup;
|
||||
}
|
||||
if (dump == DUMP_VM) {
|
||||
spl_prog_dump(&ir2vm.prog);
|
||||
// memory leak
|
||||
return 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
spl_prog_store_to_file(outpath, &ir2vm.prog);
|
||||
rc = 0;
|
||||
|
||||
spl_ir2vm_drop(&ir2vm);
|
||||
spl_ast2ir_drop(&a2ir);
|
||||
spl_sema_drop(&sema);
|
||||
spl_ast_drop(&ast);
|
||||
// memory leak
|
||||
return 0;
|
||||
cleanup:
|
||||
if (ir2vm_ok)
|
||||
spl_ir2vm_drop(&ir2vm);
|
||||
if (a2ir_ok)
|
||||
spl_ast2ir_drop(&a2ir);
|
||||
if (irb_ok)
|
||||
spl_ir_builder_drop(&ir_builder);
|
||||
if (sema_ok)
|
||||
spl_sema_drop(&sema);
|
||||
if (scope_ok)
|
||||
spl_scope_drop(&scope);
|
||||
if (lang_type_ok)
|
||||
spl_lang_type_drop(&lang_type);
|
||||
if (attr_ok)
|
||||
spl_attr_drop(&attr);
|
||||
|
||||
spl_ast_drop(&drv.main_ast);
|
||||
for (usize i = 0; i < vec_size(drv.modules); ++i) {
|
||||
spl_ast_t *a = vec_at(drv.modules, i).ast;
|
||||
if (a) {
|
||||
spl_ast_drop(a);
|
||||
free(a);
|
||||
}
|
||||
free(vec_at(drv.modules, i).abs_path);
|
||||
free(vec_at(drv.modules, i).src);
|
||||
}
|
||||
vec_free(drv.modules);
|
||||
/* map 的 key 是 module 里 strdup 出的 abs_path,已随 module 释放 */
|
||||
map_free(drv.path_to_idx);
|
||||
free(drv.main_path);
|
||||
spl_diag_drop(&diag);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@@ -194,20 +325,20 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
const char *flags = argv[argi + 1];
|
||||
if (strstr(flags, "lex") != NULL) {
|
||||
if (strcmp(flags, "lex") == 0) {
|
||||
dump = DUMP_TOKEN;
|
||||
} else if (strstr(flags, "ast") != NULL) {
|
||||
} else if (strcmp(flags, "ast") == 0) {
|
||||
dump = DUMP_AST;
|
||||
} else if (strstr(flags, "sema") != NULL) {
|
||||
} else if (strcmp(flags, "sema") == 0) {
|
||||
dump = DUMP_SEMA;
|
||||
} else if (strstr(flags, "ir") != NULL) {
|
||||
} else if (strcmp(flags, "ir") == 0) {
|
||||
dump = DUMP_IR;
|
||||
} else if (strstr(flags, "vm") != NULL) {
|
||||
} else if (strcmp(flags, "vm") == 0) {
|
||||
dump = DUMP_VM;
|
||||
} else if (strstr(flags, "none") != NULL) {
|
||||
} else if (strcmp(flags, "none") == 0) {
|
||||
dump = DUMP_NONE;
|
||||
} else {
|
||||
Panic("--dump unknown flags");
|
||||
LOG_FATAL("splc0: --dump takes one of lex|ast|sema|ir|vm|none, got `%s`", flags);
|
||||
return 1;
|
||||
}
|
||||
argi += 2;
|
||||
|
||||
Reference in new issue
Block a user