前章のプログラムは出席番号、氏名、テストの得点すべてをキーボードから入力するものでした。作ったプログラムを実行してみていかがでしたか。データ入力がかなりたいへんだと感じた方も多いのではないでしょうか。小学校の先生なら(原則的には)すべての教科を担任の先生が教えます。中学・高校の先生なら担当教科は一つでも同じ学年の複数のクラスを担当することも多いでしょう。その度に出席番号、氏名、得点を入力することになり、入力が多くなればなるほど誤入力(誤操作)が発生する確率も高くなります。これをなんとかしましょう。
1: *SAKKYOKUKA
2: DATA "J.S.バッハ",1665,1750
3: DATA "ベートーヴェン",1770,1826
4: DATA "ショパン",1810,1849
5: DATA "チャイコフスキー",1840,1893
6: DATA "ドビュッシー",1862,1918
7: DATA "//",0,0
8: PRINT "偉大なる作曲家"
9: RESTORE *SAKKYOKUKA
10: NAMAE$=""
11: WHILE NAMAE$<>"//"
12: READ NAMAE$,SEINEN,BOTSUNEN
13: IF NAMAE$<>"//" THEN
14: PRINT NAMAE$;" ";SEINEN;" ~";BOTSUNEN;
15: END IF
16: WEND
17: END
図12-1.DATA文の内容をREAD命令で読み込むプログラム
[プログラム中にデータを入れる]
図12-1のプログラムを見てください。Tiny BASICでは固定的なデータはDATA文でプログラム中に置いてそれをREAD命令で変数に読み込むことができます。1行目はプログラム中の特定の場所に目印を付けるものでラベルといいます。ラベルを付けるときは半角の*に続けてラベル名を指定します。ラベル名の付け方の規則は変数名と同じです。
2~4行目はDATAという指示語から始まって、その後に何か書いてあります。これはプログラム中に入れたデータです。このサンプルはクラシック音楽の作曲家の名前と生年、没年です。ラベルやDATA文は何かの動作をするわけではないので、プログラムを実行すると8行目から実行されます。
12行目のREADはDATA文でプログラム中に埋め込まれたデータを変数に読み込む命令です。9行目のRESTOREはREAD命令で読み込むデータがどこからかを指示するものです。ここで1行目に付けたラベルの意味が出てきます。
DATA文で入れるデータとREAD文で読み込む変数の型は一致していなくてはなりません。DATA文で用意されたデータの個数(a)とREAD文で指定した変数の個数(b)が一致していないとき、a<bだと余ったデータは無視されます。反対にa>bだと「お~い、データがないぞ」というエラーになります。このプログラムを実行すると図12_1.のようになります。
図12-2.DATA文の内容をREAD命令で読み込む
DATA文で入れるデータはデータの型、読み込む変数の数が合っていればプログラム中のどこへ置いてもかまいません。またTiny BASICではDATA文は制御文ブロックの中に置いてもかまいません。DATA文は繰り返し処理や選択処理の対象にはなりません。図12-3のプログラムも図12-1のプログラムと同じ動作をします。
1: RESTORE *SAKKYOKUKA
2: *SAKKYOKUKA
3: PRINT "偉大なる作曲家"
4: DATA "j.S.バッハ",1665,1750
5: NAMAE$=""
6: DATA "ベートーヴェン",1770,1826
7: WHILE NAMAE$<>"//"
8: READ NAMAE$,SEINEN,BOTSUNEN
9: DATA "ショパン",1810,1849
10: IF NAMAE$<>"//" THEN
11: DATA "チャイコフスキー",1840,1893
12: LIFE= BOTSUNEN-SEINEN
13: PRINT NAMAE$;" ";SEINEN;" ~";BOTSUNEN
14: END IF
15: DATA "ドビュッシー",1862,1918
16: WEND
17: DATA "//",0,0
18: END
図12-3.DATA文を制御文ブロックの中に置く
しかし、プログラム上は正しく動作するといっても、このようなプログラムはわかりにくいことこの上ないですね。後でプログラムの修正が必要になったとき作った当人でもかなり苦労すると思います。プログラムは後々のことを考えてわかりやすく書きましょう。
[固定的なデータをプログラムの中に置く]
このREAD、DATA文を使って第11章の図11-4のプログラムを改良しましょう。前章のプログラムでの問題点は出席番号、氏名、試験の点数すべてをキーボードから入力することでした。ここでこのプログラムで扱うデータの「性格」を考えてみましょう。出席番号、氏名といったデータは普通に考えれば学年の途中で全員分が変わるということはそうそうあることではありません。このような固定的なデータをマスターといいます。これに対し、試験の点数は変動的なデータ(トランザクション、元々は取引、売買の意味)です(筆者の体育の成績は例外です。5段階評価で3以下しか取れたことありません💦)。
効率良さを考えるならマスターデータはDATA文でプログラム中に置き、これをREAD命令で読み込みながらトランザクションデータをキーボードから入力するというのが一般的です。プログラムは図12-4のようになります。
1:DIM BANGO$(100),NAMAE$(100),TENSU(100) ' データ保存領域
2:RESTORE *CLASS_MEIBO ' READで読み込むデータの開始位置を指定
3:PRINT "***テストの平均点***"
4:GOKEI=0
5:NINZU=0
6:I=0
7:
8: NUM$="-1"
9:WHILE NUM$<>"999" ' 出席番号が終端値ではない間、以下の処理を繰り返す
10: READ NUM$,SHIMEI$ ' クラス名簿のデータを1件ずつ読み込む
11: IF NUM$<>"999" THEN ' 終端マークでなければ以下の処理を行なう
12: PRINT NUM$;" ";SHIMEI$;
13: INPUT "点数 ",TOKUTEN
14: BANGO$(I)=NUM$
15: NAMAE$(I)=SHIMEI$
16: TENSU(I)=TOKUTEN
17: GOKEI=GOKEI+TOKUTEN
18: NINZU=NINZU+1
19: I=I+1
20: END IF ' 出席番号が終端マークでないときの処理ここまで
21:WEND ' 出席番号が終端値ではない間の繰り返しここまで
22:LASTNUM=I-1
23:
24: PRINT
25:' 平均点と、各自の得点と平均点の差を求めて表示
26:HEIKIN=INT(GOKEI/NINZU)
27:PRINT USING "受験者は ###人";NINZU
28:PRINT USING "平均点は ###点";HEIKIN
29:PRINT
30:' 各自の得点と平均点との差を求める
31:FOR I=0 TO LASTNUM
32: TENSA=TENSU(I)-HEIKIN
33: PRINT BANGO$(I);" ";NAMAE$(I);TAB(20); ' 出席番号、氏名を表示
34: PRINT USING "### (###)";TENSU(I);TENSA ' 得点と平均点との差を表示
35:NEXT I
36:END
37:
38:' クラスの名簿(出席番号と氏名)
39:*CLASS_MEIBO
40:DATA "A001","青木 郁夫"
41:DATA "A002","岩本 浩司"
42:DATA "A003","大田 喜美子"
43:DATA "A004","加藤 正孝"
44:DATA "A005","山口 小夜子"
45:DATA "B001","江藤 今日子"
46:DATA "B002","近藤 仁"
47:DATA "B003","中田 真一"
48:DATA "B004","森田 淳二"
49:DATA "B005","渡辺 三郎"
50:DATA "999","" ' 終端マーク
図12-4.マスターデータをプログラム中に置く
今回はプログラムを見やすく、また処理結果を見やすくを意識してみました。
まずプログラム中のあちこちに出てくる ' (アポストロフィー)に続くなんたらかんたらですが、これは注釈です。Tiny Basicでは半角の ' は引用符ではなく、その後から行の終わりまでが注釈であることを示します。行の先頭に ' を付けると1行全部が注釈行になります。注釈はプログラム実行の際、無視されますから、通常のキーボードから入力できる文字なら何でも書けます。アラビア文字、ハングル文字、キリル文字などもOKですが、プログラム保存の際、エンコーディングをUTF-8にする必要があります。後にプログラムの修正等が必要になったとき、この変数は何のため?ここでどういう処理やってるの?などをわかりやすくしておくため注釈はどんどん入れましょう。
7、23、37行目は処理のかたまりをわかりやすくするために置いた空行です。空行を置くときは全角の空白(スペース)が入ってしまわないように気をつけてください(エラーになります。修正の際、探すのがけっこう大変です)。
24、29行目のPRINT(オペランドなし)は、実行画面上で1行空行を空けて画面を見やすくするためのものです。
27、28行目のPRINT USINGは続く" "内で指定した書式にしたがってデータを表示するものでした(第7章の後ろの方でやりました)。" "内に書式設定子以外の文字を入れると、その文字はそのまま表示されます。ここでは受験者数と平均点の1の位を合わせて見やすくするために使っています。
33行目に出てくるTABは、tabulatorの意味で昔、タイプライターを使ったことのある方なら、ああ、あれか、とピンときたと思います。TABは行の左端から( )内で指定した位置まで表示位置を移動するものです。表示位置を移動するだけで空白を埋めるわけではないので、PRINT USINGと併用すると各項目の位置を揃えて見やすく表示させることができます。
38~50行目は10行目のREAD命令で読み込んでゆくデータ(今回の例ではクラス名簿マスタデータ)です。ここで10行目は
READ ストリング変数1,ストリング変数2
なのでデータの並びはこれに従っていれば、たとえば
DATA "A001","青木 郁夫"
DATA "A002","岩本 浩司"
DATA "A003","大田 喜美子"
と書くところを
DATA "A001","青木 郁夫","A002"
DATA "岩本 浩司","A003","大田 喜美子"
と書いてもTiny Basicの文法的には問題ないのですが、プログラムとデータの関係がわかりにくくなってしまいます。メモリ節約との戦いだった1980年代頃ならともかく、今のパソコンとTiny Basicでのプログラミングでは、メモリ節約よりプログラムがわかりやすい書き方でいきましょう。
50行目はデータの終端です。出席番号が"//"だったらデータ読み込み終了なので、出席番号にあたるデータを // にしています。その後の "" はNULL(ヌルストリング)といい、何も文字がないストリングです。10行目のREAD命令は出席番号と氏名を読み込むようになっているので、データの終端でも氏名のデータがないとエラーになります。そこで氏名の部分にダミーのデータを置いておく必要があるのです。
このプログラムの実行結果は図12-5のようになります。
図12-5.図12-4のプログラムの実行結果
このようにマスタデータはDATA文でプログラム中に置いてREAD命令で読み込んでゆくようにすると入力が楽になると同時に入力ミスを防ぐことができます。またマスタデータに変動が起こったとき、DATA文の部分を追加・削除・修正すれば済むことになり、システム全体のメンテナンス性も向上します。
【昔はよかったなぁ】
昔のBASICを使って、図12-4のプログラムを平均点以下の受験者を黄色で、さらに平均点より20点以上低い受験者を赤で表示する鬼畜なプログラムにしてみましょう(図12-6)。
図12-6.平均点より低い受験者を色付きで表示する
プログラムは図12-7のようになります。昔のBASICは文字に色を付けるのは簡単でした。行番号380に出てくるCOLOR命令がそれです。
行番号200にGOTOという命令がありますが、これは無条件ジャンブといい、指定された行番号(またはラベル)まで処理の手順を飛ばすものです。今のTiny Basicにもあることはあります。ただしGOTO命令をむやみに使うとプログラムがわかりにくくなります。IT関連企業の中にはGO TO(GOTO)命令の使用を禁止している会社もあるくらいです。ただ、昔のBASICではどうしても使わざるを得ないケースがありました(第14章の【昔はよかったなぁ】に出てきます)。
もうひとつ、DATA文のところを見てください。昔のBASICではDATA文に含まれるストリングは" "で囲む必要はありませんでした。昔のBASICではDATA文群はかなりすっきりと書けました。
図12-7.平均点より低い受験者を色付きで表示するプログラム
【この章のまとめ】
DATA文でプログラム中にデータを置くことができる。
DATA文で置いたプログラムはREAD命令で変数に読み込むことができる。
RESTORE文でREAD文で読み込むDATA文がどこからかを指示できる。
マスタデータはDATA文でプログラム中に置くようにすると、入力が楽になり、入力ミスも防ぐことができる。
マスタデータはDATA文で置くようにするとマスタデータのメンテナンス性が向上する。
PRINT USING" "とTAB( )を上手に組み合わせると処理結果を見やすく表示させることができる。