はじめに
前回に続き、Forth言語との関連でMindの仕組みの根幹をなすスタックフレームについて説明させてください。
スタックフレーム
Cで「スタックフレーム」という言い方をするときCPUのスタックポインタ(SPレジスタ)を使った操作を指すようです。関数の入り口でSPを下げてメモリ領域を確保し、そこを関数内のローカル変数群として使うようです。
またコンパイラの内部動作に限らずとも、プログラム作成者が自前のスタック機構を書いてデータを保持することもあると思います。
一方でFORTH系、あるいはスタック指向言語ではスタックポインタを2本使うのが特徴です。
1本目は従来通り、Call/Returnの戻り番地を積む、スタックフレームとして使うなどの用途で、もう1本はデータの受け渡しに使います。
FORTHの生みの親のチャールズ・ムーアは スタックポインタが1本でも3本でもなく2本というのが重要だ と言っています。
プログラムの記述という面から見ると、1本目のリターンスタックは(コンパイラが内部で使うことはあっても)プログラム作成者が意識することはありませんが、2本目のスタック(データスタック)については明確に意識したプログラムを書くことになります。ここがFORTHでいうスタックと、一般に言われるスタックの違いかと思います。
8087のマシンコードってFORTHなんです
スタックを明に使ったハードとしては(昔の話なのですが)インテル社の浮動小数点コプロセッサ 8087 があります。8087のマシンコードってまんまFORTHなんですね。
私が昔、FORTHをやっていたころですが、あるとき浮動小数のライブラリを作ることになりました。8087が使われ始めた時期で、ソフト処理でやるタイプと8087を使うタイプとで2種類のライブラリを開発しました。
いざ8087の命令セットを見たらまるでFORTHで小躍りしたことがあります。浮動小数演算についてはFORTHコンパイラはほとんど何もせずそのまま機械語に置き換えていけば良いからです。
たとえば当時のFORTHのソースコードこんなふうに書いたとします。
1.2 3.4 F+ (数値定数は F 1.2 のような前置きがあったと思いますが簡単にします)
FORTHコンパイラは上のソースをこんなふうに処理すれば良いわけです。
1.2
3.4
F+
↓
PUSH 1.2 (8087のニモニックはこの通りではありません。あくまで概念です)
PUSH 3.4
ADD
何のことはない、FORTHのコンパイラなのに、やっていることはアセンブラです。私はライブラリ作成でだいぶ手抜きができました。(ややこしいのですが当時の私のFORTHはアセンブラ記述もできました)
FORTHって低水準言語なの?
FORTHって低水準言語なの?と思われた方もおられるかもしれません。ただ、たとえばHP社の逆ポーランド電卓の操作が「低水準だ」とか「これじゃアセンブラみたいだ」と思う人はいないと思います。逆に私がFORTHをやっているときは、CだのPascalだの当時流行していた言語が逆に低水準に見えていました。
スタック指向の言語としてはこのほかにプリンタ制御言語の PostScript があります。ただ、これを使ってプログラムを書くのはプリンタのドライバを開発する人など限られていると思います。あまり知られていないという点では8087と似ています。
スタックを用意すれば日本語の語順にできる
CであれJavaであれ、まずはスタック機構を用意しておけばあとは比較的簡単に日本語の語順を受け入れることができると思います。
Mindのディスパッチャ(Mコードを解読実行するもの)はデータスタックを実現するためにCをごりごり書いてスタック操作をおこなっています。なくべく簡単にするためマクロを用意しています。カーネルのソースにはこんな記述があります。
PUSH_L( result, 0 ); ←64bit整数をpush (上位32, 下位32で分けています)
極端に単純化すればですが、数値定数があったらPushし、数値でないワードがあったらCallするという感じで仕組みを作れば行けるように思います。
多くの言語にある配列型を使えば容易にスタックになりますが汎用のスタックという用途で数値も文字列も混在してpushする使い方なので工夫が必要で、Cではunionを使って型を管理しています。
Javaだとリスト型みたいなのがあったと思うのですが、それなら「汎用オブジェクトのリスト」みたいな定義をして、その仮想スタック(?)には数値も文字列も混在して入れられるのではと思ったことがあります。
おわりに
このあたりを書き始めるときりがないのですが、実はだいぶ前にFacebookで「スタックコンピュータとFORTH」という長い記事を投稿したことがあります。あとでQiitaのほうにも投稿できるといい思っています。そちらのほうがより正確に説明できるかと思います。
Mindユーザーの@mylifewithviolinさんのQiitaの記事のご質問に対してコメントしていた内容ですが、独立した記事にまとめてみました。