V5R3 での CL の拡張 (V5R2 でも動きます!)

V5R3 では CL にずいぶんいろんな拡張がありました。
いろんなものがありますが、やはりかなりインパクトがあるのは、DO ループや SELECT 文といった構造化プログラミングの要素が取り入れられたことでしょう。(何をいまさら ... なんて言わないでくださいね ... )

今回の拡張ですごいのは、この CL の拡張の恩恵を V5R2 のシステムで受けられることでしょう。
V5R3 側に SI13505/SI13408/SI13509 を適用し、V5R2 側には SI13416/SI13417 を適用することで、V5R3 で新しくサポートされるようになった機能を使った CL を TGTRLS(*PRV) でコンパイルするだけで、V5R2 のシステム上で動かすことができます。SE15114 を参照してみてください。

もちろん、開発は V5R3 のシステムでしかできません。つまりプログラムの TGTRLS(*PRV) で正しくコンパイルさせるために V5R3 側での PTF が必要で、そのコンパイルされたプログラムの実行環境として V5R2 側の PTF が必要になります。
実際に以下の一連の例は V5R3 のシステムでコンパイルし、V5R2 のシステムで実行したもののスクリーンショットです。

ちなみに V5R2 のシステムで RTVCLSRC は正しく行えます。もちろん RTV された CL のソースをコンパイルすることはできませんが ...


SELECT 〜 WHEN/OTHERWISE と DOUNTIL を使ったメニュー処理プログラムの例

まず最初に SELECT 〜 WHEN と DOUNTIL の紹介から始めてみましょう。

たとえば、これを使うと、メニュータイプの画面の処理がとってもシンプルになります。

以下のようなメニュー画面があったとしましょう。

DDS のソースとしては以下のようになります。

この画面の SNDRCVF にたいして、SELECT WHEN で OPTION という DDS 上のフィールドの値に応じて WHEN でコマンド (通常は CALL コマンドで該当プログラムを呼ぶことになると思います) を実行させるようにします。

DOUNTIL で F3 キーの標識がオンになるまでのあいだ、ループするようにしています。つまり、F3 キーが押されたら終了する、ということですね。

V5R2 のシステムでも実行させるのであれば CRTCLPGM に TGTRLS(*PRV) オプションを指定するのを忘れずに。

また、OTHEWISE で、メニューに入力されたものが WHEN で設定されているどれでもなかった場合の処理を指定することができます。

以下の例では、たとえば 4 や 5 などを入力した場合は WRKJOB コマンドが実行されます。

こちらが CL プログラムのソース全文です。

             PGM                                                                
             DCLF       FILE(MENU1)                                             
             DOUNTIL    COND(&IN03)                                             
             SNDRCVF                                                            
             SELECT                                                             
             WHEN (&OPTION = '1') THEN(WRKACTJOB)                               
             WHEN (&OPTION = '2') THEN(WRKSYSSTS)                               
             WHEN (&OPTION = '3') THEN(WRKSYSACT)                               
             OTHERWISE  CMD(WRKJOB)                                             
             ENDSELECT                                                          
             ENDDO                                                              
             RETURN                                                             
             ENDPGM                                                             

単にいろんなループのテスト

