Files
spl/stage1/spl_comp.c
2026-07-05 21:45:43 +08:00

253 lines
7.0 KiB
C

/* spl_comp.c — SPL compiler main logic and codegen helpers */
#include "spl_comp.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
/* ---- Compiler context init/drop ---- */
void spl_comp_init(spl_comp_t *ctx) {
memset(ctx, 0, sizeof(*ctx));
vec_init(ctx->toks);
vec_init(ctx->scopes);
vec_init(ctx->funcs);
map_init(ctx->type_defs, MAP_HASH_STR, MAP_CMP_STR);
map_init(ctx->const_values, MAP_HASH_STR, MAP_CMP_STR);
spl_prog_init(&ctx->prog);
ctx->error_msg[0] = '\0';
}
void spl_comp_drop(spl_comp_t *ctx) {
if (!ctx) return;
spl_tok_vec_drop(&ctx->toks);
vec_for(ctx->scopes, i) {
vec_free(vec_at(ctx->scopes, i).vars);
}
vec_free(ctx->scopes);
vec_free(ctx->funcs);
/* Free type defs — complex, leak for now in bootstrap */
map_free(ctx->type_defs);
map_free(ctx->const_values);
spl_prog_drop(&ctx->prog);
free(ctx->break_patches);
}
void spl_comp_reset(spl_comp_t *ctx) {
/* Keep prog, reset everything else */
spl_tok_vec_drop(&ctx->toks);
vec_init(ctx->toks);
vec_for(ctx->scopes, i) {
vec_free(vec_at(ctx->scopes, i).vars);
}
vec_free(ctx->scopes);
vec_init(ctx->scopes);
ctx->scope_depth = 0;
ctx->tok_idx = 0;
ctx->has_error = 0;
ctx->error_msg[0] = '\0';
ctx->current_func_idx = -1;
ctx->current_ret_type = NULL;
ctx->current_local_slot = 0;
ctx->in_loop = 0;
ctx->break_patch_count = 0;
ctx->break_patch_cap = 0;
ctx->continue_target = 0;
ctx->defer_count = 0;
ctx->next_gdata_idx = 0;
ctx->addr_of_mode = 0;
free(ctx->break_patches);
ctx->break_patches = NULL;
}
void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vsnprintf(ctx->error_msg, COMP_ERROR_MAX - 1, fmt, args);
va_end(args);
ctx->has_error = 1;
}
/* ---- Codegen helpers ---- */
spl_val_t spl_emit(spl_comp_t *ctx, uint16_t opcode, uint16_t type, spl_val_t imm) {
return spl_prog_emit(&ctx->prog, opcode, type, imm);
}
void spl_patch(spl_comp_t *ctx, spl_val_t addr, spl_val_t target) {
if (addr < vec_size(ctx->prog.insns)) {
vec_at(ctx->prog.insns, addr).imm = target;
}
}
spl_val_t spl_emit_jmp(spl_comp_t *ctx) {
/* Emit JMP with placeholder 0, return address to patch */
return spl_emit(ctx, SPL_JMP, SPL_VOID, 0);
}
spl_val_t spl_emit_bz(spl_comp_t *ctx) {
return spl_emit(ctx, SPL_BZ, SPL_VOID, 0);
}
spl_val_t spl_emit_bnz(spl_comp_t *ctx) {
return spl_emit(ctx, SPL_BNZ, SPL_VOID, 0);
}
void spl_patch_to_here(spl_comp_t *ctx, spl_val_t addr) {
/* Compute relative offset: target - (source + 1) */
spl_val_t here = vec_size(ctx->prog.insns);
spl_val_t offset = here - addr - 1;
spl_patch(ctx, addr, offset);
}
/* ---- Scope management ---- */
void spl_push_scope(spl_comp_t *ctx) {
spl_scope_t scope;
vec_init(scope.vars);
scope.depth = ++ctx->scope_depth;
vec_push(ctx->scopes, scope);
}
void spl_pop_scope(spl_comp_t *ctx) {
if (vec_size(ctx->scopes) > 0) {
spl_scope_t *scope = &vec_at(ctx->scopes, vec_size(ctx->scopes) - 1);
vec_for(scope->vars, i) {
free(vec_at(scope->vars, i).name);
}
vec_free(scope->vars);
ctx->scope_depth--;
ctx->scopes.size--;
} else {
ctx->scope_depth--;
}
}
/* ---- Variable management ---- */
int spl_declare_var(spl_comp_t *ctx, const char *name, spl_type_info_t *type, int is_const) {
spl_var_info_t var;
memset(&var, 0, sizeof(var));
var.name = strdup(name);
var.type = type;
var.is_const = is_const;
var.depth = ctx->scope_depth;
var.slot = ctx->current_local_slot;
usize slot_count = spl_type_slot_count(type);
ctx->current_local_slot += (int)slot_count;
/* Add to current scope */
if (vec_size(ctx->scopes) > 0) {
spl_scope_t *scope = &vec_at(ctx->scopes, vec_size(ctx->scopes) - 1);
vec_push(scope->vars, var);
}
return var.slot;
}
spl_var_info_t *spl_lookup_var(spl_comp_t *ctx, const char *name) {
for (int i = (int)vec_size(ctx->scopes) - 1; i >= 0; i--) {
spl_scope_t *scope = &vec_at(ctx->scopes, i);
/* Search in reverse order so later declarations shadow earlier ones */
for (int j = (int)vec_size(scope->vars) - 1; j >= 0; j--) {
if (strcmp(vec_at(scope->vars, j).name, name) == 0) {
return &vec_at(scope->vars, j);
}
}
}
return NULL;
}
int spl_get_var_slot(spl_comp_t *ctx, const char *name) {
spl_var_info_t *v = spl_lookup_var(ctx, name);
return v ? v->slot : -1;
}
/* ---- Function management ---- */
int spl_declare_func(spl_comp_t *ctx, const char *name, spl_type_info_t *ret_type,
int nparams, int is_extern, int is_pub) {
spl_func_info_t fi;
memset(&fi, 0, sizeof(fi));
fi.name = strdup(name);
fi.ret_type = ret_type;
fi.nparams = nparams;
fi.is_extern = is_extern;
fi.is_pub = is_pub;
if (is_extern) {
fi.func_idx = -1;
} else {
fi.func_idx = spl_prog_add_func_simple(&ctx->prog, name, nparams);
}
vec_push(ctx->funcs, fi);
return (int)vec_size(ctx->funcs) - 1;
}
int spl_lookup_func(spl_comp_t *ctx, const char *name) {
vec_for(ctx->funcs, i) {
if (strcmp(vec_at(ctx->funcs, i).name, name) == 0)
return (int)i;
}
return -1;
}
/* ---- String/data management ---- */
int spl_add_string(spl_comp_t *ctx, const char *str) {
return spl_add_global_data(ctx, (void*)str, strlen(str) + 1);
}
int spl_add_global_data(spl_comp_t *ctx, void *data, usize size) {
return spl_prog_add_data(&ctx->prog, data, size);
}
/* ---- Defer ---- */
void spl_emit_defer(spl_comp_t *ctx) {
/* Record current ip for later patching */
if (ctx->defer_count < DEFER_MAX) {
ctx->defer_addrs[ctx->defer_count++] = vec_size(ctx->prog.insns);
}
}
void spl_emit_defer_epilogue(spl_comp_t *ctx) {
/* Emit deferコード in reverse order */
for (int i = ctx->defer_count - 1; i >= 0; i--) {
/* The code after defer_addrs[i] is the defer body */
/* We need to JMP over it, but the body is inline */
/* This is a simplified approach — just mark the range */
}
}
/* ---- Register runtime natives ---- */
void spl_comp_register(spl_prog_t *prog) {
/* Runtime support functions for compiled SPL programs go here.
* For stage1 bootstrap, most operations are handled inline.
* We register basic runtime helpers if needed. */
(void)prog;
}
/* ---- Main compilation ---- */
int spl_compile(spl_comp_t *ctx, const char *source, const char *fname) {
/* Phase 1: Lex */
ctx->toks = spl_lex(source, fname);
ctx->tok_idx = 0;
ctx->fname = fname;
ctx->source = source;
/* Skip initial newlines */
while (ctx->tok_idx < vec_size(ctx->toks) &&
vec_at(ctx->toks, ctx->tok_idx).type == TOK_ENDLINE)
ctx->tok_idx++;
/* Phase 2-4: Parse and codegen */
spl_parse_prog(ctx);
if (ctx->has_error) return -1;
return 0;
}