ILE RPG サブプロシージャの使い方 (2) - サブプロシージャからサブプロシージャを呼び出す -

ILE RPG サブプロシージャの使い方 (1) - C の関数との類似性 -」で ILE RPG のサブプロシージャが C の関数と同じようなものであることを見ました。

今回は、違いについて、です。
C の関数ではできてしまう関数内の関数の定義が ILE RPG ではできないようになっていることの紹介です。


サブプロシージャからサブプロシージャを呼び出す

今度は↓のプログラムを見てみてください。
(「C による統計データ解析入門」からの続きの例題です)

/* Program 2-4(順列数計算のプログラム) */

#include <stdio.h>
double factorial(int n);
double perm(int m, int n);

void main( )
{
  double k;
  int n, r;
    n=5;
    r=2;
    k=perm(n,r);
    printf("P(%d",n);
    printf(",%d",r);
    printf(")=%f\n",k);
}


double factorial(int n)
{
   int i, m;
   double k;
   k=1;
     if(n == 0) 
     m=1;
     else 
     m=n;
   for(i=1; i<=m; i++) 
   k=k*i;
     return k;
}

double perm(int n, int r)
{
  int nr; 
  double n1, nr1, p; 
    nr = n - r;
    n1 = factorial(n);
    nr1 = factorial(nr);
    p = n1 / nr1;
     return p;
}

perm という名の新たな関数が定義され、その中から、その前のプログラムからの流用である factorial 関数を使用しています。
C では、関数をさらに別の関数から使用できることの例として↑のようなコーディングがされているのでしょう。

現実の開発では、ひとつのプログラムの中のプライベートな関数の中でさらにそのプライベートな関数を使用する、というのはあまり実際的なものとは言えません。プログラムを大きく、複雑なものにしてしまいがちです。
ひとつのプログラムの中で共有されるようなものであれば、他のプログラムでも共有できる可能性は高く、きちんとそのことを踏まえた設計をした方がいいわけですね。(実際、この本でも例題が進むとそうなっています)

ILE RPG では、はじめからこのようなプライベートな関数の中でさらにプライベートな関数を使う、というようなことはできないようになっています。

あるサブプロシージャからサブプロシージャを使いたい、といった場合はそのモジュールを独立させる必要があります。
別のソースに記述し、別のモジュールとしてコンパイルする必要があるわけですね。

"ローカル"なサブプロシージャから共有可能なモジュールへ

の ILE RPG のコーディング例から、"Factorial" 関数(サブプロシージャ)を「プライベート(ローカル)」なものから独立した共有可能な「モジュール」に変更してみましょう。

処理部分はそのまま利用可能です。
つまり、モジュールとして独立させるために、処理自体に特別な手を入れることは必要ありません。

サブプロシージャ記述の開始/終了

まず、の最後にある

     Pfactorial        B                                                                            

     Pfactorial        E                                                                            

で囲まれた部分(= プロシージャの記述)を切り出します。

     Pfactorial        B                                                                            
     Dfactorial        PI             8f                                                            
     D n                             10i 0                                                          
     D i               S             10i 0                                                          
     D m               S             10i 0                                                          
     D k               S              8f                                                            
      *                                                                                             
      /free                                                                                         
                                                                                                    
          k = 1 ;                                                                                   
                                                                                                    
          if n = 0 ;                                                                                
             m = 1      ;                                                                           
          else ;                                                                                    
             m = n ;                                                                                
          endif ;                                                                                   
                                                                                                    
          for i = 1 to m ;                                                                          
             k = k*i;                                                                               
          endfor ;                                                                                  
                                                                                                   
          return k ;                                                                                
                                                                                                    
      /end-free                                                                                     
     Pfactorial        E                                                                            

プロトタイプ宣言

その前にプロトタイプ宣言の記述を追加します。

     Dfactorial        PR             8f                                                            
     D p1                            10i 0                                                          

↓のプロシージャ・インターフェイスと比べるとわかりますが、プロトタイプ宣言には引数名の定義は必須ではありません。
引数のデータ型とサイズ、そして引数をいくつ取るかが、呼び出しに必要な情報ですね。ですから↑では p1 という適当な名前をつけてありますが、ここは空欄でもいいんです。

     Dfactorial        PI             8f                                                            
     D n                             10i 0                                                          

こんなかんじに空欄でもいいんですね。

     Dfactorial        PR             8f                                                            
     D                               10i 0                                                          

とは言うものの、呼び出しのためにわかりやすい名前をつけておくに越したことはありません。(p1 というのもあんまりいい名前ではないですね)

単体では実行できなくてよい

このプロシージャは他のプログラムから呼び出されることがお仕事で、単体で実行可能な"プログラム"ではありません。
最初にその旨を宣言する一文を追加します。

     H NOMAIN                                                                                       
※C や Java ではコマンドライン等から直接実行できるモジュールには main 関数/ main メソッドを記述する必要がありますが、ILE RPG の場合は逆に普通に作成したプログラムは直接実行可能で、コンパイラが自動的に main 関数を挿入してくれるようなイメージになっています。
こうした他のモジュールから呼び出されるだけの機能しかないのであれば、その「直接実行可能である」という機能は必要ないので、「main の挿入は必要ない」といった意味で NOMAIN と指定するわけです。

外部から呼び出せるようにする

他のプログラムから "factorial" として呼び出されるようにするため、EXPORT キーワードをプロシージャ記述の最初に追加します。
C の extern 宣言と同じようなものですね。

     Pfactorial        B                   EXPORT                                                   

