「700行手写编译器」Part 2.2:栈与函数调用 笔记

在这里插入图片描述
问:为什么内存空间中要有code和data?
答:因为代码要执行需要地方存储代码,代码执行过程中需要用到或者存储一些数据,需要一些地方存数据。

问:为什么要有stack?
答:因为有函数调用,要存储函数调用的过程以及过程中的相关变量。
在这里插入图片描述
函数调用的过程中stack主要是存储函数地址,参数值,返回值,返回地址。可以用别的方式不用stack的方式实现函数调用过程,但是内存空间的维护会更加复杂。

上图中的code是实现了一个二元的加法,如3+4这种
上图中的code是实现了一个二元的加法,如3+4这种,“,”输入数字3,探针右移,“,”输入数字4,然后“[”判断4!=0那就不会跳转继续执行,在“[ < + > ]”的循环过程中让3的位置不断+1,4的位置不断-1,直到4的位置减到0,那么原本3的位置就实现了3+4的结果。

问:是不是一定要有函数调用?
答:可以没有函数调用,比如Brain-Fuck,一共只有八个语句“<”“>”“+”“-”“[”“]”“,”“.”。

关于Brain-Fuck:一共只有八个语句“<”“>”“+”“-”“[”“]”“,”“.”,假设有两个纸带,一个纸带装语言本身,另一个指带装数据,有一个指针指在数据的纸带位置上,关于符号:
“<”探针左移一格;
“>”探针右移一格;
“+”是探针所指地方的数据+1;
“-”是探针所指地方的数据-1;
“[”是代码区根据条件判断是否要跳转(条件是探针所指的位置是否为0,不为0直接执行,为0就跳转到对应的“]”),类似JZ;
“]”是代码区根据条件判断是否要跳转(条件是探针所指的位置是否为0,为0直接执行,不为0就跳转到对应的“[”),类似JNZ;

任何计算机的复杂性问题都能通过设计中间层或抽象层去解决,比如设计抽象层----函数。

在这里插入图片描述
这里以执行main函数的过程中调用add函数为例。

// some complicate instructions for function call
// call function: push pc + 1 to stack & pc jump to func addr(pc point to)
else if (op == CALL)    {*--sp = (int)(pc+1); pc = (int*)*pc;}
// new stack frame for vars: save bp, bp -> caller stack, stack add frame
else if (op == NVAR)    {*--sp = (int)bp; bp = sp; sp = sp - *pc++;}
// delete stack frame for args: same as x86 : add esp, <size>
else if (op == DARG)    sp = sp + *pc++;
// return caller: retore stack, retore old bp, pc point to caller code addr(store by CALL) 
else if (op == RET)     {sp = bp; bp = (int*)*sp++; pc = (int*)*sp++;}        
// end for call function.

CALL过程的解析:首先把pc的下一个位置的值,压入栈中;然后pc跳转到CALL所调用函数的位置
NVAR(new stack frame for variable,为函数调用中需要传递的参数开辟存储的空间)过程的解析:先把目前的栈底压入栈中;然后bp移动到sp的位置;移动sp给栈增加一些空间存储局部变量。
DARG(delete stack frame for argument,删除为函数调用中需要传递的参数存储的空间)过程的解析:sp上移回去,释放一部分栈的存储空间。
RET过程的解析:sp移动到bp的位置,中间所有的栈空间都销毁;bp指到sp所指位置中描述的地址,也就是上一个函数的bp位置,然后sp++;pc指到原先应该要执行的下一条指令的位置(存在当前的sp中),然后sp++。

在这里插入图片描述

// native call
else if (op == OPEN)    {ax = open((char*)sp[1], sp[0]);}
else if (op == CLOS)    {ax = close(*sp);}
else if (op == READ)    {ax = read(sp[2], (char*)sp[1], *sp);}
else if (op == PRTF)    {tmp = sp + pc[1] - 1; ax = printf((char*)tmp[0], tmp[-1], tmp[-2], tmp[-3], tmp[-4], tmp[-5]);}
else if (op == MALC)    {ax = (int)malloc(*sp);}
else if (op == FREE)    {free((void*)*sp);}
else if (op == MSET)    {ax = (int)memset((char*)sp[2], sp[1], *sp);}
else if (op == MCMP)    {ax = memcmp((char*)sp[2], (char*)sp[1], *sp);}
else if (op == EXIT)    {printf("exit(%lld)\n", *sp); return *sp;}
else {printf("unkown instruction: %lld, cycle: %lld\n", op, cycle); return -1;}

native call部分完全copy from C4
printf = write(fd=1, …)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃小酥肉的小波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值