前回のロジックをフローチャートにまとめました。情報処理試験の参考書を参考に作成しました。前と違うのは、ファイルのオープンやクローズが入っているくらいで、後は、同じです。このフローを頭にたたき込んでください。フローチャートなんて簡単です。相性占いや、性格判断の、「YES」「NO」のチャートと同じです。でも、記号にいろいろ意味を持たせていますので、よく覚えてください。情報処理試験の参考書に出ています。
フローチャートの説明
@フローチャートは、必ず「開始 : START」で始まり、フローの最後は「終了
: END」で終わります。Aに進みます。
Aここでは、プログラムのフローを意識するので、ボールがファイルからやってくるのだ、と考えています。そこで、そのファイルをオープンします。Bに進みます。
B数を数えるための変数フィールドを「COUNT」と名付け、そこを0にしています。AAAA
← 0 は、変数AAAAに0を代入する事です。Cに進みます。
Cファイルを読み込みます。もし、EOF(End of File)なら、Jへ進み、そうでなければDに進みます。
D第1サイクルか、を判定して、もし、第1サイクルならば、Eへ進み、そうでなければ、Fへ進みます。
E比較用変数、OldBallに、今受け取ったNewBallを代入します。Fへ進みます。
FOldball = NewBallを比較します。もし、両者が同じならば、Hへ進みます。そうでなければ、Gへ進みます。
Gカウントアップ用変数Countに+1をして、その値を再び、Countに代入します。この後Cへ進みます。
ここを通る度、Countの内容は、1,2,3,4,5,....とカウントアップしていきます。右のCountは古い値のCountで、左のCountが式の結果のCountです。(※同じフィールドですよ。)カウンターの仕組みは、単純ですね。(古いCount+1)を(新しいCount)に入れているだけです。「新しい」とか「古い」とかは、式の実行順序が、最初か、最後か、と同じです。
Hカウントを印刷します。別に印刷しないでも良いのですが、なにもしなければ、なにも成果物を生まないので、こうしました。Iに進みます。
Iカウントを出力して、Countを0にしています(「ゼロクリア」とよく言います。)Gに進みます。
JCountを印刷します。本当なら、Countが0ではないなら、という条件をつけた方がいいかもしれません。ファイルが空っぽということも有るので。Kに進みます。
Kファイルを閉じます。開いたら、閉じます。開きっぱなし、というのは、かなり特殊な場合だけです。Lに進みます。
L終了
この部分は、とても重要です。分かるまで良く読み、出来れば、空で言えるくらい、暗記して下さい。本当に大事です。英語で言えば、中学初期に習う、基本的挨拶くらい重要で、誰でも知っているものです。知っていて、偉いわけではなく、「当たり前」と思われる部分です。
参考までに、RPGサイクルの詳細フロー図を掲げます。ちょっと細かすぎるので、後で簡略図を掲げます。
では、いよいよ、サイクルのプログラムを作ってみましょう!まず、下記のようなファイルを準備をします。また、ロジックは今のボールのカウントを例に挙げます。
A*------------------------------------*
A R BALLR
A*------------------------------------*
A COLOR 5O COLHDG('ボールの色')
A*
A K COLOR
これを、CRTPFで作成します。COLORは5バイトのオープンフィールド(O)です。SBCSとDBCSの混在可能ということです。漢字だけで良かったのですが、順番が緑から始まって欲しかったので、このようにしています。レコード様式名はBALLRです。また、このCOLORフィールドをキーにしています。
データの内容は、以下のように入力しています。フィールドCOLORの中身です。
1緑
1緑
2赤
2赤
2赤
2赤
2赤
2赤
2赤
2赤
2赤
2赤
2赤
3青
3青
3青
3青
3青
全部で18レコードです。
もし漢字だけだと、青が先に来てしまいますが、こうすると、1が先頭に来ます。本来は、1=緑のようにコードだけで、行うところですが、RPGのサンプルがややこしくなるので、こうしました。ご容赦下さい。
さて、RPGのソースサンプルです。
(1) H Y/ 1
(2) FBALLP IP E K DISK
(3) FQPRINT O F 132 OF PRINTER
(4) IBALLR 01
(5) I COLOR L1
(6) C*
(7) C ADD 1 O1CNT 50
C*
(8) C *INZSR BEGSR
(9) C TIME O1TIME 60
(10) C ENDSR
O*
(11) OQPRINT H 101 1P
(12) O OR OF
(13) O 1 'H'
(14) O 26 'NUMBER OF BALLS BALLR1'
(15) O 43 '実行日付:'
(16) O UDATE Y 52
O*
(17) O H 1 1P
(18) O OR OF
(19) O 1 'H'
(20) O 43 '実行時間:'
(21) O O1TIME 52 '0 : : '
O*
(22) O D 1 01
(23) O 1 'D'
(24) O COLOR 10
O*
(25) O T 1 L1
(26) O 1 'T'
(27) O O1CNT JB 20 |
ソースの解説
やりたいことは、BALLPを順次読み込み、COLORフィールドの値が変わったら、そのレコード件数を印刷する、というものです。いきなりRPGソースでびっくりでしょう。分からない単語がたくさん出ているのでしょうが、平気です。どんどん先に進んで下さい。分からなくても、先に進んで下さい。やがて、必ず、分かるようになります。それから、上記のフローとの関連は、後ほど説明します。さあ、1行づつ見てゆきましょう。このソースは、「純粋な」RPGサイクルで出来ています。これが、原点です。
尚、標識という言葉が、解説の中に出てきます。これはRPG特有の概念ですが、後ほど、説明します。今は、この標識は、ONとOFFの、2つの状態を表現して、プログラムの流れを制御出きるもの、くらいに考えておいてください。
これは、H仕様書ですね。Y/はYMD形式で、日付のセパレータは/と宣言していますね。後ろの1は、漢字の透過指定でしたね。覚えていますか?
ここは、F仕様書です。BALLPを、IPつまり、「入力」「RPGサイクル」でオープンする指定をしていますね。その後の、Eは、「外部記述」であることをRPGコンパイラに指示していますね。その後ろのKはキー付きの処理を行う指定です。もしここをスペースにすると、キー順ではなく「到着順」の指定になります。「DISK」は、データファイルの場合の決まり文句でしたね。
(3) FQPRINT O F 132 OF PRINTER
ここも、F仕様書です。成果物である印刷をするための、印刷装置ファイル(プリンターファイル)の指定をしていますね。OはOutputつまり、出力です。Fはプログラム内部記述であることを指定しています。Outputの内部記述なので、o仕様書があることを示唆しています。(入力ファイルの内部記述のレコード定義はi仕様書で行い、出力ファイルの内部記述は、o仕様書で行います。)132の部分は、内部記述の場合、記述しなければならない項目で、132桁のレコード(レコード長)である、ということです。OFは、このプログラムで使われるオーバーフロー標識の宣言です。もし、OAと書いたら、このプログラムで使われるオーバーフロー標識は、OAとなります。ここではOFですよね。「PRINTER」は、印刷装置ファイルの場合の、決まり文句でしたね。
ここは、i仕様書です。BALLRは、ファイルBALLPのレコード様式です。ファイル名BALLPを記述しなくても、コンパイルは、BALLRがBALLPのレコード様式と判断できる仕組みになっています。というのは、1つのプログラム内では、同じレコード様式を、2つ以上定義できないのです。もし、同じレコード様式名を持つファイルを2つ以上定義したいならば、F仕様書で、各々のレコード様式をリネームしなくてはなりません。まあ、今は、その程度の知識でとどめて下さい。ここでは、BALLPのレコード様式、BALLRを読み込んだら、レコード標識 01 をオンにして下さい、と指定していますね。
さて、続くi仕様書で、このBALLRについて、さらに定義を続けています。BALLRの中の、COLORというフィールドが、変わったら、制御レベル標識 L1をオンにしてください、と定義しています。ここは最重要です。これが、RPGサイクルの特徴なのです。プログラムが動き出して、レコード1を一件、一件読み込んでいくときに、このCOLORフィールドの値が、変わったら(キーブレイクが起きたら)、このL1なる標識がONになるのです。この標識で、キーブレイクが起きたときに(L1がonの時に)、このようにしてくれ、と「プログラムの動き」を指定できます。
これは、コメント行です。このほかに、H*やF*やi*やO*などもコメントです。仕様書を表す、H,F,E,i,C,Oのすぐ後に*(アスタリスク)をつければ、その行はコメント行です。コンパイラはその行を解釈しません。見やすくするためにつけたり、他のプログラマーへのメッセージとして、説明をつけたり、そんな目的でつけます。
ここで、C仕様書が出てきました。ADDとは、数値の足し算を行う命令です。O1CNTは、プログラマーが自由に決めることが出来る、フィールドを定義している部分です。なんでも良いのですが、6文字以内で、英語のアルファベットなどで始まり、後は英数で構成されるフィールド名をあなたが決めます。ここでは、出力目的なので、Oで始まるフィールドにしました。(何でも良いのですよ)。この後ろに続く、50とは、全体の桁数5桁、小数点以下は0桁、つまり、数字整数5桁、を指定しています。もし、外部記述のファイルのフィールドならば、属性(フィールドタイプとか桁数など)を定義する必要はありません。コンパイラが勝手に、ファイル記述から取り込んでくれます。また、定義方法は、このほかに、データ構造や、*LIKE
DEFNとかありますが、今は、まだ気にしないで下さい。
C仕様書は。大まかに言うと、「条件標識」「演算項目1」「命令語」「演算項目2」「結果」「結果フィールド属性」「結果の標識」に分かれています。
条件標識 |
演算項目1 |
命令語 |
演算項目2 |
結果 |
結果フィールド属性 |
結果の標識 |
|
|
ADD |
1 |
O1CNT |
50 |
|
この行を別の言語で表現すると、O1CNT [結果]
= O1CNT [演算項目1] + 1 [演算項目2]となります。このADD
1 O1CNTは、本来、O1CNT ADD 1
O1CNTなのです。つまり、O1CNT + 1 = O1CNT(普通の表現とは逆ですね)。※数学の式とは、違いますよ。コンピュータ言語独特の表現です。
条件標識 |
演算項目1 |
命令語 |
演算項目2 |
結果 |
結果フィールド属性 |
結果の標識 |
|
O1CNT |
ADD |
1 |
O1CNT |
50 |
|
と同じ事なのですが、RPGでは、「演算項目1」=「結果」の場合、演算項目1を省略できます。したがって、ソースのように、演算項目1をスペースにしています。この演算により、O1CNTの中身は、1,2,3,4,5,...と1づつカウントアップしていきます。
ここもC仕様書です。ここからは、サブルーチンとなります。BEGSRがキーワードです。ここと、ENDSRがペアになり、ここで囲まれた、部分が、1つのサブルーチンとなります。サブルーチンとは、何度も使われる部分を、独立させて定義したプログラムの一部の事です。また、定義の書式もある程度決まっています。BEGSRはBeginning
of SubRoutineの事です。
ところで、この*INZSRはとても、特殊です。RPG全体を通じて、*で始まる名前は、特殊な予約語と考えて下さい。もともと、*で始まるフィールドは定義できません。でも、この*INZSRは、特別にRPGが準備している予約サブルーチンです。これは、まさにこのサンプルにぴったりの場合に使われるものです。*INZSRが無いころは、後述する、標識1Pは、一切C仕様書を通らずに、いきなり、o仕様書の1Pを指定された部分を印刷していたのです。しかし、これでは時間の印刷(TIME命令)が不可能な為に、追加されたサブルーチンでした。このサブルーチンは、プログラムを呼び出した直後の初期処理で、実行される特殊なサブルーチンです。
条件標識 |
演算項目1 |
命令語 |
演算項目2 |
結果 |
結果フィールド属性 |
結果の標識 |
|
サブルーチン名 |
BEGSR |
|
|
|
|
昔は、CSRと定義したことも有りますが、RPG2での話しで、今は省略しています。もし、CSR XXXX BEGSRというのを見かけたら、かなり古いプログラムと考えて良いでしょう。
H |
|
|
F |
|
|
E |
|
|
L |
|
|
I |
|
|
C |
メインルーチン |
EXSR A |
EXSR B |
EXSR C |
サブルーチンA |
BEGSR |
ENDSR |
サブルーチンB |
BEGSR |
ENDSR |
サブルーチンC |
BEGSR |
ENDSR |
O |
|
|
** |
|
|
このように、サブルーチンは、C仕様書の最後の方に定義します。
ここは、サブルーチン*INZSRの中身です。時間を印刷するために、TIME命令で、時間をとりだしています。
条件標識 |
演算項目1 |
命令語 |
演算項目2 |
結果 |
結果フィールド属性 |
結果の標識 |
|
|
TIME |
|
時間+日付 |
60 or 120 or 140 |
|
この結果のフィールドの桁数は重要です。整数6桁か12桁か14桁で、結果のフィールドに入る値が異なります。
6.0の場合 システム時間6桁のみが結果のフィールドに入ります。例)101531つまり10:15:31
12.0の場合 システム時間6桁と、システム日付6桁が結果のフィールドに入ります。例)101531981231つまり10:15:31と98/12/31
14.0の場合 システム時間6桁と、システム日付8桁が結果のフィールドに入ります。
例)10153119981231つまり10:15:31と1998-12-31
注意:システム日付の日付の形式は、ジョブ環境の日付の形式に由来します。H仕様書のY/の効果は及びません。(Y/はUDATEや*DATEだけです)
ここで、サブルーチンの定義は終了します。ENDSRとはEnd
SubRoutineの事です。
条件標識 |
演算項目1 |
命令語 |
演算項目2 |
結果 |
結果フィールド属性 |
結果の標識 |
|
タグ名 |
ENDSR |
エラー復帰 |
|
|
|
|
見出し1行目 |
|
|
O 26 'NUMBER OF BALLS BALLR1'
|
|
|
|
見出し2行目 |
|
|
|
|
|
明細1行目 |
|
|
|
合計1行目 |
|
|
o仕様書の始まりです。印刷の1行目の定義です。このQPRINTはF仕様書で、定義してありましたね。132桁でオーバーフロー標識はOFでしたね。ここに書くことが出来るのは、F仕様書で指定したファイルのみです。Hはヘッダーの事です。帳票の見出しに当たる部分を定義します。101は、最初の「1」は、「印刷後スペース1行(ベタ打ち)」、その次の「01」は「印刷前に絶対行01へスキップ」という指示でしたね。
ここででてくる、1Pは特殊です。サイクルの中で、*INZSRの直後にONになる標識です。以下の項目を印刷する条件を制御しています。プログラムの中で、この1PがONになるのは、一回だけです。2Pや3Pなんて、有りません。
※この標識1PがONになっても、まだファイルのレコードは一件も読み込まれていないことに注意して下さい。レコードのデータはこの部分では、印刷出来ません。
この、部分では、OR(もしくは)の指定が有りますね。以下の項目を印刷する条件に、OR条件が付加されています。それは、OFがonになったらという場合です。オーバーフローになったら、この部分を実行してくれ、と指示しているのです。
ここからは、印刷する項目を指定しています。印刷用紙(実際は出力域:出力バッファ。以前に入力域のお話をしましたよね。その逆に、今度は出力する場合の緩衝域のことです。)の1桁めに「H」を印刷しています。本来こんなもの印刷しなくて良いのですが、後で印刷物を見てわかりやすいようにしただけです。実務ではこんなものは印刷しません。
(14) O 26 'NUMBER OF BALLS BALLR1'
これは、帳票のタイルのつもりです。26桁をおしりにして、印刷する指示です。BALLR1とはこのRPGの名前です。本当はプログラム名を取りだす最もいい方法が有るのですが、ここではふれません。いづれ、「プログラム状況データ構造」で説明します。
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
N |
U |
M |
B |
E |
R |
|
O |
F |
|
B |
A |
L |
L |
S |
|
B |
A |
L |
L |
R |
1 |
ここは、「実行日付:」を、43桁をおしりにして、印刷する指示です。漢字ですので、0e0fが漢字の前後に付くのでしたよね。
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
0e |
実 |
行 |
日 |
付 |
0f |
: |
ここでは、ジョブ日付を52桁をおしりにして、編集コードYで印刷する指示をしています。後ろの桁の指定をはずすと、「位取り基数法」の0が指定されたのと同じになり、一つ前のフィールドにぴったりとくっつきます。また、52の代わりに、+
1を指定すると、一桁スペースを開けて、前のフィールドにくっつきます。桁数を数得るのが面倒な場合に使います。
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
9 |
8 |
/ |
1 |
0 |
/ |
2 |
5 |
上記3つをまとめると、
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
H |
|
|
|
N |
U |
M |
B |
E |
R |
|
O |
F |
|
B |
A |
L |
L |
S |
|
B |
A |
L |
L |
R |
1 |
|
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
|
|
|
|
|
0E |
実 |
行 |
日 |
付 |
0F |
: |
|
9 |
8 |
/ |
1 |
0 |
/ |
2 |
5 |
となります。
ここから印刷の2行目の定義です。あとは1行目と同じです。Oの次がスペースですよね。ここは、QPRINTと入っていても良いのですが、省略可能です。省略した場合は、一つ上のファイル名が継承されます。
1行目の定義と同じです。
1行目の定義と同じです。
ここでは、43桁をおしりに、「実行時間:」と印刷していますね。
(21) O O1TIME 52 '0 : : '
ここでは、*INZSRで取りだした、時間を印刷しています。時間用の編集コードは無いので、編集語を使います。もし、' : :
'と0を入れないと、午前0時ちょうどの時、なにも印刷されません。気をつけましょう。
上記3つをまとめると、
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
H |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
|
|
|
|
|
0E |
実 |
行 |
時 |
間 |
0F |
: |
|
1 |
0 |
: |
1 |
5 |
: |
3 |
1 |
ここからは、明細行(レコードを読む度に印刷する)部分の定義です。Dが明細Detailを意味しています。1は印刷後1スペース(ベタ打ち)です。01はレコード標識です。これが無いと、o仕様書に来る度に、無意味に印刷するので、H印刷の時に、無駄に1行印刷してしまいます。そこで、ファイルを読んだら、という条件で、BALLRのレコード標識01を条件付けします(i仕様書を参照)。
ここでは、1桁目に「D」を印刷します。本来こんなもの印刷しなくて良いのですが、後で印刷物を見てわかりやすいようにしただけです。実務ではこんなものは印刷しません。
ここでは、レコード様式BALLRの中のフィールド、COLORを10桁目をおしりに印刷しています。注意事項があります。ここで、Blank After(後述)を指定してしまうと、L1はここで印刷する度にONになります。注意しましょう。
ここから、合計時の印刷の定義です。TはTotalの意味です。キーブレイクが起きた場合の定義です。L1はi仕様書のレベル標識L1と関連づけるために指定します。これで、L1がONになったときだけ、実行される部分となりました。
ここでは、1桁目に「T」を印刷します。本来こんなもの印刷しなくて良いのですが、後で印刷物を見てわかりやすいようにしただけです。実務ではこんなものは印刷しません。
ここで、C仕様書で、カウントしていた、O1CNTを、20桁目をおしりにして、編集コードJで印刷しています。その後のBは、Blank
Afterのことで、印刷が完了すると。数字なら0に、文字ならばブランクにしてくれます。便利な反面、ロジックが分散(集計値を0にするタイミングは重要なので)するため、Blank
Afterの使用を禁止する場合もあります。私は、便利なので、ばんばん使っています。集計して、印刷すれば、用の無くなった、集計値は、印刷直後に消えてくれればいいわけです。Blank
Afterは、よく考えられた、オプションと考えています。
実行結果
これが、実行結果です。ここはPC上なので、漢字の前後に0E0Fが入っているものが、無くなっていることに注意して下さい。本来は、漢字の前後に1スペース空いています。
H NUMBER OF BALLS BALLR1 実行日付: 98/10/10
H 実行時間: 9:24:16
D 1緑
D 1緑
T 2
D 2赤
D 2赤
D 2赤
D 2赤
D 2赤
D 2赤
D 2赤
D 2赤
D 2赤
D 2赤
D 2赤
T 11
D 3青
D 3青
D 3青
D 3青
D 3青
T 5 |
だいぶ、この講義も長くなってきました。フローチャートとの関連や、その他の例など、は次回以降に説明します。解説部分を良く読んで、ソースリストだけ見て、その内容を理解できるようにして下さい。では、今日は、ここまで。
起立、礼、着席
1998/10/25 |