Next: , Previous: , Up: An Introduction to Standard Forth   [Contents][Index]


4.4 How does that work?

ここで、 前のセクションの add-two の定義をもう一度見てみましょう。 テキスト・インタプリタの動作方法に関する知識から、 add-two を定義しようとしたとき、 私達は以下の結果を予期したかもしれません:

: add-two 2 + . ;RET
*the terminal*:4: Undefined word
: >>>add-two<<< 2 + . ;

しかし、 これが起こらなかった理由は、 : の動作方法に関係しています。 : というワードは 2 つの特別な働きをします。 1つ目の特別な機能は、 テキスト・インタプリタが add-two という文字を認識できないようにすることです。 テキスト・インタプリタは、 >IN (to-in;トゥーイン)という変数を使用して、 入力行のどこを追跡するかを保持し、 : というワードに遭遇すると、 他のワードの場合とまったく同じように動作します。 名前ディクショナリでそれを検索し、 その xt を見つけて実行します。 実行される : は、 入力バッファーを調べてワード add-two を見つけ、 >IN の値をその後ろを指すように進めておきます。 次に、 新しい定義の作成に関連するその他の処理を実行します(名前ディクショナリに add-two のエントリを作成する等)。 : の実行が完了すると、 制御はテキスト・インタプリタに戻ります。 テキスト・インタプリタは、 このトリックにより入力行の一部をスキップしていることに気づきません。

: のようなワード(>IN の値を進めて、 テキスト・インタプリタが入力行全体に作用するのを妨げるワード)は、 「構文解析ワード」(parsing words)と呼ばれます。

: が行う 2 つ目の特別な処理は、 state と呼ばれる変数の値を変更することです。 これは、 テキスト・インタプリタの振る舞いに影響します。 Gforth が起動するとき、 state の値は 0 であり、 テキスト・インタプリタはインタプリタ状態(interpreting)であると言われます。 (: で始まる)コロン定義中 、 state は -1 に設定され、テキスト・インタプリタはコンパイル状態(compiling)と言われます。

この例では、 テキスト・インタプリタは文字列 “2 + . ;”。引き続き同じ方法で文字列を文字シーケンスに分割します。ただし、数値 2 をスタックにプッシュする代わりに、 数値 2 を取得する魔法を add-two の定義に組み込み(コンパイル)、 add-two が「実行」されたときスタックにプッシュされます。 同様に、 +. の振る舞いも定義にコンパイルされます。

特定の種類のワードはコンパイルされません。 これらのいわゆる「即実行ワード」(immediate word)は、 テキスト・インタプリタがインタプリタ状態であるかコンパイル状態であるかに関係なく、 実行されます(今、 直ちに実行されます)。 ; というワードは即実行ワードです。 定義にコンパイルされるのではなく、 実行されます。 その効果は、 state の値を 0 に戻すことを含む、 現在の定義を終了することです。

あなたが add-two を実行すると、 その定義の外で 2 + . RET と入力した場合とまったく同一の「実行時効果」(run-time effect) が生じます。

Forth では、 すべてのワードまたは数値は以下の 2 つの性質を持ちます:

数値は常に決まった方法で処理されます:

ワードは常にこのような通常の振る舞いをするとは限りませんが、 ほとんどのワードにはデフォルトの機能(default semantics)があり、 以下のように振る舞うことを意味します:

特定のワードの実際の振る舞いは、 ワードの定義時に immediatecompile-only というワードを使用することで制御できます。 これらのワードは、 最後に定義されたワードの名前ディクショナリ・エントリにフラグを設定します。 これらのフラグは、 名前ディクショナリでワードが見つかったときにテキスト・インタプリタによって取得されます。

immediate としてマークされたワードは、 そのインタプリタ機能(interpretation semantics)と同じコンパイル機能(compilation semantics)を持ちます。 つまり、 以下のように振る舞います:

ワードを compile-only としてマークすると、 インタプリタ状態(interpretation state)でこのワードを検出したときにテキスト・インタプリタが警告を生成することを意味します。 (' または ['] を使用して) ワードをティックすると、 警告が生成されます。

compile-only を使用する必要はありません(多くの実装によって提供されてはいますが、 標準 Forth の一部でもありません)が、 インタプリタ態(interpret state)で正しく振る舞わないワードに compile-only を適用するのは良いエチケットです(そして予期しない副作用が発生する可能性があります)。 たとえば、 定義内で条件ワード IF を使用することのみが正当です。 これを忘れて別の場所で使用しようとすると、 (Gforth では) compile-only としてマークされているため、 テキスト・インタプリタが有用な警告を生成できます。

以下の例は、 即実行ワードと非即実行ワードの違いを示しています:

: show-state state @ . ;
: show-state-now show-state ; immediate
: word1 show-state ;
: word2 show-state-now ;

show-state-now の定義の後にあるワード immediate は、そのワードを即実行ワードにします。 これらの定義では、 @(「フェッチ」と発音します) という新しいワードが導入されています。 このワードは変数の値を取り出し(フェッチし)、 それをスタックに残します。 したがって、 show-state の振る舞いは、 state の現在の値を表す数値を出力することです。

word1 を実行すると、 システムがインタプリタ状態であることを示す数値 0 が出力されます。 テキスト・インタプリタが word1 の定義をコンパイルしたときに、 コンパイル機能が現在の定義に実行時コードを追加する show-state に遭遇しました。 word1 を実行すると、 show-state のインタプリタ機能(interpretation semantics)が実行されます。 word1 (つまり show-state) が実行される時点で、 システムはインタプリタ状態です。

word2 の定義を入力した後に RET を押すと、 数値 -1 が出力され、 その後に ok が表示されるはずです。 テキスト・インタプリタが word2 の定義をコンパイルすると、 即実行ワードである show-state-now が検出されたため、 そのコンパイル機能(compilation semantics)はインタプリタ機能(interpretation semantics)を実行します。 これは直ちにに実行されます(テキスト・インタプリタが次の文字グループ(この例では ;)の処理に移る前に)。 これを実行すると、 word2 の定義途中の state の値が表示されます。 -1 を出力するので、 システムがその時点でコンパイル状態であることがわかります。 もし あなたが word2 を「実行」しても何も行いません。

即実行ワードの話題を離れる前に、 前のセクションの greet の定義における ." の振る舞いについて検討してみましょう。 このワードは構文解析ワード(parsing word)でもあり、 かつ、 即実行ワードでもあります。 ." とそのテキストの先頭 Hello and welcome の間にはスペースがありますが、 welcome の最後の文字と " 文字の間にはスペースがありません。 これは、." が Forth ワードであるということです。 テキスト・インタプリタがその Forth ワード ." を識別できるように、 ." の後ろにスペースが必要です。 " は Forth ワードではなく、 区切り文字(delimiter)です。 先の例では、 文字列が表示されるときに、 H の前にも e の後ろにもスペースがないことを示しています。 ." は即実行ワードなので、 greet の定義中に実行されます。 実行されると、 入力行内を前方に走査して区切り文字を探します。 区切り文字が見つかると、 区切り文字の後ろを指すように >IN を更新します。 また、 いくつかのマジック・コード、 つまりテキスト文字列を出力する実行時コード xtを greet の定義にコンパイルします。 文字列 Hello and welcome をメモリにコンパイルして、 後で出力できるようにします。 その後、 テキスト・インタプリタが制御を取得すると、 入力ストリーム内で次に検出されるワードは ; であるため、 greet の定義を終了します。


Next: Forth is written in Forth, Previous: Your first Forth definition, Up: An Introduction to Standard Forth   [Contents][Index]