用Scheme写一个Scheme编译器(一)

在博主的大学生涯中,感觉最头痛的一门课程就是编译原理了,学习完这门课程之后,虽然知道了LL,LR算法,和一系列与编译原理相关的术语,可是对它的了解一直停留在做题上,虽然博主一直希望能够通过自己写一个编译器来加深对编译原理的理解,可是用C语言写编译器真的是一场噩梦,每天大把的时间都花在了调试bug上,更没有时间和精力去思考有关编译原理的东西@~@。

int scheme_entry();

int main(int argc, char** argv)
{
	printf("%d\n", scheme_entry());
	return 0;
}

 


 

2 Scheme编译程序

(define (compile-program x)
 (emit "    .text")
 (emit "    .global_scheme_entry")
 (emit "    .def_scheme_entry; .scl    2; .type    32; .endef")
 (emit "_scheme_entry:")
 (emit "LFB0:")
 (emit "   .cfi_startproc")
 (emit "    pushl %ebp")
 (emit "   .cfi_def_cfa_offset 8")
 (emit "    .cfi_offset 5,-8")
 (emit "    movl %esp,%ebp")
 (emit "   .cfi_def_cfa_register 5")
 (emit "    movl $~a,%eax" x)
 (emit "    popl %ebp")
 (emit "    .cfi_restore5")
 (emit "    .cfi_def_cfa 4,4")
 (emit "    ret")
 (emit "   .cfi_endproc")
 (emit "LFE0:"))


这是编译器的主程序,emit函数就是把字符串输出到我们规定的output-port里面,这个程序的字符串由汇编构成,不熟悉汇编语言的朋友看起来会感觉比较奇怪,其中大部分我们都不需要了解,我们需要注意的是(emit "    movl $~a,%eax" x),x就是我们的立即数,这里把它放入eax寄存器中,因为计算机在执行完一个函数后会把结果放入eax寄存器中。

 

(define (emit . args)
 (apply fprintf (compile-port) args)
 (newline (compile-port)))


这是emit函数的定义,将结果显示入我们规定的端口。

 

(define compile-port
 (make-parameter
  (current-output-port)
  (lambda (p)
    (unless (output-port? p)
      (error 'compile-port (format "not an output port ~s" p)))
    p)))


current-output-port在rnrs/io/ports-6模块中定义,我们需要(require rnrs/io/ports-6)。

 

(define (compile expr)
 (run-compile expr)
 (build)
 (execute))


这个函数帮我们执行函数的编译,链接,执行。

 

(define (run-compile expr)
  (let((p (open-output-file "program.s" #:exists 'replace)))
   (parameterize ((compile-port p))
     (compile-program expr))
(close-output-portp)))


我们将输出端口规定为program.s。

 

(define (build)
 (unless (not (false? (system (format "gcc -m32 -Wall -o program ~a program.s"
                                 (runtime-file)
                                 ))) )
(error 'make"could not build target")))


连接我们使用gcc与我们前面准备的C运行时程序连接。

 

(define (execute)
 (unless (not (false? (system "./stst > stst.out")))
(error 'make"produced program exited abnormally")))


执行程序。

 

好了,执行完以上步骤后,你就得到了一个能编译数字的编译器了,虽然很简单,但是这个编译器是我们以后构造更复杂的编译器的基础,希望感兴趣的朋友认真对待它。

 

最后,我们先休息一下,希望大家玩的开心
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值