%PARMSでCLに関する2つの問題を解決する
IBMの優秀なスタッフたちが、また素晴らしい仕事をしてくれました。2つの問題を解決する新たなCL機能を追加してくれたおかげで、私はもうそれらの問題の対処に悩む必要がなくなりました。この記事では、新たな%PARMS組み込み関数について紹介します。
%PARMS関数は、CLプロシージャー(すなわちCLプログラムまたはCLモジュール)に渡されるパラメーターの数を返します。以前は、私はメッセージMCH3061を監視していました。そうすることで問題が何も生じないケースもありますが、すべてのケースでうまく行くわけではありません。%PARMS関数は、パラメーターが渡されたかどうかを知る明確な方法を提供してくれます。IBMは、PTF SI66721でIBM i 7.3向けに%PARMSをリリースしています。
以下では、2つの問題を取り上げて、%PARMSを使ってそれらの問題を防止する方法について説明します。
プログラムの問題
次のPARMTESTというプログラムについて検討してみましょう。
pgm (&p1 &p2 &p3)
dcl &p1 *char 3
dcl &p2 *char 3
dcl &p3 *char 3
dcl &msg *char 14
ChgVar &msg ('/' *cat &p1 *cat ' ' *cat +
&p2 *cat ' ' *cat +
&p3 *cat '/')
SndPgmMsg msg(&msg) MsgType(*comp)
3つのパラメーターを渡してこのプログラムを呼び出すと、渡した値を含んだメッセージが表示されます。
call PARMTEST (AAA BBB CCC)
/AAA BBB CCC/
しかし、渡したパラメーターが3つに満たない場合は、別の表示になります。
call PARMTEST (AAA BBB)
MCH3601 Pointer not set for location referenced.
CPF9999 Function check. MCH3601 unmonitored by PARMTEST at statement 0000000900,
instruction X'0000'.
CPA0702 MCH3601 received by procedure PARMTEST. (C D I R)
CHGVARコマンドがキャンセルされました。これは1つパラメーター値が与えられなかったためです。%PARMSを使用してこの問題を回避する方法を以下に示します。
pgm (&p1 &p2 &p3)
dcl &p1 *char 3
dcl &p2 *char 3
dcl &p3 *char 3
dcl &x1 *char 3 value('DFT')
dcl &x2 *char 3 value('DFT')
dcl &x3 *char 3 value('DFT')
dcl &msg *char 14
if (%parms *ge 1) then(ChgVar &x1 &p1)
if (%parms *ge 2) then(ChgVar &x2 &p2)
if (%parms *ge 3) then(ChgVar &x3 &p3)
ChgVar &msg ('/' *cat &x1 *cat ' ' *cat +
&x2 *cat ' ' *cat +
&x3 *cat '/')
SndPgmMsg msg(&msg) MsgType(*comp)
コードを書き直して、CHGVARコマンドがパラメーター変数を参照するのではなく、ローカル変数を参照するようにしました。パラメーターからローカル変数をロードしますが、それは、それらのパラメーターがプログラムに渡された場合だけです。それ以外の場合、ローカル変数はデフォルト値になります。
call PARMTEST (AAA BBB CCC)
/AAA BBB CCC/
call PARMTEST (AAA BBB)
/AAA BBB DFT/
call PARMTEST (AAA)
/AAA DFT DFT/
call PARMTEST
/DFT DFT DFT/
1つ目の問題は解決しました。今度は2つ目の問題を見てみましょう。
モジュールの問題
同じコードを検討しますが、今度はPARMTESTがプログラムではなく、モジュールとしてコンパイルされます。以下は、モジュールCALLERのソースコードです。これはモジュールPARMTESTを呼び出します。
pgm
CallPrc PARMTEST (AAA BBB CCC)
CallPrc PARMTEST (DDD EEE)
CallPrc PARMTEST (FFF)
CallPrc PARMTEST
endpgm
CRTCLMOD(Create CL Module:CLモジュールの作成)コマンド(PDMのオプション15)を使用して両モジュールを作成し、CRTPGMを使用してそれらを1つのプログラムにバインドします。
CRTCLMOD MODULE(MYLIB/PARMTEST) +
SRCFILE(QCLSRC) SRCMBR(PARMTEST)
CRTCLMOD MODULE(MYLIB/CALLER) +
SRCFILE(QCLSRC) SRCMBR(CALLER)
CRTPGM PGM(CALLER) MODULE(CALLER PARMTEST) +
ACTGRP(*NEW)
これでプログラムが作成されました。このプログラムを呼び出すと、結果は以下のようになります。
CALL CALLER
/AAA BBB CCC/
/DDD EEE CCC/
/FFF EEE CCC/
/FFF EEE CCC/
3つのパラメーターをすべて渡していなくても、CALLERは、3つすべてが渡されたとみなします。パラメーターを渡さないと、CALLERは以前の呼び出しのデータを使用します。そのデータへのポインターがたまたまメモリー内に残っているためです。これでは、誤った、予測できない、好ましくない結果が生じる可能性があります。
けれども、代わりに新バージョンのPARMTESTモジュールを使用すれば、以下のようになります。
CALL CALLER
/AAA BBB CCC/
/DDD EEE DFT/
/FFF DFT DFT/
/DFT DFT DFT/
%PARMSのおかげで、渡されていないパラメーターに対してデフォルト値を使用することができました。
MCH3601を監視する必要はあるでしょうか。さあどうでしょう。私がそうすることは、たぶんないでしょう。