DO ループ等の処理をテストするために、以下のようなプログラムも作ってみました。

             DCL        VAR(&INTF) TYPE(*INT) LEN(2)                            
             DCL        VAR(&INTU) TYPE(*INT) LEN(2)                            
             DCL        VAR(&INTW) TYPE(*INT) LEN(2)                            
             DCL        VAR(&INTC) TYPE(*CHAR) LEN(2)                           
             DCL        VAR(&LGLW) TYPE(*LGL)                                   
             DCL        VAR(&MSG) TYPE(*CHAR) LEN(128) +                        
                          VALUE('This message is sent by')                      
             DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(128)                       
    /* DOFOR FROM 1 TO 10 INCREMENT BY 1 */                                     
             DOFOR      VAR(&INTF) FROM(1) TO(10) BY(1)                         
             CHGVAR     VAR(&INTC) VALUE(&INTF)                                 
             CHGVAR     VAR(&MSGDTA) VALUE(&MSG |< ' DOFOR. ' || +              
                          &INTC |< ' times')                                    
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(&MSGDTA)            
             ENDDO                                                              
    /* DOUNTIL &INT GT 10 INCREMENT BY 1 */                                     
    /* AT LEAST 1 STATEMENT WILL BE EXECUTED */                                 
             CHGVAR     VAR(&INTU) VALUE(1)                                     
             DOUNTIL    COND(&INTU > 10)                                        
             CHGVAR     VAR(&INTC) VALUE(&INTU)                                 
             CHGVAR     VAR(&MSGDTA) VALUE(&MSG |< ' DOUNTIL. ' || +            
                          &INTC |< ' times')                                    
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(&MSGDTA)            
             CHGVAR     VAR(&INTU) VALUE(&INTU + 1)                             
             ENDDO                                                              
    /* DOWHILE UNTIL &LGL IS SET TO FALSE */                                    
             CHGVAR     VAR(&INTW) VALUE(1)                                     
             CHGVAR     VAR(&LGLW) VALUE('1')                                   
             DOWHILE    COND(&LGLW)                                             
             CHGVAR     VAR(&INTC) VALUE(&INTW)                                 
             CHGVAR     VAR(&MSGDTA) VALUE(&MSG |< ' DOWHILE. ' || +            
                          &INTC |< ' times')                                    
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(&MSGDTA)            
             CHGVAR     VAR(&INTW) VALUE(&INTW + 1)                             
             CHGVAR     VAR(&LGLW) VALUE('0')                                   
             ENDDO                                                              
    /* SAMPLE OF LEAVE */                                                       
    /* DOUNTIL &INT GT 10 INCREMENT BY 1 */                                     
    /* AT LEAST 1 STATEMENT WILL BE EXECUTED */                                 
             CHGVAR     VAR(&INTU) VALUE(1)                                     
             DOUNTIL    COND(&INTU > 10)                                        
             CHGVAR     VAR(&INTC) VALUE(&INTU)                                 
             CHGVAR     VAR(&MSGDTA) VALUE(&MSG |< ' DOUNTIL. ' || +            
                          &INTC |< ' times')                                    
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(&MSGDTA)            
             IF         COND(&INTU = 5) THEN(LEAVE CMDLBL(*CURRENT))            
             CHGVAR     VAR(&INTU) VALUE(&INTU + 1)                             
             ENDDO                                                              
    /* SAMPLE OF ITERATE */                                                     
    /* DOUNTIL &INT GT 10 INCREMENT BY 1 */                                     
    /* AT LEAST 1 STATEMENT WILL BE EXECUTED */                                 
    /* NEXT SAMPLE LINES CAUSE LOOP (&INTU NEVER BE UP 5) +                     
             CHGVAR     VAR(&INTU) VALUE(1)               +                     
             DOUNTIL    COND(&INTU > 10)                  +                     
             CHGVAR     VAR(&INTC) VALUE(&INTU)           +                     
             CHGVAR     VAR(&MSGDTA) VALUE(&MSG |< ' DOUNTIL. ' || +            
                          &INTC |< ' times')              +                     
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +          
             IF         COND(&INTU = 5) THEN(ITERATE CMDLBL(*CURRENT))+         
             CHGVAR     VAR(&INTU) VALUE(&INTU + 1)                  +          
             ENDDO                                                   +          
             */                                                                 

実行するとループの中が実行される度にメッセージが表示されるようになっています。
実行結果はこんなかんじになります。

DOFOR の例です。

FROM でカウントの最初の数、TO でカウントをいくつまで、BY で増分の指定ができます。

    /* DOFOR FROM 1 TO 10 INCREMENT BY 1 */                                     
             DOFOR      VAR(&INTF) FROM(1) TO(10) BY(1)                         
             CHGVAR     VAR(&INTC) VALUE(&INTF)                                 
             CHGVAR     VAR(&MSGDTA) VALUE(&MSG |< ' DOFOR. ' || +              
                          &INTC |< ' times')                                    
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(&MSGDTA)            
             ENDDO        

DOUNTIL の例です。

条件の指定のみですね。
DOUNTIL は DO の内容を一回は実行し、その結果をもとに次の実行をするかどうかをループさせます。

    /* DOUNTIL &INT GT 10 INCREMENT BY 1 */                                     
    /* AT LEAST 1 STATEMENT WILL BE EXECUTED */                                 
             CHGVAR     VAR(&INTU) VALUE(1)                                     
             DOUNTIL    COND(&INTU > 10)                                        
             CHGVAR     VAR(&INTC) VALUE(&INTU)                                 
             CHGVAR     VAR(&MSGDTA) VALUE(&MSG |< ' DOUNTIL. ' || +            
                          &INTC |< ' times')                                    
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(&MSGDTA)            
             CHGVAR     VAR(&INTU) VALUE(&INTU + 1)                             
             ENDDO                                                              

