LispEx 是用 Go 语言编写的一款符合 R5RS 标准的 Lisp 解释器。
有意思的地方是,在设计之初我就考虑是否能为其添加一些并发编程的语言特性,让这门古老的编程语言充满生机起来。
于是便选择了 Go 语言来实现它,耗时近 2 个月,Go 里面的一些特性如:goroutine, channel, select 等语义都在 LispEx 中有了支持。
遵守 KISS 原则,尽量把代码设计的简单,易懂。很多模块被很好的分离出来,想添加新的语义支持的话,只需要添加、修改个别文件的源代码。
借鉴了王垠大神 Yin 语言的代码设计思路:任何一个 Node 都会被解释成 Value;Parser 被拆分成了 2 个阶段:包括预处理生成语法单元,然后 Parse 成语法树。顺着这个思路,代码会变得非常易读,当然在设计的时候针对这点是费了很多心思的,希望对一些后人能有借鉴意义。
并发的词法分析器。这点 Rob Pike 在 http://cuddle.googlecode.com/hg/talk/lex.html#title-slide 提到过。LispEx 把它实践了一遍。
Go liked 并发语义支持。下面一段代码演示了并发编程里面经典的 ping-pong 案例,并且借助 channel 实现了信号量:
; define channels
(define ping-chan (make-chan))
(define pong-chan (make-chan))
; define a buffered channel
(define sem (make-chan 2))
(define (ping n)
(if (> n 0)
(begin
(display (<-chan ping-chan))
(newline)
(chan<- pong-chan 'pong)
(ping (- n 1)))
(chan<- sem 'exit-ping)))
(define (pong n)
(if (> n 0)
(begin
(chan<- ping-chan 'ping)
(display (<-chan pong-chan))
(newline)
(pong (- n 1)))
(chan<- sem 'exit-pong)))
(go (ping 6)) ; start ping-routine
(go (pong 6)) ; start pong-routine
; implement semaphore with channel, waiting for ping-pong finishing
(<-chan sem) (newline)
(<-chan sem) (newline)
; should close channels if you don't need it
(close-chan sem)
(close-chan pong-chan)
(close-chan ping-chan)
; the output will be: ping pong ping pong ... exit-ping exit-pong
再来一段 select 语义示例:
(define chan-1 (make-chan))
(define chan-2 (make-chan))
(go (chan<- chan-1 'hello-chan-1))
(go (chan<- chan-2 'hello-chan-2))
; sleep for 20 millisecond
(sleep 20)
(select
((<-chan chan-1))
((<-chan chan-2))
(default 'hello-default))
(close-chan chan-1)
(close-chan chan-2)
; the output will be randomized: hello-chan-1 or hello-chan-2
更多精彩代码演示请见: https://github.com/kedebug/LispEx
PS: LispEx 已经被 Go Community Wiki 和 Hacker News 收录: https://code.google.com/p/go-wiki/wiki/Projects#Virtual_Machines_and_Languages https://news.ycombinator.com/item?id=8074334