大雑把にいえば、POSTPONEは、IMMEDIATEの逆、といえます。もっとも構文は違います。
POSTPONEは、その次にくるワード(一つ)について、その呼び出しをコンパイルする、というワードです。ですからPOSTPONEはコンパイル状態でしか利用しません。そして、特に、IMMEDIATEワードの定義の中で重要になります。
あまり意味のない例ですが、その動作の説明を例で示しましょう。例えば、
: greeting ( -- ) ." Hello Everybody!" cr ; immediate
というコードを書いたとします。このgreetingを何かのワードの定義で呼び出すとどうなるでしょうか。結果は、それをコンパイルしているときに、Hello Everybody!のメッセージが、Mopsウィンドウにプリントされます。例えば、
: myword1 greeting ;<ENTER>
とすれば
のような結果になります。myword1自体には実行コードはありません。
これに対して、
: myword2 POSTPONE greeting ;<ENTER>
としたとします。このときは、コンパイルの時点ではメッセージはプリントしません。
しかし、myword2を実行すれば、メッセージがプリントされます。
つまりPOSTPONEは
Immediateワードを普通のワードと同じようにコンパイルするワードです。POSTPONEは上の例のように、コンパイルのためではないワードでも使うこともできます。しかし、これは、コンパイラ拡張用のワードと考えるのが自然です。具体的には次のような局面で役に立ちます。
POSTPONEがもっとも威力を発揮するのは、IMMEDIATEワードの定義であるワードをPOSTPONEするときであると思われます。 例えば、ある目的でコンパイラ拡張用のImmediateワードIMMEDWORDを定義したとします。IMMEDIATEワードは、何かのワードのコンパイル中に呼び出され、実行されることが予定されているわけですが、このとき、IMMEDWORDが、例えばワード"POSTDWORD"のPOSTPONEを内容として含んでいると、その実行の時点にPOSTDWORDの呼び出しを その場にコンパイルすることになります。かなりややこしいですが、そのようにPOSTPONEされたワードは、ちょうど"<BUILDS - DOES>"対のDOES>以下に書くコードと同じように、別のワードに内容として追加されるコードとなるのです。
: POSTDWORD [コード] ;
: IMMEDWORD ... POSTPONE POSTDWORD ... ; IMMEDIATE
: SPECIALWORD IMMEDWORD [CODE] ;
\ このようにすると、SPECIALWORDはコンパイル時にIMMEDWORDの内容(「...」部分に該当)
\ であるコードが実行されて特殊コンパイルされるが、
\ 加えてその内容である[CODE]部分の先頭には、POSTDWORDが追加されることになる。
\ つまり、特殊コンパイル部分を度外視すれば、SPECIALWORDの内容は、
: SPECIALWORD POSTDWORD [CODE] ;
\ とするのに等しくなる。
この技巧は、毎度毎度表立っては書きたくないような、呼び出し前後のローレベルの定型処理コードを追加するのに利用できます。これは、ローレベルのメモリーやレジスタの操作に関するコントロール力を保持したつつも、それを適宜抽象化して、通常のプログラミングにおいてはハイレベルなコードを書く、ということを可能にしているのです。
関連項目:
最終更新:2022年02月13日 18:35