ＲＰＧで動的配列

先日の投稿「[画面レコードを構造体で操作する](http://qiita.com/ushiday/items/703f62cfa8a00217389d)」で５２５０画面に入力履歴の機能を付けました。１０履歴固定で行ったので、今回は動的配列を使って可変でやった場合のサンプルです。
動的記憶域を使う場合は、ＲＰＧの命令とＢＩＦを使うか、ＡＰＩを使うパターンがあります。
今回は命令とＢＩＦを使ったパターンで、前者はデフォルトヒープが使用され、活動化グループに依存します。後者は、ユーザー自身が任意でヒープを作るパターンで、初期サイズや拡張サイズなどをコントロールする事が出来ます。
静的配列と動的配列の２つのプログラムをDSPPGMで確認すると静的記憶域のサイズが若干小さくなってます。
●静的配列
![2015-12-02_154805.png](https://qiita-image-store.s3.amazonaws.com/0/100029/9a163b65-d19d-556f-3cb8-adaebb5bc00b.png)

●動的配列
![2015-12-02_154905.png](https://qiita-image-store.s3.amazonaws.com/0/100029/5589df08-3db7-9083-62e0-6ccad37312a9.png)

```rpg:USR400A.rpgle
     H****************************************************************
     H*-------------------------------*
     H*----<<日付・著作権    >>-----*
     H*-------------------------------*
     H DATEDIT(*YMD)
     H COPYRIGHT('(C) CHUBU SYSTEM CO,.LTD 1996 - ')
     H*-------------------------------*
     H*----<<コンパイル条件  >>-----*
     H*-------------------------------*
     H DFTACTGRP(*NO) ACTGRP(*NEW)
     F*----<<ファイル定義   >>-----*
     FUSR400FM  CF   E             WORKSTN INDDS(INDICATORS)
     D*-----<<画面フィールド定義>>-----*
     D INDICATORS      DS
     D  KEY@END                        N   OVERLAY(INDICATORS:03)
     D  KEY@HST                        N   OVERLAY(INDICATORS:09)
     D*----<<変数定義 >>-----*
     D*現在の画面レコード
     D GCUR            DS                  LIKEREC(GAMEN1 :*ALL)
     D                                     INZ
     D*画面レコードの履歴
     D GHST            DS                  LIKEREC(GAMEN1 :*ALL)
     D                                     DIM(8192)
     D                                     BASED(GHST@)
     D*
     D DUPE            S               N
     D*
     D IX              S              4S 0 INZ
     D HSTNOW          S              4S 0 INZ
     D*
     D NOW             S              4S 0 INZ
     D ARYMAX          S              4S 0 INZ
     D EXTEND          C                   10
     D SIZE            S              9B 0 INZ
     C*-------------------------------*
     C*----<<メインルーチン  >>-----*
     C*-------------------------------*
      /FREE
           //画面履歴の配列を記憶域に割り振る
           ARYMAX += EXTEND  ;
           SIZE   = %SIZE(GHST) * ARYMAX ;
           GHST@  = %ALLOC(SIZE) ;
           FOR  IX = 1 TO ARYMAX         ;
               CLEAR GHST(IX) ;
           ENDFOR           ;

           DOW 1 = 1        ;
              WRITE GAMMSG      ;
              EXFMT GAMEN1 GCUR ;
              IF KEY@END       ;          //終了
                 LEAVE         ;
              ENDIF            ;
              IF KEY@HST       ;          //履歴取得
                 EXSR  @GETHST ;
                 ITER          ;
              ENDIF            ;

              EXSR  @CHK    ;             //入力チェック
              IF DUPE          ;          //エラー
                 ITER          ;
              ENDIF            ;

              EXSR  @SAVE   ;             //登録
           ENDDO            ;

           EXSR  @END    ;

           //入力チェック
           BEGSR  @CHK      ;
              DUPE = *OFF   ;
              //全く同じ内容があったらエラー
              FOR  IX = 1 TO NOW         ;
                IF GCUR = GHST(IX)   ;
                    DUPE = *ON    ;
                    GMEMSG = '履歴'
                           + %CHAR( NOW -IX + 1  )
                           + '回前と同じ内容' ;
                    LEAVE   ;
                ENDIF            ;
              ENDFOR           ;
           ENDSR            ;

           //画面内容保存
           BEGSR  @SAVE     ;
              NOW  += 1     ;
             //配列を拡張
              IF NOW > ARYMAX ;
                  ARYMAX += EXTEND  ;
                  SIZE = %SIZE(GHST) * ARYMAX ;
                  GHST@  = %REALLOC(GHST@ : SIZE)  ;
                  //要素を初期化
                  FOR  IX = NOW TO ARYMAX         ;
                      CLEAR GHST(IX) ;
                  ENDFOR           ;
              ENDIF ;
              EVAL-CORR GHST( NOW ) = GCUR  ;
              CLEAR GCUR ;
              GMEMSG = '入力内容を保存しました' ;
              HSTNOW = *ZERO ;
           ENDSR            ;

           //履歴を取得
           BEGSR  @GETHST   ;
              HSTNOW += 1 ;
              IF HSTNOW > NOW ;
                 HSTNOW = 1 ;
              ENDIF     ;
              EVAL-CORR GCUR = GHST( NOW - HSTNOW + 1 )  ;
              GMEMSG = '履歴'
                         + %CHAR( HSTNOW )
                         + '回前の履歴' ;
           ENDSR            ;

           //終了
           BEGSR  @END      ;

             //配列の記憶域解放
             DEALLOC  GHST@ ;

             *INLR = *ON    ;
              RETURN        ;
           ENDSR            ;

      /END-FREE 

```