用Scheme寫一個Scheme編譯器(二):當即數

在上一篇博客中,我介紹了這個Scheme編譯器的主要框架,以及運行它編譯的程序的運行時系統。這篇博客中,咱們將要嘗試去表示一系列在Scheme中的值,也就是當即數。框架



首先咱們要解釋什麼是當即數,當即數就是直接存儲在一個字節或幾個字節中的值,包括定點數,布爾值,字符,空表等。這些不一樣類型的當即數在咱們人看來是徹底不一樣的,可是在計算機的表示之中,他們都是一系列相同的0/1串,因此如何去區分他們呢?less



咱們經過爲不一樣類型的值設立不一樣的掩碼和標識來區分這些不一樣的值:函數

對於定點數,咱們使用最底兩位爲掩碼,標識爲0x00編碼

布爾值,咱們使用一個字節來表示它們,分別把#f定義爲0x6f#t定義爲0x2fspa

空表咱們使用0x3f來標識,rest

字符咱們使用兩個字節來存放它們的值,一個字節是掩碼,一個字節指明該字符的值,字符的掩碼是0xff,字符的標識爲0x0fcode



1 添加與當即數相關的函數



定義完這些之後,咱們須要添加這些定義到咱們的Scheme編譯程序之中:blog

(define fxshift 2)

(define fxmask #x03)

(define fxtag #x00)

(define bool_t #x2f)

(define bool_f #x6f)

(define list_nil #x3f)

(define charshift 8)

(define charmask #xff)

(define chartag #x0f)

 



而後是當即數的判別和求值:編譯器

(define (immediate-value? expr)

(or (fixnum? expr) (boolean? expr) (null? expr) (char? expr)))



(define (immediate-value-rep expr)

(cond ((fixnum? expr) (arithmetic-shift expr fxshift))

((boolean? expr) (if expr bool_t bool_f))

((null? expr) list_nil)

((char? expr) (bitwise-ior (arithmetic-shift (char->integer expr) charshift) chartag))))

 

對於定點數,咱們只須要對它原始值進行兩位的算數移位,對於字符,除了對它進行算術移位外,咱們還須要將其與咱們的標識進行或運算。博客



2 修改編譯主程序



以上工做作好以後,咱們要先對咱們開始時的編譯程序作一個簡單的調整:

 1 (define (compile-program expr)
 2 
 3 (unless (immediate-value? expr)
 4 
 5 (error 'compile-program "immediate-value?"))
 6 
 7 (emit " .text")
 8 
 9 (emit " .global _scheme_entry")
10 
11 (emit " .def _scheme_entry; .scl 2; .type 32; .endef")
12 
13 (emit "_scheme_entry:")
14 
15 (emit "LFB0:")
16 
17 (emit " .cfi_startproc")
18 
19 (emit " pushl %ebp")
20 
21 (emit " .cfi_def_cfa_offset 8")
22 
23 (emit " .cfi_offset 5, -8")
24 
25 (emit " movl %esp, %ebp")
26 
27 (emit " .cfi_def_cfa_register 5")
28 
29 (emit " movl $~a, %eax" (immediate-value-rep expr))
30 
31 (emit " popl %ebp")
32 
33 (emit " .cfi_restore 5")
34 
35 (emit " .cfi_def_cfa 4, 4")
36 
37 (emit " ret")
38 
39 (emit " .cfi_endproc")
40 
41 (emit "LFE0:"))

 

在原先是 (emit " movl $~a, %eax" x)的地方,咱們將其改成 (emit " movl $~a, %eax" (immediate-value-rep expr))immediate-value-rep就是咱們對當即數進行編碼的地方



3 修改運行時程序



而後,咱們還須要對C的運行時程序進行調整,讓其可以進行解碼工做:

#include<stdio.h>

 

#define fxshift 2

#define fxmask 0x03

#define fxtag 0x00

#define bool_f 0x2f

#define bool_t 0x6f

#define list_nil 0x3f

#define word_size 4

#define charshift 8

#define charmask 0x0f

#define chartag 0x0f

 

int scheme_entry();

 

int main(int argc, char** argv)

{

int val = scheme_entry();

 

printf("%d",val);

if((val&fxmask) == fxtag)

{

printf("%d", val >> fxshift);

}

else if(val == bool_f)

{

printf("#f");

}

else if(val == bool_t)

{

printf("#t");

}

else if(val == list_nil)

{

printf("'()");

}

else if((val & charmask) == chartag)

{

printf("%c",val>>charshift);

}

return 0;

}

 


這就是今天的內容,咱們得到了一個可以編譯當即數的程序!

相關文章
相關標籤/搜索