DOWHILE の例です。

やはり条件の指定をします。
条件が満たされなかったら最初から DO の内容を実行はしません。

    /* DOWHILE UNTIL &LGL IS SET TO FALSE */                                    
             CHGVAR     VAR(&INTW) VALUE(1)                                     
             CHGVAR     VAR(&LGLW) VALUE('1')                                   
             DOWHILE    COND(&LGLW)                                             
             CHGVAR     VAR(&INTC) VALUE(&INTW)                                 
             CHGVAR     VAR(&MSGDTA) VALUE(&MSG |< ' DOWHILE. ' || +            
                          &INTC |< ' times')                                    
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(&MSGDTA)            
             CHGVAR     VAR(&INTW) VALUE(&INTW + 1)                             
             CHGVAR     VAR(&LGLW) VALUE('0')                                   
             ENDDO                       

LEAVE と ITERATE の例です。

10 回のカウントに達するまでループする DOUNTIL の中で、カウントが 5 に達した時に LEAVE するケース (前半) と ITERATE するケース (後半) を記述してみました。
後半 (ITERATE のケース) は無限ループに入ってしまうのでコメントアウトしてあります。

    /* SAMPLE OF LEAVE */                                                       
    /* DOUNTIL &INT GT 10 INCREMENT BY 1 */                                     
    /* AT LEAST 1 STATEMENT WILL BE EXECUTED */                                 
             CHGVAR     VAR(&INTU) VALUE(1)                                     
             DOUNTIL    COND(&INTU > 10)                                        
             CHGVAR     VAR(&INTC) VALUE(&INTU)                                 
             CHGVAR     VAR(&MSGDTA) VALUE(&MSG |< ' DOUNTIL. ' || +            
                          &INTC |< ' times')                                    
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(&MSGDTA)            
             IF         COND(&INTU = 5) THEN(LEAVE CMDLBL(*CURRENT))            
             CHGVAR     VAR(&INTU) VALUE(&INTU + 1)                             
             ENDDO                                                              
    /* SAMPLE OF ITERATE */                                                     
    /* DOUNTIL &INT GT 10 INCREMENT BY 1 */                                     
    /* AT LEAST 1 STATEMENT WILL BE EXECUTED */                                 
    /* NEXT SAMPLE LINES CAUSE LOOP (&INTU NEVER BE UP 5) +                     
             CHGVAR     VAR(&INTU) VALUE(1)               +                     
             DOUNTIL    COND(&INTU > 10)                  +                     
             CHGVAR     VAR(&INTC) VALUE(&INTU)           +                     
             CHGVAR     VAR(&MSGDTA) VALUE(&MSG |< ' DOUNTIL. ' || +            
                          &INTC |< ' times')              +                     
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(&MSGDTA) +          
             IF         COND(&INTU = 5) THEN(ITERATE CMDLBL(*CURRENT))+         
             CHGVAR     VAR(&INTU) VALUE(&INTU + 1)                  +          
             ENDDO                                                   +          
             */                                                      

サンプルプログラムの実行結果の最後の部分です。

LEAVE のケースの結果に該当していますが、LEAVE はループの外に出る、という命令ですのでちゃんと 5回で終わっていますね。

ITERATE の場合は DO ループの条件部分に戻ります。この例ではカウントが 5 になった時に ITERATE が実行される (IF の後のカウントアップは実行されない) ので、DOUTIL が 10 以下であるという条件には常に合致し続けてしまいます。それで無限ループになってしまうわけですね。

(今回、この例は LEAVE と ITERATE がどう違うかをわかりやすく見るためだけの例です。特にそれ以外の意図はありませんのでご容赦を)


TGTRLS(*PRV) を忘れずに!

V5R2 にコンパイル済みの CL プログラムを配布する時には SAVOBJ/SAVLIB にも TGRLS(*PRV) を忘れずに指定しましょう。復元できませんよ。

[Top Pageに戻る]

Ads by TOK2