You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开关解释器带参数过程调用实现困惑:actual_i与栈使用疑问

自研语言Switch解释器的过程调用问题

我正在为自研语言构建一个简单的switch解释器,已实现无参数函数的调用,但带参数的调用无法正常工作。执行call分支前会运行以下字节码:

18 (op code for `pushconst_i`)
20 (value) 20 (opcode for `actual_i`)

我不清楚actual_i的作用,只知道它应该把当前值传递给下一个调用者,但不理解具体实现逻辑。目前仅使用一个栈,不确定是否可行,还是应创建调用栈?当前可运行的无参数call分支代码如下:

stack[sp++].i=fp
stack[sp++].i=pc+callSize
fp=sp-2
pc+=(*(int *)&prog[pc+1])

一、actual_i的核心作用

actual_i是实参处理指令,配合pushconst_i完成函数调用前的实参准备:

  • pushconst_i 20:把常量20压入栈顶,此时栈顶是待传递的实参值
  • actual_i:将栈顶的临时值标记/固定为当前调用的实参,确保后续函数调用时能通过帧指针(fp)直接访问到这个值。简单说就是把临时栈值转成被调用函数可识别的参数。

二、单栈完全够用,无需单独创建调用栈

你现在用的单栈已经涵盖了调用栈的功能——栈中会同时存储局部变量、实参、返回地址、帧指针等信息,只要通过fp(帧指针)划分不同函数的调用帧即可,没必要额外维护独立的调用栈。

三、带参数过程调用的完整流程

带参数函数调用的核心是用调用帧隔离不同函数的上下文,完整步骤如下:

  1. 准备实参:依次将每个实参压栈,通过actual_i标记为实参(确保栈中顺序与函数形参顺序一致)
  2. 保存调用上下文:将当前的fp和返回地址(pc+callSize)压栈,更新fp指向新调用帧的起点
  3. 跳转函数入口:修改pc至函数的起始地址,开始执行函数体
  4. 函数内访问实参:通过fp的偏移量访问实参,比如第一个实参位于stack[fp + 2].i(fp指向旧帧指针,fp+1是返回地址,fp+2就是第一个实参)
  5. 函数返回:从栈中恢复旧fp和返回地址,调整sp释放当前调用帧空间,跳转回返回地址继续执行

四、适配带参数调用的call分支代码修改

你当前的代码仅处理无参数场景,带参数调用只需保留实参在调用帧中即可,修改后的代码如下:

// 保存当前帧指针和返回地址
stack[sp++].i = fp;
stack[sp++].i = pc + callSize;
// 新帧指针指向保存的旧帧指针位置,此时栈中fp到sp之间的区域为实参
fp = sp - 2;
// 跳转到函数入口地址
pc += (*(int *)&prog[pc+1]);

对应的函数返回逻辑示例:

// 取出返回地址和旧帧指针
int return_addr = stack[fp + 1].i;
fp = stack[fp].i;
// 释放当前调用帧的所有空间(实参、帧指针、返回地址)
sp = fp;
// 跳转回调用处继续执行
pc = return_addr;

五、pushconst_i + actual_i的执行细节

以调用func(20)为例,字节码执行流程:

  1. pushconst_i 20:将20压入栈顶,sp自增1
  2. actual_i:无需额外移动栈值,仅标记该位置为实参(部分简单解释器中,此指令也可省略,只要保证实参在call前按顺序压栈即可)
  3. call func:执行上述修改后的call逻辑,完成函数跳转

内容的提问来源于stack exchange,提问作者Fancyson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 17:44:52