文档章节

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

刘军兴
 刘军兴
发布于 2014/05/12 17:23
字数 1004
阅读 85
收藏 0

对基础的 lisp.h 的研究当然还没完,该文件可是有 3700+ 行之多的。前几篇基本只涉及了 15%?左右吧。
因为各部分之间是相互有关联的,单独看 lisp.h 文件也不可能理解其自身,所以在了解了很基本的 Lisp_Object,
Lisp_Symbol, Lisp_Cons 之后,我们就可以试着去研究一下 lisp 的核心:求值 eval() 了。

在研究之前,再略微啰嗦一点,Lisp 语言中有著名的 REPL -- Read,Eval,Print,Loop 循环,(当然
其它脚本语言中也有。。。),其中 eval 负责对读入的表达式进行求值,print 负责打印求值结果,
顾名思义 read 负责读入表达式。这个表达式就是著名的 s-expr。当然 read, print 部分我们只能先
假设已经存在并且按我们的愿望运转,这样我们就能专心研究 eval 部分了。

 

从外部来看,在读取一个表达式 form 后,调用函数 Feval(form, ...) 进行求值。由于 Feval() 中仅是
设置了一下词法环境(稍后再研究的),然后调用主要求值函数 eval_sub() 进行求值,因此我们主要
从函数 eval_sub(form) 开始。 

Lisp_Object eval_sub(Lisp_Object form) {
   if (form 是 symbol) 对 symbol 求值并返回。
   if (form 是 atom) 返回 atom 自身,因为 lisp 求值规则 atom 求值为自身。
   否则 form 必定是一个列表(list),对该列表求值,当做函数调用(或宏)。
}

为研究这个函数,对 lisp 求值规则的了解是不可少的。首先,对 symbol 的求值,就是得到该
symbol 绑定的值,一般而言就是 Lisp_Symbol 结构中的 value 值。如果有词法绑定,会略微复杂
一点,我们将词法绑定相关的部分放到研究函数(lambda)的时候再细究。

次之,是对 atom 的求值,在 lisp 中,数字(整数、浮点数等)、字符串、字符等非 list 的对象
都是 atom,它们求值返回其自身。

最复杂的是对 list 的求值,list 是由 Lisp_Cons 点对单元构成的单链表,car 槽存放值,cdr 槽存放
链表剩余部分。当对一个 list 求值的时候,列表的第一项被当做是函数(或宏),列表的剩余部分被
作为是函数的参数。

例如,我们以 lisp 表达式 (+ 3 4) 为例,该 form 求值为 3+4 即 7.

第一步,获得此 form 的第一个元素,如果该元素是一个 symbol 则得到该 symbol 的函数:

Lisp_Object original_fun = XCAR(form);   // 即得到 +那个 Lisp_Symbol
// 中间一些关于 gc, stack backtrace, debug 等暂时略,以后详细说明。
Lisp_Object fun = XSYMBOL (original_fun) -> function;  // 得到该符号绑定的函数

这里 ‘+’ 对应 +符号,在 emacs lisp 初始化的时候构造此符号,并将函数(function)
Fadd() 绑定到该‘+’ 符号。 Fadd() 函数负责执行数学加法。具体初始化过程以后详述。

第二步:根据第一个元素(如果是函数则得到其函数对象 fun),有三种处理分支:
   (a) 是 lisp 内建函数(builtin, primitive)或原语(special operator),则调用该函数对应的
        实现 C 函数。
   (b) 是编译之后的字节码(compiled bytecode),我们以后研究 emacs lisp 编译的时候再看。
   (c) 如果第一个元素不是 symbol,那就必须是一个 list,否则报错。到第四步详述。

第三步:执行 lisp 内建函数,或原语。
   这一执行过程需要展开描述,我们下面叙述。

第四步:fun 是一个 list,则取出这个 list 的第一个元素:
   Lisp_Object funcar = XCAR (fun)
并根据这个元素是 lambda, macro, autoload 的不同而执行。如果不是这些则报错。

最后,上面各步骤或分支的执行结果为一个 Lisp_Object, 作为结果值返回。

