progn
是Common Lisp里面的一个special operator,见这份文档的说明:http://clhs.lisp.se/Body/s_pr...git
如今已经支持了二元四则运算了,但如今这里有一个大问题,就是这四个运算没办法嵌套着组合使用。好比,遇到下面这样的代码,jjcc2
函数就懵逼了github
(+ 1 (+ 2 3))
那要编译这种代码的话怎么办呢?一个比较直观的作法,是引入临时变量,来保存嵌套在其中的表达式的求值结果,而后再用变量来代替本来嵌套的表达式。修改后的代码可能长这个样子app
(setq a (+ 2 3)) (+ 1 a)
显然,这是有前后的时间依赖关系的两条语句,所以应当使用progn
将它们包裹起来,结果以下函数
(progn (setq a (+ 2 3)) (+ 1 a))
这样整个表达式的求值结果,或者说它被编译以后的运行结果,应当就是在寄存器EAX
中放入整数6了。因此,本篇未来解决对progn
的编译问题。rest
其实很简单,progn
可能有不定数量的form在其中,那么只须要按照顺序对它们一个个进行编译,输出汇编代码就能够了,所以最终jjcc2
被修改成以下的样子code
(defun jjcc2 (expr) "支持两个数的四则运算的编译器" (cond ((eq (first expr) '+) `((movl ,(second expr) %eax) (movl ,(third expr) %ebx) (addl %ebx %eax))) ((eq (first expr) '-) `((movl ,(second expr) %eax) (movl ,(third expr) %ebx) (subl %ebx %eax))) ((eq (first expr) '*) ;; 将两个数字相乘的结果放到第二个操做数所在的寄存器中 ;; 由于约定了用EAX寄存器做为存放最终结果给continuation用的寄存器,因此第二个操做数应当为EAX `((movl ,(second expr) %eax) (movl ,(third expr) %ebx) (imull %ebx %eax))) ((eq (first expr) '/) `((movl ,(second expr) %eax) (cltd) (movl ,(third expr) %ebx) (idivl %ebx))) ((eq (first expr) 'progn) (let ((result '())) (dolist (expr (rest expr)) (setf result (append result (jjcc2 expr)))) result))))
就酱就足够了。下一篇,是时候讲一下如何编译setq
了。orm
全文完。htm
阅读原文ci