emacs
源码中的Qtop_level
和Vtop_level
有时候光顾着调试看流程,忽略了代码中的细小差别,如果不特别留意的话很难发现这是两个不同的变量Qtop_level
和Vtop_level
,它们是如此相似:
(gdb) p Qtop_level
$1 = (struct Lisp_X *) 0xdd70
(gdb) xtype
Lisp_Symbol
(gdb) p Vtop_level
$2 = XIL(0x6fffffc7a343)
(gdb) xtype
Lisp_Cons
(gdb) pp Qtop_level
$3 = top-level
(gdb) pp Vtop_level
$4 = (normal-top-level)
(gdb) p XTYPE(Qtop_level)
$5 = Lisp_Symbol
(gdb) p XTYPE(Vtop_level)
$6 = Lisp_Cons
它们的定义都可以在globals.h
中找到:
#define Vtop_level globals.f_Vtop_level
#define Qtop_level builtin_lisp_symbol (1181)
(预备知识)如何生成globals.h
,详见“emacs 源码分析(一)”,简单来说:
emacs
开始时,make-docfile
首先会被调用生成globals.h
。make-docfile
会调用每个xxx.c
文件里的syms_of_xxx()
函数,这里的xxx
表示.c
的文件名,比如keyboard.c
,就会去调用syms_of_keyboard()
函数。syms_of_xxx()
中的定义都放在globals.h
中。DEFUN
定义的Primitive Function
,DEFVAR_LISP
定义的variable
。有了这里的预备知识,现在就知道了Qtop_level
是一个Lisp_Symbol
,它是一个primitive
函数,即:
DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "",
doc: /* Exit all recursive editing levels.
This also exits all active minibuffers. */
attributes: noreturn)
(void)
{
#ifdef HAVE_WINDOW_SYSTEM
if (display_hourglass_p)
cancel_hourglass ();
#endif
/* Unblock input if we enter with input blocked. This may happen if
redisplay traps e.g. during tool-bar update with input blocked. */
totally_unblock_input ();
Fthrow (Qtop_level, Qnil);
}
可以通过C-h f
来查看帮助:
top-level is an interactive built-in function in ‘src/keyboard.c’.
(top-level)
Exit all recursive editing levels.
This also exits all active minibuffers.
Probably introduced at or before Emacs version 1.1.
再说Vtop_level
,它是一个Lisp_Cons
,它的定义在src/keyboard.c
中,它其实就是一个emacs-lisp
表达式,是一个list
,这里是(normal-top-level)
:
DEFVAR_LISP ("top-level", Vtop_level,
doc: /* Form to evaluate when Emacs starts up.
Useful to set before you dump a modified Emacs. */);
可以通过C-h v
来查看帮助:
top-level is a variable defined in ‘src/keyboard.c’.
Its value is (normal-top-level)
Form to evaluate when Emacs starts up.
Useful to set before you dump a modified Emacs.
Probably introduced at or before Emacs version 1.1.