全文

まとめると、全体としては↓のようなかんじになります。

      *                                                                                             
      * CRTRPGMOD MODULE(FACTORIAL) SRCFILE(QRPGLESRC) DBGVIEW(*SOURCE)                             
      *                                                                                             
     H NOMAIN                                                                                       
      *                                                                                             
     Dfactorial        PR             8f                                                            
     D p1                            10i 0                                                          
      *                                                                                             
     Pfactorial        B                   EXPORT                                                   
     Dfactorial        PI             8f                                                            
     D n                             10i 0                                                          
     D m               S             10i 0                                                          
     D i               S             10i 0                                                          
     D k               S              8f                                                            
      *                                                                                             
      /free                                                                                         
                                                                                                    
          k = 1 ;                                                                                   
                                                                                                    
          if n = 0 ;                                                                                
             m = 1      ;                                                                           
          else ;                                                                                    
             m = n ;                                                                                
          endif ;                                                                                   
                                                                                                    
          for i = 1 to m ;                                                                          
             k = k*i;                                                                               
          endfor ;                                                                                  
                                                                                                    
          return k ;                                                                                
                                                                                                    
      /end-free                                                                                     
     Pfactorial        E                                                                            

作成方法

CRTRPGMOD コマンドでモジュールとしてコンパイルします。

サブプロシージャから(共有)サブプロシージャを使用する

Factorial サブプロシージャは共有化されるので、呼び出す側にはその処理の記述は必要なくなります。

Perm サブプロシージャの中からだけの使用なので、perm サブプロシージャ記述の中に factorial サブプロシージャのプロトタイプ定義を記述することになります。

プロトタイプ定義さえあれば、使用するサブプロシージャの仕様がわかります。
このモジュールをコンパイルする際、コンパイラがその呼び出しの妥当性チェックをすることができるわけですね。

の例(TESTF プログラム)と、メイン・プロシージャとサブプロシージャがそれぞれ 1つづつで構成されている、という構造はまったく同じになりました。
違いは、そのサブプロシージャの中にプロトタイプ定義がある、ということだけです。

ILE RPG ではじめからこのようなプライベートな関数の中でさらにプライベートな関数を使う、というようなことはできないようになっています」ということの意味は、サブプロシージャ記述の中にプロトタイプ定義をすることはできるがサブプロシージャ自体の記述をすることはできないようになっている、ということなんですね。

TESTFP1

      *                                                                                             
      * CRTRPGMOD MODULE(TESTFP1) SRCFILE(QRPGLESRC) DBGVIEW(*SOURCE)                               
      * CRTPGM PGM(TESTFP1) MODULE(TESTFP1 FACTORIAL)                                               
      *                                                                                             
     DPerm             PR             8f                                                            
     D p1                            10i 0                                                          
     D p2                            10i 0                                                          
      *                                                                                             
     D k               S             10i 0                                                          
     D r               S             10i 0                                                          
     D n               S             10i 0                                                          
      *                                                                                             
      /free                                                                                         
                                                                                                    
          n = 5 ;                                                                                   
          r = 2 ;                                                                                   
          k = perm(n : r) ;                                                                         
          dsply  %char(k) ;                                                                         
          return ;                                                                                  
                                                                                                    
      /end-free                                                                                     
      *                                                                                             
     PPerm             B                                                                            
     DPerm             PI             8f                                                            
     D n                             10i 0                                                          
     D r                             10i 0                                                          
      *                                                                                             
     D nr              S             10i 0                                                          
     D n1              S              8f                                                            
     D nr1             S              8f                                                            
     D p               S              8f                                                            
      *                                                                                             
     DFactorial        PR             8f                                                            
     D p1                            10i 0                                                          
      *                                                                                             
      /free                                                                                         
                                                                                                    
          nr = n - r ;                                                                              
                                                                                                    
          n1 = factorial(n) ;                                                                       
          nr1 = factorial(nr) ;                                                                     
          p = n1/nr1 ;                                                                              
                                                                                                    
          return p ;                                                                                
                                                                                                    
      /end-free                                                                                     
     Pperm             E                                                                            
      *                                                                                             

CRTRPGMOD コマンドでモジュールを作成後、

先に作っておいた Factorial モジュールと CRTPGM コマンドを使用してバインドすると、実行可能プログラムとなります。

考慮点

ソースの内部にサブプロシージャを定義する場合と、共有化して外部に記述する場合の違いをいくつか挙げてみましょう。

まず、↑で述べたように、

が大きな利点として挙げられると思います。

ちょっと気をつける必要があるのが、

ということですね。

同一のプログラム内(別々にコンパイルはしませんよね)なので当然といえば当然なのですが、
独立させた場合は原則として引数として受け取った変数(↓の n )と

     Dfactorial        PI             8f                                                            
     D n                             10i 0                                                          

戻り値(↑の PI に定義されている 8F の値、で↓の return で返されている k がそれにあたります)

          return k ;                                                                                

がメインプログラムとのインターフェイスになります。
(今回は 1つのフィールドだけですが、もちろんもっと複雑なものを返すこともできます)

こうした、やり取りをきちんと限定して独立性を高める、というのがモジュール性を高める、ということになりますね。
Java のクラスなどでも同様です。

同一ソースに記述した時の、呼び出し元の変数(グローバル変数)を変更できてしまう、というのは決して利点ではありません。(今回も利用していませんね)
そのあたりはぜひ気をつけたいところですね。

[Top Pageに戻る]

Ads by TOK2