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))  ci

宏 XSYMBOL() 用於當已知 o 是一個 symbol 對象(指針)時,獲得到 Lisp_Symbol 結構的指針。
這個宏和 XCONS() 宏是相似的,原 lisp.h 中實際也是定義在一個地方。 字符串

另外的細節是,Lisp_Symbol 結構當前的字節尺寸是 sizeof(Lisp_Symbol)=24,這個數字是 8 字節的
整數倍,對於稍後研究的內存分配系統來講是有影響的。 emacs

 

前面介紹 Lisp_Cons 的時候,漏掉一點,即已知一個 Lisp_Cons 結構的指針,構造出一個
Lisp_Object 以指向該結構:
#define XSETCONS(a, b)    ((a) = make_lisp_ptr (b, Lisp_Cons)) hash

例如:
   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) it

宏(函數) make_lisp_ptr() 用於將指針 c 轉換爲指定tag 類型的 Lisp_Object: io

#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 中各個字段的宏,待咱們須要使用它們的時候再研究吧。

相關文章
相關標籤/搜索