scallop
ムラムラしてきたので、なんとなく俺Lisp作り始めた。SICPはもはや積読タワーで埃をかぶってます。
んで、ついでに先日作ったGitHubアカウントでリポジトリ(https://github.com/yagiey/scallop)を公開しておいた。ぼちぼち勉強しながらとりあえずはR5RSに準拠するようにするのが目標。そのためにはもっと勉強しなきゃなぁ...。処理系の名前は以前と同じくscallopにした。前のscallopはdefineが無かったので名前をつけられなかったけど、今回はできるようにしたよ。開発環境はMac OS X 10.6.5上のmono 2.8.1。
とりあえず、現時点で純LISPにはなってるみたい?自信ないけど。
実行するには、monoをインストールしてGitHubからscallopをcloneして
$cd scallop $make $mono ./scallop.exe
するとREPLが起動。手続きexitを引数なしで実行すればREPLは終了。REPLでソースコードの改行はまだできないよ><
scallop> cons {procedure:cons} scallop> lambda {syntax:lambda} scallop> (lambda (n) n) {closure} scallop> (define n 42) n scallop> n 42 scallop> (set! n 23) n scallop> n 23 scallop> (+ 1 2 3) 6 scallop> (* 1 2 3) 6 scallop> (define Y (lambda (f) ((lambda (g) (g g)) (lambda (g) (f (lambda (x) ((g g) x))))))) Y scallop> ((Y (lambda (f) (lambda (n) (if (< n 2) 1 (* n (f (- n 1))))))) 5) 120 scallop> (eval (quote (+ 1 2 3)) ()) Identifier '+' is undefined. scallop> (eval (quote (+ 1 2 3)) (interaction-environment)) 6 scallop> (exit) Scalop was terminated.
現時点でできていることを以下にまとめてみる。
使える値
- 論理
- 整数
- 文字列
- シンボル
- ペア
- nil
論理値はリテラルを書けないけど、内部的には実装している。(not 1)とかやると#fが取り出せる。#f以外は全部#tとみなされるようにしている。もちろん(not (not 1))ってやれば#tになる。
負数も同じくリテラルを書けないが、(- 1)ってやると-1ができる。R5RSでは多倍長整数は必須ではないそうなので実装の予定なし。ってかそもそもC#のInt32型に丸投げなので、バイト数とか全然気にしていないけどそれでいいのかなー。正確?非正確?何スかそれ?おいしいの?
文字列中のエスケープ(\nとか\tとか)はサポートしていない。
シンボルは、数値で始まらなければなんでもあり。
コンスセルはドット対の形式で表記できないけど、(cons 1 2)とかやると(1 . 2)ができる。
実数は未実装。よって除算は用意していない。
用意している手続き
- cons
- car
- cdr
- eq?
- atom?
- eval
- exit
- null?
- not
- +
- -
- *
- >
- =
- interaction-environment
上記の全ての手続きは、それらに対応するC#の手続きを呼び出しているだけ。だから簡単にスタックがあふれてしまう。解決するには「継続を伴った引数付きgoto文」ってなやつを実現しないと無理ぽい?うーん...。
用意している構文
-
- define
- lambda
- quote
- if
- cond
- or
- and
- let
構文も同じように環境に保持しているけど、これで良いのかは不明。マクロ展開に対する先入観 - チキン煮込みチーズミックス4辛なんかも考慮すると、かなーり怪しい。
ユーザ定義の構文はまだできない。