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 コマンドであり、複数の候補のなかから代替実行フローを選択するために用意されています。このコマンドの方が、深く入れ子になった ifthen コマンドよりも読みやすいという利点があります。

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

表 4-22 case文コマンド

コマンド  

スタックダイアグラム 

説明 

case

( selector -- selector )  

caseendcase 条件付き構造を開始します。

endcase

( selector | {empty} -- ) 

caseendcase 条件付き構造を終了します。

endof

( -- ) 

caseendcase 条件付き構造内の ofendof 句を終了します。

of

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

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

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...				flag		while
			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 ループ (カウント付きループとも呼ばれます) は、ループの繰り返し回数があらかじめ計算できるときに使用します。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 を使用してそのファイル内の定義をコンパイルできます。