是的,您可以采用
格林斯潘第十法则,在C语言中开发一个完整的动态语言,并在此过程中开发一个相对干净的C运行时,可从C语言内部使用。
在
这个项目中,我就是这样做的,之前也有其他人这样做过。
在该项目的C运行时中,会从C数字创建一个通用数字,如下所示:
val n = num(42);
由于
val
的表示方式,它只占用一个机器字。几位类型标记被用来区分数字、指针、字符等。
另外还有这个:
val n = num_fast(42);
这是英文原文的翻译:
这个宏(位操作宏)要快得多,因为它没有进行任何特殊检查以确保数字42适合“fixnum”范围;它用于小整数。
一个将其参数添加到向量的每个元素的函数可以像这样编写(非常低效):
val vector_add(val vec, val delta)
{
val iter;
for (iter = zero; lt(iter, length(vec)); iter = plus(iter, one)) {
val *pelem = vecref_l(vec, iter);
*pelem = plus(*pelem, delta);
}
return nil;
}
由于
plus
是通用的,因此它可以与fixnums、bignums和实数一起使用,也可以与字符一起使用,因为通过
plus
可以向字符添加整数位移。
类型不匹配错误将被低级函数捕获并转换为异常。例如,如果
vec
不是可以应用
length
的东西,
length
将抛出异常。
带有
_l
后缀的函数返回一个位置。而
vecref(v, i)
返回向量
v
中偏移量
i
处的值,
vecref_l(v, i)
返回存储该值的
val
类型位置的指针。
这都是C语言,只不过ISO C规则有点弯曲:在严格符合C规范的情况下,无法有效地创建像
val
这样的类型,但您可以在支持的体系结构和编译器中相当可移植地完成。
我们的
vector_add
不够通用。有可能做得更好:
val sequence_add(val vec, val delta)
{
val iter;
for (iter = zero; lt(iter, length(vec)); iter = plus(iter, one)) {
val elem = ref(vec, iter);
refset(vec, iter, plus(elem, delta));
}
return nil;
}
通过使用通用的
ref
和
refset
,现在它也适用于列表和字符串,而不仅仅是向量。我们可以这样做:
val str = string(L"abcd");
sequence_add(str, num(2));
变量
str
的内容将会发生改变,因为每个字符都会被原地加上位移量
2
,最终结果为
cdef
。
type_size
字段似乎是多余的,因为你只能存储void*
大小的数据。你可以选择存储任意固定一致大小的内存块,而不是存储指针。 - Ben Voigt