読者です 読者をやめる 読者になる 読者になる

レガシーコード生産ガイド

私に教えられることなら

Forthでごく簡単なRegion

forth

mkforth4-jsではQuotationの実装を、RetroForthに倣って

1) 次の2を飛ばすジャンプ命令
2) ワードのアドレス列(ワード定義の本体部分)
3) 2のアドレスをスタックに置く

としている。

これで一応高階関数みたいなことはできるんだけど、関数ポインタと同じような動作なので

  1. 使う度に辞書に定義が残っていく
  2. 実行時に「生成」されるわけではない

という問題がある。

2を解決するにはやっぱりGCが無いと不便だけど、1については簡単なリージョン管理みたいなもので対応できるな、とPostScriptのsave/restoreを調べてて思ったので実装した。

https://github.com/phaendal/mkforth4-js/blob/master/builtin.fs で定義しているregion-save//region-restoreを使う。

実装は単純で、

  • region-save/で辞書の「次の空いているアドレス」のポインタ(dict-here)と、定義された最後のワードへのポインタ(latest)を専用のスタックに積み、リージョンを使用していない場合はリージョン開始位置にdict-hereを移動させる
  • /region-restoreで、dict-hereとlatestを元にもどす。

囲まれていたリージョンのメモリ内容はもちろん残っているけど、次に使用するときに上書きされるのでいいや、といういつものパターン。

次のような使い方で、REPL上でも気軽にQuotationを使えるようになった

|   : latest&here "latest: " latest@ + print  "here: " dict-here@ + print ;
|   latest&here  ( => 5389, 5402)
|
|   region-save/
|     latest&here ( => 5389, 100100 )
|
|     : hello "world!" print ;
|     latest&here ( => 100100 100106 )
|
|     [ "yo!" print ] apply
|     latest&here ( => 100100 100110 )
|
|   /region-restore
|
|   latest&here  ( => 5389, 5402 )

PostScriptのはstate?を保存しているみたいだし、Level2,3にはGCもあるようなので、調べてみようと思う。vocabularyスタックの使い方とか、結構興味深いのでしっかり見てみよう。

最終的にGCもForth自身で書いて、Quotationは生成するようにして、関数型プログラミングと一番下のメモリを直にいじる世界を言語内で行き来できると楽しそうだなあとぼんやり考えている。

広告を非表示にする