所以,这里的关键是第三和第四(三、四是分支)的情况。

===

由于 eval() 较复杂,第三、四步我们下一篇继续研究。

 

© 著作权归作者所有

刘军兴
粉丝 59
博文 189
码字总数 237645
作品 0
昌平
私信 提问
emacs lisp 研究 lisp.h (几何画板开发笔记 四)

由于想为所做的几何画板(类)和几何推理引入一种驱动语言,近期研究了 lisp 语言, 其中 emacs lisp 方言的实现看起来规模大小适合,我基本选择它作为研究对象,以 期待能引入到几何软件中。...

刘军兴
2014/05/11
149
0
对 volatile 的对象取值和赋值 (几何画板开发笔记 二)

问题提出: 在研究和借鉴 emacs lisp 实现程序时, 有部分值被定义为 volatile 的, 则对其取值和赋值都有些不同, 在 C++ 中. 例子: struct Lisp_Object { int i; }; // 这是 lisp 基本对象结构...

刘军兴
2014/05/03
224
0
emacs lisp 研究 lisp.h 继续 (几何画板开发笔记 七)

粗略地研究了 LispCons 结构之后,建议研究下一个重要的结构 LispSymbol: struct LispSymbol { unsigned gcmarkbit : 1; // gc 标记位,与 gc 相关以后详述。 enum symbolredirect redirect...

刘军兴
2014/05/12
94
0
emacs lisp 研究 lisp.h 继续 (几何画板开发笔记 五)

在前一篇中我们已经研究了结构 Lisp_Object,因为其太重要了,并且本篇要继续研究它, 所以再次列出其结构如下: typedef struct { int i; } Lisp_Object; 然后是对其进行访问的一系列宏及函...

刘军兴
2014/05/11
85
0
emacs lisp 研究 lisp.h 继续 (几何画板开发笔记 六)

继续前一篇,关于 struct Lisp_Object 还有一点点相关的宏(函数)要说明。 已知 struct Lisp_Object 的字段 i 中有 val+tag 两种信息,也已知 XTYPE() 宏用于得到 tag 信息,那么也一定有获...

刘军兴
2014/05/12
73
0

没有更多内容

加载失败,请刷新页面

加载更多

CentOS 7 搭建源码包搭建LNMP环境

1,安装epel源 yum install -y epel-release 2, 安装需要的软件 yum install -y gcc automake autoconf libtool make gcc-c++ glibc libxslt-devel \libjpeg libjpeg-devel libpng libpng......

hansonwong
52分钟前
7
0
基于 K8s 做应用发布的工具那么多, 阿里为啥选择灰姑娘般的 Tekton ?

作者 | 邓洪超,阿里云容器平台工程师, Kubernetes Operator 第二人,云原生应用标准交付与管理领域知名技术专家 导读:近年来,越来越多专门给 Kubernetes 做应用发布的工具开始缤纷呈现,...

阿里巴巴云原生
53分钟前
4
0
ZStack的普惠云计算到底是“随大流”还是真功夫?(转自社区)

作为一名深耕技术圈的“老男人”,也算是经历过云计算领域的成长。近些年云计算技术不断成熟,百行百业开始云上之路,各大云计算厂商开始逐渐意识到云计算是一项“普惠”技术。 我一直很看好...

ZStack社区版
54分钟前
5
0
一个备份MySQL数据库的简单Shell脚本

Shell脚本是我们写不同类型命令的一种脚本,这些命令在这一个文件中就可以执行。我们也可以逐一敲入命令手动执行。如果我们要使用shell脚本就必须在一开始把这些命令写到一个文本文件中,以后...

旺仔大战肥五花
59分钟前
3
0
TiDB Binlog 源码阅读系列文章(四)Pump server 介绍

作者: satoru 在 上篇文章 中,我们介绍了 TiDB 如何通过 Pump client 将 binlog 发往 Pump,本文将继续介绍 Pump server 的实现,对应的源码主要集中在 TiDB Binlog 仓库的 pump/server.go...

TiDB
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部