1.はじめに
この記事は2025年に2回目の開催となった「IBM i RiSING」にBチームとして参加した際の活動を記録したものになります。
社内システムの保守・開発でまだまだ RPGⅢ が使われている環境は多いと思います。
私たちのチームも例外ではなく、RPGⅢを少ししか触ったことがないRPG初心者メンバー で勉強会を行いました。
その中で「既存のRPGⅢのソースをRPGIVにコンバートしてみよう」という取り組みを実施しましたが、実際に変換してみると コンバートでは見た目の違いがほとんどない という気づきがありました。
そこで今回は、コンバートしたソースをさらに手修正で 「RPGIV(ILERPG)らしい書き方」 に書き直し、まとめてみました。
「RPGⅢからRPGIVに移行するけれど、違いがピンとこない…」という方の参考になれば嬉しいです。
2.書き換え時に意識したこと
RPGⅢからRPGIV(ILERPG)にそのまま自動コンバートすると、命令やインジケータの使い方がそのまま残ってしまいます。 RPGIVではRPGⅢで使用していた命令が非推奨であったり、インジケータ(標識)は使用しない方法があるという記事をネットでチラホラと見たことがあったので、それらのポイントを意識して「RPGIVらしい」書き方に修正しました。
2-1.非推奨命令を使わない
RPGⅢではよく使われる命令は、RPGIVでも使用することは可能です。
しかし推奨はされていません。
代表例は以下になります。
RPGⅢの命令 | RPGⅣ(ILERPG)での推奨書き方 | 説明 |
---|---|---|
Z-ADD A B |
EVAL B = A |
ゼロ加算(実質代入)は EVAL に置換 |
A ADD B C |
EVAL C = A + B |
算術演算は EVAL と演算子で記述 |
A SUB B C |
EVAL C = A - B |
引き算も同様に記述 |
A MULT B C |
EVAL C = A * B |
掛け算は * 演算子を使用 |
A DIV B C |
EVAL C = A / B |
割り算は / 演算子を使用 |
MOVE A B |
EVAL B = A |
MOVEは用途に応じて型変換を明示 |
2-2.インジケータ(標識)は使用しない
RPGⅢでは「*INxx」というインジケータを多用します。
しかし、インジケータ(標識)は 番号で管理されるため直感的に分かりづらく、初心者にとって理解が難しい という問題があります。
RPGIVでは 論理式や組み込み関数 を直接使うことで、処理の意図が分かりやすくなります。
以下の表は一例です。
RPGⅢでの書き方 | RPGⅣ(ILERPG)での推奨書き方 | 説明 |
---|---|---|
IF *IN99 = *OFF |
IF NOT %FOUND(FILE) |
レコード存在チェックはインジケータではなく %FOUND を使用 |
IF *IN90 = *ON |
IF %EOF(FILE) |
EOFチェックは %EOF を使用 |
修正イメージ(サンプル):
C CHUBAN CHAINJUMIDP 50
C *IN50 IFEQ '0'
C SETON 30
C GOTO @START
C END
C CHUBAN CHAIN JUMIDP
C IF %FOUND
C EXSR SHOW_DUP_MSG
C LEAVESR
C ENDIF
%FOUND とは?
%FOUNDは直前のデータベース操作(READ, CHAIN, SETLLなど)が
成功してレコードを取得できた場合に TRUE を返す 組み込み関数です。
逆にレコードが見つからなかった場合は FALSE になります。
➡ RPGⅢでは「*INxx = *OFF/ON」で判定していましたが、
RPGIVでは %FOUND を使うことで「レコードが見つかったかどうか」が
直感的に分かるようになります。
3.ソースコード例比較(IPH220:抜粋)
RPGIV(コンバート直後)
H DATEDIT(*YMD/)
H*****************************************************************
H*受注入力プログラム(サブファイル)IPH220
H*****************************************************************
FIPH220S CF E WORKSTN
F SFILE(PANEL81:RRN01)
FJUMIDP UF A E K DISK
FJUMEIP O A E K DISK
FTOKMSP IF E K DISK
FHINMSP IF E K DISK
D*****************************************************************
D @MSG S 20 DIM(1) CTDATA PERRCD(1)
C*****************************************************************
C*見出し画面入力
C*****************************************************************
C @START TAG
C SETOFF 35
C WRITE PANEL02
C EXFMT PANEL01
C*(F3が押されたとき)
C *IN03 IFEQ '1'
C SETON LR
C RETURN
C END
C*(受注番号重複チェック)
C SETOFF 30
C CHUBAN CHAIN JUMIDP 50
C *IN50 IFEQ '0'
C SETON 30
C GOTO @START
C END
C*(得意先番号チェック)
C TOKBAN CHAIN TOKMSP 31
C *IN31 IFEQ '1'
C GOTO @START
C END
C*****************************************************************
C*明細入力画面表示
C*****************************************************************
C*(見出し再表示)
C SETON 35
C WRITE PANEL01
C WRITE PANEL02
C*(サブファイルの初期設定)
C Z-ADD 0 RRN01
C MOVE *BLANK HINBAN
C MOVE *ZERO SURYO
C MOVE *ZERO TANKA
C MOVE *BLANK HNNAKJ
C SETOFF 51
C *IN51 DOWEQ '0'
C ADD 1 RRN01
C MOVE RRN01 RRNS
C WRITE PANEL81 51
C END
C*(サブファイルの表示)
C @DSP81 TAG
C SETON 41
C EXFMT PANEL91
C SETOFF 41
C*(F3が押されたとき)
C *IN03 IFEQ '1'
C SETON LR
C RETURN
C END
C*(F5が押されたとき)
C *IN05 IFEQ '1'
C EXSR ¥CLEAR
C GOTO @START
C END
C*
C EXSR ¥CHECK
C*(実行キーが押されたとき)
C *IN08 IFEQ '0'
C WKERR ORGT 0
C GOTO @DSP81
C END
C*(F8が押されたとき)
C EXSR ¥WRITE
C EXSR ¥CLEAR
C GOTO @START
C*****************************************************************
C*クリアー・サブルーチン
C*****************************************************************
C ¥CLEAR BEGSR
C SETON 42
C WRITE PANEL91
C SETOFF 42
C MOVE *BLANK TKNAKJ
C MOVE *BLANK TKADR1
C MOVE *BLANK TKADR2
C ENDSR
C*****************************************************************
C*チェック・サブルーチン
C*****************************************************************
C ¥CHECK BEGSR
C Z-ADD 0 WKERR 3 0
C Z-ADD 1 RRN01 1 0
C*
C SETOFF 52
C *IN52 DOWEQ '0'
C RRN01 CHAIN PANEL81 52
C *IN52 IFEQ '0'
C MOVE *BLANK HNNAKJ
C HINBAN IFNE *BLANK
C HINBAN CHAIN HINMSP 32
C TANKA IFEQ 0
C Z-ADD HNTEIK TANKA
C END
C *IN32 IFEQ '1'
C MOVE @MSG(1) HNNAKJ
C ADD 1 WKERR
C END
C*
C END
C UPDATE PANEL81
C END
C ADD 1 RRN01
C END
C ENDSR
C*****************************************************************
C*レコード書出しサブルーチン
C*****************************************************************
C ¥WRITE BEGSR
C Z-ADD 0 JHKING
C Z-ADD 0 JHGYOS
C*
C Z-ADD 0 RRN01
C SETOFF 53
C *IN53 DOWEQ '0'
C ADD 1 RRN01
C RRN01 CHAIN PANEL81 53
C *IN53 IFEQ '0'
C HINBAN IFNE *BLANK
C MOVE CHUBAN JDCHUB
C MOVE TOKBAN JDTOKB
C MOVE HINBAN JDHINB
C Z-ADD SURYO JDSURY
C Z-ADD TANKA JDUTAN
C JDSURY MULT JDUTAN JDKING
C Z-ADD RRN01 JDGYOB
C WRITE JUMEIR
C ADD 1 JHGYOS
C ADD JDKING JHKING
C END
C END
C END
C*
C MOVE CHUBAN JHCHUB
C MOVE TOKBAN JHTOKB
C MOVE CHUBI JHDATE
C WRITE JUMIDR
C ENDSR
品番エラー
RPGIV(MOVE/Z-ADD不使用 EVALに置き換え)
H DATEDIT(*YMD/)
H*****************************************************************
F* 受注入力プログラム(サブファイル)IPH220
H*****************************************************************
FIPH220S CF E WORKSTN
F SFILE(PANEL81:RRN01)
FJUMIDP UF A E K DISK
FJUMEIP O A E K DISK
FTOKMSP IF E K DISK
FHINMSP IF E K DISK
D*****************************************************************
D @MSG S 20 DIM(1) CTDATA PERRCD(1)
D RRN01 S 1 0 INZ(0)
D RRNS S 1 0 INZ(0)
D WKERR S 3 0 INZ(0)
C*****************************************************************
C* 見出し画面入力
C*****************************************************************
C @START TAG
C SETOFF 35
C WRITE PANEL02
C EXFMT PANEL01
C*(F3が押されたとき)
C *IN03 IFEQ '1'
C SETON LR
C RETURN
C END
C*(受注番号重複チェック)
C SETOFF 30
C CHUBAN CHAIN JUMIDP 50
C *IN50 IFEQ '0'
C SETON 30
C GOTO @START
C END
C*(得意先番号チェック)
C TOKBAN CHAIN TOKMSP 31
C *IN31 IFEQ '1'
C GOTO @START
C END
C*****************************************************************
C* 明細入力画面表示
C*****************************************************************
C*(見出し再表示)
C SETON 35
C WRITE PANEL01
C WRITE PANEL02
C*(サブファイルの初期設定)
C EVAL RRN01 = 0
C EVAL HINBAN = *BLANK
C EVAL SURYO = 0
C EVAL TANKA = 0
C EVAL HNNAKJ = *BLANK
C SETOFF 51
C *IN51 DOWEQ '0'
C EVAL RRN01 = RRN01 + 1
C EVAL RRNS = RRN01
C WRITE PANEL81 51
C END
C*(サブファイルの表示)
C @DSP81 TAG
C SETON 41
C EXFMT PANEL91
C SETOFF 41
C*(F3が押されたとき)
C *IN03 IFEQ '1'
C SETON LR
C RETURN
C END
C*(F5が押されたとき)
C *IN05 IFEQ '1'
C EXSR ¥CLEAR
C GOTO @START
C END
C*
C EXSR ¥CHECK
C*(実行キーが押されたとき)
C *IN08 IFEQ '0'
C WKERR ORGT 0
C GOTO @DSP81
C END
C*(F8が押されたとき)
C EXSR ¥WRITE
C EXSR ¥CLEAR
C GOTO @START
C*****************************************************************
C* クリア・サブルーチン
C*****************************************************************
C ¥CLEAR BEGSR
C SETON 42
C WRITE PANEL91
C SETOFF 42
C EVAL TKNAKJ = *BLANK
C EVAL TKADR1 = *BLANK
C EVAL TKADR2 = *BLANK
C ENDSR
C*****************************************************************
C* チェック・サブルーチン
C*****************************************************************
C ¥CHECK BEGSR
C EVAL WKERR = 0
C EVAL RRN01 = 1
C*
C SETOFF 52
C *IN52 DOWEQ '0'
C RRN01 CHAIN PANEL81 52
C *IN52 IFEQ '0'
C EVAL HNNAKJ = *BLANK
C HINBAN IFNE *BLANK
C HINBAN CHAIN HINMSP 32
C TANKA IFEQ 0
C EVAL TANKA = HNTEIK
C END
C *IN32 IFEQ '1'
C EVAL HNNAKJ = @MSG(1)
C EVAL WKERR = WKERR + 1
C END
C*
C END
C UPDATE PANEL81
C END
C EVAL RRN01 = RRN01 + 1
C END
C ENDSR
C*****************************************************************
C* レコード書出しサブルーチン
C*****************************************************************
C ¥WRITE BEGSR
C EVAL JHKING = 0
C EVAL JHGYOS = 0
C*
C EVAL RRN01 = 0
C SETOFF 53
C *IN53 DOWEQ '0'
C EVAL RRN01 = RRN01 + 1
C RRN01 CHAIN PANEL81 53
C *IN53 IFEQ '0'
C HINBAN IFNE *BLANK
C EVAL JDCHUB = CHUBAN
C EVAL JDTOKB = TOKBAN
C EVAL JDHINB = HINBAN
C EVAL JDSURY = SURYO
C EVAL JDUTAN = TANKA
C EVAL JDKING = JDSURY * JDUTAN
C EVAL JDGYOB = RRN01
C WRITE JUMEIR
C EVAL JHGYOS = JHGYOS + 1
C EVAL JHKING = JHKING + JDKING
C END
C END
C END
C*
C EVAL JHCHUB = CHUBAN
C EVAL JHTOKB = TOKBAN
C EVAL JHDATE = CHUBI
C*
C WRITE JUMIDR
C ENDSR
** C
品番エラー
RPGIV(MOVE/Z-ADD不使用+標識・TAGを使わない)
H DATEDIT(*YMD/)
H*****************************************************************
H* 受注入力プログラム(サブファイル)IPH220
H*****************************************************************
FIPH220S CF E WORKSTN
F SFILE(PANEL81:RRN01)
FJUMIDP UF A E K DISK
FJUMEIP O A E K DISK
FTOKMSP IF E K DISK
FHINMSP IF E K DISK
D*****************************************************************
D @MSG S 20 DIM(1) CTDATA PERRCD(1)
D RRN01 S 1 0 INZ(0)
D RRNS S 1 0 INZ(0)
D WKERR S 3 0 INZ(0)
D CTL S 8A INZ('HEAD')
D EXIT_FLG S 1N INZ(*OFF)
D IDX S 1 0 INZ(0)
C*****************************************************************
C*
C*****************************************************************
C EXSR INIT
C EXSR MAIN
C*****************************************************************
C* INIT
C*****************************************************************
C INIT BEGSR
C EVAL CTL = 'HEAD'
C ENDSR
C*****************************************************************
C* ルーチン作成(状態遷移で制御)
C*****************************************************************
C MAIN BEGSR
C DOU EXIT_FLG = *ON
C SELECT
C WHEN CTL = 'HEAD'
C EXSR GET_HEAD
C WHEN CTL = 'DETAIL'
C EXSR GET_DETAIL
C WHEN CTL = 'CHECK'
C EXSR CHECK_DETAIL
C WHEN CTL = 'WRITE'
C EXSR WRITE_DETAIL
C END
C ENDDO
C SETON LR
C ENDSR
C*****************************************************************
C* 見出し画面入力
C*****************************************************************
C GET_HEAD BEGSR
C EXSR CLEAR_ERROR
C WRITE PANEL02
C EXFMT PANEL01
C*(F3が押された時)
C IF *IN03
C EVAL EXIT_FLG = *ON
C LEAVESR
C ENDIF
C*(受注番号重複チェック)
C CHUBAN CHAIN JUMIDP
C IF %FOUND
C EXSR SHOW_DUP_MSG
C LEAVESR
C ENDIF
C*(得意先番号チェック)
C TOKBAN CHAIN TOKMSP
C IF NOT %FOUND
C EXSR SHOW_TOKER_MSG
C LEAVESR
C ENDIF
C EVAL CTL = 'DETAIL'
C ENDSR
C*****************************************************************
C* 明細入力画面表示
C*****************************************************************
C GET_DETAIL BEGSR
C WRITE PANEL01
C WRITE PANEL02
C*(サブファイル初期化)
C EVAL RRN01 = 0
C EVAL HINBAN = *BLANK
C EVAL SURYO = 0
C EVAL TANKA = 0
C EVAL HNNAKJ = *BLANK
C FOR IDX = 1 TO 9
C EVAL RRN01 = RRN01 + 1
C EVAL RRNS = RRN01
C WRITE PANEL81
C END
C*(サブファイルの表示)
C EXFMT PANEL91
C*(F3が押されたとき)
C IF *IN03
C EVAL EXIT_FLG = *ON
C LEAVESR
C ENDIF
C*(F5が押されたとき)
C IF *IN05
C EXSR CLEAR_DETAIL
C EVAL CTL = 'HEAD'
C LEAVESR
C ENDIF
C*(実行キーが押されたとき)
C IF *IN08
C EVAL CTL = 'CHECK'
C EVAL CTL = 'WRITE'
C LEAVESR
C ENDIF
C EVAL CTL = 'DETAIL'
C ENDSR
C*****************************************************************
C* クリア・サブルーチン 関連
C*****************************************************************
C CLEAR_DETAIL BEGSR
C EVAL TKNAKJ = *BLANK
C EVAL TKADR1 = *BLANK
C EVAL TKADR2 = *BLANK
C WRITE PANEL91
C ENDSR
C*
C CLEAR_ERROR BEGSR
C EVAL WKERR = 0
C EVAL HNNAKJ = *BLANK
C ENDSR
C*
C SHOW_DUP_MSG BEGSR
C EVAL HNNAKJ = ' '
C ENDSR
C*
C SHOW_TOKER_MSGBEGSR
C EVAL HNNAKJ = ' '
C ENDSR
C*****************************************************************
C* チェック・サブルーチン
C*****************************************************************
C CHECK_DETAIL BEGSR
C EVAL WKERR = 0
C EVAL RRN01 = 1
C*
C DOU RRN01 > 9
C RRN01 CHAIN PANEL81
C IF NOT %FOUND
C ITER
C ENDIF
C EVAL HNNAKJ = *BLANK
C HINBAN IFNE *BLANK
C HINBAN CHAIN HINMSP
C IF NOT %FOUND
C EVAL HNNAKJ = @MSG(1)
C EVAL WKERR = WKERR + 1
C ELSE
C IF TANKA = 0
C EVAL TANKA = HNTEIK
C ENDIF
C ENDIF
C ENDIF
C*
C UPDATE PANEL81
C EVAL RRN01 = RRN01 + 1
C ENDDO
C IF WKERR > 0
C EVAL CTL = 'DETAIL'
C ELSE
C EVAL CTL = 'WRITE'
C ENDIF
C ENDSR
C*****************************************************************
C* レコード書出しサブルーチン
C*****************************************************************
C WRITE_DETAIL BEGSR
C EVAL JHKING = 0
C EVAL JHGYOS = 0
C EVAL RRN01 = 1
C*
C DOU RRN01 > 9
C RRN01 CHAIN PANEL81
C IF NOT %FOUND
C ITER
C ENDIF
C HINBAN IFNE *BLANK
C EVAL JDCHUB = CHUBAN
C EVAL JDTOKB = TOKBAN
C EVAL JDHINB = HINBAN
C EVAL JDSURY = SURYO
C EVAL JDUTAN = TANKA
C EVAL JDKING = JDSURY * JDUTAN
C EVAL JDGYOB = RRN01
C*
C WRITE JUMEIR
C*
C EVAL JHGYOS = JHGYOS + 1
C EVAL JHKING = JHKING + JDKING
C ENDIF
C EVAL RRN01 = RRN01 + 1
C ENDDO
C*
C EVAL JHCHUB = CHUBAN
C EVAL JHTOKB = TOKBAN
C EVAL JHDATE = CHUBI
C WRITE JUMIDR
C*
C EXSR CLEAR_DETAIL
C*
C EVAL CTL = 'HEAD'
C ENDSR
** C
品番エラー
3-1.改善ポイント(ソース比較)
・非推奨の命令(MOVEやZ-ADD)は使用しない書き方に改善
⇒初期化や加算については、EVAL関数記述 書き換え。
・標識は使用しない
⇒レコード存在チェックについて、インジケータではなく %FOUND を使用
C HINBAN IFNE *BLANK
C HINBAN CHAIN HINMSP 32
C TANKA IFEQ 0
C Z-ADD HNTEIK TANKA
C END
C *IN32 IFEQ '1'
C MOVE @MSG(1) HNNAKJ
C ADD 1 WKERR
C END
C END
C HINBAN IFNE *BLANK
C HINBAN CHAIN HINMSP
C IF NOT %FOUND
C EVAL HNNAKJ = @MSG(1)
C EVAL WKERR = WKERR + 1
C ELSE
C IF TANKA = 0
C EVAL TANKA = HNTEIK
C ENDIF
C ENDIF
C ENDIF
・TAG/GOTOは使用しない書き方に改善
⇒CTLで状態を判断して遷移するように書き換えました。
C @START TAG
C SETOFF 35
C WRITE PANEL02
C EXFMT PANEL01
C ...
C*(受注番号重複チェック)
C SETOFF 30
C CHUBAN CHAIN JUMIDP 50
C *IN50 IFEQ '0'
C SETON 30
C GOTO @START
C END
C MAIN BEGSR
C DOU EXIT_FLG = *ON
C SELECT
C WHEN CTL = 'HEAD' EXSR GET_HEAD
C WHEN CTL = 'DETAIL' EXSR GET_DETAIL
C ...
C END
C ENDDO
4.まとめ
今回の取組を通じて、以下のような気づきを得ることができました。
4-1.技術的な学び
-
非推奨の命令を使わない方がシンプル
-
MOVE
/Z-ADD
/ADD
をすべてEVAL
に統一することで、意図が明確になりソースの可読性も向上すると感じた。 - また、代入は全て
EVAL
だけ覚えておけば良いと思うので、初学者にとって分かりやすいと感じた。
-
-
インジケータ依存からの脱却は可読性が上がると感じた。
-
*IN××
は「何を表しているの?」を都度確認しなければならず、理解するのに時間がかかっていたが、%FOUND
/%EOF
を使用することで、そこについても大幅に改善できるのではないかと感じた。
-
-
TAG/GOTOを使わない構造化のメリット
-
TAG
/GOTO
を使わなくても変数(今回はctl
)を使うことで処理の流れを明示できる。RPGⅢでもこの記述ならできると思ったので試してみたい。
-
4-2.まとめ
単なるコンバートでは命令の置換に過ぎず、得られるメリットは限定的だと感じました。
しかし、EVALや%FOUND、構造化 といったRPG IV本来の書き方に改めることで、コードの意図が明確になり、読みやすくなったと感じました。
今後は、この経験を基に、Free-form RPG などさらにモダンな書き方にも挑戦し、RPGⅢから続く資産を“今の開発者が安心して触れる形”へ進化させていきたいと思いました。
▼チームBの活動内容を以下にまとめていますので、是非読んでみてください。
チームB活動報告 記事一覧
5.参考資料
下記資料を参考に作業をおこないました。
-
201. RPGソース の近代化 (1)
https://www.as400-net.com/cgi-bin/contents/tips.cgi?con=rpg&num=201 -
ILE RPGによる簡単モダナイゼーション②|非常に便利な命令語EVALを活用しよう!
https://www.istechnoport.com/2021/04/23/tech_ilerpd002/
当記事の著作権はIBMに帰属します。詳細はこちらを参照ください。