CLのリーダマクロで里々を読む

うかべんに向けて色々模索中。
私をうかべんに誘って頂いたさとーさん
「里々がLispに近いシンタックスを持つ」
というアドバイスを頂いたので、
Lispと里々の類似点、相違点について話そうかと考えたのですが、
私がだらだらと30分も話してもただ眠くなるだけなので、
何か一つものを作って持っていくことにしました。
里々は

*終了
:えんいー
:なんか懐かしいなそれ

の様な、いかにも文字列の出力が主体のスクリプト言語らしい文法を持っていて、
これだけを見たらLispとは似ても似つかないのですが、
その一方で、変数の代入や条件分岐のシンタックスを見ると、

(set,[変数名],[値])
(if,[条件式],[真の場合に返す文字列],[偽の場合に返す文字列])

とのように、これはまあLispそっくりになっています。
そこで思いついたのが、

1. リーダマクロを書き、里々のスクリプトをS式として読めるようにする
(ちょっとしたパースをするだけだからきっと簡単なはず)
2. 読み込んだS式をCLのプログラムに展開するマクロを書く
(きっと、ちょっとしたマクロで書けると思う。根拠はないけど。)
3. ここまで出来たら、里々のスクリプトをCLのプログラムとしてコンパイルできるぞ!
(そしたら、バイトコード or ネイティブコード or Cのソースコードになる。)
4.きっと楽に書いた割には高速に動作するに違いない!
(特にCのソースコードを吐き出せたらちょと手を加えてDLLにしてSHIORIにできるはず)

という妄想をしてみました。
で、コードを書いてみたところ、それらしく見えるものができました。

#dic01.txt
*終了
:えんいー
:なんか懐かしいなそれ

このプログラムをリードすると、次のように変換されます。

(DEFTALK 終了 :TRUE
(話し手交代)
"えんいー"
(話し手交代)
"なんか懐かしいなそれ")

本当はこれを伺かと通信できる様にdeftalkマクロ展開する必要があるのですが、
今は面倒なので標準出力に文字を出すように展開。

(PUSH
(LAMBDA ()
(FORMAT T "~&~A:~A" "さくら" "えんいー")
(FORMAT T "~&~A:~A" "うにゅう" "なんか懐かしいなそれ"))
(GETHASH '終了 *TALK-TABLE*))

実際に、里々のスクリプトを書いたファイルをコンパイルして、
実行する流れはこんな感じです。

MATSURI> (matsuri-compile-file "dic01.txt")
;; Compiling file /usr/home/zick/dic01.txt ...
;; Wrote file /usr/home/zick/dic01.fas
0 errors, 0 warnings
#P"/usr/home/zick/dic01.fas" ;
NIL ;
NIL
MATSURI> (load "dic01.fas")
;; Loading file dic01.fas ...
;; Loaded file dic01.fas
T
MATSURI> (call-talk '終了)
さくら:えんいー
うにゅう:なんか懐かしいなそれ
NIL

なかなかいい感じに動いています。
しかし、今になってLispと一見似ている括弧を使ったシンタックスが厄介だと気づきました。
括弧の内側から評価されるというのはLispと同じですが、
内側を評価して得られた値を使って外側の括弧をリードし直す
という恐ろしい仕様が里々では使われているそうです。

((今の季節)の味覚)

この式を評価するとき、
まず、内側の (今の季節) が評価され 秋 になりますが、
その次には (秋の味覚) が評価されることになります。
(詳しくはこちらを参照してください)
これは思った以上に手強そうです..

Leave a Reply