292 lines
9.0 KiB
C
292 lines
9.0 KiB
C
/* splc0.c - SPL compiler CLI (stage 1, 引导用)
|
||
*
|
||
* splc0 --dump tokens|ast|all <file> dump 前端产物
|
||
* splc0 <in> <out> 编译 (阶段 B 实现)
|
||
*/
|
||
#define __SCC_LOG_IMPL_IMPORT_SRC__
|
||
#include "../stage0/include/utils.h"
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#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 <flags>] <in> [out]");
|
||
return 1;
|
||
}
|
||
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
|
||
LOG_INFO("splc0 <in> <out> compile (.spl -> .sir, stage B)");
|
||
LOG_INFO("splc0 --dump <flags> <file> dump: tokens,ast,sema,ir,all");
|
||
return 0;
|
||
}
|
||
int argi = 1;
|
||
if (argi >= argc) {
|
||
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]");
|
||
return 1;
|
||
}
|
||
if (strcmp(argv[argi], "--dump") == 0) {
|
||
if (argc < argi + 3) {
|
||
LOG_INFO("splc0: --dump need <flags> <file>");
|
||
return 1;
|
||
}
|
||
return cmd_dump(argv[argi + 1], argv[argi + 2]);
|
||
}
|
||
/* splc0 [-g] <in> <out> */
|
||
if (argc < argi + 2) {
|
||
LOG_FATAL("Usage: splc0 <in> <out> [-g] or splc0 --dump <flags> <file>\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 <in> <out> [-g] or splc0 --dump <flags> <file>\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;
|
||
}
|