elisp动态作用域的实现
2012-06-05
主要文件在 lisp.h 和 eval.c
symbol 对象包含4个域:
name 符号名
value 值
function 函数
plist 属性链
隐含一个 next 域指针,指向下一个 symbol
有个全局的 obarray,其实就是个 vector 类型的 lisp 对象。
符号名通过 hash 确定在 obarray 中的哪一个桶,然后根据 next 域出去找到最终的 symbol 对象
struct specbinding
{
Lisp_Object symbol, old_value;
specbinding_func func;
Lisp_Object unused; /* Dividing by 16 is faster than by 12 */
};
全局有个 specpdl 指向 specbinding 的数组,specpdlptr 指向数组的当前位置
相当于一个栈。通过这个结构体做绑定的。
每进入一个新的作用域,比如 (let (x) ...)
,将符号 x 的旧值放在 specpdlptr 中存起来
x 的新值替换 x 的 symbol对象中原来的 value。
当退出作用域的时候用 specpdlptr 中的值恢复 x 的原值
elisp 中没有环境的概念,就通过全局的 obarray 寻找符号的值,通过 specbinding 保存符号在各调用栈上的值
其实本质上就相当于 elisp 中,仅有一个全局的 env,就是 obarray。
然后每个符号都有一个值的栈。进放一个作用域就进栈一个值,出作用域时这个值出栈,符号始终绑定到栈顶的值
没有闭包。闭包=代码+环境。这里环境不成立了
emacs 的源代码比较乱,文档对于 internals 的解释也不好。
对照 xemacs internals 看比较容易看懂。