昔、AS400会議室という掲示板に上司から今あるサブ・ルーチンを
プロシージャーに置換えるように言われて困っています、という相談が
あったがその上司の方は先見の明があったということになる。
ここでサブ・ルーチンの記述をプロシージャーに書き換えると
どうなるかを例を挙げて解説する。

最初にサブ・ルーチンで書かれたILE-RPGのサンプルを示す。
[サブ・ルーチン: TESTSUBR ]
ソースはこちらから
0001.00 H DFTNAME(TESTSUBR) DATEDIT(*YMD/) BNDDIR('QC2LE')
0002.00 F********** サブ・ルーチンのテスト ************************************
0003.00 F*
0004.00 F**********************************************************************
0005.00
0006.00 * CRTRPGMOD OBJ(QTEMP/TESTSUBR) SRCFILE(R610SRC/QRPGLESRC)
0007.00 * DBGVIEW(*SOURCE) AUT(*ALL)
0008.00 * CRTPGM PGM(ASNET.COM/TESTSUBR) MODULE(QTEMP/TESTSIBR ACTGRP(*NEW)
0009.00 * AUT(*ALL)
0010.00
0011.00 *-------------------------------------------------------------------*
0012.00 * 2020/08/08 : 作成
0013.00 *-------------------------------------------------------------------*
0014.00 *( 作業変数 )
0015.00 D MSR S 80 DIM(1) CTDATA PERRCD(1) 配列
0016.00 D MSG S 3000A
0017.00 D MSGFFLIB S 20 INZ('QCPFMSG QSYS ')
0018.00 D MSGLEN S 10I 0
0019.00 D CALLSTK S 10I 0 INZ(1)
0020.00 D MSGKEY S 4A
0021.00 D AR S 1A DIM(256)
0022.00 D N S 4S 0
0023.00 D NULL S 1A INZ(X'00')
0024.00 D QMHSNDPM C CONST('QSYS/QMHSNDPM')
0025.00
0026.00 D APIERR DS QUALIFIED
0027.00 D GETBYT 1 4B 0 INZ(160)
0028.00 D AVLBYT 5 8B 0 INZ(0)
0029.00 D MSGID 9 15
0030.00 D MSGDTA 17 160
0031.00
0032.00 C*( メイン・ルーチンの始まり )
0033.00 C MOVEL MSR(1) MSG
0034.00 C EXSR SNDPGMMSG
0035.00 C SETON LR
0036.00 C RETURN
0037.00 C*( メイン・ルーチンの終わり )
0038.00
0039.00 C******************************************************
0040.00 C *INZSR BEGSR
0041.00 C******************************************************
0042.00 C* 初期 CYCLE のみの実行
0043.00 C ENDSR
0044.00 C******************************************************
0045.00 C SNDPGMMSG BEGSR
0046.00 C******************************************************
0047.00 C EVAL MSG = MSR(1)
0048.00 C EVAL MSGLEN = %LEN(%TRIM(MSG))
0049.00 *-------------------------------------------------------------------*
0050.00 C CALL QMHSNDPM
0051.00 C PARM 'CPF9897' MSGID 7
0052.00 C PARM MSGFFLIB
0053.00 C PARM MSG
0054.00 C PARM MSGLEN
0055.00 C PARM '*DIAG ' MSGTYPE 10
0056.00 C PARM '*PGMBDY ' PGMQUE 10
0057.00 C PARM CALLSTK
0058.00 C PARM MSGKEY
0059.00 C PARM APIERR
0060.00 *-------------------------------------------------------------------*
0061.00 C IF APIERR.AVLBYT <> 0
0062.00 C 'MSGID=' CAT APIERR.MSGID DSP40 40
0063.00 C DSP40 DSPLY ANS 1
0064.00 C ENDIF
0065.00 C ENDSR
0066.00 ** MSR -- 以下は配列
0067.00 これはメッセージ送信のテストです。
[解説]
これは API: QMHSNDPM(プログラム・メッセージの送信)を使って
自分のジョブにメッセージを送信する例である。
サブ・ルーチンは SNDPGMMSG という名前で
0034.00 C EXSR SNDPGMMSG
によってサブ・ルーチンを呼び出してはいるがサブ・ルーチンに必要な変数というか
パラメータはプログラムを読んでみないとわからない。
また API: QMHSNDPM の呼び出しは CALL命令で呼び出しているが
CALL命令はフリー・フォーマットで記述することはできない。
AS400会議室の別の書き込みではすべてフリー・フォーマットで記述するには?
との問いもあったがCALL命令はフリー・フォーマットでは使えない。
プログラムの呼び出しはプロシージャーとして定義すれば
フリー・フォーマットで使用することができる。
後でそのサンプルも示す。
さて同じ処理をプロシージャーを使って記述すると次のようになる。
[プロシージャー: TESTPROC ]
ソースはこちらから
0001.00 H DFTNAME(TESTPROC) DATEDIT(*YMD/) BNDDIR('QC2LE')
0002.00 F********** プロシージャーのテスト ************************************
0003.00 F*
0004.00 F**********************************************************************
0005.00
0006.00 * CRTRPGMOD OBJ(QTEMP/TESTPROC) SRCFILE(R610SRC/QRPGLESRC)
0007.00 * DBGVIEW(*SOURCE) AUT(*ALL)
0008.00 * CRTPGM PGM(ASNET.COM/TESTPROC) MODULE(QTEMP/TESTPROC ACTGRP(*NEW)
0009.00 * AUT(*ALL)
0010.00
0011.00 *-------------------------------------------------------------------*
0012.00 * 2020/08/08 : 作成
0013.00 *-------------------------------------------------------------------*
0014.00 *( 作業変数 )
0015.00 D MSR S 80 DIM(1) CTDATA PERRCD(1) 配列
0016.00 D AR S 1A DIM(256)
0017.00 D N S 4S 0
0018.00
0019.00 D*( SNDPGMMSG のプロトタイプ宣言 )
0020.00 D SNDPGMMSG PR
0021.00 D MSG 3000A Value
0022.00 D MSGTYPE_IN 10A value OPTIONS(*NOPASS)
0023.00 D CALLSTACKC_IN 10I 0 CONST OPTIONS(*NOPASS)
0024.00
0025.00 C*( メイン・ルーチンの始まり )
0026.00 C CALLP SNDPGMMSG(MSR(1))
0027.00 C SETON LR
0028.00 C RETURN
0029.00 C*( メイン・ルーチンの終わり )
0030.00
0031.00 C******************************************************
0032.00 C *INZSR BEGSR
0033.00 C******************************************************
0034.00 C* 初期 CYCLE のみの実行
0035.00 C ENDSR
0036.00 *********************************************************
0037.00 * SNDPGMMSG: メッセージを現在の CALLSTACK に送信 *
0038.00 *********************************************************
0039.00 *---( SNDPGMMSG PROCEDURE ここから )------------------------*
0040.00 P SNDPGMMSG B EXPORT
0041.00 D PI
0042.00 D MSG 3000A Value
0043.00 D MSGTYPE_IN 10A value OPTIONS(*NOPASS)
0044.00 D CALLSTACKC_IN 10I 0 CONST OPTIONS(*NOPASS)
0045.00
0046.00 D APIERR DS
0047.00 D GETBYT 1 4B 0 INZ(160)
0048.00 D AVLBYT 5 8B 0 INZ(0)
0049.00 D MSGID 9 15
0050.00 D MSGDTA 17 160
0051.00
0052.00 D QMHSNDPM PR ExtPgm('QMHSNDPM')
0053.00 D MSGID 7A CONST
0054.00 D MSGFILE 20A CONST
0055.00 D MSGDATA 6000A CONST OPTIONS(*varsize)
0056.00 D MSGDATALEN 10I 0 CONST
0057.00 D MSGTYPE 10A CONST
0058.00 D CALLSTACKE 10A CONST
0059.00 D CALLSTACKC 10I 0 CONST
0060.00 D MSGKEY 4A
0061.00 D APIERR LIKEDS(APIERR)
0062.00 D OPTIONS(*VARSIZE)
0063.00 D PARMS S 4S 0
0064.00 D MSGKEY S 4A
0065.00 D CALLSTACKC S 10I 0 INZ(1)
0066.00 D MSGTYPE S 10A INZ('*DIAG ')
0067.00
0068.00 C EVAL PARMS = %PARMS()
0069.00 C SELECT
0070.00 C WHEN PARMS = 1
0071.00 C WHEN PARMS = 2
0072.00 C EVAL MSGTYPE = MSGTYPE_IN
0073.00 C WHEN PARMS = 3
0074.00 C EVAL CALLSTACKC = CALLSTACKC_IN
0075.00 C EVAL MSGTYPE = MSGTYPE_IN
0076.00 C ENDSL
0077.00 /FREE
0078.00 QMHSNDPM('CPF9897':'QCPFMSG *LIBL':MSG:
0079.00 %LEN(%TRIM(MSG)):MSGTYPE:'*PGMBDY':
0080.00 CALLSTACKC:MSGKEY:APIERR);
0081.00 /END-FREE
0082.00 C RETURN
0083.00 P E
0084.00 *---( SNDPGMMSG PROCEDURE ここまで )------------------------*
0085.00
0086.00 ** MSR -- 以下は配列
0087.00 これはメッセージ送信のテストです。
[解説]
サブ・ルーチンはプロシージャー: SNDPGMMSG として定義している。
プロシージャーは演算命令文の中で使用する前に型を
次のようにして D-仕様書で定義しなければならない。
0019.00 D*( SNDPGMMSG のプロトタイプ宣言 ) 0020.00 D SNDPGMMSG PR 0021.00 D MSG 3000A Value 0022.00 D MSGTYPE_IN 10A value OPTIONS(*NOPASS) 0023.00 D CALLSTACKC_IN 10I 0 CONST OPTIONS(*NOPASS)
この型のことをプロトタイプと呼んでいる。
関数の型を使用する前に定義するのはILE-RPGだけでなく
一般的に C言語、Java, VisualBASIC, VC++, VBA ,…などの開発言語における
共通のルールである。
次にプロシージャーを記述する位置はサブ・ルーチンのまだ後ろで
演算の最後に追加する。
ひとつのプロシージャーは
0040.00 P SNDPGMMSG B EXPORT
から始まって
0083.00 P E
の E で終わる。
入り口は
0041.00 D PI 0042.00 D MSG 3000A Value 0043.00 D MSGTYPE_IN 10A value OPTIONS(*NOPASS) 0044.00 D CALLSTACKC_IN 10I 0 CONST OPTIONS(*NOPASS)
のようにして受取りパラメータを記述する。
Value がパラメータを表している。
OPTIONS(*NOPASS) はこのパラメータが省略可能であることを意味している。
演算中にある
0068.00 C EVAL PARMS = %PARMS()
によって受取ったパラメータの数を調べることができる。
またプロシージャーが呼び出すプログラムはプロシージャーとして
0052.00 D QMHSNDPM PR ExtPgm('QMHSNDPM')
0053.00 D MSGID 7A CONST
0054.00 D MSGFILE 20A CONST
0055.00 D MSGDATA 6000A CONST OPTIONS(*varsize)
0056.00 D MSGDATALEN 10I 0 CONST
0057.00 D MSGTYPE 10A CONST
0058.00 D CALLSTACKE 10A CONST
0059.00 D CALLSTACKC 10I 0 CONST
0060.00 D MSGKEY 4A
0061.00 D APIERR LIKEDS(APIERR)
0062.00 D OPTIONS(*VARSIZE)
定義する。
API: QMHSNDPM はプログラムであるがプロシージャーとして
定義したので
0077.00 /FREE
0078.00 QMHSNDPM('CPF9897':'QCPFMSG *LIBL':MSG:
0079.00 %LEN(%TRIM(MSG)):MSGTYPE:'*PGMBDY':
0080.00 CALLSTACKC:MSGKEY:APIERR);
0081.00 /END-FREE
のようにしてフリー・フォーマットで呼び出すことができる。
プロシージャー化のサンプルは上記のTESTPROCのILE-RPGソースを
入手してご自分のライブラリーに保存してじっくり眺めてみて欲しい。
最初はこのTESTPROCによるプロシージャーを見慣れるところから
始めてほしい。
次回は作成したプロシージャーの公開と利用方法について解説する。
