IBM i (旧AS400）の自己学習メモ０６　CLプログラム（Control Language） Part4

# 自己学習メモインデックス

[IBM i (旧AS400）の自己学習メモ　インデックス](https://qiita.com/You_name_is_YU/items/3964849e7803c8eaf767)

# 概要

CLプログラムサンプルをため込んでいこうの第2弾。

# CLサンプルプログラム

## *DEC型を利用した計算

DCLで定義する際のTYPEに指定するデータ型で、*DECを利用した際の計算処理の結果を出力するサンプルです。
ちなみに、*DECはIBMのサイトで以下のように説明されていました。

> パック10進数値を含む10進変数。

参考：https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_73/cl/dcl.htm#DCL.TYPE

自分が無知なんだと思うのですが、何言ってんのかよくわかりませんでした。
Javaなどのプログラミング言語の経験はあるので、イメージとしては小数点を含んだ数値を扱うことのできる、floatやdoubleの位置付けに近いものかなと思っています。

ただ、LEN(n m)と、全体の桁数と小数点の桁数を指定しなければならず、Oracleのnumber型と定義の方法が似ているので、そんな感じかなと思っています。

```shell:PGM
 FMT **  ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00              PGM                                                                                    
0002.00              DCL        VAR(&PRICE) TYPE(*DEC) LEN(10 0) VALUE(158)                                 
0003.00              DCL        VAR(&TAX) TYPE(*DEC) LEN(3 2) VALUE(0.10)                                   
0004.00              DCL        VAR(&AMOUNT) TYPE(*DEC) LEN(12 2)                                           
0005.00 START:                                                                                              
0006.00              CHGVAR     VAR(&AMOUNT) VALUE(&PRICE + &PRICE * &TAX)                                  
0007.00              SNDPGMMSG  MSG('The calculation result is' *BCAT +                                     
0008.00                           %CHAR(&AMOUNT))                                                           
0009.00              RETURN                                                                                 
0010.00 END:                                                                                                
0011.00              ENDPGM                                                                                 
        ****************** End of data *********************************************************************
```

```shell-session:出力結果
The calculation result is 173.80
```

## *INT型を利用した計算

DCLで定義する際のTYPEに指定するデータ型で、*INTを利用した際の計算処理の結果を出力するサンプルです。
*INTはIBMのサイトで以下のように説明されていました。

> 符号付き2進値を含む整変数。

参考：https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_73/cl/dcl.htm#DCL.TYPE

*DECよりはまだなんとなく分かる。。。
整変数→整数なんでしょ？小数点を扱わない数値型なんでしょ？という感じ。

計算は*DECのサンプルと同じ数値を利用して計算しているため、出力結果として`173.80`が`173`に丸められて出ているのが分かる。
特に意識しない場合、小数点以下の数値は切り捨てられるんですね。

`%DECH`という組み込み関数を使うことで、四捨五入ができるような記事があるのですが、
これってCLだと使えないんでしょうか？
CLだと四捨五入ってどうやるんだろう・・・

```shell:PGM
 FMT **  ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 ...+... 9 ...+... 0 
        *************** Beginning of data *******************************************************************
0001.00              PGM                                                                                     
0002.00              DCL        VAR(&PRICE) TYPE(*DEC) LEN(10 0) VALUE(158)                                  
0003.00              DCL        VAR(&TAX) TYPE(*DEC) LEN(3 2) VALUE(0.10)                                    
0004.00              DCL        VAR(&AMOUNT) TYPE(*INT)                                                      
0005.00 START:                                                                                               
0006.00              CHGVAR     VAR(&AMOUNT) VALUE(&PRICE + &PRICE * &TAX)                                   
0007.00              SNDPGMMSG  MSG('The calculation result is' *BCAT +                                      
0008.00                           %CHAR(&AMOUNT))                                                            
0009.00              RETURN                                                                                  
0010.00 END:                                                                                                 
0011.00              ENDPGM                                                                                  
        ****************** End of data **********************************************************************
```

```shell-session:出力結果
The calculation result is 173
```

## IF/ELSE IFの条件分岐

ELSE IFの書き方としては２パターンあるようで、F4キーを押下してコードを自動保管し、整形してしまうとPattern1のようなごちゃごちゃしたコードになってしまう。
こういうときは、行コピー＆ペーストでIF文をコピーして、その左側にELSEを添えてあげ、F4キーに頼らないようにすれば、少し見やすいコードになる。

```shell:PGM
 FMT **  ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00              PGM                                                                                    
0002.00              DCL        VAR(&PWD) TYPE(*CHAR) LEN(10) VALUE('Pwd01')                                
0003.00              DCL        VAR(&DIV) TYPE(*CHAR) LEN(1) VALUE('3')                                     
0004.00 START:                                                                                              
0005.00 /* IF ELSE */                                                                                       
0006.00              SNDPGMMSG  MSG('Section IF ELSE')                                                      
0007.00              IF         COND(&PWD = 'Password01') THEN(DO)                                          
0008.00              SNDPGMMSG  MSG('Success!')                                                             
0009.00              ENDDO                                                                                  
0010.00              ELSE       CMD(DO)                                                                     
0011.00              SNDPGMMSG  MSG('Fail')                                                                 
0012.00              ENDDO                                                                                  
0013.00 /* IF ELSE IF Pattern1 */                                                                           
0014.00              SNDPGMMSG  MSG('Section IF ELSE IF Pattern1')                                          
0015.00              IF         COND(&DIV = '1') THEN(SNDPGMMSG MSG('Div1'))                                
0016.00              ELSE       CMD(IF COND(&DIV = '2') THEN(SNDPGMMSG +                                    
0017.00                           MSG('Div2')))                                                             
0018.00              ELSE       CMD(IF COND(&DIV = '3') THEN(SNDPGMMSG +                                    
0019.00                           MSG('Div3')))                                                             
0020.00 /* IF ELSE IF Pattern2 */                                                                           
0021.00              SNDPGMMSG  MSG('Section IF ELSE IF Pattern2')                                          
0022.00              IF         COND(&DIV = '1') THEN(SNDPGMMSG MSG('Div1'))                                
0023.00         ELSE IF         COND(&DIV = '2') THEN(SNDPGMMSG MSG('Div2'))                                
0024.00         ELSE IF         COND(&DIV = '3') THEN(SNDPGMMSG MSG('Div3'))                                
0025.00              RETURN                                                                                 
0026.00 END:                                                                                                
0027.00              ENDPGM                                                                                 
        ****************** End of data *********************************************************************
```

```shell-session:出力結果
Section IF ELSE             
Fail                        
Section IF ELSE IF Pattern1 
Div3                        
Section IF ELSE IF Pattern2 
Div3                        
```

ちなみに、ここでは比較演算子として＝（イコール）記号を利用しているが、以下のような記号ではない指定の方法もあるので、どちらかを指定する。（コーディングルールに準拠する。）

|事前定義値|事前定義記号|意味|
|:--|:--|:--|
|*EQ|=|等しい|
|*GT|>|より大きい|
|*LT|<|より小さい|
|*GE|>=|より大きいまたは等しい|
|*LE|<=|より小さいまたは等しい|
|*NE|¬=|等しくない|
|*NG|¬>|より大きくない|
|*NL|¬<|より小さくない|

参考：https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_73/rbam6/rbam6opsinexp.htm

## SELECT条件分岐

switch文のような条件分岐を実現する方法についてサンプルを作成。

```shell:PGM
 FMT **  ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00              PGM                                                                                    
0002.00              DCL        VAR(&DIV) TYPE(*CHAR) LEN(1) VALUE('3')                                     
0003.00              SELECT                                                                                 
0004.00              WHEN       COND(&DIV *EQ '1') THEN(SNDPGMMSG MSG('Div1'))                              
0005.00              WHEN       COND(&DIV *EQ '2') THEN(SNDPGMMSG MSG('Div2'))                              
0006.00              WHEN       COND(&DIV *EQ '3') THEN(SNDPGMMSG MSG('Div3'))                              
0007.00              OTHERWISE  CMD(SNDPGMMSG MSG('Div other'))                                             
0008.00              ENDSELECT                                                                              
0009.00              ENDPGM                                                                                 
        ****************** End of data *********************************************************************
```

```shell-session:出力結果
Div3                        
```

## 繰り返し処理

### IFとラベル（GOTO）を利用した繰り返し処理

```shell:PGM
 FMT **  ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00              PGM                                                                                    
0002.00              DCL        VAR(&NUM1) TYPE(*INT) VALUE(1)                                              
0003.00              SNDPGMMSG  MSG('Start IF loop')                                                        
0004.00  LOOP1:      IF         COND(&NUM1 <= 3) THEN(DO)                                                   
0005.00              SNDPGMMSG  MSG('The number is' *BCAT %CHAR(&NUM1))                                     
0006.00              CHGVAR     VAR(&NUM1) VALUE(&NUM1 + 1)                                                 
0007.00              GOTO       CMDLBL(LOOP1)                                                               
0008.00              ENDDO                                                                                  
0009.00              SNDPGMMSG  MSG('End IF loop')                                                          
0010.00              ENDPGM                                                                                 
        ****************** End of data *********************************************************************
```

```shell-session:出力結果
Start IF loop
The number is 1
The number is 2
The number is 3
End IF loop
```

### DOWHILEを利用した繰り返し処理

DOWHILEは、CONDの条件がTRUEの間繰り返し処理をする。

```shell:PGM
 FMT **  ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00              PGM                                                                                    
0002.00              DCL        VAR(&NUM1) TYPE(*INT) VALUE(1)                                              
0003.00              SNDPGMMSG  MSG('Start Do While')                                                       
0004.00              DOWHILE    COND(&NUM1 <= 3)                                                            
0005.00              SNDPGMMSG  MSG('The number is' *BCAT %CHAR(&NUM1))                                     
0006.00              CHGVAR     VAR(&NUM1) VALUE(&NUM1 + 1)                                                 
0007.00              ENDDO                                                                                  
0008.00              SNDPGMMSG  MSG('End Do While')                                                         
0009.00              ENDPGM                                                                                 
        ****************** End of data *********************************************************************
```

```shell-session:出力結果
Start Do While  
The number is 1 
The number is 2 
The number is 3 
End Do While    
```

### DOFORを利用した繰り返し処理


```shell:PGM
 FMT **  ...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 ...+... 9 ...+... 0
        *************** Beginning of data ******************************************************************
0001.00              PGM                                                                                    
0002.00              DCL        VAR(&NUM1) TYPE(*INT) VALUE(1)                                              
0003.00              SNDPGMMSG  MSG('Start For')                                                            
0004.00              DOFOR      VAR(&NUM1) FROM(1) TO(3)                                                    
0005.00              SNDPGMMSG  MSG('The number is' *BCAT %CHAR(&NUM1))                                     
0006.00              ENDDO                                                                                  
0007.00              SNDPGMMSG  MSG('End For')                                                              
0008.00              ENDPGM                                                                                 
        ****************** End of data *********************************************************************
```

```shell-session:出力結果
Start For
The number is 1 
The number is 2 
The number is 3 
End For    
```