第 1 章において、Mindのプログラムが自然な日本語に近い表現で記述できることを示した。
もし、プログラムが、「あれをして、これをして、・・・をして・・・」というように、実行すべきことがらの羅列だけであるなら、第2章までで解説は終わってしまうのだが、プログラムである以上、条件判断や繰り返し処理というようなものが加わる。これはコンピュータがコンピュータらしい働きをするために大切な仕掛けである。
これら条件判断・繰り返し処理など、プログラムの処理の分岐が起こるような機能を制御構文と呼ぶことにする。
まず、次のプログラムをご覧頂きたい。
構文=
上のプログラムがどういう意味を持つかは、説明するまでもないが蛇足を承知で解説しよう。
まず「雨降り?」が、ある条件を判定する部分である。次の「ならば」によって処理の分岐が起こる。条件が真の場合には、処理は「ならば」を通り「傘を差す」が実行される。条件が偽の場合には処理が分岐し、「つぎに」の直後へスキップが起こる。
記述スタイルであるが、「雨降り?」の直後で改行し、「ならば」を新しい行に、しかも字下げして記述している。しかしこのような表記は強制されるわけではないのだが、分岐構文を読みやすくするため、Mindでは慣習としてこのように記述することが多い。
このあたりはよいとして、おそらく読者は、「つぎに」にひっかかったのではないだろうか。つまり、
雨降り?
ならば 傘を差す
だけで済んでいれば、もっと「日本語らしい」のに...と。
残念ながら、「ならば」だけでは処理の分岐を正確に記述できない。
「ならば」に続く「真の場合の処理」がたった1つの単語だけで済めばいいのだが、場合によっては、
雨降り?
ならば 傘を差し
レインコートを着て
ブーツを履く
となるかも知れない。そうすると、「ならば」が及ぶ範囲がどこまでなのかを示す必要があり、「つぎに」がその役割を負う。「ならば」による処理の分岐は、この「つぎに」によって合流することになる
。
雨降り?
├ 真→ ならば 傘を差し
偽 レインコートを着て
| ブーツを履く
↓ つぎに
外出する
上のようになっていれば、雨降りの場合の行動として、「傘を差す」「レインコートを着る」「ブーツを履く」の3つが行われることが明解となる。
もう1つ、この条件判断には「もし」という言葉がないことに疑問を持たれたかも知れない。次のように記述したいと思う読者もおられるだろう。
もし 雨降り?
ならば 傘を差し
レインコートを着て
ブーツを履く
英語のプログラム言語では、条件分岐にif文を用いることが多い。if〜thenの日本語訳が「もし...ならば」なので、〔if=もし〕のように考えがちであるが、日本語で重要なのは「ならば」の方であり、「もし」は飾りに過ぎない。実際、日本語で主語がない場合には「もし」は省略されることが多い。
ただ、主語がある場合、「もし」を記述することで表現が安定することもあるので、Mindでは「もし」を擬似語(ダミーの単語)として登録してあり、(見た目の安定のために)記述することもできる。
ここで、「ならば」の動きについて補足しておこう。
「ならば」は、「加える」や「表示する」などと同じように、積極的な行動を起こす単語である。
「ならば」は、実行時に1つのデータをスタックから受け取る。これが条件値である。この値がゼロ以外の場合に〔真〕と判定し、「ならば」以降の文を実行する。逆に、この値がゼロの場合は〔偽〕と判定し、「つぎに」のところまで処理をスキップする。
真偽の判定が「ゼロかそうでないか」で行われることは重要である。「ならば」に与えるデータは偽の場合には必ずゼロでなくてはならないが、真であることを伝えるにはゼロ以外のどんな数値であっても(マイナスでも)よいのである。これを利用して、プログラムを簡単にできることが多い。
この性質(真理値の評価)は、「ならば」「でなければ」の2つの分岐用単語の他に、「または」「かつ」といった論理演算の単語も持つ性質である。
さて、先のプログラム例は、
[A] 雨降り?
[B] ならば 傘を差す
つぎに
のように分離して考えることができる。上図の[A]がまず実行され、条件値がスタックに積まれ、その状態で[B]に突入すると考えたい。
[B]に入って最初に実行されるのが「ならば」であり、[A]で積んだデータをスタックから取り出し、これによって分岐を行う。つまり、条件判断と分岐処理は独立していることになる。これは他のプログラム言語にない特徴である。
次の文を見てみよう
計算結果が 100
ならば ・・・・
つぎに
一見、これでよさそうに見えるが、正しく動作しない。なぜなら、「ならば」に与えられるデータは常に 100 であり、これはゼロではないので、「ならば」は常に成立してしまう。
念のためにスタックを図示しよう。「ならば」が実行される直前には、スタック内容は次のようになっている。
(計算結果)
100
上の状態で「ならば」に入るから、常に100が与えられてしまう。次のように修正すべきである。
計算結果が 100に 等しい
ならば ・・・・
つぎに
「等しい」は、2つのデータをスタックから取り出して比較し、一致しているなら1を、さもなければ0をスタックに返す単語である。「等しい」の実行前後のスタックの動きは次のようになり、
(計算結果)
100
↓「等しい」の実行
1または0
これが「ならば」に与えられるデータとなり、うまく動作する。
↓「ならば」の実行
(空)
ところで、先の例にあった「雨降り?」という単語であるが、もちろん、こんな単語はMindに備わってはおらず、ユーザーがこの単語を定義していれば...という前提で書いたものである。簡単なものでは、次のような定義で実現できるだろう。
雨降り?とは
「雨が降っていますか?(はい/いいえ)」を 表示し
文字列入力したものが 「はい」に 等しい文字列であること。
上の定義はすべてMindの標準単語を使用しているので、これは本当に動く。これを実行すると、コンソールに質問文が表示され、オペレータが「はい」または「いいえ」を答えると、スタックに1か0を積んで帰ってくる。もちろん、この値は「ならば」に与えるデータとしてマッチしたものである。
コンピュータらしく天候を自動検出しようとするなら、次のようなプログラムがいいだろう。
雨降り?とは
測候所からデータを受信し 降雨量が 1ミリ 以上であること。
こちらの「雨降り?」も、先の定義例と同じく、スタックに1か0を積んで帰る。ただ、こ
れは仮想の単語が2つ引用されており、この段階ではまだ動作するプログラムにはならない。
ここまでは、Mindらしいプログラムとするために、プログラムを細かく分岐しているが、参考までに、上の「雨降り?」を、独立単語とせずに、「ならば」の展開と同じ場所に記述したものをお見せしよう。
測候所からデータを受信し 降雨量が 1ミリ 以上
ならば 傘を差す
つぎに
もちろん上記のように書いても間違いではないが、先頭の1行を「雨降り?」という独立語で外に出し、こちらの上位側で「雨降り? ならば 傘を...」と引用した方が優れていることは明白であろう。
測候所がどうしたとか、降雨量がどうしたとかいうような細かい話は「雨降り?」という下位の単語にやらせて、上位単語はもっと抽象的な言葉の世界で記述するのがMind的なやり方である。
他の言語でいえば〔if...then...else...〕の構文に相当する。
次のように用いる
構文=
雨降り?
ならば テレビを見る
さもなければ 外出する
つぎに
この場合でも、分岐の判定を行うのは「ならば」だけである。
他のプログラム言語ではあまり見掛けない構文である。次のように用いる。
構文=
要するに「ならば」の逆の判定を行う構文である。「ならば」と同格の単語であり、この「でなければ」も、スタックからデータを1つ受け取って分岐するという積極的な行動を起こす。
「でなければ」の構文は、必ず「ならば」の構文に変換することができる(逆もいえる)。わかりやすい例として、
室温が 25度より 大きい
ならば エアコンのスイッチを入れる
つぎに
は、
室温が 25度 以下
でなければ エアコンのスイッチを入れる
つぎに
のように変換できる。つまり、条件値を計算するところを逆の結果が出るようにすることで、「ならば」が「でなければ」に、あるいはその逆になるのである。
なお、この構文に「さもなければ」を加えた、〔でなければ...さもなければ...つぎに〕という構文も使えなくはないが、二重否定の文になり、まぎらわしいのでやめた方がいいだろう。
これは制御構文ではなく、単に数値の演算を行う処理単語なのだが、「ならば」などの構文と組み合わせて用いられることが多いのでここで解説しておく。
これらは普通の日本語通りの使い方で、
構文=
のように記述する。
�� の「または」は論理和(OR)を演算する。バイナリの各ビットを演算するのではなく、真理値のORである(注 1)。すなわち、Aが真(ゼロ以外)を返すか、あるいは、Bが真を返す場合に1を、さもなければ0をスタックに返す演算語である(結果が再びスタックに置かれることに注目)。
- 注1
- 各ビットごとの論理和・論理積をとるのは、Mindでは「OR」「AND」という処理単語である。
�△痢屬�つ」は論理積(AND)を演算する。Aが真を返し、かつ、Bも真を返す場合のみ1を、さもなければ0をスタックに返す。
Mindの単語の中には、このような真理値をスタックに返すものが数多く存在するが、すべて1(真)か0(偽)を返す。
「または」と「かつ」の単語は、Mindの文法としては例外的に、中置記法(注2)を用いる。接続詞を独立した単語として扱うためである。
- 注2
- 中置記法とは2つのデータの間に演算子を書く記法。
一般の数式では「2+3」などと記述する中置記法をとっている。
Mindでは「2に 3を 加える」のような後置記法が標準であるが、例外的に「または」「かつ」は中置記法とする。普通の日本語表現に合わせるためこのような例外を設けた。
中置記法であることと関係するが、これを記述している箇所は「行」が意味を持つ。前記�,任�
またはの左側 の計算結果と、
またはの右側 の計算結果とのORがとられることになる。つまり、「または」の影響範囲はその行内に限られる。
「ならば」との組み合わせとしては次のような例をあげることができる。
室温が 25度 以上 かつ 温度が 65% 以上
ならば エアコンのスイッチを入れる
つぎに
上記の1行目の処理と2行目以降の処理はたがいに独立していることを思い起こして欲しい。1行目の「または」による演算によってスタックには1または0が置かれ、これを「ならば」が受け取る...という手順で分岐が行われる。
従って、上記の判定部分だけを独立単語とすることもできる。次のようになる。
蒸し暑い?とは
室温が 25度 以上 かつ 温度が 65% 以上。
エアコン操作とは
蒸し暑い?
ならば エアコンのスイッチを入れる
つぎに。
「または」と「かつ」は同じ行内にいくつも引用することができる。
A または B かつ C
「かつ」の方が計算が優先するので、上記の場合、「B かつ C」が先に計算され、その結果と「A」が計算される。
さて、ここまでは行内での演算であったが、行間で同様の計算を行うことができる。次のようになる。
・・・・・・・ D ・・・・・・・
または
・・・・・・・ E ・・・・・・・
このような行間の演算は、1行が長くなってしまうような場合に用いられるのはもちろんであるが、「または」と「かつ」の演算が複雑にからむような場合の有効な手段でもある。上記でいえば、DやEの行内にさらに「または」「かつ」の演算(行内演算)を含むケースである。この場合は行内の演算が先に行われ、その各行の結果同士でAND/ORの演算が行われることになる。次のような場合である。
室内に人が居る?
かつ
室温が 25度 以上 かつ 温度が 65% 以上
ならば エアコンのスイッチを入れる
つぎに
なお、次のような場合であるが、
・・・・・・・ D ・・・・・・・
または
・・・・・・・ E ・・・・・・・
かつ
・・・・・・・ F ・・・・・・・
この場合、「かつ」の優先はなく、単純に上の方から順に演算される。
繰り返し処理の最も標準的なものである。次のような構文で用いる。(赤字が構文の基本要素)
構文=
ここから
・・・・・・・・・・・・
・・・・・・・・・・・・
<条件値発生処理>
ならば 打ち切り
つぎに
繰り返し
この構文は基本的に永久ループであり、打ち切りたいときに「打ち切り」を実行することで、明に打ち切る方法をとっている。この方法の利点は、打ち切り条件が複数になった場合でもまったく形を変える必要がないこと、打ち切りの判定がループの最初にあっても終りにあっても、形は同じであるという点である。
少し極端であるが、無限ループは
「打ち切り」を書かない ことで実現でき、次のような記述になる。
無数のAを表示するとは
ここから
'A'を 一文字表示し
繰り返すこと。
上のプログラムを実行すると、コンソールには次のような表示が次々となされ、止まらなくなる。(CTRL-Cの打鍵でプログラムを強制終了すれば止まるが、少し乱暴なプログラムなので注意されたい)
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAA
A^C
以下のように改良すればエンターキーを打鍵することでスマートに表示をやめさせることができる。(注:これであっても、CPUに負荷をかけるので短時間の実行に留めたい)
無数のAを表示するとは
ここから
'A'を 一文字表示し
文字列入力有り?
ならば 打ち切り
つぎに
繰り返すこと。
もう少し実務に近いものをやってみよう。
全てのデータを入力とは
ここから
伝票終り?
ならば 打ち切り
つぎに
伝票を箱から取り出し
伝票のデータを入力し
繰り返すこと。
上記で「伝票〜〜」という3種の単語はいずれも架空の単語である。ループに入って最初に打ち切り条件の判定を行っていることに注目したい。なるべくこの形式を使うことを勧める。我々の日常感覚としては、
全てのデータを入力とは
ここから
伝票を箱から取り出し
伝票のデータを入力し
伝票終り?
ならば 打ち切り
つぎに
繰り返すこと。
と書きたくなる。ほとんどの場合、後者でも不都合はないだろうが、万が一、最初から伝票が存在しない状態でこの単語が呼び出される可能性を考えると、前者の方が、空の箱から伝票を取り出すという異常行為を避けられるメリットがある。
ループ内での積極的な処理が存在せず、ただ、ひたすら打ち切り条件を調べるという場合もある。ある状態になるまで待つ(特定の事象を待つ)場合である。これも形式としては同じである。
晴れるまで待って外出とは
ここから
晴れ?
ならば 打ち切り
つぎに
一時間待ち
繰り返し
外出すること。
前記をベースにちょっと仕様を変更してみよう。たとえ雨が降っていても、午後3時には外出しなくてはならないとする。次のようになる。
[A]
晴れるまで待って外出とは
ここから
晴れ?
ならば 打ち切り
つぎに
午後3時?
ならば 打ち切り
つぎに
一時間待ち
繰り返し
外出すること。
上のような簡単な条件判定であれば、次のようにしてもよいだろう。
[B]
晴れるまで待って外出とは
ここから
晴れ? または 午後3時?
ならば 打ち切り
つぎに
一時間待ち
繰り返し
外出すること。
どちらによるかは好みの問題である。ただ、この2例はまったく等価ではない。
Aでは、今すでに晴れている場合、「午後3時?」の処理はまったく実行されないが、Bでは必ず両者の問い合わせが実行されるという微妙な違いはある。
次に、「気分が良くて晴れている」場合のみ外出する...という条件にしてみよう。普通に記述するなら次のようになる。
[C]
晴れるまで待って外出とは
ここから
気分が良い? かつ 晴れ?
ならば 打ち切り
つぎに
一時間待ち
繰り返し
外出すること。
ここで、「もう一度」を使ってみよう。上記のCは次のように変形できる。
[D]
晴れるまで待って外出とは
ここから
気分が良い?
でなければ
一時間待ち
もう一度
つぎに
晴れ?
ならば 打ち切り
つぎに
一時間待ち
繰り返し
外出すること。
「もう一度」は、〔ここから...繰り返す〕の文あるいは、次に解説する〔回数指定し...繰り返す〕の構文で用いることができ、強制的に、繰り返しの最初に戻す効果を持つ特殊な単語である(「打ち切り」の逆のような働きである)。
上記Dでわかるように、「気分が良い?」が偽の場合には絶対に外出しないので、「晴れ?」を調べる必要がなく、「もう一度」によってループの最初に戻してしまっている。
「打ち切り」は〔ここから...繰り返す〕の構文に必須であるが、「もう一度」は他の表現で代替できることが多い。以下では「ならば」を多段にすることで代替している。
[E]
晴れるまで待って外出とは
ここから
気分が良い?
ならば 晴れ?
ならば 打ち切り
つぎに
つぎに
一時間待ち
繰り返し
外出すること。
回数があらかじめ分かっている繰り返し処理は、この構文を使用する。
構文=
nを 回数指定し
・・・・・・・・し
・・・・・・・・し
繰り返す
上記が基本的な形式である。回数を指定する 数値 n はスタックからデータとして渡すので、必ずしもこの箇所に記述する必要はない。
ゼロの回数を与えた場合、何もしないで直ちにループを抜けるようになっている。負の値は非常に大きな正の値とみなされるので注意すること。
次のプログラムは、画面に A の文字を10個表示する(これは本当に動く)。
[A]
十個のAを表示とは
10を 回数指定して
'A'を 一文字表示し
繰り返すこと。
AAAAAAAAAA
さて、これを変形してみよう。「与えられた回数だけAの文字を表示する」とする。
他のプログラム言語の経験者はすぐに、「回数を(仮引数も含めて)変数で渡せばよい」などと考えるかも知れないが、Mindの場合はもっと簡単になる。
[B]
複数のAを表示とは
回数指定して
'A'を 一文字表示し
繰り返すこと。
AとBをよく見比べてみると、Bは、Aから「10を」の記述を削除しただけである。
Bは 「回数指定の左側に必ず回数が記述されるとは限らない」 良い例になる。この単語を引用する時には、
[C]
のように引用すれば、画面に
AAAAAAAAAA
が表示できる。
まず、Cの「10個だけ」の実行により、スタックには10という数値が置かれる。
次いで、「複数のAを表示する」の実行に入る。呼ばれた「複数のAを表示」は直ちに「回数指定し」を実行するが、そのときすでにスタックには10が積まれているから、これが取り出されて指定回数として処理され、うまく動作する。
さて、〔回数指定し......繰り返す〕の構文の中でも、〔ここから......繰り返す〕の構文で解説した「打ち切り」と「もう一度」が利用できる。
〔ここから......繰り返す〕の項の解説で次のような例文をあげた。
全てのデータを入力とは
ここから
伝票終り?
ならば 打ち切り
つぎに
伝票を箱から取り出し
伝票のデータを入力し
繰り返すこと。
もし、上記が「伝票100枚を処理しなさい」という命令に変更されれば、次のような回数指定の構文を使うことになるだろう。
全てのデータを入力とは
100を 回数指定し
伝票終り? −−−
ならば 打ち切り |この部分は無くても良い
つぎに −−−
伝票を箱から取り出し
伝票のデータを入力し
繰り返すこと。
「ここから」 が 「100を回数指定し」 に変わっただけである(ループ最後の「繰り返す」が同一であることに注目)。
この繰り返し文は、伝票100枚を処理したとき、あるいは、その枚数に満たなくても伝票が終わってしまったときに打ち切られることになる。
次に「回数」という処理単語を解説しておく。「回数」は、〔回数指定し......繰り返す〕のループ内で、現在の回数を引用するのに用いられる。1から数えるので初回ループでは1である。
次のプログラムを実行すると、
十個のAを表示とは
10を 回数指定して
回数を 数値表示し 空白表示し
繰り返すこと。
画面には、
1 2 3 4 5 6 7 8 9 10
という数値の列が表示される。
「回数」は必ず1から始まるので、もし、0から始まる値が必要な場合には(たとえば問題「0から9の数字を表示せよ」)、次のように、引用した「回数」に補正をかければよい。
十個の数を表示とは
10を 回数指定して
回数から 一つ引いたものを 数値表示し 空白表示し
繰り返すこと。
1単位ではない増分を得たい場合には、「回数」を引用してから補正するよりは、別途、専用の変数を設けて、それをある値ずつ増加しながら処理するほうが柔軟性があって良いことが多い。
ネストとは、入れ子とか多重使用のことである。
すべての制御構文はネストすることができる。ただ、1つの単語定義の中にあまり多くの制御構文を入れることは、プログラムの可読性を下げるので好ましくない。複雑な展開になったときには、一定のブロックを外に出して別単語定義とすることを勧める。
繰り返し構文の中で実行される「打ち切り」や「もう一度」は、その最も内側のループに対してのみ有効である。ネストされた繰り返し構文中で、一気に外側に脱出する方法を解説しておく。
構文=
処理1とは
ここから
・・・・・・・・し
回数指定し
・・・・・・・・し
・・・・・・・・し
ならば 終り
つぎに
繰り返し
繰り返すこと。
上記で、赤い文字で示した「終り」がポイントである。これを実行すると、いま実行中の単語(この場合は「処理 1」)の実行を強制的に終わらせる働きがある。上記はこの性質を利用して多重のループから脱出を図ったものである。
(このほかに、フラグと「打ち切り」を併用し、外側ループに打ち切りを知らせる方法もあるがここでは述べない)
注意したいのは、「終り」が単語全体の脱出を図るものなので、繰り返し文の脱出とは必ずしも一致しない(本例ではたまたま一致)という点である。
もし、次のように、
処理1とは
ここから
・・・・・・・・し
回数指定し
・・・・・・・・し
・・・・・・・・し
ならば 終り
つぎに └→親側に戻る
繰り返し
繰り返し
後片付けすること。
上では、外側の繰り返しのあとにも他の処理(「後片付け」)が存在するためには、内側で「終り」を実行すると、「後片付け」をしないで戻ってしまうという不都合がある。
このような場合には、後片付けを上位単語(「処理 1」を呼んだ親の単語側)にまかせ、ここには記述しないようにすれば「終り」が使えるようになる。親側は次のようになるだろう。
処理100とは
処理1し
後片付けして
また別なことをすること。
ところで、「終り」は繰り返し構文の中で使うような説明をしてきたが、実はどんな場面でも使用できる。次の例を参考にして欲しい。
[A]
エラー処理とは
エラー?
ならば エラー表示し 音を鳴らす
つぎに。
[B]
エラー処理とは
エラー?
でなければ
終り
つぎに
エラー表示し 音を鳴らすこと。
上記AとBは同じ処理結果になる。「ならば」の分岐が複雑な場合、適当に「終り」を使うことで、字下げをせずに済んだり、見やすくなったりする(ただし、この程度ならAの方を勧める)。
さて、「終り」はもう1つ別の顔を持っている。前記のものは定義文の中で使われていたが、定義外でも記述できる。
構文=
上記のように、ソースコード中にいきなり「終り。」と記述した場合には、その位置でコンパイルを終りにする働きを持つ。つまり、これ以降のソースコードはまったく無視されることになる。
次の図にここまで述べた「終り」の使い分けを整理した。
「終り」の使い方
〔処理単語定義内で記述〕
○○とは
・・・・・・・・・
ならば 終り ←「○○」の処理をここで終る
つぎに (リターン)
・・・・・・・・・
〔(定義内ではなく)ソースコード内に宣言〕
○○とは
・・・・・・・・・ ←ソースプログラム前半
△△とは
・・・・・・・・・
終り。 ←ここでコンパイル終り
◎◎とは ←後半はコンパイルされない
・・・・・・・・・
先の「終り」と似ているが、プログラム全体の実行を終わる点が異なる。次のように使用する。
構文=
○○とは
・・・・・・・・・
ならば 実行終り
つぎに
・・・・・・・・・
多くの場合「ならば」文と組み合わせて使用する。この単語を実行するとプログラム全体の実行を終了する(そのプログラムがコマンドプロンプトから起動されたものであれば、再びコマンドプロンプトに戻る)。
第2章の「処理単語」の節のメインの解説で、Mindのプログラムが起動したとき、「メイン」という単語の実行から始まることを述べたが、プログラムの終りは、普通は「メイン」の処理が「。」に到達した時点となる。言い換えれば「メイン」の内部に記述したすべての処理が終わったときにプログラムの実行も終わるようになっている。
ところが、エラー発生その他により、ずっと下位の単語の中においてプログラム実行を終了させたい場合もある。そのようなときに使われるのがこの「実行終り」である。ちなみに、「メイン」の定義文の中においては「実行終り」と「終り」は等価である。
以下で解説する「選択」、「事例」、「範囲事例」は、いずれも処理単語定義の内部で使用する構文である。
いずれも、値の比較と「ならば」の分岐を組み合わせれば実現できるものだが、これらを使ったほうがプログラムがエレガントに組め、メンテナンスもし易い。
選択
構文=
<整数値>で
選択する
<選択肢>
<選択肢>
・・・・・
選択終り
1から始まる整数をスタックに積んで「選択」に入ると、その値に対応する選択肢の1つが実行され、実行が終わると「選択終り」の次の箇所から次の処理が続行される。
選択肢としては、
ただ1つの単語だけが記述できる。それは定数や変数であっ
ても良いし、処理単語であってもよいが、いずれにしても1語だけである。
また特別に、「打ち切り」「もう一度」「終り」の3つの分岐語を含めることができる(「打ち切り」と「もう一度」は、この構文全体が繰り返し構文の中に入っている場合に限られる)。
第5章「配列」の
「定数配列」のセクションの中で「金種」という名前の定数配列の例を示したが、あれと同じ効果を「選択」を使って記述してみよう。
金種選択とは (番号 → 金額)
選択する
10000 5000 1000 500
100 50 10 5 1
選択終り。
第5章での定数配列「金種」は、文字通り配列として機能したが、上の「金種選択」は処理単語として機能する点が異なる。もちろん、これを引用する場合も、
金種配列(3)を 数値表示する ←定数配列を使う場合
3で 金種選択し 数値表示する ←選択を使う場合
のような違いがでる。
これでわかるように、単純な数値あるいは文字列の定数を並べただけの場合には、定数配列と選択構文は、ほとんど同じ機能に見える。
選択を使うメリットは、処理単語内部で引用することから、その前後に処理を記述することができる点、そして、定数・変数・処理単語など、多種の選択ができる点にある。
事例
他のプログラム言語でcase文と呼ばれるものに相当する。
(数値の比較)
構文=
<整数値>で
事例をとる
<比較値1> <選択肢1>
<比較値2> <選択肢2>
・・・・・・ ・・・・・
例外なら <選択肢>
事例終り
(文字列の比較)
構文=
<文字列>で
文字列事例をとる
<比較値1> <選択肢1>
<比較値2> <選択肢2>
・・・・・・ ・・・・・
例外なら <選択肢>
事例終り
比較する対象が数値なのか文字列なのかで上記2種類の構文を使い分ける。
上記では1行につき1組を記述しているがソースコード上の縦横構成は自由である。いずれも、スタックに積まれた比較値がテーブル状に並んだ値と次々に比較され、一致したものがあると、その直後に記述されている選択肢が実行される。
一致項目が見つからない場合には、テーブルの最後にある「例外」という特別な項目の選択肢が実行される(「例外」の項目は必須である)。
選択肢は、定数・変数・処理単語のどれでも使うことができる。また特別に、「打ち切り」「もう一度」「終り」の三つの分岐語を含めることができる。(「打ち切り」と「もう一度」は、この構文全体が繰り返し構文の中に入っている場合に限られる)。
事例の例を示す。
月の日数を得るとは (月 → 日数)
事例をとる
2月なら 28日
4月なら 30日
6月なら 30日
9月なら 30日
11月なら 30日
例外なら 31日
事例終り。
上の処理単語は整数で月を与えると、その月の日数を返す。簡単にするためうるう年は考慮していない。
処理単語「事例」は実行時にスタックに値が積まれていさえすれば良いので、かならずしも「事例」の直前に数値が記述されるとは限らない。上はその例でもある。
2、4、6、9、11月を小の月として扱い、それ以外のケースを「例外なら 31」で受けることて30日を返している。(ちなみに助数詞の「月」「日」や、送りがなの「なら」に意味はない)
上の例では、事例の比較項目の右辺に数値を書くことで、いずれの選択がおこなわたとしても、「選択終り」の段階でスタックには数値が1つ積まれている‥という仕様であったが、そうではなく、右辺に処理単語を書くことでいくつかの候補のうち
1つの単語を実行することもできる。その場合、「何もしない」という選択肢をとる必要が生ずることもある。特に、「例外」の選択肢としてそうなるケースが多い。このようなときでも何か単語を記述しなくてはならない。そのときは、
構文=
を使う。文字通り、何もしない処理単語である。
文字列事例の例を示す。
英訳とは (文字列 → ・)
文字列事例をとる
「ピアノ」なら "PIANO"を
「犬」なら "DOG"を
「猫」なら "CAT"を
例外なら "?"を
事例終り
表示し 改行することである。
上の定義をしておけば、
「犬」を 英訳する
のように使うことで、
DOG
を表示させることができる。
もし、
「大仏」を 英訳する
と記述した場合、これは事例項目にないので、最後の「例外」の選択肢が実行され、
?
が表示されることになる。
なおこのプログラムでは、「例外」の選択肢として「無処理」を記述できないので注意したい。事例構文の中でスタックに文字列を1つ積み、これを「表示」で表示するという前提になっているので、どの選択肢が選ばれようと文字列を1つ積む必要がある。このようなとき、「無処理」を記述したのでは、データが足りなくなってしまうからである。
範囲事例
構文=
<整数値>で
範囲事例をとる
<比較値1> <選択肢1> ←整数値が「比較1」以下の場合
<比較値2> <選択肢2> ←整数値が「比較2」以下の場合
・・・・・・ ・・・・・
範囲外なら <選択肢>
事例終り
「範囲事例」は「事例」とよく似ているが、数値が「この値に等しいか?」ではなく、「この値以下か?」を見る点が異なる。
以下は例である。
決済とは (文字列 → ・)
支払額で
範囲事例をとる
9999円までは 現金支払い
999999円までは 小切手支払い
範囲外は 手形支払い
事例終り。