◎本記事は、i Magazine 2014年2月号に掲載されたものです。RPG Ⅳの基本情報に大きな変更はないため掲載します。
2013年に25周年を迎えたIBM i 。同年10月にはIBM i 7.1 TR7が発表され、時を同じくしてRPGにも大きな進化があった。ほぼすべての構文がフリーフォーム化され、固定フォームの制限から解放されたのである。
IBMは今回のフリーフォーム化により、既存のRPGプログラマーはもちろんのこと、JavaやPHP、Visual Basicなどの開発経験がある新規RPGプログラマーにとっても、RPGがより理解しやすいものとなったとしている。
振り返ってみると、RPGのフリーフォーム化はOS/400 V5R1のC仕様書フリーフォーム化から始まった。IBMでは、OS/400 V5R1からV5R2までをRPGの進化における第1フェーズと位置づけている。第2フェーズは、i5/OS V5R3からIBM i 7.1までで、組み込みSQLがフリーフォーム化された。そして今回が第3フェーズとなる。
第3フェーズでは新たに、制御(H)仕様書、ファイル(F)仕様書、定義(D)仕様書、プロシージャー(P)仕様書がフリーフォーム化された。これで、入力(I)および出力(O)仕様書とRPGサイクルなどを除き、すべての構文がフリーフォーム化されたことになる。
本稿では第3フェーズで変革を遂げたRPGについて、使用の前提要件から新フリーフォーム文法、導入にあたっての考慮点などを考えてみる。
フリーフォームRPGを
使用するための前提要件
フリーフォーム構文のRPGをコンパイルするには、IBM i 7.1にRPGコンパイラー用PTF SI51094の適用が必要である。同PTF適用後もRPGは上位互換であり、固定フォームRPGのコンパイルをサポートする。
コンパイルされたフリーフォームRPGのプログラムは、同PTFやTR7が未適用のマシン上でも実行できる。ただし、コンパイル時にターゲット・リリース(TGTRLS)がサポートされないので、IBM i 7.1上でのみ実行可能である。
なおPTF SI51094の適用は、TR7の適用を前提としない。つまりTR7が未適用であっても、PTFを適用してフリーフォームRPGを使用できる。
●IBM i の前提要件
コンパイルおよび構文チェック
OS:IBM i 7.1
PTF:SI51094の適用(5770WDS、即時適用可)コンパイル済みプログラムの実行
OS : IBM i 7.1
GUI統合開発ツールの「IBM Rational Developer for i」(図表1)は、v9.0.1 がフリーフォームに対応する。
●GUI統合開発ツールの前提要件
IBM Rational Developer for i 9.0.1
これ以降、フリーフォームRPGについて解説を進める前に、小文字でのコーディングについて注意点を述べておく。
本稿で紹介するサンプルコードは小文字でコーディングされたものがほとんどだ。これらのサンプルコードを使用する際には、ソース物理ファイルのCCSIDとエミュレータ端末のコードページの設定に注意してほしい。たとえば、ソース物理ファイルのCCSID=5035の場合は、エミュレータのコードページ=939という組み合わせが必要となる。
フリーフォームRPGの概要
ここでは、フリーフォーム化の概要とそのメリットについて見ていこう。また、最後に今回のフェーズで変更されない部分についても触れる。
■ 各種仕様書のフリーフォーム化
今回の目玉は制御(H)仕様書、ファイル(F)仕様書、定義(D)仕様書、プロシージャー(P)仕様書がフリーフォーム化されたことである。以下にその概要について述べる。
・ 仕様書の構文概要
フリーフォーム構文の仕様書は、命令コードで開始し、セミコロンで終了する。コーディングの詳細は後ほど解説するので、ここでは以下に仕様書宣言のための命令コードとコーディング例を示す。なお、命令コードは大文字でも小文字でもかまわない。
○ 仕様書宣言の命令コード一覧
1 2 3 4 5 |
制御(H)仕様書:CTL-OPT ファイル(F)仕様書:DCL-F 定義(D)仕様書:DCL-S、DCL-DS、DCL-SUBF、 DCL-C、DCL-PR、DCL-PI、DCL-PARM プロシージャー(P)仕様書: DCL-PROC |
○ 仕様書のコーディング例
1 2 3 |
ctl-opt bnddir('ACCRCV'); dcl-f empfile usage(*update); dcl-ds empDs likerec(empRec); |
・ 長い名前やキーワードでも容易なコーディング
仕様書がフリーフォーム化されるメリットの1つは、コーディングが容易になり、ソースコードの可読性が高まることだ。固定フォームは入力桁に厳しい制限があり、名前やキーワードの長さによっては、仕様書のコードが複数行にわたることがあった。
フリーフォームの場合、8〜80桁目までであれば入力桁数を気にすることなく、名前やキーワードの入力が可能である。これでほとんどの仕様書は、1行でコーディングできるはずである。コーディング後に名前やキーワードの変更があっても、複数行にわたって桁数を調整しつつ修正する必要はない。メンテナンスも容易になるだろう。
○ 固定フォームの定義(D)仕様書例:長い項目名
1 2 3 4 5 |
D getNextCustoinf... D pr D areallylong... D name S 10A |
○ フリーフォームの定義(D)仕様書例:長い項目名
1 2 3 |
dcl-pr getNextCustoinf; dcl-s areallylongname CHAR(10); |
○ 固定フォームの定義(D)仕様書例:長いキーワード
1 2 3 |
D HSSFCellStyle c D 'org.apache.poi.hssf.- D usermodel.HSSFCellStyle' |
○ フリーフォームの定義(D)仕様書例:長いキーワード
1 2 |
dcl-c HSSFCellStyle 'org.apache.poi. hssf.usermodel.HSSFCellStyle'; |
■ 固定フォームとフリーフォームの混在
以前から固定フォーム構文とフリーフォーム構文の混在は可能であったが、今回のフリーフォームRPGもそれが可能である。大きく変わったのは、/FREE、 /END-FREEを使ってフリーフォーム部分を範囲指定する必要がなくなったことである。ソース内の/FREE、/END-FREEはコンパイラーから無視される。
○ 従来の混在コード例
1 2 3 4 5 6 7 8 9 10 |
/FREE exec sql whenever sqlerror goto err1; ... return; /END-FREE C err1 tag /FREE ok = *off; sendSqlError (); /END-FREE |
○ フリーフォームRPGの混在コード例
1 2 3 4 5 6 |
exec sql whenever sqlerror goto err1; ... return; C err1 tag ok = *off; sendSqlError (); |
■ 仕様書構文内のコンパイラー指示
仕様書の宣言構文内で、/IF、 /ELSEIF、 /ELSE、/ENDIFコンパイラー指示が使用できるようになった。
○ コンパイラー指示を含む仕様書例
1 2 3 4 5 6 7 |
dcl-s salary /if defined(large_vals) packed(13 : 3); /else packed(7 : 3) /endif ; |
■ 固定フォームとフリーフォームの双方で使用可
これはつまり、/COPY対象のファイルに書かれている構文と、コピー先構文のフォームが異なる場合もコピーが可能ということである。下記の使用例1は、固定フォーム構文が書かれたfile1がコピー対象ファイルであり、コピー先はフリーフォーム構文で書かれた定義(D)仕様書である。これに対して使用例2は逆のパターンとなる。
○ /COPY構文の使用例1
<固定フォーム構文が書かれたファイルfile1の内容>
1 2 |
D subf1 10A D subf2 5P 0 |
<フリーフォーム構文内でのfile1のコピー>
1 2 3 |
dcl-ds testDs1; /copy file1 end-ds testDs; |
○ /COPY構文の使用例2
<フリーフォーム構文が書かれたファイルfile2の内容>
1 2 |
Subf1 char(10); Subf2 packed(5); |
<固定フォーム構文内でのfile2のコピー>
1 2 |
D testDs2 DS /copy file2 |
■ 名前付き定数のキーワードとしての使用
名前付き定数をキーワード値として使用できるようになった。下記の例では、QTR_END_RPT_FILEという名前の定数を使って、ファイル(F)仕様書のファイル名を指定している。なお、名前付き定数の宣言ルール等については後述する。
○ 名前付き定数のキーワード値としての使用例
1 2 3 4 5 6 7 |
dcl-c QTR_END_RPT_FILE 'QTRRPT'; dcl-f qtr_end_report printer oflind(overflow) extdesc(QTR_END_RPT_FILE) extfile(*extdesc); dcl-ds report_ds extname(QTR_END_RPT_FILE:*output); |
■ 制限の残る部分
ここまで見てきたように、RPGの主要部分はほぼフリーフォーム化されたと言える。「フリー」でない部分は、以下を残すのみとなった。
・フリーフォームのコードの入力は、8〜80桁目まで
・入力(I)仕様書と出力(O)仕様書は固定フォームのみ
・RPGサイクル関連のコードは固定フォームのみ
制御(H)仕様書
■ 基本構文
フリーフォームの制御(H)仕様書は、命令コードCTL-OPT(Control-Option)で開始する。キーワードがあればそれが続き、最後はセミコロンで終了する。
例1は、3つのキーワードを指定する制御(H)仕様書の例である。CTL-OPT命令コードで始まり、キーワードが3つ続いて、セミコロンで終了している。キーワードによる指定内容は、日付形式=*ISO、時刻形式=*ISO、ヌル値を含むレコードの処理=*USRCTLとなる。
○ 制御(H)仕様書の例1
1 2 |
ctl-opt datfmt(*iso) timfmt(*iso) alwnull(*usrctl); |
■ その他のルール
複数の制御(H)仕様書を宣言でき、固定フォームの制御(H)仕様書との混在も可能である。なお、繰り返しが許されないキーワードは、すべての制御(H)仕様書にわたって1度しか指定できない。
また、フリーフォームの制御(H)仕様書が1つでも含まれていて、コンパイル・オプション・キーワードACTGRP、BNDDIR、STGMDLのいずれかがあれば、DFTACTGRP(*NO)がデフォルトで指定されるので、これを明示的にコーディングする必要がなくなった。
○ 制御(H)仕様書の例2
1 2 3 4 5 6 7 |
ctl-opt; // キーワードなし ctl-opt option(*srcstmt : *nodebugio) dftactgrp(*no); // キーワード2つ H datfmt(*iso) text(‘My Program’) //フリーフォーム再開 ctl-opt alwnull(*usrctl); |
ファイル(F)仕様書
■ 基本構文
ファイル仕様書は、DCL-F(Declare file)で開始し、ファイル名、0個以上のキーワード、セミコロンで終了する。
以下の例は、外部記述DISKファイルの定義である。DCL-Fで始まり、ファイル名、キーワードが2つ続き、セミコロンで終了している。DISK(*EXT)で外部記述DISKファイルを指定し、USAGE(*INPUT)により入力用のファイルであることを指定している。
○ ファイル(F)仕様書の例
1 |
DCL-F file1 DISK(*EXT) USAGE(*INPUT); |
■ ファイル名の指定
EXTFILEキーワード(外部記述であればEXTDESCも必要)があれば、10文字以上の名前が使用できる。
○ 10文字以上のファイル名を持つファイル仕様書の例
1 2 3 4 |
dcl-f qtr_end_report printer oflind(overflow) extdesc('qeRPT') extfile(*extdesc); |
■ キーワードの指定
ファイル(F)仕様書の一番目のキーワードは、装置タイプまたは LIKEFILE でなければならない。また、デフォルト値を持つキーワードやパラメーターがあり、明示指定しない場合はそれらの値が使用されることになる。
ファイル仕様書の主要なキーワードに注目してみよう。
・ 装置タイプ
装置タイプはDISK、PRINTER、SEQ、SPECIAL、WORKSTNの5つあり、明示指定しない場合のデフォルトは DISKである。さらに各キーワードには、オプションで指定できるパラメーターが2種類用意されている。
1つ目は外部記述を意味する「*EXT」で、これがデフォルト値となる。もう1つはプログラム記述の場合に指定する「レコード長」である。これらのデフォルト値により、装置タイプを指定しない場合は、DISK(*EXT)を指定したのと同じになる。
○ ファイル仕様書の例〜装置タイプ
1 2 3 |
dcl-f tkorder; // デフォルト DISK(*EXT) dcl-f qprint printer(132); dcl-f scrns workstn; // デフォルト *EXT |
・ ファイルタイプ
ファイルタイプは、USAGEキーワードで指定する。USAGE
キーワードは、*INPUT、*OUTPUT、*UPDATE、*DELETEの4つである。これらを組み合わせると、固定フォームのファイルタイプ (I、O、U、C) やファイルの追加と同様のことが指定可能となる。
たとえばファイルタイプ=U、ファイルの指定=F、つまり更新・全手順ファイルの場合は、USAGE(*UPDATE:*DELETE)と指定する。指定方法の詳細については、図表2を参照されたい。なお、キーワードを明示指定しない場合は、装置タイプに依存したデフォルト値が使用される(図表3)。
○ ファイル仕様書の例〜USAGEキーワードの非明示指定
1 2 3 4 |
dcl-f tkorder disk; // *INPUTを意味する dcl-f report printer; // *OUTPUTを意味する dcl-f scrns workstn; // *INPUT:*OUTPUTを意味する |
USAGEキーワードの使用で、注意すべきことがある。固定フォームのファイルタイプとフリーフォームUSAGEキーワードには、INPUT(固定:I、 フリー:*INPUT)やUPDATE(固定:U、フリー:*UPDATE)といった同じ値が存在するが、その意味するところが異なる場合がある。
たとえば、固定フォームのファイルタイプ“U”は、入力(INPUT)・更新(UPDATE)・削除(DELETE)が可能だが、フリーフォームのUSAGEキーワードに*UPDATEを指定しても、レコードの削除(DELETE)はできない。明示的に*DELETEを指定する必要がある(図表4)。
○ ファイル仕様書の例〜USAGEキーワードの明示指定
1 2 3 4 5 6 7 |
//usage(*input:*update)と同じ dcl-f orders disk usage(*update); //usage(*input:*update:*delete)と同じ dcl-f arrears disk usage(*delete); dcl-f orders disk usage(*update : *input); |
・ キー付きファイル
キー付きファイルについては、外部記述ファイルとプログラム記述ファイルで指定方法が異なる。指定方法は、図表5に示すとおりだが、プログラム記述ファイルでは文字列キーのみがサポートされるので注意したい。文字列キー以外については、データ構造を使用することになる。
○ キー付きファイルの宣言例
1 2 3 4 |
dcl-f tkorder disk keyed; // キー付き外部記述ファイル dcl-f prdinfo disk(2000) keyed(*CHAR: 100); // キー付きプログラム記述ファイル |
○ キー付きプログラム記述ファイルの宣言例
1 2 3 4 5 6 7 |
dcl-f prdinfo disk(2000) keyed (*CHAR:7); dcl-ds key len(7); prd_num packed(12); end-ds; key.prd_num = 14; chain key prdinfo; |
■ ファイル(F)仕様書と定義(D)仕様書の混在
フリーフォームRPGでは、ファイル(F)仕様書と定義(D)仕様書を混在させてコーディングできるようになった。ソースコード内で関連する項目の宣言文をまとめておけば、よりわかりやすいコードとなり、後のメンテナンスも容易になる。なお、固定フォームの仕様書であっても混在可能である。
○ ファイル(F)仕様書と定義(D)仕様書の混在例
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 注文に関するもの dcl-f tkorders usage (*update : *output)keyed; dcl-ds tkorders_dsi likerec (tkordersR:*input); dcl-ds tkorders_dso likerec (tkordersR:*output); dcl-s num_orders int(10); // 報告書に関するもの dcl-f report printer; dcl-ds report_ds likerec (reportR:*output); |
■ ファイル(F)仕様書の変更点のまとめ
最後に、ファイル(F)仕様書のフリーフォームの比較を図表6に示す。今回かなり大きな変更が加えられ、対応するフリーフォームがないものもある。固定フォームと勝手が違い、馴染みにくいと感じるかもしれないが、柔軟なコーディングや明示指定なしで使用できるデフォルト値などフリーフォーム化によるメリットは大きい。
定義(D)仕様書
定義(D)仕様書では、名前付き定数、独立フィールド、データ構造、プロシージャー・プロトタイプ、プロシージャー・インターフェースの5つの項目を定義できる。
■ 基本構文
命令コードDCL-X(Xは定義項目に依存)で開始し、定義項目の名前(名前がない場合は*Nも可)、0個以上のキーワードが続き、セミコロンで終了する。
以下の例は、独立フィールドの定義である。DCL-S命令コードにより独立フィールドの宣言を開始し、独立フィールド名limitが続く。次に、PACKEDキーワードにより5桁のパック・フィールドであることを指定し、INZキーワードで初期値を200としている。最後はセミコロンで終了である。
○ 定義(D)仕様書の例
1 |
DCL-S limit PACKED(5) INZ(200); |
■ 複数行にわたる宣言〜継続行
フリーフォームでは、定義項目の名前の最後に省略記号“…”は使わない。次の行に名前が継続する場合にのみ、省略記号“…”を使ってつなげることができる。構文の余りと名前をつなげるために使用することもない。
■ データ型キーワード
データ型キーワードには、CHAR、INT、POINTERなどのようにキーワード名とデータ型が一致しているものと、そうでないものがある(図表7)。キーワード名とデータ型が一致しているものについては、これまでのデータ型と同様と考えてよい。一方、データ型とそれを修飾するキーワード(VARYING、DTFMTなど)が統合されて新しいデータ型となったものがあり、注意が必要である。
新しいデータ型は、VARYING、DATFMT、TIMFMT、PROCPTR、CLASSなど、従来のデータ型を修飾するキーワードとデータ型が統合して作られている。たとえば、VARCHARというデータ型キーワードは、文字データ型(A)とVARYINGキーワードを統合したものだ。以下に、いくつかの例を挙げる。
○ キーワード名とデータ型が一致している例
1 2 3 |
CHAR : 文字 INT : 整数 POINTER : 基底ポインター |
○ データ型と他キーワードの統合例
1 2 3 4 |
VARCHAR : データ型A(=文字)+VARYING(可変長) DATE : データ型D(=日付)+DATFMT(形式) OBJECT : データ型O (=オブジェクト) + CLASS (クラス名) |
○ データ型の宣言例:固定フォームとフリーフォーム
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
D* fixed-form declarations D string S 100A VARYING D date S D DATFMT(*MDY) D obj S O CLASS(*JAVA:'TestClass') D pptr S * PROCPTR // free-form declarations DCL-S string VARCHAR(100); DCL-S date DATE(*MDY); DCL-S obj OBJECT(*JAVA:'TestClass'); DCL-S pptr POINTER(*PROC); |
■ 名前付き定数
・ 基本構文
命令コードDCL-Cで開始し、定数名、オプションでCONSTキーワード、値が続き、セミコロンで終了する。CONSTキーワードがなくとも定義の意味は変わらない。
以下の例1および2では、それぞれ同じ定義内容で3つの定数を定義している。違いはCONSTキーワードがあるかないかだけであり、定義の意味するところは変わらない。
1番目のmin_numは─50という値を持ち、次のmax_numは200という値を持つ。最後のfirst_letterは‘A’という文字値を持つ定数である。
○ 名前付き定数の宣言例1〜CONSTキーワードあり
1 2 3 4 |
// CONSTキーワードあり DCL-C min_num -50; DCL-C max_num 200; DCL-C first_letter 'A'; |
○ 名前付き定数の宣言例2〜CONSTキーワードなし
1 2 3 4 |
// CONSTキーワードなし DCL-C min_num CONST(-50); DCL-C max_num CONST(200); DCL-C first_letter CONST('A'); |
注意すべき点は、リテラル値に対する引用符( ‘)の使用がフリーフォームと固定フォームとで異なることである。固定フォームではDTAARA、EXTNAME、EXTFLDなどのキーワードのパラメーターについて、リテラルを引用符(‘)で囲まずに指定できたが、フリーフォームではできない。
下記の例では、文字リテラル値を持つnameという定数が定義されている。DTAARAキーワードのパラメーター指定で、これがどのように働くかを見ていこう。
まず固定フォームで定義したdata1では、実行時に「*LIBL/NAME」が使用される。引用符(‘)なしでリテラルを指定できるからだ。
一方、フリーフォームによる定義のdata3では、実行時に「MYLIB/DTAARA1」が使われる。data1と同様に「*LIBL/NAME」を使いたい場合は、DTAARA(‘NAME’)、またはDTAARA(‘*LIBL/NAME’)と指定しなければならない。
次にdata2の定義を見てみると、*VARを使ってデータ域名を変数または定数で指定している。フリーフォーム(data4)では*VARが不要なので、data3と同様の指定方法となる。
○ 固定フォームとフリーフォームのリテラルの取り扱い例
1 2 3 4 |
D name C 'MYLIB/DTAARA1' D data1 S 10A DTAARA(name) D data2 S 10A DTAARA (*VAR:nameFld) |
1 2 3 |
dcl-s data3 char(10) dtaara(name); dcl-s data4 char(10) dtaara (nameFld); |
■ 独立フィールド
・ 基本構文
命令コードDCL-Sで開始し、定義項目名、データ型キーワード(オプション)、0以上のキーワード、最初のキーワードが続き、セミコロンで終了する。
1番目のキーワードは、データ型キーワードかLIKEキーワードにする必要がある。データ型キーワードが存在する場合は、そちらを1番目にしなければならない。LIKEキーワードを使用する場合は、データ型キーワードは指定不可である。LIKEキーワードは、オプションで2番目のパラメーターを使って長さを指定できる。
以下の例では、4つの独立フィールドを定義している。どれもDCL-S命令コードで始まり、定義項目名、キーワード、セミコロンで終了している。
上の2つはパック・フィールドの定義例である。salaryは9桁(小数点以下2桁)で初期値0、qtr_salaryは7桁(小数点以下2桁)で初期値0である。
下の2つは文字フィールドで、first_nameは固定長10文字で初期値が‘Taro’、last_nameは可変長で最大20文字である。
○ 定義仕様書〜独立フィールドの例
1 2 3 4 |
dcl-s salary packed(9:2) inz(0); dcl-s qtr_salary like(salary : +2); dcl-s first_name CHAR(10) INZ('Taro'); dcl-s last_name VARCHAR(20); |
■ データ構造
・ 基本構文
命令コードDCL-DSで開始し、データ構造の名前(名前がない場合は*N)、0個以上のキーワードが続き、セミコロンで終了する。次にサブフィールド定義が続き、最後はEND-DS構文で終了する必要がある。オプションでEND-DSの後にデータ構造名を続けてもよい。
またサブフィールドを持たない場合は、END-DSをDCL-DS構文の一部とすることもできる。この場合は、END-DSの後にデータ構造名を続けることができない。
以下は、プログラム記述データ構造の例である。どちらもDCL-DSで始まり、データ構造名、サブフィールド定義が続き、END-DS構文で終了している。
datastr1は、サブフィールドに固定長10文字の文字フィールド2つとパック・フィールド1つを持つデータ構造である。END-DSの後にデータ構造名が続いている。
datastr2は、likedsキーワードによりdatastr1と同様のデータ構造を持つ。サブフィールドの定義がないので、END-DSをDCL-DS構文の一部としている。
○ データ構造の例
1 2 3 4 5 6 |
DCL-DS datastr1; first_name CHAR(10); last_name CHAR(10); salary PACKED(8:2); END-DS datastr1; DCL-DS datastr2 likeds(datastr1) END-DS; |
・ 外部記述データ構造
外部記述の場合は、EXTキーワードもしくはEXTNAMEキーワードを1番目のキーワードとして指定しなければならない。END-DSはDCL-DS構文の一部としてもよいし、次の行で指定してもよい。
○ 外部記述データ構造の例
1 2 3 4 |
DCL-DS tkrecord EXT; END-DS; //上と同じ内容の構文 DCL-DS tkrecord EXT END-DS; |
・ プログラム記述データ構造
プログラム記述でサブフィールドを持つ場合は、END-DS構文でサブフィールド・リストを終了する。サブフィールドを持たない場合は、END-DSをDCL-DS構文と同じ行にコーディングできる。
なお、END-DS構文はLIKEDSやLIKERECで定義するデータ構造では使用しない。
[サブフィールド宣言]
サブフィールドは、正式にはDCL-SUBで開始する。しかし、サブフィールドの名前がRPGの命令コード(add、readなど)と同じでない場合は、DCL-SUBの指定は任意である。
○ サブフィールドを持つプログラム記述データ構造の例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
DCL-DS prd_inf; prd_name CHAR(10); price PACKED(8:2); END-DS prd_inf; //prd_infはなくてもよい DCL-DS *N; //名前なしデータ構造 item VARCHAR(40); END-DS; DCL-DS record_one; buffer CHAR(25); //addは命令コードと同じ名前なのでDCL-SUB必須 DCL-SUBF add INT(3); END-DS; |
○ サブフィールドを持たないプログラム記述データ構造の例
1 |
DCL-DS PRINT_DS LEN(132) END-DS; |
○ LIKERECを使用するデータ構造の例
1 |
DCL-DS custoutput LIKEREC(custrec); |
[POSキーワード]
フリーフォームでは、データ構造のオーバーレイにPOSキーワードを使用する。固定フォームでの開始・終了位置およびOVERLAYが、POSキーワードに置き換えられた形だ。
フリーフォームにもOVERLAYキーワードは存在するが、これはサブフィールドのみをオーバーレイする。データ構造をオーバーレイしたい場合は、POSキーワードを使用しなければならない。
固定フォームのOVERLAY(ds:*NEXT)に対応するフリーフォーム構文は存在しない。OVERLAY(ds:*NEXT)は、“ここまでの全サブフィールドの後から”を意味しており、これはつまり、何もオーバーレイしないことと同じであるからだ。
○ POSキーワードの例
1 2 3 4 5 6 7 8 9 10 11 12 |
D* 固定フォーム D info DS D sub1 25 34A D sub2 D OVERLAY(info:100) D sub3 5P 2 OVERLAY(info) //フリーフォーム dcl-ds info; sub1 char(10) pos(25); sub2 date pos(100); sub3 packed(5 : 2) pos(1); end-ds info; |
■ プロシージャー・プロトタイプ
・基本構文
DCL-PRで開始し、プロトタイプ名、0個以上のキーワードが続き、セミコロンで終了する。プロシージャーに戻り値があり、そのデータ型をデータ型キーワードで指定する場合は、それを1番目のキーワードにしなければならない。
定義の最後には、END-PR構文が必須である。オプションで、END-PRの後にプロトタイプ名を続けてもよい。パラメーターがない場合は、END-PRをDCL-PR文に続けて1つの構文にできる。ただしこの場合は、END-PRの後にプロトタイプ名を続けることができないので注意しよう。
例1は、どちらもプロシージャーの戻り値のデータ型を指定した例である。1番目のキーワードでCHAR(10)を指定し、プロシージャーが固定長10文字の戻り値を持つことを示している。また、パラメーターがないので上の例のようにEND-PRをDCL-PR構文の一部としてもよいし、下の例のように行を分けてもよい。
○ プロシージャー・プロトタイプの定義例1
1 2 3 |
DCL-PR getCurcust CHAR(10) END-PR; DCL-PR getCuremp CHAR(10); END-PR; |
例2は、プログラムの外部名がtestPgmで、固定長10文字のnameという定数をパラメーターとして持つプロトタイプである。END-PRの後にプロトタイプ名を続けた形である。
○ プロシージャー・プロトタイプの定義例2
1 2 3 |
dcl-pr testPgm EXTPGM; name CHAR(10) CONST; end-pr testPgm; |
・パラメーター宣言
パラメーターの宣言は、正式にはDCL-PARMで開始する。ただし、データ構造のサブフィールド定義のDCL-SUBFと同様のルールが適用でき、パラメーター名がRPGの命令コード(read、writeなど)と同じでない場合はDCL-PARMを省略できる。
○ プロシージャー・プロトタイプの宣言〜パラメーター1
1 2 3 4 5 |
dcl-pr qcmdexc extpgm; // extpgmはなくてもよい cmd char(3000); cmd_len packed(15 : 5); end-pr qcmdexc; |
○ プロシージャー・プロトタイプの宣言〜パラメーター2
1 2 3 4 |
dcl-pr sine FLOAT(8) EXTPROC('sin'); // C言語のsin関数のプロトタイプ angle FLOAT(8) VALUE; end-pr; |
■ プロシージャー・インターフェース
・基本構文
プロシージャー・インターフェースの定義は、プロシージャー・プロトタイプと非常によく似ている。DCL-PIで開始し、インターフェース名(名前がない場合は、*N)、0個以上のキーワードが続き、セミコロンで終了する。
プロシージャーに戻り値があり、そのデータ型をデータ型キーワードで指定する場合は、それを1番目のキーワードにしなければならない。
最後のEND-PI構文も、プロシージャー・プロトタイプと同様に必須である。関連するルールも同じだ。オプションでEND-PIの後にインターフェース名を続けることができる。ただし、END-PIをDCL-PI文の一部にする場合は、END-PIの後にインターフェース名を続けることはできない。
例1は名前なし、パラメーターなしのインターフェースの定義である。1番目のキーワードで、プロシージャーの戻り値のデータ型(固定長10文字)を指定している。パラメーターがないのでEND-PIをDCL-PI構文の一部としてもよいし、行を分けてもよい。
○ プロシージャー・インターフェースの定義例1
1 2 3 4 |
DCL-PI *N CHAR(10) END-PI; DCL-PI *N CHAR(10); END-PI; //2行にわけてもよい |
例2のtestPI1は、2つのパラメーターを持つインターフェースである。END-PIの後にインターフェース名を指定している。一方、testPI2は、パラメーターを持たず、END-PIをDCL-PI構文の一部としているため、END-PIの後にインターフェース名は指定できない。
○ プロシージャー・インターフェースの定義例2
1 2 3 4 5 6 |
DCL-PI testPI1; prdid INT(10) CONST; price PACKED(7 : 2) CONST; END-PI testPI1; DCL-PI testPI2 END-PI; |
・パラメーター定義
パラメーター定義についても、プロシージャー・プロトタイプの場合と同様である。正式にはDCL-PARMで開始するが、RPGの命令コード(read、writeなど)とパラメーター名が異なる限りはDCL-PARMを省略できる。
○ プロシージャー・インターフェースの定義例
〜パラメーター
1 2 3 4 5 6 |
// 命令コードと同名の場合はデータ構造の定義ルールと同様に // dcl-parmが必要 dcl-pi proc_a; buffer char(25) const; dcl-parm read int(3) value; end-pi proc_a;a |
プロシージャー(P)仕様書
■ 基本構文
命令コードDCL-PROCで開始し、プロシージャー名、オプションで戻り値タイプ、0個以上のキーワード、セミコロンで終了する。次に、オプションでパラメーター定義が続く。最後にEND-PROC構文が必須である。END-PROCの後に、オプションでプロシージャー名を続けることができる。
例1は、exportキーワードを使って他のモジュールからの呼び出し可能なプロシージャーを定義している。定義はDCL-PROCで開始し、END-PROCで終了する。この例ではEND-PROCの後にプロシージャー名を指定していない。
○ プロシージャー(P)仕様書の例1
1 2 3 4 5 6 |
dcl-proc getExUser export; dcl-pi *n char(10) end-pi; dcl-s exUser char(10) inz (*user); return exUser; end-proc; |
例2では、プロシージャー・インターフェースでEXTPROC(*DCLCASE)が指定されている。*DCLCASEはフリーフォームでのみ使用できるパラメーターで、外部名とここでの定義名が同じであることを意味する。この例ではインターフェースに名前がないので、外部名はプロシージャー名“getNextOrder”と同じということになる。
またINDキーワードもフリーフォームでのみ使用でき、識別子を意味する。ここではプロシージャーの戻り値が識別子であることを示す。
END-PROCの後には、プロシージャー名が続いている。
○ プロシージャー(P)仕様書の例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
DCL-PROC getOrder; DCL-PI *N IND //INDは識別子を意味する EXTPROC(*DCLCASE); //ここまでDCL-PI構文 order LIKEDS(order_ds); //パラメーター定義 END-PI; DCL-F order1 STATIC; //ファイル仕様書 READ order1 order; RETURN %EOF(order1); END-PROC getNextOrder; |
これまで見てきたとおり、第3フェーズに入ったRPGは、制御(H)仕様書、ファイル(F)仕様書、定義(D)仕様書、プロシージャー(P)仕様書をフリーフォーム化した。これによりさまざまな制限がなくなり、仕様書のコーディングが飛躍的に容易になった。全般的にも固定フォームとフリーフォームの混在の許可や、デフォルト値によるコード省略など、細かい部分でコーディングのしやすさが配慮されているといえる。
IBMは今回のフリーフォーム化の目的を、新規のRPGプログラマーに対しても、既存のRPGプログラマーに対しても、RPGプログラミングを容易にすることとしており、これを機にRPGプログラマーと非RPGプログラマーの間の垣根を取り除き、RPG全体の活性化を促進したい考えだ。
今回のフリーフォームRPGについてはいろいろなご意見があるだろうが、まずは既存の固定フォーム構文をフリーフォームに変換するなどして、ぜひ進化したフリーフォームRPGを体験してほしい。
著者|岩下 文香
日本アイ・ビー・エム システムズ・エンジニアリング株式会社
クライアント・イノベーション
[i Magazine 2014年2月号掲載]