11
 11 スタック操作 





 
 
スタック検査
 
 


構文=
スタック検査 → ・ <メッセージ>で このメッセージでスタック検査 → ・
 これを呼び出したときスタックが空でない場合、次のようなエラーメッセージを表示し、プログラムが強制終了する。
   ↓「スタック検査」の場合
スタックがずれています。

   ↓「このメッセージでスタック検査」の場合
スタックがずれています(メッセージ)。
 プログラム作成の初期段階で、うっかりミスにより、ある処理単語の定義で想定しているスタックデータ数と、それを呼び出す側で積んだデータ数が異なってしまうことがある。そのようなとき、本来はスタックが空になっているはずの場所で空でない状態となる。
 そのような問題を抱えたプログラムが変な動作をすればすぐ気が付くが、一見すると正常に動作してしまうこともあり、ミスの発見が遅れることもある。あるいは長時間時間経過したあとで問題を起こすこともある。
 そのような問題に備え、プログラム中のいくつかの箇所にこの検査を入れておくことで、バグやスタックのズレを発見でき、プログラムの信頼性を上げることができる。
 次のように、ループ処理の一部に組み込むのも良いだろう。
メインとは     いろいろ初期化し     ここから         ・・・・し         ・・・・し         ・・・・し    ↓このような位置に入れる         「ループ末尾」で このメッセージでスタック検査し     繰り返すこと。 ↓出力例 スタックがずれています(ループ末尾)。
 これはいわばガス漏れ検知器のようなものだと思って欲しい。本来、スタックが空であるべき場所で空になっていない場合にこの検査にひっかかっる仕掛けである。
 この単語の挿入は、バグの発見にも役立つ。 Mind のバグの多くのケースで、スタックのズレを引き起こすからである。



 
 
スタック操作語
 
 

 スタック上に置かれたデータを捨てたり、スタック上で複写する(1つのデータを2つにする)といった特殊な単語がある。
 局所変数を使用すれば、このような単語は必要ないのだが、プログラムの能率を上げたり、短く書くのに有効な手段でもある。あまり凝ったプログラムにならない範囲で適切に使いたい。


 
捨てる
 

構文=
<データ>を 捨てる → ・
 スタックにあるデータを1つ捨てるだけの機能である。上記で <データ> と抽象的に書いたのは、これが数値でも文字列でも、何でもいいからである。
 一旦、スタックにデータを積んだものの、不要になってしまったような場合(後述する「複写」したあとで不要になるというケースもある)に、その不要のデータを捨てて、スタックの後片付けをする目的で使用する。
 (正しいプログラム)
正常なら登録とは (文字列 → ・)     システムが正常?         ならば 登録し         さもなければ 捨てる         つぎに。
 (誤ったプログラム)
正常なら登録とは (文字列 → ・)     システムが正常?         ならば 登録し         つぎに。
 初心者は後者のような間違いを犯しやすい。
 スタックにデータが積まれた状態で「正常なら登録」が実行されるのだが、その処理の最初で、「システムが正常?」の検査を行っている。後者のプログラムでは、この検査が偽( 0)の場合に、何もしないで処理を終了してしまっているが、これは誤りである。不要なデータがスタックに積まれたままになるからである。
 実際には、このような単語を1回実行したぐらいではプログラムは一見、正常に動作を続ける。ところが、この処理がループになっているような場合、1 回のループごとにゴミが溜まるようになり、長時間のうちには、いずれはスタックがオーバーフローしてシステムが異常な動作をするようになる。
 同様に、次の例も参考にして欲しい。
緊急通報とは (文字列 → ・) ※ダミー定義     捨てること。
 上のプログラムは一見まったく無意味な処理であるが、ソフトの開発途中でよく使われる手法なので覚えておきたい。
 この単語は、メッセージ文字列を渡して、これをどこかに通報する処理を行うのだが、開発途中で、まだその機能が完成していない場合には、このようなダミー処理を定義して、万一呼び出されても支障がないようにする。(逆に言えば、このようにしておけば呼び出し主側は本番通りのプログラムを書ける)
 くどいようだが、このような、データをスタックから渡される処理単語をダミー定義するときに、
緊急通報とは (文字列 → ・) ※ダミー定義     。
 と定義してはならない。「ダミー処理だから何もしなくてよい」と考えて上記のようなプログラムを書きがちである。スタックからデータを渡される場合には、「何もしない」のはいけないことになる。
 これとは逆のケースだが、スタックにデータを返すようなダミー単語は、
危険水位?とは (・ → 真偽) ※ダミー定義     偽を 返すこと。
 のように、スタックの帳尻を合わせるような処理だけは入れておく必要がある。


 
二番目を捨てる
 

構文=
<データ1> <データ2> 二番目を捨てる → <データ2>
 スタックに2つのペアデータが積まれているとき、その奥の方にあるデータを捨てるのに使われる。
 例を示す。
 既に「座標を得る」という架空の単語が定義されているとする。仕様は次のようなものである。
座標を得る → X座標、Y座標
次に、この上位語として、X座標だけ、あるいはY座標だけを単独で得るための処理単語「X座標を得る」と「Y座標を得る」を定義してみよう。
X座標を得るとは (・ → X座標)     座標を得て 捨てること。 Y座標を得るとは (・ → Y座標)     座標を得て 二番目を捨てること。
 上の定義では共に下位の処理単語として「座標を得る」を引用している。その単語はX座標とY座標の2つのデータをスタックに返すが、このうちの一方を捨てることにより、どちらか一つだけを返す上位単語が定義できるのである。一旦局所変数に入れてから参照しなおす方法よりもプログラムが簡潔になる。


 
複写
 

構文=
<データ>を 複写 → <データ>、<データ>
 スタックにあるデータの複製をとるのに使用する。主に、同じデータについて2つの処理を施したい場合に用いる。次がその例である。
二色で表示とは (文字列 → ・)     複写し       赤色表示し 改行し       黄色表示し 改行すること。 JIS変換してから一文字送信とは (文字 → ・)     一文字JIS変換し (→JISコード)     複写し       上位バイトをとり 一文字送信し       下位バイトをとり 一文字送信すること。
 後者は、ワード型データ(16bit整数)の上位バイトと下位バイトを別々に処理したい場合に応用できるので覚えておくとよい。(下図)
         (定型として使える) 複写し       上位バイトを ○○し       下位バイトを ○○する
上のプログラム例の下段の定義にある「一文字送信」は昔、MindがMS-DOSで使われていた時代にRS-232Cライブラリで定義されていた単語だったが現在は無い。