RPG

384. 数字に変換する%DECの使い方

文字列を数字に変換する %DEC の使い方を紹介する。

・%DEC の基本形

%DEC(変換する文字列:長さ:小数)

の形式で必ず変換先の数字の長さと小数を合わせて指定しなければ
ならない。

・カンマ(,)は無視、マイナス(-)、小数点(.)は認識される

カンマ(,)は無視されエラーとはならないがその時点で変換は
終了する。
例えば 13,2 は 13 と変換される。
  ハイフン(-)はマイナス符号と見なされる。
ピリオド(.)は小数点として認識される。

・上記以外の英字や記号はエラーとなる。

前述以外の英字(A-Z)や記号(カッコ((や), [ ] …)が変換対象に
含まれている場合は変換エラーとなる。

  RNX0105 : 数値の文字表現にエラーがあります

  で終了する。

  ..これは%DECの不便なところで要注意である。
   カンマ(,)の場合と同じようにその時点で変換が終了すれば
よいのだがエラーとして異常終了してしまう。
これが %DEC を使うときの注意点である。
C言語にも atoi という関数があり、文字列を整数(INTEGER)に
   変換することができるが atoi は決してエラーにはならず
数字以外の文字が見つかるとそこで変換が終了する。
%DECもそうあって欲しいものであるがエラーとなってしまう。

[%DECを使うサンプルRPG: TESTDEC6 ]

ソースはこちらから

0001.00 H DFTNAME(TESTDEC6) DATEDIT(*YMD/)                                             
0002.00 D STR             S             80A                                            
0003.00 D ROW             S             10I 0                                          
0004.00 D COL             S             10I 0                                          
0005.00 D N               S              4S 0                                          
0006.00 D VALUE           S             10A                                            
0007.00 C                   EVAL      STR = 'POS(13,25)'                               
0008.00 C     'POS('        SCAN      STR:1         N                        50        
0009.00 C     *IN50         IFEQ      *ON                                          POS(
0010.00 C                   ADD       4             N                                  
0011.00 C                   EVAL      VALUE = %SUBST(STR:N:4)                          
0012.00 C                   EVAL      ROW = %DEC(VALUE:4:0)                            
0013.00 C     ','           SCAN      STR:1         N                        50        
0014.00 C     *IN50         IFEQ      *ON                                          ,   
0015.00 C                   ADD       1             N                                  
0016.00 C                   EVAL      VALUE = %SUBST(STR:N:4)                          
0017.00 C                   EVAL      COL = %DEC(VALUE:4:0)                            
0018.00 C                   ENDIF                                                  ,   
0019.00 C                   ENDIF                                                  POS(
0020.00 C                   SETON                                        LR     


        

[解説]

0011.00 C                   EVAL      VALUE = %SUBST(STR:N:4)

の演算によってフィールド:VALUE には 13,2 という値が入る。
これを

0012.00 C                   EVAL      ROW = %DEC(VALUE:4:0)

で変換すると ROW には 13 という値が入る。
次に

0016.00 C                   EVAL      VALUE = %SUBST(STR:N:4)

の演算では VALUE には 25) という値が入る。
これを

0017.00 C                   EVAL      COL = %DEC(VALUE:4:0)

で変換を試みると

 数値の文字表現にエラーがあります

というエラーが発生する。変換対象の文字列の中に ) という文字が含まれているからである。
このエラーを避けるのは上記のTESTDEC6 は次のように修正する必要がある。

[修正したTESTDEC61 ]

ソースはこちらから

0001.00 H DFTNAME(TESTDEC6) DATEDIT(*YMD/)                                              
0002.00 D STR             S             80A                                             
0003.00 D ROW             S             10I 0                                           
0004.00 D COL             S             10I 0                                           
0005.00 D N               S              4S 0                                           
0006.00 D M               S              4S 0                                           
0007.00 D L               S              4S 0                                           
0008.00 D VALUE           S             10A                                             
0009.00 C                   EVAL      STR = 'POS(13,25)'                                
0010.00 C     'POS('        SCAN      STR:1         N                        50         
0011.00 C     *IN50         IFEQ      *ON                                          POS( 
0012.00 C                   ADD       4             N                                   
0013.00 C                   EVAL      VALUE = %SUBST(STR:N:4)                           
0014.00 C                   EVAL      ROW = %DEC(VALUE:4:0)                             
0015.00 C     ','           SCAN      STR:1         N                        50         
0016.00 C     *IN50         IFEQ      *ON                                          ,    
0017.00 C                   ADD       1             N                                   
0018.00 C     ')'           SCAN      STR:N         M                        50         
0019.00 C                   EVAL      L = M - N                                         
0020.00 C                   EVAL      VALUE = %SUBST(STR:N:L)                           
0021.00 C                   EVAL      COL = %DEC(VALUE:4:0)                             
0022.00 C                   ENDIF                                                  ,    
0023.00 C                   ENDIF                                                  POS( 
0024.00 C                   SETON                                        LR


 

[解説]

演算

0018.00 C     ')'           SCAN      STR:N         M                        50

によって閉じカッコ ) の位置を調べて

0019.00 C                   EVAL      L = M - N

によって数字だけの長さ L を取得して

0020.00 C                   EVAL      VALUE = %SUBST(STR:N:L)

で取り出すと VALUE には 25という値が入るので

0021.00 C                   EVAL      COL = %DEC(VALUE:4:0)

を行うと COLには首尾よく 25という値を取得することができる。

ところでTESTDEC61の演算方法は複雑で読み手にとって難解なものとなってしまっている。
これは単純な演算を複数組み合わせているために読み手にとって
流れを把握しにくくなってしまっているのだ。
フリー・フォーマットであれば複数の演算をまとめて記述することができるので
演算の意図を読み手にわかりやすく表現することができる。

[フリー・フォーマットにしたTESTDEC62]

ソースはこちらから

0001.00 H DFTNAME(TESTDEC62) DATEDIT(*YMD/)                                            
0002.00 D STR             S             80A                                            
0003.00 D ROW             S             10I 0                                          
0004.00 D COL             S             10I 0                                          
0005.00 D N               S              4S 0                                          
0006.00 D M               S              4S 0                                          
0007.00 D L               S              4S 0                                          
0008.00 C                   EVAL      STR = 'POS(13,25)'                               
0009.00 C     'POS('        SCAN      STR:1         N                        50        
0010.00 C     *IN50         IFEQ      *ON                                          POS(
0011.00  /FREE                                                                         
0012.00    ROW = %DEC(%SUBST(STR:N+4:4):4:0);                                          
0013.00  /END-FREE                                                                     
0014.00 C     ','           SCAN      STR:1         N                        50        
0015.00 C     ')'           SCAN      STR:N         M                        50        
0016.00 C     *IN50         IFEQ      *ON                                          ,   
0017.00  /FREE                                                                         
0018.00    L   = M - N - 1;                                                            
0019.00    COL = %DEC(%SUBST(STR:N+1:L):4:0);                                          
0020.00  /END-FREE                                                                     
0021.00 C                   ENDIF                                                  ,   
0022.00 C                   ENDIF                                                  POS(
0023.00 C                   SETON                                        LR 


            

[解説]

フリー・フォーマットにすると複数の演算がひとつにまとめられている。

演算

0012.00 C                   ADD       4             N                                   
0013.00 C                   EVAL      VALUE = %SUBST(STR:N:4)                           
0014.00 C                   EVAL      ROW = %DEC(VALUE:4:0)

0012.00    ROW = %DEC(%SUBST(STR:N+4:4):4:0);

としてまとめられているし

演算

0017.00 C                   ADD       1             N                                   
0018.00 C     ')'           SCAN      STR:N         M                        50         
0019.00 C                   EVAL      L = M - N                                         
0020.00 C                   EVAL      VALUE = %SUBST(STR:N:L)                           
0021.00 C                   EVAL      COL = %DEC(VALUE:4:0)

0018.00    L   = M - N - 1;                                                            
0019.00    COL = %DEC(%SUBST(STR:N+1:L):4:0);

にまとめられている。
これは 1行にもすることができるが長さL = M – N – 1の意味がわかりにくく
なってしまうのであえてこの演算を残した。

このようにフリー・フォーマットは単に自由形式で記述するというのではなく
複数の演算をまとめて記述することができる。

例えば

URIAGE = (SURYO x TANKA) X 1.10 + SORYO

を計算するのに

0022.01 C     SURYO         MULT      TANKA         URIAGE
0022.02 C     URIAGE        MULT      1.10          URIAGE
0022.03 C                   ADD       SORYO         URIAGE

と記述するのと

0022.04  /FREE                                     
0022.05    URIAGE = (SURYO * TANKA) * 1.10 + SORYO;
0022.06  /END-FREE                                 

の記述するのとどちらが簡単で読み手にもわかりやすいのだろうか?
RPG IIIからILE-RPGへの移行をためらっている人やフリー・フォーマット
難しそうだと思っている人は少しずつでもフリー・フォーマットへ
一部ずつでも記述してみることをお奨めする。