* 32位指令: op(8)|A(8)|B(8)|C(8)
* 支持:多函数、调用栈、内置函数、用户函数调用/返回
*/
#define _POSIX_C_SOURCE 200809L
#include "cvm_core.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
enum {
R_NOP, R_CONST, R_INT, R_TRUE, R_FALSE, R_NIL,
R_LOAD, R_STORE,
R_MOV, R_ADD, R_SUB, R_MUL, R_DIV, R_MOD,
R_EQ, R_LT, R_LE, R_INV,
R_JMP, R_JT, R_JF,
R_CALL, R_RET, R_HALT,
R_LOAD_FUNC,
R_CALL_IDX,
R_ADD_IMM,
R_SUB_IMM,
R_LT_IMM,
R_LE_IMM
};
typedef struct {
int32_t *code; int clen, ccap;
Value *pool; int plen, pcap;
char **names; int nlen, ncap;
int nregs, nvars, nargs, max_args;
int unsupported;
struct { const char *name; int reg; } vars[64]; int nvar;
struct { const char *name; int index; } funcs[64]; int nfunc;
} Rc;
static void re(int32_t v, Rc *c) {
if (c->clen >= c->ccap) { c->ccap = c->ccap < 256 ? 256 : c->ccap * 2; c->code = realloc(c->code, c->ccap * 4); }
c->code[c->clen++] = v;
}
#define E(v) re(v, c)
static int addc(Value v, Rc *c) {
for (int i = 0; i < c->plen; i++) if (value_equal(c->pool[i], v, 0)) return i;
if (c->plen >= c->pcap) { c->pcap = c->pcap < 64 ? 64 : c->pcap * 2; c->pool = realloc(c->pool, c->pcap * sizeof(Value)); }
c->pool[c->plen] = v; return c->plen++;
}
static int addn(const char *s, Rc *c) {
for (int i = 0; i < c->nlen; i++) if (!strcmp(c->names[i], s)) return i;
if (c->nlen >= c->ncap) { c->ncap = c->ncap < 64 ? 64 : c->ncap * 2; c->names = realloc(c->names, c->ncap * sizeof(char *)); }
c->names[c->nlen] = strdup(s); return c->nlen++;
}
static int vfind(const char *nm, Rc *c) {
for (int i = 0; i < c->nvar; i++) if (!strcmp(c->vars[i].name, nm)) return c->vars[i].reg;
return -1;
}
static int vreg(const char *nm, Rc *c) {
int r = vfind(nm, c);
if (r >= 0) return r;
r = c->nregs++;
if (c->nvar < 64) { c->vars[c->nvar].name = nm; c->vars[c->nvar].reg = r; c->nvar++; }
return r;
}
static int vname(const char *nm, Rc *c) { return addn(nm, c); }
static int func_index(const char *nm, Rc *c) {
for (int i = 0; i < c->nfunc; i++) if (!strcmp(c->funcs[i].name, nm)) return c->funcs[i].index;
return -1;
}
static int comp_expr(Expr*, Rc*);
static void comp_stmt(Stmt*, Rc*);
static int comp_expr(Expr *e, Rc *c) {
if (!e) { int r = c->nregs++; E(R_NIL | (r << 8)); return r; }
switch (e->kind) {
case EXPR_NIL: { int r = c->nregs++; E(R_NIL | (r << 8)); return r; }
case EXPR_BOOL: { int r = c->nregs++; E(e->u.boolean ? R_TRUE | (r << 8) : R_FALSE | (r << 8)); return r; }
case EXPR_NUM: {
int r = c->nregs++;
if (e->u.numlit.is_int) { int ci = addc(val_int(e->u.numlit.ival), c); E(R_INT | (r << 8)); E(ci); }
else { int ci = addc(val_num(e->u.numlit.fval), c); E(R_CONST | (r << 8)); E(ci); }
return r;
}
case EXPR_STR: { int r = c->nregs++; int ci = addc(val_str(e->u.str), c); E(R_CONST | (r << 8)); E(ci); return r; }
case EXPR_VAR: {
int r = vfind(e->u.name, c);
if (r < 0) { c->unsupported = 1; r = c->nregs++; E(R_NIL | (r << 8)); }
return r;
}
case EXPR_UNARY: {
int a = comp_expr(e->u.unary.inner, c), r = c->nregs++;
if (e->u.unary.op == TK_MINUS) { int z = c->nregs++; E(R_INT | (z << 8)); E(addc(val_int(0), c)); E(R_SUB | (r << 8) | (z << 16) | (a << 24)); }
else { E(R_INV | (r << 8) | (a << 16)); }
return r;
}
case EXPR_BINARY: {
int a = comp_expr(e->u.binary.left, c);
int op = e->u.binary.op;
if (e->u.binary.right && e->u.binary.right->kind == EXPR_NUM && e->u.binary.right->u.numlit.is_int &&
(op == TK_PLUS || op == TK_MINUS || op == TK_LT || op == TK_LE)) {
int r = c->nregs++;
int32_t imm = (int32_t)e->u.binary.right->u.numlit.ival;
if (op == TK_PLUS) E(R_ADD_IMM | (r << 8) | (a << 16));
else if (op == TK_MINUS) E(R_SUB_IMM | (r << 8) | (a << 16));
else if (op == TK_LT) E(R_LT_IMM | (r << 8) | (a << 16));
else E(R_LE_IMM | (r << 8) | (a << 16));
E(imm);
return r;
}
int b = comp_expr(e->u.binary.right, c), r = c->nregs++;
if (op == TK_PLUS) E(R_ADD | (r << 8) | (a << 16) | (b << 24));
else if (op == TK_MINUS) E(R_SUB | (r << 8) | (a << 16) | (b << 24));
else if (op == TK_STAR) E(R_MUL | (r << 8) | (a << 16) | (b << 24));
else if (op == TK_SLASH) E(R_DIV | (r << 8) | (a << 16) | (b << 24));
else if (op == TK_PERCENT) E(R_MOD | (r << 8) | (a << 16) | (b << 24));
else if (op == TK_EQEQ) E(R_EQ | (r << 8) | (a << 16) | (b << 24));
else if (op == TK_LT) E(R_LT | (r << 8) | (a << 16) | (b << 24));
else if (op == TK_LE) E(R_LE | (r << 8) | (a << 16) | (b << 24));
else if (op == TK_GT) { E(R_LE | (r << 8) | (b << 16) | (a << 24)); E(R_INV | (r << 8) | (r << 16)); }
else if (op == TK_GE) { E(R_LT | (r << 8) | (b << 16) | (a << 24)); E(R_INV | (r << 8) | (r << 16)); }
else if (op == TK_NOTEQ) { E(R_EQ | (r << 8) | (a << 16) | (b << 24)); E(R_INV | (r << 8) | (r << 16)); }
else { E(R_MOV | (r << 8) | (a << 16)); }
return r;
}
case EXPR_ASSIGN: {
int v = comp_expr(e->u.assign.value, c);
int t = vreg(e->u.assign.name, c);
E(R_MOV | (t << 8) | (v << 16));
return v;
}
case EXPR_CALL: {
int argc = e->u.call.argc;
int first_arg = c->nregs;
if (argc > 0) {
for (int i = 0; i < argc; i++) {
c->nregs = first_arg + i;
int rr = comp_expr(e->u.call.args[i], c);
if (rr != first_arg + i) { int dst = first_arg + i; E(R_MOV | (dst << 8) | (rr << 16)); }
}
c->nregs = first_arg + argc;
}
if (e->u.call.callee->kind == EXPR_VAR) {
const char *callee_name = e->u.call.callee->u.name;
if (!strcmp(callee_name, "ffi_decl") || !strcmp(callee_name, "import") ||
!strcmp(callee_name, "ffi_enable")) {
c->unsupported = 1;
}
}
if (e->u.call.callee->kind == EXPR_VAR) {
const char *callee_name = e->u.call.callee->u.name;
int fidx = func_index(callee_name, c);
if (fidx >= 0) {
int result_reg = c->nregs++;
E(R_CALL_IDX | (result_reg << 8) | (first_arg << 16) | (argc << 24));
E(fidx);
if (argc + 1 > c->max_args) c->max_args = argc + 1;
return result_reg;
}
}
int callee_reg = c->nregs++;
if (e->u.call.callee->kind == EXPR_VAR) {
int ni = vname(e->u.call.callee->u.name, c);
E(R_LOAD_FUNC | (callee_reg << 8) | (ni << 16));
} else {
c->unsupported = 1; int r = c->nregs++; E(R_NIL | (r << 8)); return r;
}
int result_reg = c->nregs++;
E(R_CALL | (result_reg << 8) | (callee_reg << 16) | (argc << 24));
if (argc + 1 > c->max_args) c->max_args = argc + 1;
return result_reg;
}
default: { c->unsupported = 1; int r = c->nregs++; E(R_NIL | (r << 8)); return r; }
}
}
static void comp_stmt(Stmt *s, Rc *c) {
if (!s) return;
switch (s->kind) {
case STMT_EXPR: { comp_expr(s->u.expr, c); break; }
case STMT_LET: {
if (s->u.let.init) { int r = comp_expr(s->u.let.init, c); int t = vreg(s->u.let.name, c); E(R_MOV | (t << 8) | (r << 16)); }
else { vreg(s->u.let.name, c); }
break;
}
case STMT_ASSIGN: {
int v = comp_expr(s->u.assign.value, c);
int t = vreg(s->u.assign.name, c);
E(R_MOV | (t << 8) | (v << 16));
break;
}
case STMT_RETURN: {
int r = 0; if (s->u.returns.value) r = comp_expr(s->u.returns.value, c);
E(R_RET | (r << 8)); break;
}
case STMT_BLOCK: for (int i = 0; i < s->u.block.count; i++) comp_stmt(s->u.block.stmts[i], c); break;
case STMT_IF: {
int cond = comp_expr(s->u.ifs.cond, c);
E(R_JF | (cond << 8)); int jf_pc = c->clen; E(0);
comp_stmt(s->u.ifs.then_b, c);
if (s->u.ifs.else_b) {
E(R_JMP); int jmp_pc = c->clen; E(0);
c->code[jf_pc] = (c->clen - jf_pc - 1);
comp_stmt(s->u.ifs.else_b, c);
c->code[jmp_pc] = (c->clen - jmp_pc - 1);
} else {
c->code[jf_pc] = (c->clen - jf_pc - 1);
}
break;
}
case STMT_WHILE: {
int loop_pc = c->clen;
int cond = comp_expr(s->u.whiles.cond, c);
E(R_JF | (cond << 8)); int exit_pc = c->clen; E(0);
comp_stmt(s->u.whiles.body, c);
E(R_JMP); int jmp_pc = c->clen; E(0);
c->code[jmp_pc] = loop_pc - (c->clen);
c->code[exit_pc] = c->clen - exit_pc - 1;
break;
}
default: c->unsupported = 1; break;
}
}
static ByteFunc finish_rc(Rc *c, const char *name, int nargs) {
ByteFunc bf; memset(&bf, 0, sizeof(bf));
bf.code = c->code; bf.clen = c->clen;
bf.consts = c->pool; bf.nconsts = c->plen;
bf.names = c->names; bf.nnames = c->nlen;
bf.nlocals = c->nregs; bf.nargs = nargs; bf.max_args = c->max_args;
bf.unsupported = c->unsupported;
bf.name = name ? strdup(name) : strdup("<anon>");
return bf;
}
static void reset_rc(Rc *c) {
int nfunc = c->nfunc;
struct { const char *name; int index; } funcs[64];
memcpy(funcs, c->funcs, sizeof(funcs));
memset(c, 0, sizeof(*c));
memcpy(c->funcs, funcs, sizeof(funcs));
c->nfunc = nfunc;
}
static ByteFunc compile_func(Stmt *fn, Rc *c) {
reset_rc(c);
c->nargs = fn->u.func.pcount;
c->nregs = c->nargs;
for (int i = 0; i < fn->u.func.pcount; i++) {
if (c->nvar < 64) { c->vars[c->nvar].name = fn->u.func.params[i]; c->vars[c->nvar].reg = i; c->nvar++; }
}
comp_stmt(fn->u.func.body, c);
E(R_RET | (0 << 8));
return finish_rc(c, fn->u.func.name, fn->u.func.pcount);
}
ByteFunc *cvm_bc_compile_all(Runtime *rt, Program *prog, int *out_count) {
(void)rt;
int func_count = 0;
for (int i = 0; i < prog->count; i++) if (prog->stmts[i]->kind == STMT_FUNC) func_count++;
int total = func_count + 1;
ByteFunc *bfs = (ByteFunc *)calloc((size_t)total, sizeof(ByteFunc));
if (!bfs) return NULL;
Rc c; memset(&c, 0, sizeof(c));
for (int i = 0, idx = 1; i < prog->count; i++) {
if (prog->stmts[i]->kind == STMT_FUNC) {
const char *name = prog->stmts[i]->u.func.name;
if (c.nfunc < 64 && name) {
c.funcs[c.nfunc].name = name;
c.funcs[c.nfunc].index = idx++;
c.nfunc++;
}
}
}
int idx = 0;
reset_rc(&c);
for (int i = 0; i < prog->count; i++) {
if (prog->stmts[i]->kind == STMT_FUNC) continue;
comp_stmt(prog->stmts[i], &c);
}
re(R_HALT, &c);
bfs[idx++] = finish_rc(&c, "<main>", 0);
for (int i = 0; i < prog->count; i++) {
if (prog->stmts[i]->kind == STMT_FUNC) {
bfs[idx++] = compile_func(prog->stmts[i], &c);
}
}
*out_count = idx;
return bfs;
}
int cvm_bc_supported(Program *prog) {
Rc c; memset(&c, 0, sizeof(c));
for (int i = 0; i < prog->count && !c.unsupported; i++) {
if (prog->stmts[i]->kind == STMT_FUNC) {
Rc fc; memset(&fc, 0, sizeof(fc));
fc.nargs = prog->stmts[i]->u.func.pcount;
fc.nregs = fc.nargs;
for (int j = 0; j < prog->stmts[i]->u.func.pcount; j++) {
if (fc.nvar < 64) { fc.vars[fc.nvar].name = prog->stmts[i]->u.func.params[j]; fc.vars[fc.nvar].reg = j; fc.nvar++; }
}
comp_stmt(prog->stmts[i]->u.func.body, &fc);
if (fc.unsupported) c.unsupported = 1;
} else {
comp_stmt(prog->stmts[i], &c);
}
}
return !c.unsupported;
}
void cvm_bc_free(ByteFunc *bfs, int n) {
if (!bfs) return;
for (int i = 0; i < n; i++) {
free(bfs[i].code);
free(bfs[i].consts);
for (int j = 0; j < bfs[i].nnames; j++) free(bfs[i].names[j]);
free(bfs[i].names);
free(bfs[i].name);
}
free(bfs);
}
#define REGS 256
#define MAX_FRAMES 512
typedef struct {
ByteFunc *bf;
int32_t *ip;
int result_reg;
Value regs[REGS];
} CallFrame;
static ByteFunc *find_func(Runtime *rt, const char *name, ByteFunc *bfs, int nbfs) {
for (int i = 0; i < nbfs; i++) if (bfs[i].name && !strcmp(bfs[i].name, name)) return &bfs[i];
return NULL;
}
int cvm_bc_run(Runtime *rt, ByteFunc *main_bf, ByteFunc *bfs, int nbfs) {
if (!main_bf || !main_bf->code || main_bf->clen == 0) return -1;
CallFrame frames[MAX_FRAMES];
int fp = 0;
frames[0].bf = main_bf;
frames[0].ip = main_bf->code;
memset(frames[0].regs, 0, sizeof(frames[0].regs));
#define I() (*cf->ip++)
#define A(v) ((v >> 8) & 0xFF)
#define B(v) ((v >> 16) & 0xFF)
#define C(v) ((v >> 24) & 0xFF)
static const void *dt[] = {
&&L_NOP, &&L_CONST, &&L_INT, &&L_TRUE, &&L_FALSE, &&L_NIL,
&&L_LOAD, &&L_STORE,
&&L_MOV, &&L_ADD, &&L_SUB, &&L_MUL, &&L_DIV, &&L_MOD,
&&L_EQ, &&L_LT, &&L_LE, &&L_INV,
&&L_JMP, &&L_JT, &&L_JF,
&&L_CALL, &&L_RET, &&L_HALT,
&&L_LOAD_FUNC, &&L_CALL_IDX,
&&L_ADD_IMM, &&L_SUB_IMM, &&L_LT_IMM, &&L_LE_IMM
};
CallFrame *cf = &frames[0];
uint32_t ins;
#define DISP { if (cf->ip >= cf->bf->code + cf->bf->clen || rt->has_error) goto L_EXIT; ins = I(); goto *dt[ins & 0xFF]; }
DISP;
L_NOP: DISP;
L_CONST: { int r = A(ins); int ci = I(); cf->regs[r] = cf->bf->consts[ci]; DISP; }
L_INT: { int r = A(ins); int ci = I(); cf->regs[r] = cf->bf->consts[ci]; DISP; }
L_TRUE: { cf->regs[A(ins)] = val_bool(1); DISP; }
L_FALSE: { cf->regs[A(ins)] = val_bool(0); DISP; }
L_NIL: { cf->regs[A(ins)] = val_nil(); DISP; }
L_LOAD: { int r = A(ins), ni = (ins >> 16) & 0xFF;
Value *vp = env_get(rt->global, cf->bf->names[ni]);
cf->regs[r] = vp ? *vp : val_nil(); DISP; }
L_STORE: { int v = B(ins), ni = (ins >> 24) & 0xFF;
env_assign(rt->global, cf->bf->names[ni], cf->regs[v], &rt->arena); DISP; }
L_MOV: { cf->regs[A(ins)] = cf->regs[B(ins)]; DISP; }
L_ADD: L_SUB: L_MUL: L_DIV: L_MOD: L_EQ: L_LT: L_LE:
{ int op = ins & 0xFF, d = A(ins), x = B(ins), y = C(ins);
Value a = cf->regs[x], b = cf->regs[y];
if (op == R_EQ) { cf->regs[d] = val_bool(value_equal(a, b, 0)); DISP; }
if (a.type == VAL_STR && b.type == VAL_STR) {
int c = strcmp(a.as.str, b.as.str);
if (op == R_LT) cf->regs[d] = val_bool(c < 0);
else if (op == R_LE) cf->regs[d] = val_bool(c <= 0);
else { snprintf(rt->errbuf, sizeof(rt->errbuf), "字符串不支持该运算"); rt->has_error = 1; goto L_EXIT; }
DISP;
}
if (a.type == VAL_INT && b.type == VAL_INT) {
int64_t ai = a.as.i, bi = b.as.i;
switch (op) {
case R_ADD: cf->regs[d] = val_int(ai + bi); break;
case R_SUB: cf->regs[d] = val_int(ai - bi); break;
case R_MUL: cf->regs[d] = val_int(ai * bi); break;
case R_DIV: if (bi == 0) { snprintf(rt->errbuf, sizeof(rt->errbuf), "div0"); rt->has_error = 1; goto L_EXIT; } cf->regs[d] = val_int(ai / bi); break;
case R_MOD: if (bi == 0) { snprintf(rt->errbuf, sizeof(rt->errbuf), "mod0"); rt->has_error = 1; goto L_EXIT; } cf->regs[d] = val_int(ai % bi); break;
case R_LT: cf->regs[d] = val_bool(ai < bi); break;
case R_LE: cf->regs[d] = val_bool(ai <= bi); break;
default: { snprintf(rt->errbuf, sizeof(rt->errbuf), "整数不支持该运算"); rt->has_error = 1; goto L_EXIT; }
} DISP;
}
double da = (a.type == VAL_INT) ? (double)a.as.i : a.as.num;
double db = (b.type == VAL_INT) ? (double)b.as.i : b.as.num;
switch (op) {
case R_ADD: cf->regs[d] = val_num(da + db); break;
case R_SUB: cf->regs[d] = val_num(da - db); break;
case R_MUL: cf->regs[d] = val_num(da * db); break;
case R_DIV: if (db == 0) { snprintf(rt->errbuf, sizeof(rt->errbuf), "div0"); rt->has_error = 1; goto L_EXIT; } cf->regs[d] = val_num(da / db); break;
case R_MOD: if (db == 0) { snprintf(rt->errbuf, sizeof(rt->errbuf), "mod0"); rt->has_error = 1; goto L_EXIT; } cf->regs[d] = val_num(da - (int64_t)(da / db) * db); break;
case R_LT: cf->regs[d] = val_bool(da < db); break;
case R_LE: cf->regs[d] = val_bool(da <= db); break;
default: { snprintf(rt->errbuf, sizeof(rt->errbuf), "数字不支持该运算"); rt->has_error = 1; goto L_EXIT; }
} DISP;
}
L_ADD_IMM: { int d = A(ins), x = B(ins); int32_t imm = I();
Value a = cf->regs[x];
if (a.type == VAL_INT) cf->regs[d] = val_int(a.as.i + (int64_t)imm);
else cf->regs[d] = val_num(((a.type == VAL_INT) ? (double)a.as.i : a.as.num) + (double)imm);
DISP; }
L_SUB_IMM: { int d = A(ins), x = B(ins); int32_t imm = I();
Value a = cf->regs[x];
if (a.type == VAL_INT) cf->regs[d] = val_int(a.as.i - (int64_t)imm);
else cf->regs[d] = val_num(((a.type == VAL_INT) ? (double)a.as.i : a.as.num) - (double)imm);
DISP; }
L_LT_IMM: { int d = A(ins), x = B(ins); int32_t imm = I();
Value a = cf->regs[x];
if (a.type == VAL_INT) cf->regs[d] = val_bool(a.as.i < (int64_t)imm);
else cf->regs[d] = val_bool(((a.type == VAL_INT) ? (double)a.as.i : a.as.num) < (double)imm);
DISP; }
L_LE_IMM: { int d = A(ins), x = B(ins); int32_t imm = I();
Value a = cf->regs[x];
if (a.type == VAL_INT) cf->regs[d] = val_bool(a.as.i <= (int64_t)imm);
else cf->regs[d] = val_bool(((a.type == VAL_INT) ? (double)a.as.i : a.as.num) <= (double)imm);
DISP; }
L_INV: { cf->regs[A(ins)] = val_bool(!val_truthy(cf->regs[B(ins)])); DISP; }
L_JMP: { int32_t off = I(); cf->ip += off; DISP; }
L_JT: { int cr = A(ins); int32_t off = I(); if (val_truthy(cf->regs[cr])) cf->ip += off; DISP; }
L_JF: { int cr = A(ins); int32_t off = I(); if (!val_truthy(cf->regs[cr])) cf->ip += off; DISP; }
L_LOAD_FUNC: { cf->regs[A(ins)] = val_str(cf->bf->names[(ins >> 16) & 0xFF]); DISP; }
L_CALL: {
int result_reg = A(ins); int callee_reg = B(ins); int argc = C(ins);
Value callee = cf->regs[callee_reg];
if (callee.type != VAL_STR) { cf->regs[result_reg] = val_nil(); DISP; }
const char *name = callee.as.str;
ByteFunc *target = find_func(rt, name, bfs, nbfs);
if (target) {
if (argc != target->nargs) { snprintf(rt->errbuf, sizeof(rt->errbuf), "函数 '%s' 期望 %d 个参数, 收到 %d", name, target->nargs, argc); rt->has_error = 1; goto L_EXIT; }
if (fp + 1 >= MAX_FRAMES) { snprintf(rt->errbuf, sizeof(rt->errbuf), "递归深度超过上限 (%d)", MAX_FRAMES); rt->has_error = 1; goto L_EXIT; }
CallFrame *next = &frames[++fp];
next->bf = target;
next->ip = target->code;
next->result_reg = result_reg;
int to_zero = target->nlocals - argc;
if (to_zero > 0) memset(next->regs + argc, 0, (size_t)to_zero * sizeof(Value));
for (int i = 0; i < argc; i++) next->regs[i] = cf->regs[callee_reg - argc + i];
cf = next;
DISP;
}
BuiltinFunc fn = (BuiltinFunc)map_get(&rt->builtins, name);
if (fn) {
Value args[8]; for (int i = 0; i < argc && i < 8; i++) args[i] = cf->regs[callee_reg - argc + i];
cf->regs[result_reg] = fn(rt, argc, args);
if (rt->has_error) goto L_EXIT;
DISP;
}
cf->regs[result_reg] = val_nil();
DISP;
}
L_CALL_IDX: {
int result_reg = A(ins); int first_arg = B(ins); int argc = C(ins);
int32_t fidx = I();
if (fidx < 0 || fidx >= nbfs) {
snprintf(rt->errbuf, sizeof(rt->errbuf), "R_CALL_IDX 函数索引越界: %d", (int)fidx); rt->has_error = 1; goto L_EXIT;
}
ByteFunc *target = &bfs[fidx];
if (argc != target->nargs) {
snprintf(rt->errbuf, sizeof(rt->errbuf), "函数 '%s' 期望 %d 个参数, 收到 %d", target->name ? target->name : "?", target->nargs, argc); rt->has_error = 1; goto L_EXIT;
}
if (fp + 1 >= MAX_FRAMES) { snprintf(rt->errbuf, sizeof(rt->errbuf), "递归深度超过上限 (%d)", MAX_FRAMES); rt->has_error = 1; goto L_EXIT; }
CallFrame *next = &frames[++fp];
next->bf = target; next->ip = target->code; next->result_reg = result_reg;
int to_zero = target->nlocals - argc;
if (to_zero > 0) memset(next->regs + argc, 0, (size_t)to_zero * sizeof(Value));
for (int i = 0; i < argc; i++) next->regs[i] = cf->regs[first_arg + i];
cf = next;
DISP;
}
L_RET: {
int r = A(ins);
Value ret = cf->regs[r];
if (fp == 0) { cf->regs[0] = ret; goto L_EXIT; }
CallFrame *prev = &frames[--fp];
prev->regs[cf->result_reg] = ret;
cf = prev;
DISP;
}
L_HALT:
L_EXIT:
return 0;
#undef I
#undef A
#undef B
#undef C
}