emacs lisp 研究 lisp.h 继续 (几何画板开发笔记 七)

粗略地研究了 Lisp_Cons 结构之后,建议研究下一个重要的结构 Lisp_Symbol:

struct Lisp_Symbol {
   unsigned gcmarkbit : 1;    // gc 标记位,与 gc 相关以后详述。
   enum symbol_redirect redirect : 3;   // 指示值存储的方式。
   unsigned constant : 2;      // 非 0 表示是常量。
   unsigned interned : 2;      // 是否 interned 标志,值为 enum symbol_interned
   unsigned declared_special : 1;   // 是否特殊变量。
   Lisp_Object name;           // 此符号的名字,是一个 Lisp_String 对象。
   Lisp_Object val.value;      // 此符号绑定的值。参见注解。
   Lisp_Object function;      // 此符号绑定的函数。如果未绑定到函数则为 Qunbound.
   Lisp_Object plist;            // 此符号的属性列表(plist)
   struct Lisp_Symbol *next;    // 在 hash 表的下一项,如果放入到 hash 表的话。一般都放的。
};
注: val.value 字段是一个 union { ... } val; 为简化问题,我们先取最主要的形式 value.

这里 Lisp_Symbol 拥有不少字段,各字段与 lisp 实现的其它部分密切相关,我们这里先不详细
研究各个字段的具体详细语义,而是仅关心当前需要的一些信息就可以。

那么现在关心的是 如何从 Lisp_Object 知道是一个 symbol,并转换为 Lisp_Symbol 结构的指针。

#define SYMBOLP(o)   (XTYPE(o) == Lisp_Symbol)   // 判断o 是一个 symbol。
#define XSYMBOL(o)   (assert(SYMBOLP(o)),  \
      (struct Lisp_Symbol *) XUNTAG (o, Lisp_Symbol)) 

宏 XSYMBOL() 用于当已知 o 是一个 symbol 对象(指针)时,得到到 Lisp_Symbol 结构的指针。
这个宏和 XCONS() 宏是类似的,原 lisp.h 中实际也是定义在一个地方。

另外的细节是,Lisp_Symbol 结构当前的字节尺寸是 sizeof(Lisp_Symbol)=24,这个数字是 8 字节的
整数倍,对于稍后研究的内存分配系统来说是有影响的。

 

前面介绍 Lisp_Cons 的时候,漏掉一点,即已知一个 Lisp_Cons 结构的指针,构造出一个
Lisp_Object 以指向该结构:
#define XSETCONS(a, b)    ((a) = make_lisp_ptr (b, Lisp_Cons))

例如:
   struct Lisp_Cons *c = alloc_cons(...);   // 分配一个 cons 内存。
   c->car = xxx; c->cdr = yyy;    // 设置点对值
   Lisp_Object a; 
   XSETCONS (a, c);  // 即  Lisp_Object a = make_lisp_ptr (c, Lisp_Cons)

宏(函数) make_lisp_ptr() 用于将指针 c 转换为指定tag 类型的 Lisp_Object:

#define make_lisp_ptr(ptr, type)   \
     (assert (ptr 必须对齐到 8 字节边界),    \
      XIL((type) | (intptr_t)(ptr)))

注意这里检测 ptr 对齐到 8 字节边界,是为了满足低 3 bit 用作 tag 的要求。
XIL() 前面已描述过,是 int -> Lisp_Object 的转换。 (type) 即为 tag。

与 XSETCONS() 类似的 XSETSYMBOL() 宏:

#define XSETSYMBOL(a, b)   ((a) = make_lisp_ptr((b), Lisp_Symbol))

其实我还是更愿意写为: a = make_symbol_object(b) 看起来更容易理解。。。

另有一组获取 Lisp_Symbol 中各个字段值得宏,如:

// 得到 Lisp_Symbol *sym 的值。
#define SYMBOL_VAL(sym)     (assert(以后描述), sym->val.value)

使用举例:
Lisp_Object s;   // 符号 
Lisp_Object value = SYMBOL_VAL (XSYMBOL (s))   // 得到符号的值。

// 得到符号的名字:
#define SYMBOL_NAME(sym)    XSYMBOL (sym)->name
// 写为函数形式:
inline Lisp_Object symbol_name(Lisp_Object sym) {
   return XSYMBOL (sym)->name;
}

其它各个 Lisp_Symbol 结构中的字段读取和设置的宏,比较类似,我们暂时略去,
待到研究其使用的地方再次回顾。


===

关于结构 Lisp_String 也可以适当先介绍一些。

struct Lisp_String {
   ptrdiff_t size;    // 字符串长度,以字符为单位。 size 的最高位用作 gcmarkbit.
   ptrdiff_t size_byte;   // 字符串的字节长度。对于 multibyte 如汉字字符串,与 size 值将不同。
   INTERVAL intervals;     // 与 emacs 文本编辑有关的结构,我们可以略去先不研究。
   unsigned char *data;   // 实际字符串数据的指针。 
};

与 Lisp_Cons, Lisp_Symbol 类似,也有 STRINGP(), XSTRING() 的宏:

#define STRINGP(o)   (XTYPE(o) == Lisp_String)
#define XSTRING(o)   (assert (STRINGP (o)), (struct Lisp_String *) XUNTAG(o, Lisp_String))
#define XSETSTRING(a, b)  类似于 XSETSYMBOL(), XSETCONS()

另有获得字符串结构 Lisp_String 中各个字段的宏,待我们需要使用它们的时候再研究吧。

 

你可能感兴趣的:(lisp)