emacs lisp 求值 eval 研究 (几何画板开发笔记 九)

eval 有些复杂, 即笨且忙的我, 能否真的弄清楚写明白是令人怀疑的.

举一个测试用例 (cons 2 3), 其返回为构造的点对 (2 . 3), 则按照上篇所述应该走第三步:

Lisp_Object original_fun = form.car;   // 即 cons
Lisp_Object fun = original_fun;  // 即 cons
fun = XSYMBOL (fun)->function;  // 为内部函数/特殊操作符 cons 在内部定义的 Lisp_Subr 对象.
if (SUBRP(fun))
   ... 执行这个内部函数/特殊操作符.

对于一个内部函数/特殊操作符 (primitive/special operator), 内部是用 Lisp_Subr 结构来定义的,
为研究该结构需要还知道 Lisp_vectorlike 等知识, 所以这里先简略一点看.

对于内部函数 cons , 对应的 Lisp_Subr 结构大致为:

Lisp_Subr S_cons = {
   min_args = 2, max_args = 2,
   func = F_cons, 其它字段暂略.
}

这个结构然后被关联到符号 Lisp_Symbol name="cons" 的 function 域, 这样在 eval() 中能够
通过 XSYMBOL(fun)->function 得到该内部函数的 Lisp_Subr 信息.

在 Lisp_Subr 中 min_args, max_args 字段用于指出这个内部函数/特殊操作符的参数数量信息,
(个人理解)基本可以分作三类:
1. 固定参数数量 min_args >=0, 以及有有限数量的可选参数即 max_args >= min_args.
    我们上面给出的测试用例 (cons 2 3) 就是这种情况.
2. 具有任意数量的参数的函数. 如 list, + 这样的函数, 其 max_args = MANY, 表示参数数量没有
   限制, 但是要先求值出来再调用 func.
3. 是特殊操作符, 不对参数求值. 例如 if, and, defalias 的特殊操作符, 其 max_args = UNEVALED,
    这些特殊操作符必须不对参数求值, 而是根据 if/and 等特殊操作符的特点, 有条件的对参数求值.

第1类的情况, 如测试用例 (cons 2 3), 对这个内建函数(primitive, built-in function) 的执行过程为:

1. 先对参数求值. 伪代码可描述为:
   for-each (a in args)   // 遍历所有参数.
      tem_arr[index++] = eval_sub (a)   // 对 a 求值, 并放在一个临时的参数结果数组中
2. 然后根据参数数量(当前实现支持对 0-8 个参数调用), 调用不同的函数形式:
    case args-num is 0:  val = func();
    case args-num is 1:  val = func(args[0]);
    ...
    case args-num is 8:  val = func(args[1], args[2], ..., args[7]);

在 Lisp_Subr 中的 function 字段在 cons 例子中所指的函数指针就是 C 语言的函数 F_cons.
通过上述过程, 将 Lisp 的函数最终地调用到 C 的实现.

在 emacs 中 lisp 函数 cons 的对应 C 实现名字实际为 Fcons, 由于我有疑似"无下划线标识符名字
识别精神障碍"病, 所以我给它改成 F_cons 好识别一些...

调用到的函数 F_cons(car, cdr) 时, 该函数按照文档和帮助所述构造出点对并返回. 具体该函数的实现,
就不在研究 eval() 的范围内了, 故而略去.

 

===

对于任意数量参数的函数, 在 Lisp_Subr 结构中 max_args 值为 MANY, min_args 可能也有非 0 值
表示需要的最少参数数量. 测试用例:
  (+ 1 2 3 4 5 6 7 8 9 10)  --- 累加 1~10.

与第1类情形相同的地方是, 这些参数要先求值, 再调用函数. 对参数求值和第1类相似, 调用函数的参数
形式略有差异:
   func(int arg-num, Lisp_Object *arg) -- 即参数是用一个数组传递的.

===

对于第3种形式, 与1,2 的最大区别是不对参数求值, 测试用例:

   (if x                           -- if (x)
       (print "x is true")    -- then
       (print "x is false"))  -- else

 当 x 求值为真的时候, 执行 then 部分的形式; x 为假的时候, 执行 else 部分的形式.

这个例子也说明了, 为什么不能对参数先求值, 因为如果先打印出 x is true, x is false 就不能
满足这个程序片段的语义需要了. 为此, if 才被称作/实现为特殊形式, 所谓特殊, 即主要指 "不对
参数求值". (在 SICP 的书上可称为正则序 vs. 应用序的对比)

由于不用对参数求值, 参数可直接使用 list 形式传递, 然后在 func 中负责拆解这个 list:

    func(args)

F_if 的具体实现部分只好再略去了. (懒, 没时间, 参见源码还算不难...)

 

转载于:https://my.oschina.net/u/232554/blog/266546

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值