Next: , Previous: , Up: Control Structures   [Contents][Index]


6.9.6 Arbitrary control structures

標準 Forth は、 ネストされない方法での制御構造の使用を許可・サポートします。 まだ完成されてない制御構造に関する情報は、 制御フロー・スタック(control-flow stack)に保存されます。 このスタックは Forth のデータ・スタック上に実装でき、 Gforth はそうしました。

orig エントリは未解決の前方分岐を表し、 dest エントリは後方分岐ターゲットを表します。 いくつかのワードは、 可能なあらゆる制御構造を構築するための基礎となります(呼び出しやコルーチンやバックトラッキングのような、 ストレージを必要とする制御構造を除く)。

IF ( compilation – orig ; run-time f –  ) core “IF”

実行時(run-time)、 f=0 の場合、 (コンパイル時に) orig を消費する THEN (または ELSE) の後から実行が続行されます。 それ以外の場合は、 IF の直後に続きます(see Selection)。

AHEAD ( compilation – orig ; run-time –  ) tools-ext “AHEAD”

実行時、 (コンパイル時に) orig を消費する THEN の後から実行が続行されます(訳注: つまり、 単純に THEN へジャンプする)。

THEN ( compilation orig – ; run-time –  ) core “THEN”

(コンパイル時に) orig をプッシュした IF または AHEAD または ELSE または WHILE は、 THEN の直後にジャンプします(see Selection)。

BEGIN ( compilation – dest ; run-time –  ) core “BEGIN”

(コンパイル時に) dest を消費する UNTIL または AGAIN または REPEAT は、 BEGIN の直後へジャンプします(see Simple Loops)。

UNTIL ( compilation dest – ; run-time f –  ) core “UNTIL”

実行時、 f=0 の場合、 (コンパイル時に) dest をプッシュした BEGIN の直後から実行が続行されます。 それ以外の場合は、 UNTILの直後から実行が続行されます(see Simple Loops)。

AGAIN ( compilation dest – ; run-time –  ) core-ext “AGAIN”

実行時、 (コンパイル時に) dest をプッシュした BEGIN の直後から実行が続行されます(see Simple Loops)。

CS-PICK ( orig0/dest0 orig1/dest1 ... origu/destu u – ... orig0/dest0  ) tools-ext “c-s-pick”
CS-ROLL ( destu/origu .. dest0/orig0 u – .. dest0/orig0 destu/origu  ) tools-ext “c-s-roll”
CS-DROP ( dest –  ) gforth-1.0 “CS-DROP”

標準ワードの CS-PICKCS-ROLL を使用すると、 移植可能な方法で制御フロー・スタックを操作できます。 これら無しだと制御フロー・エントリが占めるスタック項目の数を知る必要があります(多くのシステムは 1 つのセルを使用します。 Gforth では現在 4 つを使用しますが、 これは将来変更される可能性があります)。

orig は 1 回だけ解決する必要があるため、 CS-PICKdest を pick することしかできず、 かつ、 CS-DROPdest を drop することしかできません。

一部の標準の制御構造ワードは、 以下のワード群から構築されます:

ELSE ( compilation orig1 – orig2 ; run-time –  ) core “ELSE”

実行時、 (コンパイル時に) orig を消費する THEN の直後から実行が続行されます。 orig1 をプッシュした IF または AHEAD または ELSE または WHILE は、 ELSE の直後にジャンプします(see Selection)。

WHILE ( compilation dest – orig dest ; run-time f –  ) core “WHILE”

実行時、 f=0 の場合、 (コンパイル時の) orig を消費する REPEAT (または THEN または ELSE) の直後から実行が継続されます。 それ以外の場合は、 WHILE の直後から実行されます(see Simple Loops)。

REPEAT ( compilation orig dest – ; run-time –  ) core “REPEAT”

実行時、 (コンパイル時に) dest をプッシュした BEGIN の直後から実行が続行されます。 orig をプッシュした WHILE または IF または AHEAD または ELSE は、 REPEAT の直後にジャンプします(see Simple Loops)。

Gforth は、さらにいくつかの制御構造ワードを追加します:

ENDIF ( compilation orig – ; run-time –  ) gforth-0.2 “ENDIF”

THEN と同一です。

?dup-IF ( compilation – orig ; run-time n – n|  ) gforth-0.2 “question-dupe-if”

これは、スタック・チェッカー(stack checker)などのツールでより適切に処理できるため、 イディオム「?DUP IF」の代替として推奨されます。 しかも、 ?DUP IF より速いです。

?DUP-0=-IF ( compilation – orig ; run-time n – n|  ) gforth-0.2 “question-dupe-zero-equals-if”

制御構造ワードのもう一つのグループ:

case ( compilation  – case-sys ; run-time  –  ) core-ext “case”

case 構造の開始。

endcase ( compilation case-sys – ; run-time x –  ) core-ext “end-case”

case 構造を終わらせます。 x を drop して、endcase の後ろへ進みます。 x の drop は、 元の(of のみの)case 構造では便利ですが、 他の場合(特に ?of を使用する場合)では(drop する為の) x を明示的に指定する必要がある場合があります。

next-case ( compilation case-sys – ; run-time –  ) gforth-1.0 “next-case”

一致する case にジャンプして、 case ループを再開します。 endcase とは異なり、 next-case はセルを drop しないことに注意してください。

of ( compilation  – of-sys ; run-time x1 x2 – |x1  ) core-ext “of”

x1=x2 の場合は続行します(両方を drop します)。 それ以外の場合は、 x1 をスタック上に残し、 endof または contof の後ろにジャンプします。

?of ( compilation  – of-sys ; run-time  f –  ) gforth-1.0 “question-of”

f が true の場合は続行します。 それ以外の場合は、 endof または contof の後ろにジャンプします。

endof ( compilation case-sys1 of-sys – case-sys2 ; run-time  –  ) core-ext “end-of”

endcase/next-case の後ろにジャンプして、 囲んでいる case 構造を終了(exit)します。

contof ( compilation case-sys1 of-sys – case-sys2 ; run-time  –  ) gforth-1.0 “cont-of”

囲んでいる case にジャンプして、 case ループを再開します。

内部的には、 of-sysorig で、 case-sys はセルとスタック深さ情報と、0 個以上の orig と、 dest です。

6.9.6.1 Programming Style

読みやすさを確保するために、 任意の制御構造を直接作成せず、 必要な制御構造に対して新しい制御構造ワードを定義し、 プログラム内でこれらのワードを使用することをお勧めします。たとえば、 以下のように書く代わりに:

BEGIN
  ...
IF [ 1 CS-ROLL ]
  ...
AGAIN THEN

以下のように制御構造のワードを定義することをお勧めします。 例:

: WHILE ( DEST -- ORIG DEST )
 POSTPONE IF
 1 CS-ROLL ; immediate

: REPEAT ( orig dest -- )
 POSTPONE AGAIN
 POSTPONE THEN ; immediate

そして、 次に、 これらを使用して制御構造を作成します:

BEGIN
  ...
WHILE
  ...
REPEAT

このほうがずっと読みやすいですよね。 もちろん、 REPEATWHILE は定義済みなので、 この例を見て改めて定義する必要はありません。


Next: Calls and returns, Previous: General control structures with case, Up: Control Structures   [Contents][Index]