Skip to content

lienhua34/CSchemer

Repository files navigation

本项目是用C语言根据R5RS标准实现的一个简易的scheme实现。本实现中省略了一些R5RS的标准内容,例如对数值类型对象只支持整数类型,对端口和卫生宏的支持等。

******************** 代码目录结构 ********************
下面是本项目的代码目录结构:
.主目录:包含主要的实现代码文件;
.子目录include:包含所有的头文件;
.子目录stdproc:包含了实现R5RS给出的scheme标准基本过程接口函数的所有文件;

在主目录中,
memory.c:实现了本scheme实现的内存模型,并提供了五个基本函数cons/car/cdr/car_set/cdr_set;
atom.c:实现了本scheme实现支持的原子对象类型的构造器,选择器和谓词,有些类型还提供了修改器;
control.c:定义了几个主要的全局变量,以及提供了用于控制参数传递的几个函数和错误处理函数error_handler;
eval.c:实现了scheme实现的两个主要函数eval和apply;
read_parse.c:实现了scheme对象的解析器;
driver_loop.c:实现了scheme实现的循环驱动程序,重复读取表达式,然后求值表达式并打印表达式的值;
garbage_collection.c:实现了本scheme实现的垃圾回收机制;
environment.c:实现环境模型;
stack.c:采用表结构实现栈;
equal_predicate.c:实现三个等价谓词eq?,eqv?和equal?
其他文件:分别是各种原子类型的操作函数;

******************** 垃圾回收 ********************
我实现的垃圾回收算法是采用SICP上面提到的停止并复制算法,其思想就是将存储器分成两半,分为“工作存储区”和“自由存储区”。当cons需要构造序对时,就在工作存储区里分配。当工作存储区满的时候就执行垃圾回收,确定位于工作存储区里的所有有用序对的位置,并将它们复制到自由存储区里的一些连续位置上。确定有用序对的方式是从某个变量出发,追踪所有的car和cdr指针。由于没复制垃圾,因此自由存储区就有一些自由空间可供分配。而工作存储区中里所有有用的序对已复制,故工作存储区的空间可释放。于是,我们将之前的自由存储区设置为现在的工作存储区,而之前的工作存储区就设置为现在的自由存储区,这样就可以供下次进行垃圾回收。

在实现垃圾回收的时候,要从某个变量(设为root)开始进行追踪所有的car和cdr。垃圾回收过程中的状态控制就是维持两个指针,free_point和scan。它们被初始化为自由存储区的开始位置。在算法开始时,把root所指向的序对重新分配到自由存储区的开始位置。在复制了这个序对之后,root指针将被调整为指向这个新位置,free_point指针的值被增加。此外还要在这个序对原来的位置加上标记,说明这个位置的内容已经移走了。标记方法如下:在原来序对的car位置里放一个特殊标记,表示这个一个已移走的对象(这种对象称为破碎的心),在其cdr位置里放一个前向指针,指向这个对象移动后的新位置。

在root重新分配之后,垃圾回收车功能续进入了基本循环。在算法的每一步,扫描指针scan指向的是一个本身已移入自由存储区的对象,但它的car和cdr指针仍然指着工作存储区里的对象。现在要重新分配这样的对象,并相应的增加scan的指针的值。为了重新分配一个对象,我们需要检查这个对象是否已被移走(查看其car位置是否存储一个破碎的心)。如果该对象没有被移走,则将其复制到由free_point指向的自由存储区的位置,更新free_point,并在这个对象的老位置设置破碎的心和前向指针,并更新指向这个对象的指针,使之指向该对象的新位置。如果这个对象已被移走,即该对象的car位置上存储一个破碎的心,则从该对象的cdr位置获取前向指针,并更新指向该对象的指针。最终所有可访问的对象都完成了移动和扫描,此时scan指针将超过free_point指针。于是垃圾回收结束。

About

implements a simple scheme implementation base on R5RS in C language.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages