内容简介:在中的嵌套的表达式PS:上面的结果中的
在 上一篇文章
中, jjcc2
函数实现了对 setq
这个语句的编译。这么一来,便可以将加减乘除运算中的嵌套表达式都替换为变量了。比如,将
(+ (+ 1 2) 3)
中的嵌套的表达式 (+ 1 2)
用一个变量 G564
代替,变成
(PROGN (SETQ #:G564 (+ 1 2)) (+ #:G564 3))
PS:上面的结果中的 #:G564
只是打印出来的时候长这个样子而已,实际地输入这段代码的话,两个 #:G564
其实是不同的符号,会导致未绑定的变量的错误的。
言归正传。既然如此,现在就要来支持编译 (+ #:G564 3)
这样的表达式了。其实这个真的是太简单了,只需要将这个符号塞入到 jjcc2
的第二个参数的 globals
中,然后在生成的“汇编指令”的S表达式中,嵌入这个符号即可。
我刚开始的时候也是这么想的,后来发现这样出来的代码编译不过,哭
折腾了一小段时间后,才知道原来有一种叫做“RIP-relative”的东西——好吧,我的X64的汇编语言知识也是赶鸭子上架的,遇到什么问题就放狗搜,所以完全不成体系——总之,我找到了解决办法,就是将原本放入一个符号的操作数,替换为类似于下面这样的内容
G564(%RIP)
所以对于操作数,实际上还需要先判断一下其类型。如果是整数,就按照原来的方式原样输出;如果是符号,就生成像上面这样的RIP-relative的结构。这部分太经常出现了,于是提炼出了一个专门处理四则运算的操作数的辅助函数 get-operand
(defun get-operand (expr n) "从EXPR中提取出第N个操作数,操作数的下标从0开始计算" (check-type expr list) (check-type n integer) (let ((e (nth (1+ n) expr))) (etypecase e (integer e) (symbol (format nil "~A(%RIP)" e)))))
借助它重写 jjcc2
,结果如下
(defun jjcc2 (expr globals) "支持两个数的四则运算的编译器" (check-type globals hash-table) (cond ((eq (first expr) '+) `((movl ,(get-operand expr 0) %eax) (movl ,(get-operand expr 1) %ebx) (addl %ebx %eax))) ((eq (first expr) '-) `((movl ,(get-operand expr 0) %eax) (movl ,(get-operand expr 1) %ebx) (subl %ebx %eax))) ((eq (first expr) '*) ;; 将两个数字相乘的结果放到第二个操作数所在的寄存器中 ;; 因为约定了用EAX寄存器作为存放最终结果给continuation用的寄存器,所以第二个操作数应当为EAX `((movl ,(get-operand expr 0) %eax) (movl ,(get-operand expr 1) %ebx) (imull %ebx %eax))) ((eq (first expr) '/) `((movl ,(get-operand expr 0) %eax) (cltd) (movl ,(get-operand expr 1) %ebx) (idivl %ebx))) ((eq (first expr) 'progn) (let ((result '())) (dolist (expr (rest expr)) (setf result (append result (jjcc2 expr globals)))) result)) ((eq (first expr) 'setq) ;; 编译赋值语句的方式比较简单,就是将被赋值的符号视为一个全局变量,然后将eax寄存器中的内容移动到这里面去 ;; TODO: 这里expr的second的结果必须是一个符号才行 ;; FIXME: 不知道应该赋值什么比较好,先随便写个0吧 (setf (gethash (second expr) globals) 0) (values (append (jjcc2 (third expr) globals) ;; 为了方便stringify函数的实现,这里直接构造出RIP-relative形式的字符串 `((movl %eax ,(get-operand expr 0)))) globals))))
现在,如果运行下面的这个 example1
函数
(defun example1 () "验证jjcc2确实可以处理含有变量的加减乘除运算" (let ((ht (make-hash-table))) (setf (gethash 'a ht) 1) (let ((asm (jjcc2 '(+ a a) ht))) (stringify asm ht))))
便可以得到下面这段汇编代码了
.data A: .long 1 .section __TEXT,__text,regular,pure_instructions .globl _main _main: MOVL A(%RIP), %EAX MOVL A(%RIP), %EBX ADDL %EBX, %EAX movl %eax, %edi movl $0x2000001, %eax syscall
全文完。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 1034 有理数四则运算 (20 分)java
- 重学前端学习笔记(二十八)--通过四则运算的解释器快速理解编译原理
- 编译原理实战入门:用 JavaScript 写一个简单的四则运算编译器(四)结语
- 编译原理实战入门:用 JavaScript 写一个简单的四则运算编译器(一)词法分析
- 编译原理实战入门:用 JavaScript 写一个简单的四则运算编译器(三)模拟执行
- 编译原理实战入门:用 JavaScript 写一个简单的四则运算编译器(二)语法分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Black Box Society
Frank Pasquale / Harvard University Press / 2015-1-5 / USD 35.00
Every day, corporations are connecting the dots about our personal behavior—silently scrutinizing clues left behind by our work habits and Internet use. The data compiled and portraits created are inc......一起来看看 《The Black Box Society》 这本书的介绍吧!