vpgl言語のプログラムは、テキストではなく図です。この記事では、その図の読み方の基本をご紹介します。
まずはこちらの図をご覧ください。詳細は、後半で詳しく説明します。
プログラム図は、3×3, 5×5 or 7×7 の格子マス目でてきています。各マス目-以下”タイル”と呼びます-は、空欄か、そうでなければ、中心に操作名があり、場合によっては、その下にオプション文字列があることもあります。さらに、四方向に線か、外向きの矢印があります。 矢印は、操作の結果データの出口を、直線は、操作に対するデータの入り口を表しています。
(VPGL言語はオブジェクト指向の言語でもあるので、以下では操作名のことを「メソッド名」ということもあります)
とりあえず、一番簡単な例を説明します。
この例は、RUNボタンを押すと、”HELLO WORLD”というメッセージを表示するダイアログが出て、ダイアログのOKボタンを押すとそのままプログラムが終了するというものです。
この図のタイルD1には、“CONST”という操作名が指定されていて、オプションとして “HELLO WORLD” という文字列が指定されています。 (図では、オプションは途中で切れていますが、このタイルの中心付近をシングルクリック/タップすると、このタイルの詳細ダイアロぐが現れ、オプション全体を見ることができます。OKかCancelを押せばこのダイアログは閉じますが、Deleteはここでは押さないでください)
D1は、入力として、上から何かが入ってきて、下に出力が出ていくように直線と矢印が指定されています。入出力は、複数あるのが普通なので、これらには、入力0, 出力0と赤いラベルかついています。
VPGLのプログラムは、いま表示されている「AppクラスのMainlineメソッド」というダイアグラムに、上から「何かしらのデータ」が”I0″(Input0)とラベルされているタイルD1に落とされることで開始します。(クラスとメソッドについては、オブジェクト指向ではおなじみの概念ですので、ここでは、詳細は省かせていただきます。いずれ別記事で説明する機会もあるかと思います。)
タイルD1の”CONST”は、入力0に何が入ってきても、オプションに書かれているデータを出力0に出すという操作として定義されています。ですので、このタイルは、データが落ちてくると、”HELLO WORLD”という文字列データを出力0からその矢印が向いている下のD2タイルに落とします。
D2タイルには、”ALRT”という操作名が書かれています。この操作は、入力0に何が入ってきても、そのデータをメッセージポップアップダイアログに表示します。そして、ユーザがダイアログを閉じるまで待って、閉じた後は、出力0に入ってきたデータをそのまま渡します。この図では、出力0は下のD3タイルに向いていますので、入ってきた”HELLO WORLD”文字列はD3タイルに上から落ちてきます。
D3のタイルは、入力が一つで、出力矢印の無い操作名”STOP”のタイルです。STOP操作は、入力0に何が入ってきても、プログラムの実行を即座に終了する操作です。STOPは正常な終了扱いになります。
次に、もう少しいろいろある図を見てみましょう。
このプログラム図は、0以上の整数を入力Nとしてとり、その総和:
Sum(N) =1+2+3+…+N=(N*(N+1))/2
を計算するものです。計算は、よく知られた公式Sum(N) = (N*(N+1))/2を使用するので、繰り返し処理はありません。
この例のRUNボタンを押すと、以下のように動作します。
最初の例でも説明したとおり、RUNボタンを押すと、App::MainlineのメソッドダイアグラムのI0タイルD1の上から、データが落ちてきて、入力が1つだけの”INPUT”操作(オプション”Input a positive integer”つき)のタイルが実行されます。
INPUT操作は、入力に何か入ってきたら、ユーザ入力ダイアログを表示します。オプションのデータは、ダイアログのメッセージ(いわゆる”プロンプト”)として使われます。そして、ユーザの入力を待った後、入力されたデータを出力0を通して、隣のタイルに渡します。入力0のデータは放棄されます。
この例では、”Input a positive integer” – 「非負の整数を一つ入力してください」のメッセージとともに、入力ダイアログが表示され、入力されたデータは、D2タイルに渡されます。
D2は、操作名の無い、1入力3出力のタイルです。操作名の無いタイルは、FLOWという操作名が省略されている表示です。FLOWに限っては、タイル上で表示が省略されます。
FLOWは、入力と出力の数によって、データの受け渡し、複製配布、合流のいずれかの操作を行う操作です。ここでは、1入力3出力になっており、入力0として入ってきたデータを出力0, 1, 2に「複製」して渡します。その結果、D2タイルに入ってきた整数は、C2, D3, E2のタイルに渡されます。
E2は、すでに説明したCONSTタイルで、オプションに整数の定数2が指定されています。
C2タイルは、”N+1″タイルで、”N+1″は、入力0に入ってきた数値データに1を加えた値を出力0に渡します。入力0が数値以外の時は、既定の動作では、未定義エラーになります。
C3, E3, E4は、1入力/1出力のFLOWタイルで、1入力/1出力の時は、単にデータを出力0に渡すだけの動作になります。
これらの動作の結果として、まずD3タイルにデータが集まり、”A*B”操作が実行されます。”A*B”操作は、入力0と入力1の掛け算を実行し、その結果を出力0に流します。(どちらの入力も数値でない場合には、既定の動作はエラーです)
ここまでの処理で、入力0はNで、入力1はN+1ですので、出力0はN*(N+1)になります。
D4タイルは、D3タイルの結果を入力0として受け取り、FLOWタイルを経由してE2タイルの出力を受け取る”A/B”操作タイルです。
“A/B”操作は、(入力0)÷(入力1)の結果を出力0から出します。この結果、D4タイルの出力0は(N*(N+1)/2になり、D5タイルに渡ります。
(ここで注意が必要なのは、入力0と入力1の区別が絶対に必要で、取り違えると2/(N*(N+1))を計算することになってしまいます。ダイアログ上に入出力の番号が表示されているのは、この違いを区別するためです。)
タイルD5は、すでに説明したALRT操作で、結果としてSum(N)が表示され、D6タイルのSTOPにデータが到達して実行は正常終了します。
最後の例は、Sum(N)の計算を、公式を使わず、条件判断と、繰り返し、手続き定義を使って実装しているものです。
この例のApp::Mailineのダイアグラムは、単に、入力して、”SUM”という操作を適用した後、その結果をALRTで表示して、STOPするというだけになっています。D2タイルのSUMは、システム定義ではなく、ユーザ定義された操作で、Number(数値の)クラスにSUMという名前で定義されています。この定義、Class:メニューから”Number”を選択し、次にMethod:メニューで”SUM”を順番に選択すると表示されます。以下の説明は、この表示を見ながら読み進めてください。
Number::SUMは、5×5サイズの格子で、I0は上としてC1、O0(出力0)としてC5が設定されています。SUMは、1入力/1出力で、C1の上から入力が下りてきて、C5の下から出ていくことになります。これらの入出力の数、方向、実行開始条件は、それぞれIN:, OUT:, IFALL:の値で決まります。実際の”プログラミング”作業では、これらの値は個別に設定可能ですが、その方法は別記事で紹介します。
このチャートを概観するために必要な情報を以下に補足します。
- C1,B1,C3タイルは、1入力/2出力のFLOWタイルで、この入出力数の時は、入力0データの複製を作って、出力0と出力1に出します。
- GT: B2 タイルは “GT”という比較操作です。この操作は数値に対して定義されており、
入力0 > 入力1の時、出力0にシンボル*T*を、
入力0 <= 入力1の時、出力0にシンボルNILを出力します。
(シンボルというデータ型については、別の記事で紹介しますが、ここでは、比較操作ができる文字列の一種くらいの理解ででよいです) - SWITCH: C2タイルのSWITCH操作は、VPGLの基本的条件分岐操作です。この操作は、2入力/2出力で、入力1が、NIL以外の時は、入力0のデータを出力0に流し、入力1がNILの時、入力0のデータを出力1に出します。どちらの場合も、反対側の出力には、何も出力されません。SWITCH操作は、入力1の結果によって、入力0のデータの流れを変えるものです。SWITCHにとっては、NILが論理的”偽”、NIL以外が論理的”真”に当たります。
- n-1: B3タイルの “n-1” はデクリメント(1を差し引く)操作で、出力0に (入力0)–1 の値を流します。.
- A+B : C4タイルの “A+B” は加算操作で、出力0に、(入力0)+(入力1)の値を流します。
- C5は、2入力/1出力のFLOW操作です、この入出力数の時のFLOWは、複数の入力のいずれかにデータが届いたら、即座にそのデータを出力0に流します。この時には、ほかの入力のデータの到着を待ちません。
このNumber::SUMは、以下のロジックを実装しています:
- (入力0) > 0かどうか調べる。
- もし、(入力0) <= 0, ならば、数値0を出力0として、FLOWのパスC1-C2-D2-D3-D4-D5を経由してC5からNumber::SUMの出力0として渡す。
- そうでなければ、SUM(n)をn + SUM(n-1)を計算することで算出しC5から、Number::SUMの出力0として渡す。
実装中では、SUM(n)の中から、SUM(n-1)を再帰呼び出ししています。VPGLでは、操作の再帰呼び出しを許容しています。
SUMは、Number(数値)のオブジェクトに対して定義されていて、ほかの型(クラス)には、SUMは定義されいませんので、最初のApp:MainlineのINPUTで数値以外が入力された場合は、いわゆる「未定義操作」エラーになります。SUM操作のタイルは、そのタイルの入力0が数値(Numberクラスのオブジェクト)の時にのみ、Number::SUMが実行されます。これは、VPGLの実行仕様になります。
この記事では、VPGLプログラム図の読み方をご紹介しましたが、書きこみ操作については、別の記事で紹介予定です。