ILE-RPG(その1)
ILE−RPGの最大の特長はバインドと呼ばれる、スタティック・リンク方式にあります。
この方式は、従来のダイナミック・リンク方式に比べ、リンクの際のオーバーヘッドが
軽減され、処理効率が大幅に向上します。
このページでは、従来のRPG(RPG-V)との相違点を中心に、
ILE−RPG(RPG-W)について紹介します。
サンプル
まず、RPG−VからRPG−Wへ、CVTRPGSRCコマンドで変換をしたサンプルを紹介します。
RPG−W
H*--------------------------------------------------------------- H* ID : LM420 H* NAME :担当者別得意先一覧 H*--------------------------------------------------------------- H DATEDIT(*YMD-) F*--------------------------------------------------------------- F*得意先マスターファイル FM420 IF E K DISK F*得意先一覧 FLM420P O E PRINTER OFLIND(*IN30) C*--------------------------------------------------------------- C*初期処理 C SETON 30 C READ M420R 99 C*本処理 +----C *IN99 DOWEQ *OFF | C MOVEL TKCDNO P1TKCD 得意先Y | C MOVEL TKNMKJ P1NMKJ 得意先名 | C MOVEL TKNMKN P1NMKN 得意先カナ | C MOVEL TKTEL P1TEL TEL | C MOVEL TKSLNO P1SLNO 担当営業Y | C MOVEL TKURJS P1URJS 売上実績額 |+---C *IN30 IFEQ *ON || C WRITE HDR01 || C SETOFF 30 |+---C ENDIF | C WRITE DTL01 | C* | C READ M420R 99 +----C ENDDO C*終了処理 C SETON LR C RETURN
RPG−V
**--------------------------------------------------------------- ** ID : LM420 ** NAME :担当者別得意先一覧 **--------------------------------------------------------------- H Y- F*--------------------------------------------------------------- F*得意先マスターファイル FM420 IF E K DISK F*得意先一覧 FLM420P O E 30 PRINTER C*--------------------------------------------------------------- C*初期処理 C SETON 30 C READ M420R 99 C*本処理 +----C *IN99 DOWEQ*OFF | C MOVELTKCDNO P1TKCD 得意先Y | C MOVELTKNMKJ P1NMKJ 得意先名 | C MOVELTKNMKN P1NMKN 得意先カナ | C MOVELTKTEL P1TEL TEL | C MOVELTKSLNO P1SLNO 担当営業Y | C MOVELTKURJS P1URJS 売上実績額 |+---C *IN30 IFEQ *ON || C WRITEHDR01 || C SETOF 30 |+---C ENDIF | C WRITEDTL01 | C* | C READ M420R 99 +----C ENDDO C*終了処理 C SETON LR C RETRN
ソースレコード様式の相違点
RPG-Vでは1行80バイトですが、RPG-Wでは1行100バイトに拡張されています。
フィールド名の長さは、最大14桁まで拡張されています。
各仕様書と仕様書コード
仕様書はファイル補足仕様書(E,L)が廃止され、定義仕様書(D)、プロシージャー仕様書(P)が
新しく設けられています。対応は次のとおりです。
RPG−III RPG−IV H H F F E D,I I D,I C C O O なし P
制御仕様書(仕様書コード:H)
固定カラム様式からキーワード・パラメータ記述の様式に改定されています。
例えば、日付編集様式がYMDで、その仕切り文字が/のとき、次のようになります。
....+... 1 ...+... 2 ...+... 3 ...+... 4...+... 5 ...+... 6 ...+... 7 ...+.
H DATEDIT(*YMD/)
ファイル仕様書(仕様書コード:F)
カラム様式のレイアウトが、改定されています。
カラム 項目 6桁 仕様書コード(F) 7〜16桁目 ファイル名
ファイル名は従来の8桁から10桁に拡張されています。17桁 ファイル・タイプ
I : 入力ファイル
O : 出力ファイル
U : 更新ファイル
C : 入出力共用ファイル18桁 ブランク :出力ファイル
P : プライマリーファイル
S : セカンダリーファイル
R : レコードアクセスファイル
T : 配列またはテーブルファイル
F : 全手順ファイル22桁 ファイル形式
F : プログラム記述ファイル
E : 外部記述ファイル23〜27桁 レコード長。プログラム記述の場合。 29〜33桁 キーの長さ。プログラム記述の場合。 34桁目 レコード・アドレス・タイプ
ブランク 相対レコード番号(RRN)を使用して処理。
K キー値を使用してファイルを処理。36〜42桁 装置
PRINTER
DISK
WORKSTN
SEQ
定義仕様書(仕様書コード:D)
カラム 項目 7〜21桁 変数名、配列名または構造名 24〜25桁 定義タイプ(C、DS、PI,PR,S) 26〜32桁 開始位置(FROM) 32〜39桁 終了位置(TO)または長さ 40桁 データタイプ 41〜42桁 少数点以下の桁数 44〜80桁 キーワードパラメータ
従来のファイル補足仕様で行っていた、配列/テーブルの定義や入力仕様書におけるデータ構造(DS)は
この部分で定義します。44桁から後に、自由形式のパラメータ記述ができるようになっています。
データのタイプとしては、アドレスを扱うポインター変数が新しく登場しています。
配列
配列の定義は、定義タイプは’S’とし、キーワードパラメータDIMで、要素数とともに定義します。
コンパイル時にデータをローディングするときは、パラメータCTDATAを与えます。
レコードあたりのデータ件数は、パラメータPERRCDで与えます。
以下に例を示します。
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+. D LDAY S 2 0 DIM(12) CTDATA PERRCD(12)
この例は、コンパイル時配列で、名称はLDAY、長さ2、少数点以下0のゾーン10進数データタイプで、
要素数は12です。データは1行あたり12個となっています。
データ構造
データ構造は、定義タイプ’DS’で構造名を定義し、所属要素(データ構造サブフィールド)を
それに引き続く行で、定義タイプ、ブランクで定義します。
所属要素の位置取りは開始位置、終了位置を指定する方法と、その要素の長さを指定する方法の
2種類が可能です。
要素の長さを指定する場合は、「終了位置」に指定し、開始位置はブランクにします。
データタイプには次のようなものがあります。(一部のみ紹介です)
コード タイプ ブランク 文字列 S ゾーン10進数 P パック10進数 B 2進数 * ポインター
初期値はキーワード・パラメータ INZで与えます。
以下に例を示します。
...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 DFLD444 DS D FLD01 6 D FLD02 12 INZ('111111111122') D FLD03 4 D AAA01 1 D AAA22 5 D BBB11 5S 0
基底付きデータ構造
基底付きデータ構造は、基底として与えられたポインター(アドレス)によって、割当てられる場所が変わるデータ構造です。
アセンブラーのDSECTに相当します。
次に示すのは、基底付きの構造の例です。
...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 DBASED1 DS BASED(PTR) D CCC11 6 D CCC22 12
上の例で、PTRはアドレスの入るポインター変数です。関数%ADDRによって基底アドレスの取得ができます。
ポインターはデータまたはデータ構造の有り場所を示すデータです。大きさは16バイトです。
世間では64ビットアドレスが最新ですが、ASでは大分前から128ビットアドレスになっています。
このポインターは権限のないプログラムが操作するとオールゼロになるようです。(ウィルス対策か?)
基底付き変数をあやつって、システムの奥の院まで侵入なんてことはできないようです。
RPG-Wでは%ADDRなどいくつかの新しい関数が使用できるようになっています。
独立変数
独立変数とは、構造に属していない単独の変数をいいます。COBOLでいえば、77項目に相当します。
定義タイプを’S’(スカラー)として、長さ、データタイプ、小数以下の桁数を指定して定義します。
初期値を与える場合は、キーワードINZで指定します。
以下に例を示します。いずれも5桁のパック10進数を定義しています。
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 D I S 5P 0 INZ(0) D J S 5P 0 D K S 5P 0 D L S 5P 0 D M S 5P 0 D N S 5P 0
可変長変数
可変長変数は長さの変わる文字列のための変数です。
定義はVARYING属性をつけて、次の例のようにします。
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 D VAR1 S 20A VARYING D VAR2 S 30A VARYING
楽屋裏では、2バイトの長さ情報+文字列の形でサポートしています。
可変長レコードのサポート
可変長レコードは、次のようにしてサポートできます。
1)可変長レコードのファイル定義
DDSでは定義できません。SQLのCREATE TABLEコマンドを使って定義します。
CREATE TABLE QTEMP/FILE1 (FLD01 VARCHAR (80 )
NOT NULL WITH DEFAULT)
この例では、1レコード1フィールドの可変長レコード(最大長80バイト)のファイルが定義されます。
2)プログラムでは、最大長80バイトの可変長フィールドを、1個だけからなる構造体を定義して
利用します。
以下に例を示します。
... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 H DATEDIT(*YMD-) FFILE1 O F 82 DISK * D FILE1R DS D VAR1 80A VARYING * C MOVEL *ALL'A' C10A 10 C MOVEL *ALL'B' C20A 20 C MOVEL *ALL'C' C30A 30 C EVAL VAR1= C10A C WRITE FILE1 FILE1R C EVAL VAR1= C20A C WRITE FILE1 FILE1R C EVAL VAR1= C30A C WRITE FILE1 FILE1R * C SETON LR C RETURN
注:
1)ファイル仕様書ではレコード長を80+2(=82)バイトで記述していることに注意してください。
2)レコードの構造体は最大長80バイトのVARYING属性の1フィールドの構造を定義しています。
3)変数VAR1にはEVAL命令でセットしていることに注意してください。
MOVELで値をセットすると、最初のMOVELでその長さが固定されてしまいます。
EVALであれば、長さの可変長属性が保たれます。
上記プログラムの実行結果は次のようになります。
先頭の2バイト(赤)が長さ情報となっていることに注意して下さい。
物理ファイル・メンバー表示
ファイル . . . : FILE1 ライブラリー . : QTEMP
メンバー . . . : FILE1 レコード . . . : 1
制御 . . . . . . 桁 . . . . . . : 1
検索 . . . . . .
* . . . + . . . . 1 . . . . + . . . . 2 . . . . + . . . . 3 . . . . . .
000AC1C1 C1C1C1C1 C1C1C1C1 40404040 40404040 40404040 40404040 40404040 40404040
0014C2C2 C2C2C2C2 C2C2C2C2 C2C2C2C2 C2C2C2C2 C2C24040 40404040 40404040 40404040
001EC3C3 C3C3C3C3 C3C3C3C3 C3C3C3C3 C3C3C3C3 C3C3C3C3 C3C3C3C3 C3C3C3C3 40404040
****** データの終わり ******
演算仕様書(仕様書コード:C)
様式の拡張
項目2の様式が2種類になっています。
RPGVからの拡張の様式
カラム様式の改訂に加え、さらに拡張様式で、「式」の記述ができるようになっています。
「式」とは評価(計算)をしたとき、最終的にある値を表わすものをいいます。
.....CL0N01FACTOR1+++++++OPCODE&EXTFACTOR2+++++++RESULT++++++++LEN++D+H C Z-ADD P@YMD W@YMD C W@YY DIV 04 W C MVR R
RPGW項目2の拡張様式
項目2が拡張されて、式を記述できるようになっています。
.....CL0N01FACTOR1+++++++OPCODE&EXTEXTENDED-FACTOR2++++++++++++++++++++ C IF AA = BB OR CC > DD C EVAL A = B**2 + C
フィールド名は14桁まで拡張されています。結果のフィールドも同様です。
添え字は、RPG−IIIでは
変数名,X
の形でしたが、RPG-IVでは
変数名(X)
の形になっています。
拡張された14桁のうち、10桁までは変数用にし、4桁分は添え字に使うことをおすすめします。
組込関数
式の記述に呼応して、各種の組込み関数が用意されています。
一部を紹介します。
関数名 機能 %SUBST 文字列の切出し %CHAR 文字列への変換 %SCAN 文字列の検索 %ADDR アドレスポインターの取得
命令
命令も拡張されています。いくつかを紹介します。
命令 機能 ALLOC メモリーの獲得(汎用機でのGETMAINマクロ相当) CALLB バインド済みプロシージャー呼び出し CALLP プロトタイププロシージャー/プログラムの呼び出し。 DOW WHILE型の繰返し DOU UNTIL型の繰返し EVAL 式の評価と割付。COBOLのCOMPUTE命令。
プロシージャーとサブ・プロシージャー
従来のRPGでのプログラムが、プロシージャーとサブ・プロシージャーの2タイプに別れています。
プロシージャーは従来のプログラムに相当し、RPGサイクルや実行のために必要なメモリーなどの
資源を準備するためのコードが付加されています。
サブ・プロシージャーは、呼び出され専門のプログラムといえます。
サブ・プロシージャーにはRPG独特のサイクルの部分はありません。
プロシージャーの一般構造は次のようになります。
プロシージャー 制御仕様書 H ファイル仕様書 F 定義仕様書 D 入力仕様書 I 演算仕様書 Cサブ・プロシージャー プロシージャー仕様書の始め P 定義仕様書 D 演算仕様書 C プロシージャー仕様書の終り P データ コンパイル時配列へのローディングデータ 仕様書コードなし
プロシージャー仕様書の始めから、同じく終りまでが、サブ・プロシージャーで、それ以外がメイン・プロシージャーです。
サブ・プロシージャー
サブ・プロシージャーは、メインプログラムの中に含まれるサブ・ルーチンで、開始のプロシージャー仕様書と
終了のプロシージャー仕様書で区切られます。
開始のプロシージャー仕様書は仕様書コード’P’で、24桁目が’B’、終了は同じく’E’です。
以下にサブ・プロシージャーを含むプログラムのサンプルを示します。
サブ・プロシージャーは複数あってもよいし、また、まったくなくてもかまいません。
なお、EXSRで呼び出す従来の内部サブルーチンも当然使用できます。
呼出使用で効率が一番よいのは内部サブルーチン、ついでサブ・プロジージャー、従来の(OPM)プログラムです。
以下に例を示します。
サンプル
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 H DATEDIT(*YMD-) D*---------------------------------------------------------------- D YMD1 S 6S 0 D YMD1A S 8S 0 D SUBY2K PR C *ENTRY PLIST C PARM YMD1C 6 C MOVE YMD1C YMD1 C CALLP SUBY2K C YMD1A DSPLY C SETON LR C RETURN P*. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 P* ここからサブプロシージャー P SUBY2K B C* C YMD1 IFGT 700000 C EVAL YMD1A = YMD1+ 19000000 C ELSE C EVAL YMD1A = YMD1+ 20000000 C ENDIF C RETURN P E
このサブプロシージャーでは、外側で定義した変数をそのままサブ・プロシージャーで使用し、
1900年代か2000年代かを判断しています。
サブ・プロシージャーの内部で、改めて定義仕様書(D仕様書)により変数の定義することもできます。
この場合、内部で定義した変数はそのサブ・プロシージャー内だけで、通用します。
(これは、PL/I のサブ・プロシージャーの場合と同じです。)
パラメータの受け渡し
外側で定義した変数を共用する方法のほかに、パラメータを定義してそれを介してデータを授受することも
できます。このためには、呼び出し側は、定義仕様書でプロトタイプと呼ばれる、受渡し情報を定義します。
プロトタイプの定義タイプは’PR’です。パラメータの形式情報は、その直後に続けて定義します。
例えば、SUBY2Kという名のサブ・プロシージャーで6S0、8S0(ゾーン10進数)のパラメータを受渡しする
場合のプロトタイプは次のようになります。
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 D SUBY2K PR D 6S 0 D 8S 0
受取り側は対応するパラメータプロシージャ・インターフェイス(PI)を定義します。
パラメータプロシージャ・インターフェイスは、定義タイプ’PI’として定義し、それにつづけて
各パラメータを定義します。
上記呼び出しを受ける場合のパラメータ・インターフェイスは次のようになります。
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 D SUBY2K PI D YMD2 6S 0 D YMD2A 8S 0
サンプル・プログラム
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 D* パラメータを使用してのプロシージャー呼び出し。 H DATEDIT(*YMD-) D*================================================================ D* プロトタイプの指定 D* 呼び出されるプログラムは 6S0 8S0 のパラメータを要求 D SUBY2K PR D 6S 0 D 8S 0 D*---------------------------------------------------------------- D YMD1 S 6S 0 D YMD1A S 8S 0 C*================================================================ C *ENTRY PLIST C PARM YMD1 C* C CALLP SUBY2K (YMD1:YMD1A) C* 6S0 8S0 C YMD1A DSPLY C YMD2A DSPLY C SETON LR C RETURN P*================================================================ P* ここからサブ・プロシージャー P SUBY2K B D* パラメータインターフェイス D SUBY2K PI D YMD2 6S 0 D YMD2A 8S 0 C* C YMD2 IFGT 700000 C EVAL YMD2A = YMD2+ 19000000 C ELSE C EVAL YMD2A = YMD2+ 20000000 C ENDIF C EVAL YMD1 = YMD1 C RETURN P E
スタティック・リンク
従来、外部プログラムを呼出し利用する場合は、ダイナミック(動的)リンクで、行っていました。
ILEの体系では、実行プログラム・オブジェクトの前に、プログラム・モジュールを作成し、
これをバインドして実行プログラム・オブジェクトを作成するようになっています。
すなわち、コンパイラーの役目はプログラム・モジュールを作成するところまでです。
バインドでは、どのコンパイラーが作り出したプログラム・モジュールも特別に区別すること
なく、実行プログラム・オブジェクトに組込まれます。これがILE(統合化言語環境)といわれる
ゆえんです。いわば、裏方の環境は激変していますが、表側からは激変というほどのことは
ありません。
スタティック・リンクにすると、ダイナミック・リンクの際に行っていた、SYSてMのいくつかの作業が
バインド時に行わなわれ、実行時に必要なくなるので、処理の効率がよくなります。
汎用機では当初から、コンパイル+リンクの形でスタティック・リンクが行われており、むしろ
ダイナミック・リンクは、どちらかというと例外的でした。AS/400では逆にダイナミック・リンクが
メインでしたが、ILEによってダイナミック・リンクのオーバーヘッドを取り除き、効率を高めようとする
ねらいと思われます。実測では約100倍となっています。
AS/400と汎用機の対応は次のようになります。
AS/400 汎用機 コンパイル コンパイル ↓ ↓ プログラム・モジュール オブジェクト ↓ ↓ バインド リンク・エディット ↓ ↓ 実行プログラム・オブジェクト ロードモ・ジュール
ILE−RPGのパフォーマンス
ある本に外部CALL命令を利用してのプログラム呼出しは莫大な「費用」がかかるので、・・・
という記述を見て、RPG-IIIによる外部CALL命令を使用した場合と、RPG-IVによるプロシージャー呼出しの
差を比較してみました。結果は下記のとおりで思わぬ大差がつきました。
LR(ラストレコード)標識をオフにしないでリターンさせるテクで、RPG−IIIをチューンナップした場合も
比較のためにあげています。
下はRPG-IVのプログラムの例です。呼出したプログラムからの戻りの値を出力したり、表示
したりはしていません。RPG-IIIも同様のプログラムでCALLによる外部プログラム呼出し
の個所が異なるだけです。(ソース省略)
200,000件の呼出しの結果は次のとおりです。ページアウトの影響をできるだけさけるため、
いずれも2回RUNして、2回目の値をとっています。時間の計測はそれほど正確ではありません。
RPG-III(SETON LRあり) 約45秒 RPG-III(SETON LRなし) 約6秒 RPG-IV 約1秒(もっと少ないかもしれません。)
マシンはAS/400−170,OSはV4.3.0です。
テストに使用したILE−RPGのソース
呼び出しプロシージャーは単なる回数稼ぎのプログラムです。
呼び出されるサブ・プロシージャーは日付の妥当性チェックのプログラムです。実戦使用に耐えます。
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 H*--------------------------------------------------------------- H DATEDIT(*YMD-) D*--------------------------------------------------------------- D LDAY S 2 0 DIM(12) CTDATA PERRCD(12) D LDAY2 S 2 0 DIM(02) INZ(3) D DS D W@YMD 1 8 0 D W@YY 3 4 0 D W@MM 5 6 0 D M 5 6 0 D W@DD 7 8 0 D P@RC S 1 D*-------------------------------------- D \CHKYMD PR D 8P 0 D 1 C*--------------------------------------------------------------- C *ENTRY PLIST C PARM P@CNT 6 C* 初期処理 C MOVE P@CNT W@CNT 6 0 C Z-ADD 900100 W@YMD C Z-ADD 000 X 6 0 C* ---------------------------------------------------------- C 001 DO W@CNT X C* C ADD 001 W@DD C W@DD IFGT 031 C Z-ADD 001 W@DD C ADD 001 W@MM C W@DD IFGT 013 C Z-ADD 001 W@MM C ADD 001 W@YY C ENDIF C ENDIF C* C Z-ADD W@YMD P@YMD 8 0 C CALLP \CHKYMD(P@YMD:P@RC) C* C ENDDO C* ---------------------------------------------------------- C SETON LR C RETURN P* ここからサブ・プロシージャー P \CHKYMD B D \CHKYMD PI D P@YMD 8P 0 D P@RC 1 D*--------------------------------------------------------------- D DS D W@YMD 1 8 0 D W@YY 3 4 0 D W@MM 5 6 0 D M 5 6 0 D W@DD 7 8 0 C*--------------------------------------------------------------- C* Z-ADD 0 X@MM(1) C Z-ADD LDAY2(2) X 7 0 C* 初期処理 C EXSR SBINZ C* 本処理 C EXSR SBMAIN C* 終了処理 C EXSR SBEND C*--------------------------------------------------------------- C SBINZ BEGSR C* 定義 C Z-ADD 000 W 7 0 C Z-ADD 00 R 7 0 C Z-ADD 00 LEAP 7 0 C* 閏年判定 C Z-ADD P@YMD W@YMD C W@YY DIV 04 W C MVR R C* 2月末日取得 C R IFEQ 00 C Z-ADD 01 LEAP C ELSE C Z-ADD 00 LEAP C ENDIF C ADD LEAP LDAY(2) C* C ENDSR C*--------------------------------------------------------------- C SBMAIN BEGSR C* 月チェック C W@MM IFLT 01 C W@MM ANDGT 12 C MOVE *ZERO P@RC C ELSE C* 日チェック C W@DD IFLT 01 C W@DD ANDGT LDAY(M) C MOVE *ZERO P@RC C ENDIF C ENDIF C* C ENDSR C*--------------------------------------------------------------- C SBEND BEGSR C* C SETON LR C RETURN C* C ENDSR P E ** LDAY ** 312831303130313130313031
プログラム・モジュールから実行プログラム作成
別々のコンパイル・タイミングで作成されたモジュールを組み合わせて、実行プログラムを作成する場合は
次のような手順になります。
手順1.モジュールの作成
CRTRPGMOD MODULE(WRKLIB/TESTR) /*サブのつもりです。*/
別のタイミングで(あるいは別の場所で)
CRTRPGMOD MODULE(WRKLIB/TESTRPG) /*メインのつもりです。*/
手順2.実行プログラムの作成
CRTPGM PGM(WRKLIB/TESTRPG) MODULE(WRKLIB/TESTRPG WRKLIB/TESTR) −
DETAIL(*BASIC)
手順3.実行
CALL WRKLIB/TESTRPG)
以下にサンプル・プログラムを示します。
メイン・プロシージャー
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 H DATEDIT(*YMD-) D*------------------------------------ D* プロトタイプの指定 D TESTR PR D 4A D 10I 0 D*------------------------------------ D AA S 4A D BB S 10I 0 C*------------------------------------ C MOVEL '1234' AA C Z-ADD 9876 BB C* C CALLP TESTR (AA: BB ) C AA DSPLY C BB DSPLY C SETON LR
サブ・プロシージャー
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 H NOMAIN DTESTR PR D AA 4A D BB 10I 0 PTESTR B EXPORT P* ****** D*------------------------------------ DTESTR PI D AA 4A D BB 10I 0 C*------------------------------------ C* C MOVEL 'ABCD' AA C BB DIV 2 BB C* C RETURN C SETON LR P E
サブ・プロシージャーにEXPORTパラメータをつけていることに注意して下さい。
これによって、入り口点TESTRが外部属性をもち、他のプロシージャーから見えるようになります。
EXPORTされていないと、外部からTESTRの入り口点が見えません。
CRTPGMでは一見ノーマルにバインドが完了するが、正常にRUNしません。(LOOPすることもある。)
(本来なら、バインドの際になんらかのメッセージがでて、しかるべきと思うのですが)
CLプロシージャーの呼び出し
サンプルのみ紹介します。
RPGによるメイン・プロシージャー
CLで扱える数値データはパック10進数のみです。
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 H DATEDIT(*YMD-) D*------------------------------------ D* プロトタイプの指定 D TESTCL PR D 4A D 09P 0 D*------------------------------------ D AA S 4A D BB S 09P 0 C*------------------------------------ C MOVEL '1234' AA C Z-ADD 9876 BB C* C CALLP TESTCL (AA: BB ) C AA DSPLY C BB DSPLY C SETON LR C RETURN
CLによるサブ・プロシージャー
PGM PARM(&AA &CC) DCL &AA *CHAR 4 DCL &CC *DEC 9 CHGVAR &AA VALUE('EFGH') CHGVAR &CC VALUE(&CC * 2) ENDPGM
プロトタイプについて
プロトタイプという一見わずらわしい宣言が呼び出し側にあります。
マニュアルには四の五のと説明がありますが、真相はコンパイルが別タイミングになるため、
呼び出し側からどのタイプのデータをパラメータとして準備して呼び出ししたらよいのかわからないので、
それをコンパイラーに知らせるためのもののようです。
たしか、はるかむかし、PL/1でも同じようなことがあったと記憶しています。
そのときのマニュアルには上記理由がきちんと書いてありました。そして、プロトタイプ(相当)を
記述しないと、呼び出しのときの属性でパラメータリストが作成されるとあったと思います。
関数型の呼び出し
ILE−COBOLにはSIN,COSなどの数学関数がいくつかあるのに、ILE−RPGには
それがありません。そのためにわざわざCOBOLを導入するのも、と数学関数COS,SINを作成し
関数呼出しをしてみました。SINはCOSの移相を90°ずらせただけです。
プロシージャーのサンプルを紹介します。
....+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 *関数型の呼出しと関数プロシージャー H DATEDIT(*YMD-) *--------------------------------------------------------------- *プロトタイプの指定 ↓戻り DCOS PR 8F D 8F * DSIN PR 8F D 8F *--------------------------------------------------------------- *WORKエリア指定 D A S 8F * D STR DS D XX 12S11 D DUMY1 1A D CX 12S11 D DUMY2 1A D SX 12S11 D DUMY3 1A D R 12S11 * D X S 8F *--------------------------------------------------------------- C CLEAR STR C EVAL X = 0.0 C EVAL XX = X C EVAL CX = COS(X) C EVAL SX = SIN(X) C EVAL R = SIN(X)*SIN(X) + COS(X)*COS(X) C STR DSPLY * C EVAL X = 3.141592/2.0 C EVAL XX = X C EVAL CX = COS(X) C EVAL SX = SIN(X) C EVAL R = SIN(X)*SIN(X) + COS(X)*COS(X) C STR DSPLY C '---' DSPLY * C* COS 0.0 --> 0.1 C Z-ADD 000 X C X DOWLT 0.1 C EVAL XX = X C EVAL CX = COS(X) C EVAL SX = SIN(X) C EVAL R = SIN(X)*SIN(X) + COS(X)*COS(X) C STR DSPLY C ADD 0.01 X C ENDDO C SETON LR C* C RETURN *================================================================= *ここから自作関数 PCOS B *関数型の戻りを示す ↓ DCOS PI 8F D X 8F * D T S 8F D Y S 8F D WK S 8F D N S 7P 0 C*--------------------------------------------------------------- C Z-ADD 001 Y C Z-ADD 001 T C Z-ADD 001 N *テーラー展開による計算 C 001 DO 999 N C EVAL T = -T*X*X/((2*N)*(2*N-1)) *絶対値を取得 C Z-ADD T WK C T IFLT 0 C 0 SUB T WK C ENDIF * C WK IFLE 0.1E-11 C LEAVE C ELSE C EVAL Y = Y + T C ENDIF C ENDDO C RETURN Y PCOS E *---------------------------------------------------------------- PSIN B *関数型の戻りを示す ↓ DSIN PI 8F D X 8F * D Y S 8F D W S 8F C*--------------------------------------------------------------- C EVAL W = X -3.14159265/2.000000000000 C EVAL Y = COS(W) C RETURN Y PSIN E
計算はテーラー展開による多項式の近似計算を行っています。
近似したかどうかは、高次項の計算結果が、十分0に近いかどうかで判定しています。
計算は倍精度の浮動小数点(FORTRANではREAL*8相当)で行っています。
プロトタイプおよび独立変数(スカラー)の定義に8Fとあるのが浮動小数点の定義です。
関数型の中にある、定数0.1E−10は0.1*10のマイナス10乗、すなわち
0.00000000001のことです。まちがっても、0.0とやらないでください。
近似のための繰返しはせいぜい12、3回です。あたえるパラメータの値によって繰り返し回数はかわります。
◆原子力コードによるシミュレーションでもないかぎり、十分実用に耐えるはずです。
プログラムのコンパイル
このプログラムのコンパイルは、モジュール経由でバインドするのでないので、
(すなわち、一気に実行プログラムをつくるので、)CRTBNDRPGで行います。
DFTACTGRPパラメータを*NOとすることを忘れないで下さい。
関数型呼出しの要点
1.呼出し側のプロトタイプ指定で戻りのデータ属性をつけます。
2.呼出しは、EVAL命令でY=COS(X)のように関数型の呼出しをします。
3.関数型のサブプロシージャーではインターフェイスで戻りのデータ属性をつけます。
4.同プロシージャーの中では、RETURN Yのように戻す式を指定します。
近いうちに、TAN,LOG,LOG10など作ってみたいと思っています。
次ページへ 目 次 へ
(C)COPYRIGHT ISHIOKA KATSUHIDE 2000、2011