/* splc0.c - SPL compiler CLI (stage 1, 引导用) * * splc0 --dump tokens|ast|all dump 前端产物 * splc0 编译 (阶段 B 实现) */ #define __SCC_LOG_IMPL_IMPORT_SRC__ #include "../stage0/include/utils.h" #include #include #include #include "spl_ast.h" #include "spl_ast2ir.h" #include "spl_ir2vm.h" #include "spl_lexer.h" #include "spl_sema.h" #include "spl_tok.h" static char *read_file(const char *path, long *out_len) { FILE *f = fopen(path, "rb"); if (!f) { perror("fopen"); return NULL; } fseek(f, 0, SEEK_END); long len = ftell(f); fseek(f, 0, SEEK_SET); char *buf = malloc((size_t)len + 1); if (!buf) { fclose(f); return NULL; } fread(buf, 1, (size_t)len, f); fclose(f); buf[len] = '\0'; *out_len = len; 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 }; static void dump_tokens(const char *src, const char *fname) { spl_tok_vec_t toks = spl_lex(src, fname); 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, t->col); } vec_free(toks); } static void dump_ast(const char *src, const char *fname) { spl_tok_vec_t toks = spl_lex(src, fname); spl_ast_t ast; spl_ast_init(&ast, &toks); spl_ast_prase(&ast); if (ast.parsed < 0) { printf("parse failed, skip AST dump\n"); spl_ast_drop(&ast); return; } spl_ast_valid(&ast); spl_ast_dump(&ast, ast.root); spl_ast_drop(&ast); } // static void dump_sema(const char *src, const char *fname) { // spl_tok_vec_t toks = spl_lex(src, fname); // spl_ast_t ast; // spl_ast_init(&ast, &toks); // spl_ast_prase(&ast); // if (ast.parsed < 0) { // printf("parse failed, skip sema dump\n"); // spl_ast_drop(&ast); // return; // } // spl_ast_valid(&ast); // spl_sema_t sema; // spl_sema_init(&sema); // sema.ast = * // spl_sema_run(&sema); // spl_sema_check(&sema); // printf("Sema root_scope=%zu scopes=%zu errors=%d\n", sema.root_scope, sema.scopes.size, // sema.error_count); // for (usize i = 0; i < sema.scopes.size; i++) { // printf("scope[%zu] parent=%zu\n", i, sema.scopes.data[i].parent); // map_for(sema.scopes.data[i].symbols, mi) { // printf(" %s -> def#%zu\n", sema.scopes.data[i].symbols.data[mi].key, // sema.scopes.data[i].symbols.data[mi].val); // } // } // printf("TypeTable:\n"); // for (usize i = 0; i < sema.type.type_table.size; i++) { // printf(" id#%zu type=", i); // spl_type_pure_dump(&sema.type, i); // printf("\n"); // } // printf("DefTable:\n"); // for (usize i = 0; i < sema.type.def_table.size; i++) { // printf(" def#%zu ", i); // spl_type_def_dump(&sema.type, i); // printf("\n"); // } // spl_sema_drop(&sema); // spl_ast_drop(&ast); // } // static void dump_ir(const char *src, const char *fname) { // spl_tok_vec_t toks = spl_lex(src, fname); // spl_ast_t ast; // spl_ast_init(&ast, &toks); // spl_ast_prase(&ast); // if (ast.parsed < 0) { // printf("parse failed, skip IR\n"); // spl_ast_drop(&ast); // return; // } // spl_ast_valid(&ast); // spl_sema_t sema; // spl_sema_init(&sema); // sema.ast = * // spl_sema_run(&sema); // spl_sema_check(&sema); // if (sema.error_count) { // printf("sema errors=%d, skip IR\n", sema.error_count); // spl_sema_drop(&sema); // spl_ast_drop(&ast); // return; // } // spl_ast2ir_t a2ir; // spl_ast2ir_init(&a2ir, &sema); // spl_ast2ir_run(&a2ir); // if (a2ir.err_count) // printf("ast2ir errors=%d\n", a2ir.err_count); // spl_ir_dump(&a2ir.ir, &sema.type); // spl_ast2ir_drop(&a2ir); // spl_sema_drop(&sema); // spl_ast_drop(&ast); // } static int cmd_dump(const char *flags, const char *path) { long len; char *src = read_file(path, &len); if (!src) return 1; int do_tokens = strstr(flags, "tokens") != NULL || strcmp(flags, "all") == 0; int do_ast = strstr(flags, "ast") != NULL || strcmp(flags, "all") == 0; int do_sema = strstr(flags, "sema") != NULL || strcmp(flags, "all") == 0; int do_ir = strstr(flags, "ir") != NULL || strcmp(flags, "all") == 0; if (do_tokens) dump_tokens(src, path); if (do_ast) dump_ast(src, path); // if (do_sema) // dump_sema(src, path); // if (do_ir) // dump_ir(src, path); free(src); return 0; } /* -g:在 .sir 尾部追加 debug 段(文本:IR 行 + VAR 行),spl_cli -g 读取 */ static void gen_debug_map(const char *outpath, spl_ast_t *ast, const spl_ir_t *ir, const spl_ir2vm_t *ir2vm) { FILE *f = fopen(outpath, "ab"); if (!f) return; fprintf(f, "SPLDBG\n"); // for (usize i = 0; i < ir2vm->fdbg.size; i++) { // const spl_ir2vm_fdbg_t *fd = &ir2vm->fdbg.data[i]; // if (fd->fid >= ir->funcs.size) // continue; // const spl_ir_func_t *fn = &ir->funcs.data[fd->fid]; // const char *fname = fn->name ? fn->name : "?"; // for (usize ref = 1; ref < fd->node_first_ip.size; ref++) { // usize ip = fd->node_first_ip.data[ref]; // if (ip == (usize)-1) // continue; // const spl_ir_node_t *n = &fn->nodes.data[ref]; // fprintf(f, "IR %zu %zu %d %s\n", ip, ref, ast_line(ast, n->src_ref), // spl_ir_kind_name(n->kind)); // } // for (usize j = 0; j < fn->dbg_vars.size; j++) { // const spl_ir_dbg_var_t *dv = &fn->dbg_vars.data[j]; // if (!dv->name) // continue; // fprintf(f, "VAR %s %s %zu %zu %d\n", fname, dv->name, dv->offset, dv->tid, // dv->is_param); // } // } fclose(f); } static int compile_spl(const char *src, const char *fname, const char *outpath, int gen_debug) { // spl_tok_vec_t toks = spl_lex(src, fname); // spl_ast_t ast; // spl_ast_init(&ast, &toks); // spl_ast_prase(&ast); // if (ast.parsed < 0) { // printf("parse failed, no output\n"); // spl_ast_drop(&ast); // return 1; // } // spl_ast_valid(&ast); // spl_sema_t sema; // spl_sema_init(&sema); // sema.ast = * // spl_sema_run(&sema); // spl_sema_check(&sema); // if (sema.error_count) { // printf("sema errors=%d, no output\n", sema.error_count); // spl_sema_drop(&sema); // spl_ast_drop(&ast); // return 1; // } // spl_ast2ir_t a2ir; // spl_ast2ir_init(&a2ir, &sema); // spl_ast2ir_run(&a2ir); // if (a2ir.err_count) { // printf("ast2ir errors=%d, no output\n", a2ir.err_count); // spl_ast2ir_drop(&a2ir); // spl_sema_drop(&sema); // spl_ast_drop(&ast); // return 1; // } // spl_ir2vm_t ir2vm; // spl_ir2vm_init(&ir2vm, &a2ir.ir, &sema.type); // int rc = spl_ir2vm_run(&ir2vm, outpath); // if (gen_debug && rc == 0) // gen_debug_map(outpath, &ast, &a2ir.ir, &ir2vm); // spl_ir2vm_drop(&ir2vm); // spl_ast2ir_drop(&a2ir); // spl_sema_drop(&sema); // spl_ast_drop(&ast); // return rc ? 1 : 0; return 0; } int main(int argc, char **argv) { if (argc < 2) { LOG_FATAL("Usage: splc0 [--dump ] [out]"); return 1; } if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { LOG_INFO("splc0 compile (.spl -> .sir, stage B)"); LOG_INFO("splc0 --dump dump: tokens,ast,sema,ir,all"); return 0; } int argi = 1; if (argi >= argc) { LOG_FATAL("Usage: splc0 [--dump ] [out]"); return 1; } if (strcmp(argv[argi], "--dump") == 0) { if (argc < argi + 3) { LOG_INFO("splc0: --dump need "); return 1; } return cmd_dump(argv[argi + 1], argv[argi + 2]); } /* splc0 [-g] */ if (argc < argi + 2) { LOG_FATAL("Usage: splc0 [-g] or splc0 --dump \n"); return 1; } int gen_debug = 0; if (strcmp(argv[argi], "-g") == 0) { gen_debug = 1; argi++; } if (argc < argi + 2) { LOG_FATAL("Usage: splc0 [-g] or splc0 --dump \n"); return 1; } long len; char *src = read_file(argv[argi], &len); if (!src) return 1; int rc = compile_spl(src, argv[argi], argv[argi + 1], gen_debug); free(src); return rc; }