Emacs 内建C语言函数实现机制
(写的不好,欢迎善意拍砖)
Emacs的历史悠久和强大自不必多说,它内建了Elisp(Lisp的一种方言)的解释引擎。它对很多后来的语言如Ruby(参见Ruby之父的How Emacs changed my life)产生了重大的影响。诸多计算机界的大拿对它青睐有加,如Donald Ervin Knuth。Coders at Work一书中有多处提到了Emacs。
Emacs是一个伟大的软件!
我在这里进行源码剖析的是GNU Emacs,而不是Emacs的其他实现(如XEmacs,它们一样很强悍)。GNU Emacs的体系架构初探,可以参见 《程序员杂志》 2003.9.1中的'GNU Emacs体系架构评论'一文,洪峰老师的评论非常犀利,见解独到。
与硬件直接作用的GNU Emacs模块(如显示模块)采用C语言编写,而绝大多数文本编辑模块则统统是利用Lisp语言来编写,据统计,Lisp占的代码量有75%之多(不是太准确的数字)。从Lisp中可以调用C语言编写的内建函数,我觉得所有C语言内建函数中最神秘的当属'eval',不管认同与否,因为eval几乎就是Elisp的解释引擎(解释引擎先进行read,再进行eval)。因此,首先窥探一下eval函数,应该是意义重大的。
时间有限,我只能先提及eval的冰山一角,它的具体逻辑还得慢慢分析。不管怎么样,先将那些神秘的宏展开,露出它的本色,再品味一下涉及到的数据结构,也是一件很爽快的事。
(注:其实我应该先说一下Lisp_Object的,但~~先来eval,我喜欢这个函数!)
// File: emacs-24.2/src/eval.c
/* Define a built-in function for calling from Lisp. `lname' should be the name to give the function in Lisp, as a null-terminated C string. `fnname' should be the name of the function in C. By convention, it starts with F. `sname' should be the name for the C constant structure that records information on this function for internal use. By convention, it should be the same as `fnname' but with S instead of F. It's too bad that C macros can't compute this from `fnname'. `minargs' should be a number, the minimum number of arguments allowed. `maxargs' should be a number, the maximum number of arguments allowed, or else MANY or UNEVALLED. MANY means pass a vector of evaluated arguments, in the form of an integer number-of-arguments followed by the address of a vector of Lisp_Objects which contains the argument values. UNEVALLED means pass the list of unevaluated arguments `intspec' says how interactive arguments are to be fetched. If the string starts with a `(', `intspec' is evaluated and the resulting list is the list of arguments. If it's a string that doesn't start with `(', the value should follow the one of the doc string for `interactive'. A null string means call interactively with no arguments. `doc' is documentation for the user. *//* This version of DEFUN declares a function prototype with the right arguments, so we can catch errors with maxargs at compile-time. */
未完待续