以降の各項では、Forth プログラム内の実行フローの制御用のワードについて説明します。
if、else、then の 各コマンドは組み合わされて単純な制御構造を作ります。
表 4-28に条件付き実行フロー制御用のコマンドを示します。
表 4-28 if...else...then コマンド
コマンド |
スタックダイアグラム |
説明 |
---|---|---|
if |
( flag -- ) |
flag が true の場合、このコマンドの後のコードを実行します。 |
else |
( -- ) |
flag が false の場合、このコマンドの後のコードを実行します。 |
then |
( -- ) |
ifelsethen を終了します。 |
これらのコマンドの書式は次のとおりです。
flag if (true の場合これを実行) then (通常どおりに実行を継続 |
または
flag if (true の場合これを実行) else (false の場合これを実行) then (通常どおりに実行を継続) |
if コマンドはスタックからフラグを 1 つ「消費」します。そのフラグが true (ゼロ以外) であれば、if の後のコマンドが実行されます。true でなければ、(存在する場合) else の後のコマンドが実行されます。
ok : testit (n -- ) ] 5 > if ." good enough " ] else ." too small " ] then ] ." Done. " ; ok ok 8 testit good enough Done. ok 2 testit too small Done. ok |
] プロンプトは、それが現れる間は、新しいコロン定義の作成の途中であることをユーザーに示します。このプロンプトはセミコロンを入力して定義を終了すると ok に戻ります。
高水準の case コマンドが、複数の候補のなかから代替実行フローを選択するために用意されています。このコマンドの方が、深く入れ子になった ifthen コマンドよりも読みやすいという利点があります。
表 4-29に条件付き case コマンドを示します。
表 4-29 case 文コマンド
次に case コマンドの使用例を示します。
ok : testit (testvalue -- ) ] case ] 0 of ." It was zero " endof ] 1 of ." It was one " endof ] ff of ." Correct " endof ] -2 of ." It was minus-two " endof ] (default ) ." It was this value: " dup . ] endcase ." All done." ; ok ok 1 testit It was one All done. ok ff testit Correct All done. ok 4 testit It was this value: 4 All done. ok |
(省略可能な) default 句はまだスタックにあるテスト値を使用できますが、その値を削除してはなりません (.でなくdup . を使用してください)。of 句が正常に実行されれば、テスト値はスタックから自動的に削除されます。
begin ループは、特定の条件が満たされるまで、同じコマンドの実行を繰り返します。そのようなループのことを条件付きループといいます。
表 4-30に条件付きループの実行制御用のコマンドを示します。
表 4-30 begin (条件付き) ループコマンド
次に 2 つの一般的な形式を示します。
begin any commands flag until |
および
begin any commands flagwhile more commands repeat |
上の両方の場合とも、所定のフラグ値によってループが終了させられるまで、ループ内のコマンドが繰り返し実行されます。ループが終了すると、通常、実行はループを閉じているワード (until または repeat) の後のコマンドに継続されます。
beginuntil の場合は、until がスタックの一番上からフラグを削除してそれを調べます。フラグが false の場合は、実行は begin のすぐ後に引き継がれて、ループが繰り返されます。フラグが true の場合は、実行はループから抜け出ます。
beginwhilerepeat の場合は、whileがスタックの一番上からフラグを削除して調べます。フラグが true の場合は、while のすぐ後のコマンドが実行されてループが繰り返されます。repeat コマンドは制御を自動的に begin に戻してループを継続させます。while が現れたときにフラグが false であった場合は、実行はただちにループから抜け出し、制御がループを閉じている repeat の後の最初のコマンドに移ります。
これらのループのいずれについても、「true ならば通り過ぎる」と覚えると忘れないでしょう。
次に簡単な例を示します。
ok begin 4000 c@ . key? until (任意のキーが押されるまで繰り返す) 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 ok |
この例では、ループはまずメモリー位置 4000 から 1 バイトを取り出して表示します。次に、key? コマンドが呼び出され、これが、ユーザーがそれまでにどれかのキーを押していれば true をスタックに残し、そうでない場合は false を残します。このフラグは until によって「消費」され、その値が false であった場合は、ループが繰り返されます。キーを押せば、次に呼び出されたとき、key? は true を返し、したがってループは終了します。
Forth の多くのバージョンとは異なり、このユーザーインタフェースの場合は、ループや条件付き制御構造を対話的に使用できます。つまり、まず最初に定義を作成する必要がありません。
do ループ (カウント付きループとも呼ばれます) は、ループの繰り返し回数があらかじめ計算できるときに使用します。do ループは、通常、指定した終了値に達する直前に終了します。
表 4-31にカウント付きループの実行制御用コマンドを示します。
表 4-31 do (カウント付き) ループコマンド
次の画面で、ループの使用方法をいくつか示します。
ok 10 5 do i . loop 5 6 7 8 9 a b c d e f ok ok 2000 1000 do i . i c@ . cr i c@ ff = if leave then 4 +loop 1000 23 1004 0 1008 fe 100c 0 1010 78 1014 ff ok : scan (byte -- ) ] 6000 5000 (5000 〜 6000 のメモリー領域を走査して指定のバイト値に 一致しないバイトを調べる) ] do dup i c@ <> (byte error? ) ] if i . then (byte ) ] loop ] drop (the original byte was still on the stack, discard it ) ] ; ok 55 scan 5005 5224 5f99 ok 6000 5000 do i i c! loop (メモリー領域にステップパターンを埋め込む) ok ok 500 value testloc ok : test16 (-- ) 1.0000 0 (do 0-ffff ) (指定位置に異なる 16 ビット値を書き込む) ] do i testloc w! testloc w@ i <> (error? ) (さらに位置をチェック) ] if ." Error - wrote " i . ." read " testloc w@ . cr ] leave (exit after first error found ) (この行は省略可能) ] then ] loop ] ; ok test16 ok 6000 to testloc ok test16 Error - wrote 200 read 300 ok |
ok 10 5 do i . loop 5 6 7 8 9 a b c d e f ok ok 2000 1000 do i . i c@ . cr i c@ ff = if leave then 4 +loop 1000 23 1004 0 1008 fe 100c 0 1010 78 1014 ff ok : scan (byte -- ) ] 6000 5000 (5000 〜 6000 のメモリー領域を走査して指定のバイト値に 一致しないバイトを調べる) ] do dup i c@ <> (byte error? ) ] if i . then (byte ) ] loop ] drop (the original byte was still on the stack, discard it ) ] ; ok 55 scan 5005 5224 5f99 ok 6000 5000 do i i c! loop (メモリー領域にステップパターンを埋め込む) ok ok 500 value testloc ok : test16 (-- ) 1.0000 0 (do 0-ffff ) (指定位置に異なる 16 ビット値を書き込む) ] do i testloc w! testloc w@ i <> (error? ) (さらに位置をチェック) ] if ." Error - wrote " i . ." read " testloc w@ . cr ] leave (exit after first error found ) (この行は省略可能) ] then ] loop ] ; ok test16 ok 6000 to testloc ok test16 Error - wrote 200 read 300 ok |
表 4-32に、前記以外のプログラム実行制御用のコマンドについて説明します。
表 4-32 プログラム実行制御コマンド
abort はプログラムの実行を即時に終了させ、制御をキーボードに返します。abort" は 2 点を除いて abort と同じです。第 1 点は、フラグが true の場合にスタックからフラグを削除し、その後は何もしないで強制終了させることです。もう 1 点は、強制終了が行われたとき、なんらかのメッセージを表示することです。
eval は (アドレスと長さにより指定された) 文字列をスタックから取り出します。次に、キーボードから入力される場合と同様に、その文字列の文字が解釈されます。Forth のテキストファイルをメモリーに読み込んでいる (第 5 章「プログラムの読み込みと実行」を参照) 場合は、eval を使用してそのファイル内の定義をコンパイルできます。