开关解释器带参数过程调用实现困惑: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(帧指针)划分不同函数的调用帧即可,没必要额外维护独立的调用栈。
三、带参数过程调用的完整流程
带参数函数调用的核心是用调用帧隔离不同函数的上下文,完整步骤如下:
- 准备实参:依次将每个实参压栈,通过
actual_i标记为实参(确保栈中顺序与函数形参顺序一致) - 保存调用上下文:将当前的
fp和返回地址(pc+callSize)压栈,更新fp指向新调用帧的起点 - 跳转函数入口:修改
pc至函数的起始地址,开始执行函数体 - 函数内访问实参:通过
fp的偏移量访问实参,比如第一个实参位于stack[fp + 2].i(fp指向旧帧指针,fp+1是返回地址,fp+2就是第一个实参) - 函数返回:从栈中恢复旧
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)为例,字节码执行流程:
pushconst_i 20:将20压入栈顶,sp自增1actual_i:无需额外移动栈值,仅标记该位置为实参(部分简单解释器中,此指令也可省略,只要保证实参在call前按顺序压栈即可)call func:执行上述修改后的call逻辑,完成函数跳转
内容的提问来源于stack exchange,提问作者Fancyson
相关产品推荐
相关产品推荐

