定义了一个宏,可以用macroexpand-1查看宏的展开式,这里介绍一种新的方法,有助于理解宏的本质。
[5]> (defmacro moo(x y) 首先定义一个宏,非常简单
`(format t "~A : ~A~%" ,x ,y))
MOO
[6]> (moo 'asdf 'er) 执行宏,就是将输入的两个参数打印出来
ASDF : ER
NIL
[7]> (macroexpand-1 '(moo 'asdf 'ar)) 查看宏的展开式
(FORMAT T "~A : ~A~%" 'ASDF 'AR) ;
T
下面开始介绍新的方法,函数macro-function是关键,它能够获取一个宏的实现,也就是一个函数。下面就是取出来的函数,看起来很复杂,下面一行行地解读。
[8]> (setf moo-fun (macro-function 'moo))
#<FUNCTION MOO (SYSTEM::<MACRO-FORM> SYSTEM::<ENV-ARG>)
函数的名称也叫MOO,它有两个参数,第一个是调用宏时的整个表达式,包括宏名和参数,没有研究第二个参数,应该用来表示环境变量。
(DECLARE (CONS SYSTEM::<MACRO-FORM>)) (DECLARE (IGNORE SYSTEM::<ENV-ARG>))
(IF (NOT (SYSTEM::LIST-LENGTH-IN-BOUNDS-P SYSTEM::<MACRO-FORM> 3 3 NIL))
检查调用宏时输入的参数个数是否正确,最少3个参数,最多3个参数
(SYSTEM::MACRO-CALL-ERROR SYSTEM::<MACRO-FORM>)
如果参数个数不对,报错
(LET* ((X (CADR SYSTEM::<MACRO-FORM>)) (Y (CADDR SYSTEM::<MACRO-FORM>)))
列表中第一个元素是宏名,第2个元素就是参数X,第3个元素是参数Y
(BLOCK MOO `(FORMAT T "~A : ~A~%" ,X ,Y))))>
这就是宏的实现体,不用解释了
前面把宏的实现函数赋给变量moo-fun,调用它试一试,结果和macroexpand-1完全相同。
[9]> (funcall moo-fun '(moo 'asdf 'ar) nil)
(FORMAT T "~A : ~A~%" 'ASDF 'AR)
[10]>
前一篇文章介绍了运行时修改函数的实现,同样地,也可以在运行时修改宏的实现,下载DTrace的源代码,看函数trace-macro的实现,方法是相似的。