支持減、乘,以及除

上一篇文章中,初步搭建了一個輸入Common Lisp代碼,輸出彙編代碼的編譯器的骨架,實現了二元整數的加法運算。在這個基礎上,要想實現減法、乘法,以及除法就是手到擒來的事情了。只需依葫蘆畫瓢,補充更多的分支狀況便可。html

我本身模仿着x64的調用約定,規定四則運算的結果始終放在EAX這個寄存器中。在稍後給出的代碼中,對於減法和除法運算,都是把運算符的左操做數放到EAX寄存器中,再從EAX中減去或者除掉右操做數。git

在摸索除法的彙編代碼怎麼生成時,遇到了個費解的問題,最後才知道,原來須要把EAX寄存器的符號擴展到高位的EDX寄存器中去。對於as這個彙編器來講,須要用到CLTD指令。github

最後,jjcc2stringify兩個函數被修改成以下的樣子segmentfault

(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)))))

(defun stringify (asm)
  "根據jjcc2產生的S表達式生成彙編代碼字符串"
  (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~%"))

全文完。oracle

閱讀原文函數

相關文章
相關標籤/搜索