如何编译setq?

栏目: 编程语言 · 发布时间: 5年前

内容简介:Common Lisp中的这样的代码,那么在最后生成的代码中,就会相应的在既然都是全局变量,那么只需要准备一个容器来盛这些变量名即可。现阶段,暂时认为所有的变量都是数值类型即可。简单起见,这个容器直接用Common Lisp内置的

Common Lisp中的 setq 类似于其它语言中的赋值语句,它可以给一个符号对象设定一个值,类似于将一个值赋值给一个变量一样。简单起见,在 jjcc2 中,我会将所有的符号都作为全局的一个label来实现。也就是说,如果代码中出现了

(setq a 1)

这样的代码,那么在最后生成的代码中,就会相应的在 .data 段中有一个同名的label,其中存放着数值1。

既然都是全局变量,那么只需要准备一个容器来盛这些变量名即可。现阶段,暂时认为所有的变量都是数值类型即可。简单起见,这个容器直接用Common Lisp内置的 HASH-TABLE 来表示。

当在 jjcc2 函数中遭遇到 setq 这个符号时,整个表的形态是这样的

(setq var form)

这时候,首先要将 var 放入到记录全局变量的哈希表中。然后,递归地调用 jjcc2 函数,先编译 form ,得到一系列的汇编代码。然后,生成一条 mov 语句,将 eax 寄存器中的内容放到 var 所指的内存位置中。最终的 jjcc2 的代码如下

(defun jjcc2 (expr globals)
  "支持两个数的四则运算的编译器"
  (check-type globals hash-table)
  (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 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 ,(format nil "~A(%RIP)" (second expr)))))
                 globals))))

然后还需要修改 stringify 函数,现在它需要处理传给 jjcc2 的全局变量的哈希表,将其转化为对应的 .data 段的声明。代码如下

(defun stringify (asm globals)
  "根据jjcc2产生的S表达式生成汇编代码字符串"
  (check-type globals hash-table)
  ;; 输出globals中的所有变量
  ;; FIXME: 暂时只支持输出数字
  (format t "        .data~%")
  (maphash (lambda (k v)
             (format t "~A: .long ~D~%" k v))
           globals)

  (format t "        .section __TEXT,__text,regular,pure_instructions~%")
  (format t "        .globl _main~%")
  (format t "_main:~%")
  (dolist (ins asm)
    (cond ((= (length ins) 3)
           (format t "        ~A ~A, ~A~%"
                   (first ins)
                   (if (numberp (second ins))
                       (format nil "$~A" (second ins))
                       (second ins))
                   (if (numberp (third ins))
                       (format nil "$~A" (third ins))
                       (third ins))))
          ((= (length ins) 2)
           (format t "        ~A ~A~%"
                   (first ins)
                   (if (numberp (second ins))
                       (format nil "$~A" (second ins))
                       (second ins))))
          ((= (length ins) 1)
           (format t "        ~A~%" (first ins)))))
  (format t "        movl %eax, %edi~%")
  (format t "        movl $0x2000001, %eax~%")
  (format t "        syscall~%"))

弄了一个辅助的函数来方便将 jjcc2stringify 串起来

(defun test (expr)
  (let ((ht (make-hash-table)))
    (multiple-value-bind (asm globals)
        (jjcc2 expr ht)
      (stringify asm globals))))

尝试在SLIME中运行

(test '(setq a (+ 1 2)))

最后得到如下的汇编代码

        .data
A: .long 0
        .section __TEXT,__text,regular,pure_instructions
        .globl _main
_main:
        MOVL $1, %EAX
        MOVL $2, %EBX
        ADDL %EBX, %EAX
        MOVL %EAX, A(%RIP)
        movl %eax, %edi
        movl $0x2000001, %eax
        syscall

全文完


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

左手打工,右手创业

左手打工,右手创业

韩垒 / 东北师大 / 2011-4 / 29.80元

《左手打工右手创业》内容简介:打工一族,不能没有激情,不能没有梦想,激情能让你战胜困难,勇往直前;同时,要让梦想变成现实,你还必须具备务实的态度和实干的精神,一步一步向目标前进。创业不是简单的乌托邦式的理想,不是仅凭一腔热血加美好梦想就能顺利到达胜利的彼岸。个人创业更多的是要依靠前期科学的规划、多角度的观察、理性的分析、有效的资源分析与整合、成熟高效的运作技能、良好的商业心态等。 《左手打工......一起来看看 《左手打工,右手创业》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码