edebug
源码级调试器Edebug 是一个源码级调试器。Edebug 通常显示你正在调试的代码的源码,左边有一个箭头,指示你当前执行的是哪一行。
你可以逐行地走过函数的执行,或者快速运行直到达到一个断点,在那里停止执行。
有关 Edebug 的详细信息,请参阅Edebug in GNU Emacs Lisp 参考手册。
下面是一个有bug的 triangle-recursively
函数定义。参见See 替代计数的递归, 进行查看。
(defun triangle-recursively-bugged (number)
"返回1到NUMBER(包括)之间数字的和,使用递归。"
(if (= number 1)
1
(+ number
(triangle-recursively-bugged
(1= number))))) ; 这里有错误。
通常,你会通过将光标定位在函数的闭括号之后,然后输入 C-x C-e(eval-last-sexp
),或者将光标定位在定义内部,然后输入 C-M-x(eval-defun
)来安装这个定义。 (默认情况下,eval-defun
命令仅在 Emacs Lisp 模式或 Lisp 交互模式下工作。)
然而,为了准备这个函数定义以供 Edebug 使用,你必须首先使用不同的命令进行仪器化。你可以将光标定位在定义内部或之后,然后输入
M-x edebug-defun RET
这将导致 Emacs 在需要时自动加载 Edebug(如果尚未加载),并正确地仪器化该函数。
在仪器化函数之后,将光标放在以下表达式之后,然后输入 C-x C-e(eval-last-sexp
):
(triangle-recursively-bugged 3)
你将跳转回 triangle-recursively-bugged
的源码,光标定位在函数的 if
行的开头。此外,你将在该行的左侧看到一个箭头。箭头标记了函数执行的行。在下面的示例中,我们使用‘=>’显示箭头;在窗口系统中,你可能会在窗口边缘看到箭头作为一个实心三角形。
=>∗(if (= number 1)
在示例中,点的位置显示为 ‘∗’(在印刷书籍中,它显示为一个五角星)。
如果现在按下 SPC 键,点将移动到下一个要执行的表达式;该行将如下所示:
=>(if ∗(= number 1)
随着你继续按下 SPC,点将从一个表达式移动到另一个表达式。与此同时,每当一个表达式返回一个值时,该值将显示在回显区域。例如,当你将点移到 number
后面时,你将看到以下内容:
Result: 3 (#o3, #x3, ?\C-c)
这意味着 number
的值是3,即八进制三,十六进制三,和 ASCII 控制字符C(字母表的第三个字母,如果你需要知道这些信息)。
你可以继续移动代码,直到到达包含错误的行。在评估之前,该行看起来像这样:
=> ∗(1= number))))) ; 这里有错误。
当你再次按下 SPC 时,将会产生一个错误消息,说:
Symbol's function definition is void: 1=
这就是bug。
按下 q 退出 Edebug。
要从函数定义中删除仪器化,只需使用不对其进行仪器化的命令重新评估它。例如,你可以将光标放在定义的闭括号之后,然后输入 C-x C-e。
Edebug 不仅仅能够与你一起逐步执行函数。你可以设置它,让它自己快速执行,只在错误或指定的停止点停下;你可以让它显示各种表达式的变化值;你可以了解一个函数被调用了多少次,等等。
有关 Edebug 的详细信息,请参阅Edebug in GNU Emacs Lisp 参考手册。