OpenBoot 2.x コマンド・リファレンスマニュアル

制御コマンド

以降の各項では、Forth プログラム内の実行フローの制御用のワードについて説明します。

if-else-then 構造

ifthenelse の各コマンドは組み合わされて単純な制御構造を作ります。

表 4-21 に条件付き実行フロー制御用のコマンドを示します。

表 4-21 if..else..then コマンド

コマンド  

スタックダイアグラム 

説明 

if

( flag -- ) 

flagtrue の場合、このコマンドの後のコードを実行します。

else

( -- ) 

iffalse の場合、このコマンドの後のコードを実行します。

then

( -- ) 

if...else...then を終了します。

これらのコマンドの書式は次のとおりです。


flag if
    (true の場合これを実行)
else
    (false の場合これを実行)
then
    (通常どおりに実行を継続) 

または


flag if
    (true の場合これを実行)
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

高水準の case コマンドであり、複数の候補のなかから代替実行フローを選択するために用意されています。このコマンドの方が、深く入れ子になった if...then コマンドよりも読みやすいという利点があります。

表 4-22 に条件付き case コマンドを示します。

表 4-22 case 文コマンド

コマンド  

スタックダイアグラム 

説明 

case

( selector -- selector )  

case...endcase 条件付き構造を開始します。

endcase

( selector | {empty} -- ) 

case...endcase 条件付き構造を終了します。

endof

( -- ) 

条件付き構造内の of...endof 句を終了します。

of

( selector test-value -- selector | {empty} ) 

case 条件付き構造内の of...endof 句を開始します。

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 ループ

begin ループは、特定の条件が満たされるまで、同じコマンドの実行を繰り返します。そのようなループのことを条件付きループといいます。

表 4-23 に条件付きループの実行制御用のコマンドを示します。

表 4-23 begin (条件付き) ループコマンド

コマンド  

スタックダイアグラム 

説明 

again

( -- ) 

begin...again 無限ループを終了します。

begin

( -- ) 

begin...while...repeatbegin...until または begin...again ループを開始します。

repeat

( -- ) 

begin...while...repeat ループを終了します。

until

( flag -- ) 

flag が true である間、begin...until ループの実行を続けます。

while

( flag -- ) 

flag が true の間、begin...while...repeat ループの実行を続けます。

次に 2 つの一般的な形式を示します。


begin    any commands...flag until 

および


begin    any commands...flagwhile
       more commands repeat

上記の両方の場合とも、所定のフラグ値によってループが終了させられるまで、ループ内のコマンドが繰り返し実行されます。ループが終了すると、通常、実行はループを閉じているワード (until または repeat) の後のコマンドに継続されます。

begin...until の場合は、until がスタックの一番上からフラグを削除してそれを調べます。フラグが false の場合は、実行は begin のすぐ後に引き継がれて、ループが繰り返されます。フラグの true の場合は、実行はループから抜け出ます。

begin...while...repeat の場合は、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 ループ (カウント付きループとも呼ばれます) は、ループの繰り返し回数があらかじめ計算できるときに使用します。do ループは、通常、指定した終了値に達する直前に終了します。

表 4-24 に カウント付きループの実行制御用コマンドを示します。

表 4-24 do (カウント付き) ループコマンド

コマンド 

スタックダイアグラム 

説明 

+loop

( n -- ) 

do...+loop 構造を終了します。ループインデックスに n を加算し、do に戻ります (n < 0 の場合は、インデックスは start から end まで使用されます)。

?do

( end start -- ) 

?do...loop の 0 回またはそれ以上の実行を開始します。インデックスは start から end-1 まで使用されます。end = start の場合はループは実行されません。

?leave

( flag -- ) 

flag がゼロ以外の場合、実行を do...loop から抜けます。

do

( end start -- ) 

do...loop を開始します。インデックスは start から end まで使用されます。

例: 10 0 do i . loop ( 0 1 2...d e f と出力します)

i

( -- n ) 

ループインデックスをスタックに残します。 

j

( -- n ) 

1 つ外側のループのループインデックスをスタックに残します。 

leave

( -- ) 

実行を do...loop から抜けます。

loop

( -- ) 

do...loop を終了します。

次の画面で、ループの使用方法をいくつか示します。


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-25 に、前記以外のプログラム実行制御用のコマンドについて説明します。

表 4-25 プログラム実行制御コマンド

コマンド  

スタックダイアグラム 

説明 

abort

( -- ) 

現在の実行を終了させ、キーボードコマンドを解釈します。 

abort"ccc"

( abort? -- ) 

abort? が true の場合は、実行を終了させてメッセージを表示します。

eval

( addr len -- ) 

配列から Forth のソースを解釈します。 

execute

( xt -- ) 

実行トークンがスタックにあるワードを実行します。 

exit

( -- ) 

現在のワードから復帰します。(カウント付きループでは使用できません。) 

quit

( -- ) 

スタック内容をまったく変えない点を除いて、abort と同じです。

abort はプログラムの実行を即時に終了させ、制御をキーボードに返します。abort" は 2 点を除いて abort と同じです。第 1 点は、フラグが true の場合にスタックからフラグを削除し、その後は何もしないで強制終了させることです。もう 1 点は、強制終了が行われたとき、なんらかのメッセージを表示することです。

eval は (アドレスと長さにより指定された) 文字列をスタックから取り出します。次に、キーボードから入力される場合と同様に、その文字列の文字が解釈されます。Forth のテキストファイルをメモリーに読み込んでいる (第 5 章「プログラムの読み込みと実行」を参照) 場合は、eval を使用してそのファイル内の定義をコンパイルできます。