条件制御とは何か
プログラムの本質は「状況に応じて異なる動作を選択する」ことである。FORTHでも、この条件分岐や繰り返し制御が重要な役割を果たす。FORTHはCやPythonのようなif (...) { ... } else { ... }という構文を持たず、スタック上の値(真/偽)を直接評価して分岐する。この単純な仕組みにより、極めて柔軟でコンパクトな制御構造が実現されている。
FORTHにおける「真」と「偽」は以下のように定義されている。
| 判定結果 | スタック上の値 | 意味 |
|---|---|---|
| 真(true) | -1 | 全ビットが1の値 |
| 偽(false) | 0 | すべてのビットが0 |
この「−1を真とする」設計はFORTHの伝統であり、ブール値をビット単位で直接処理できる利点がある。
IF ELSE THEN 構造 ― 条件分岐の基本
FORTHの基本的な分岐構文は次の形である。
(条件) IF
(条件が真のときの処理)
ELSE
(偽のときの処理)
THEN
この構文では、スタックのトップの値が評価対象となる。真(−1)の場合はIF〜ELSEブロックを実行し、偽(0)の場合はELSE以降の処理を実行する。
偽のときの処理を行わない場合は、ELSE を書かない。
(条件) IF
(条件が真のときの処理)
THEN
: SIGN-CHECK ( n -- )
DUP 0 > IF
." Positive"
ELSE
DUP 0 < IF
." Negative"
ELSE
." Zero"
THEN
THEN ;
5 SIGN-CHECK → Positive
-3 SIGN-CHECK → Negative
0 SIGN-CHECK → Zero
IF〜ELSE〜THEN構造はネスト可能であり、条件の入れ子を作ることで多段判定を行える。C言語のif-else if-elseに相当する構造である。
論理演算と複合条件
FORTHの条件式はスタック操作で構成されるため、AND, OR, INVERT を使って柔軟に複合条件を作成できる。演算もすべてスタック上で行われる。
| ワード | スタック効果 | 意味 |
|---|---|---|
= |
( a b -- flag ) | 等しいなら真 |
<> |
( a b -- flag ) | a <> b なら真 |
< |
( a b -- flag ) | a < b なら真 |
<= |
( a b -- flag ) | a <= b なら真 |
> |
( a b -- flag ) | a > b なら真 |
>= |
( a b -- flag ) | a >= b なら真 |
AND |
( x y -- z ) | ビット単位AND(真偽判定にも使える) |
OR |
( x y -- z ) | ビット単位OR |
XOR |
( x y -- z ) | ビット単位XOR |
INVERT |
( x -- y ) | ビット反転(NOTに相当) |
: RANGE? ( n -- )
DUP 0 >= SWAP 5 <= AND
IF
." In Range" CR
ELSE
." Out of Range" CR
THEN ;
これをループ内で使うと、指定範囲内の値だけ処理することもできる。
: FILTER-RANGE ( -- )
10 0 DO
I DUP . RANGE?
LOOP ;
1 In Range
2 In Range
3 In Range
4 In Range
5 In Range
6 Out of Range
7 Out of Range
8 Out of Range
9 Out of Range
FORTHでは、条件式を組み立てる際に論理積をスタック上で構築するという特徴がある。これが「スタックで考える脳」を鍛える重要な練習になる。
BEGIN UNTIL / BEGIN WHILE REPEAT ― 条件付きループ
条件分岐と並んで、条件付きループもFORTHの特徴的な構文である。DO ... LOOP がカウンタ制御ループであるのに対し、BEGIN ... UNTIL は条件制御ループである。
BEGIN
(処理内容)
(条件) UNTIL
この場合、UNTIL はスタック上の値を評価する。偽(0)の間はループを続け、真(−1)になると終了する。
CREATE BUF 80 ALLOT \ BUFを確保
: WAIT-ZERO ( -- )
BEGIN
CR ." Enter number: "
BUF 80 ACCEPT \ 入力文字列をBUFに格納( addr len -- actual-len )
BUF SWAP \ スタックに ( addr len )
0 0 2SWAP \ スタックに( 0 0 addr len )
>NUMBER \ 数値変換( 変換後の倍精度数値 未変換のアドレス 未変換の文字数 )
2DROP D>S \ 符号付倍精度整数を符号付整数に変換
0= \ 0以外なら入力を繰り返す
UNTIL
." Done" ;
0が入力されるまで繰り返し処理を行うループである。BEGIN〜UNTIL の組み合わせは「後判定ループ」であり、少なくとも1回は必ず実行される。
WHILE 構文を使う場合
BEGIN
(条件) WHILE
(処理内容)
REPEAT
これは「前判定ループ」に相当し、条件が最初から偽なら一度も実行されない。
CASE 構文
ネストしたIFが増えると、プログラムの可読性が低下する。そのような場合には CASE 構文が有効である。
CASE
( 値 ) OF (処理) ENDOF
( 値 ) OF (処理) ENDOF
(その他) (処理)
ENDCASE
: DAY-NAME ( n -- )
CASE
1 OF ." Monday" ENDOF
2 OF ." Tuesday" ENDOF
3 OF ." Wednesday" ENDOF
4 OF ." Thursday" ENDOF
5 OF ." Friday" ENDOF
6 OF ." Saturday" ENDOF
7 OF ." Sunday" ENDOF
." Invalid day"
ENDCASE ;
この構文はFORTH-83以降で標準化されており、C言語のswitch文に相当する。条件を階層的に書かずに整理できるため、複雑な判定処理をわかりやすく記述できる。
状態機械(State Machine)としてのFORTHプログラム
FORTHの条件制御の真価は、単なるIF文ではなく、「状態の遷移を明示的に記述できる」 点にある。これを活用することで、イベント駆動的な制御系やインタラクティブな動作を小さなコードで表現できる。
状態機械とは
状態機械(finite state machine, FSM)は、「現在の状態」と「入力」によって次の状態を決定するモデルである。FORTHでは、この状態を変数や定数で管理し、CASE や IF によって状態遷移を記述する。
VARIABLE STATE \ 状態を保持(0:待機(初期値), 1:硬貨投入, 2:商品選択, 3:排出)
: VEND ( -- )
BEGIN
STATE @
CASE
0 OF ." Waiting for coin" 1 STATE ! ENDOF \ 「待機」を出力してSTATEを1にする
1 OF ." Coin inserted" 2 STATE ! ENDOF \ 「硬貨投入」を出力してSTATEを2にする
2 OF ." Selecting item" 3 STATE ! ENDOF \ 「商品選択」を出力してSTATEを3にする
3 OF ." Dispensing..." 0 STATE ! ENDOF \ 「排出」を出力してSTATEを0にする
ENDCASE
CR STATE @ 0= \ STATEが0以外なら繰り返し
UNTIL ;
このプログラムは、STATE 変数を利用して状態を切り替える単純な例である。「待機 → 硬貨投入 → 選択 → 排出 → 待機」と状態が循環し、制御の流れが明確に可視化されている。
このような設計は、センサー制御・通信プロトコル解析・ユーザインタフェース処理など、状態遷移が頻繁に発生する分野で威力を発揮する。
条件制御とスタックの使い方の注意
FORTHでは、条件式や状態判定もすべてスタック上の値で処理される。したがって、条件分岐の中でスタック操作を誤ると、次の評価に影響を及ぼし、誤判定の原因となる。
特に注意すべき点は以下の通り。
-
条件式の結果を消し忘れない
IFで消費されない値が残ると、次の条件が誤動作する。 -
ネストしたIF構文ではTHENを忘れない
IF〜ELSE〜THENはペアで動作するため、構文が不一致だとコンパイルエラーになる。 -
ループ構造内でRスタックを乱用しない
>R/R>によって制御情報を破壊するおそれがある。
状態遷移型プログラミングの利点
FORTHで状態機械を記述すると、次のような利点が得られる。
- 実行フローが明快で、スタックの動きが予測しやすい
- IF文のネストを避け、CASE構文で整理できる
- 小さなワードの組み合わせで大きな制御が構築できる
- 割り込み的動作やイベント応答を模倣できる
状態をスタック上のフラグや変数で保持することにより、「今プログラムがどの段階にあるか」が常に明確になる。これは、低レベル制御を多用するFORTHらしい設計思想であり、マイコン制御や機械動作シーケンスにも応用しやすい。
まとめ
FORTHの条件制御は、一般的な高級言語のような構文糖衣ではなく、「スタック上の真偽値をもとに直接実行を切り替える」 という極めてシンプルな設計に基づいている。
このため、
- 条件式は演算結果としてスタック上に現れ、
-
IF,UNTIL,WHILEなどはそれを即座に評価する。
つまり、FORTHでは条件制御そのものが「データフローの一部」なのだ。これを理解すると、スタック上の値の流れと制御の流れが一致し、「状態で考える」プログラム設計が自然に身につく。