0.目次
1. はじめに
この記事は、2026年度の IBM RiSING、f-モダナイゼーションチームへ参加した際の記録です。
IBM Bob (PP4i無し、自社環境接続用のMCPサーバー構築) を利用して、固定長 RPG IV から FFRPG への変換タスクを実行しています。
2. 活動内容
2-1. 検証方針
最優先目標は「コンパイルが通るソースコードを安定して出力すること」としました。
- サブプロシージャによる責務分離や深いネストの改善などのリファクタリングは行わない
本検証では、変換タスクの都度プロンプトの修正やルールの追加を Bob 自身に行わせ、コンパイルが通る FFRPG のコードを安定的に出力させるエージェントになってもらうことを目指しました。
- Bob coin の消費は度外視し、プロンプトとルールファイルを作り込んでいく作戦
※同活動内では、プロンプトによる補正効果ではなく、Bob が標準状態でどの程度ソースコードを理解し FFRPG へ変換できるのかを検証した記事もありますので是非読んでみてください
2-2. 進め方
基本的に下記の流れを繰り返します。
- 変換元の 固定長 RPG IV ソースを Bob に伝え、MCP サーバー経由でコードや関連ファイルを解析してもらい、FFRPG の新規ソースメンバーとして出力してもらう
- 変換後のソースをコンパイルし、エラーとなった場合はコンパイルリストを Bob に読み込ませ、エラー原因を分析させる
- 同じエラーが発生しないようにプロンプトおよびルールファイルを Bob に修正させる
- 手順 1 に戻る
3. 変換結果
ここからは実際に変換タスクを実行した結果が続いていきます(長いです)。
3-1. ソース①
ルールファイル不使用、初回トライ
コンパイル結果
警告 |
エラー |
重大エラー |
|---|---|---|
| 2 | 35 | 68 |
うまく変換できたロジック
- WORKSTN / DISK ファイルを
DCL-F+KEYED USAGE(*INPUT)で正しく定義(DP011D0、WK003W1 等) - 複数の無名 DS を
DCL-DS *N;+OVERLAYに変換(日付分解 DS、配列 DS など網羅) - QUALIFIED DS(KEYMS_DS)を用意し
%KDS()で複合キー CHAIN を実現(固定長 KLIST/KFLD の代替) - CAT 命令を
%TRIMR() + '-' + %TRIMR()の文字列連結式に変換 - SELECT/WHEN/ENDSL、IF/ELSE/ENDIF など制御構造をほぼ漏れなく変換
- DIV/MVR を
%DIV()/%REM()に変換し添字計算ロジックを再現 - SUBST 命令を
%SUBST()に変換(WKMH 分解・WKTK 分解ともに正確) -
MOVEL *IN(01) PIDAIをIF *IN01 = *ON; PIDAI = '1'; ELSE; PIDAI = '0'; ENDIF;の条件分岐に変換 - CALL 'XY012C'/PARM を
CALLP XY012C( arg1 : arg2 : ... )形式に変換(引数も完全列挙) - インジケーター配列参照(
*IN(@ + 30)等)を*IN(%INT(K)) = (W1K = '1')のブール代入に変換
変換に失敗したロジック(エラー原因になった可能性)
- プロシージャー名に ¥(円マーク)を使用(
¥SB100等)→ RNF1510 が全プロシージャーで発生、すべて定義失敗 - ¥ 付きプロシージャー呼び出し(
¥SB100();等)→ RNF0604(無効トークン)が呼び出し箇所すべてで連発 - PSDS の
W¥PGM *PROC/W¥WSID/W¥JBNO→ RNF3308(不正キーワード)・RNF3315(名前重複) - CTL-OPT に
DFTACTGRP(*NO)が未指定 → RNF1520(#FGB・#SB801等が DFTACTGRP(*YES) 下で定義不可) - SETGT EK003W11 *HIVAL; のオペランド順が固定長式のまま → RNF0637(
SETGT *HIVAL EK003W11;が正しい) - SETLL / READE のキー引数に
#KNO(PACKED)を渡した形式 → RNF7260 が SETLL/READE の全呼び出しで発生 -
%YEAR(%DATE())/%MONTH(%DATE())/%DAY(%DATE())の使用 → RNF0604(これらの関数名は不正) - 1行に複数ステートメントをセミコロン区切りで記述(
*IN31 = *OFF; *IN32 = *OFF; ...)→ RNF5508 が15行分発生 -
DCL-S D1JHN CHAR(12)が画面ファイル外部フィールドと桁数不一致 → RNF6033(仕様が無視される) -
%TRIM(W1MBMN)を ZONED 型フィールドに使用 → RNF0371 /%EDITW(NO: ' ')の編集語が2桁不足 → RNF8004
まとめ
ファイル定義・DS 定義・SELECT/IF などの骨格部分は広い範囲をカバーしており、%KDS や %DIV/%REM への変換など難易度の高い箇所も手が届いていた。
致命傷は「プロシージャー名の ¥(円マーク)除去漏れ」で、これ1点が原因で全サブプロシージャーの定義と呼び出しがまるごとエラーになった。
SETGT のオペランド順・SETLL/READE のキー引数・%YEAR 等の不正関数名・1行複数ステートメントと、フリーフォーマット固有のルール違反も散在しており、「骨格は取れているが細かい記法ルールの詰めが甘い」という結果になった。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
- MYLIB/QPGMSRC(MBR_01) を RPGⅣ の固定長形式からフリーフォーマットの RPG に変換してください
- 変換が終わったら下記を精査し、間違っていれば修正してください
- コードの文法があっているか
- コンパイル時にエラーになる可能性が無いか
- 最後に、変換タスクのサマリーを html ファイルにして、メンバー名 + "_変換サマリー" の名前で下記のローカ> ルディレクトリに出力してください
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
なし
3-2. ソース②
ルールファイル使用開始
コンパイル結果
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 7 | 18 |
うまく変換できたロジック
- DISK ファイルの DCL-F 定義(XHSPL14、XHSPL24、XHSPL11、FKBPL01 相当)
- RPGサイクル相当処理を
DOW NOT *INLR+READ+%EOFによるループに変換 - GOTO/TAG を
EXSR+ サブルーチン化(@END、STP2、@JUMP 等)に構造化 - KLIST/KFLD の複合キーを
(WTOKU:FSIKU)等のコロン区切り形式の SETLL/READE/CHAIN に変換 - Z-ADD/MOVEL/MOVE による代入を
=演算子に置換 - SELECT/WHEN/ENDSL による多分岐の構造を正確に変換
- ネストした IF/ELSE/ENDIF(西暦2000年対応の年月計算)の変換
- LOOKUP を
%LOOKUP+ 比較式(> *ZERO)に変換 - 固定長 O 仕様の出力処理を
%SUBST+%EDITC+ バッファ変数(ABAWREC 等)方式に変換 - CTDATA(TB1 テーブル)の
DCL-S … DIM CTDATA PERRCDへの変換
変換に失敗したロジック(エラー原因になった可能性)
- プログラム記述ファイル(F区分)に
RECLNキーワードを付与 → RNF2023→RNF2121→RNF2109 が 3ファイルで発生しファイルが無視される -
OFLIND(*INOF)をOFLIND(*INOF)のまま変換(*IN0Fでなく*INOF)→ RNF2014(QPRINT も同名様式で RNF2109 連鎖) - プログラムパラメータを
DCL-PARM単独で定義 → RNF3703(DCL-PI ~ END-PI が必要)が2件発生 - DCL-DS のサブフィールドに
POS(n)キーワードを使用 → フリーフォーマットでは使用不可(多数のDS全体に残存) -
%DEC(%TIME():6:0)のように TIME 型に桁数・小数パラメーターを指定 → RNF0328/RNF0339 -
READE複合キー後の%EOF(GADPL141)/%EOF(GADPL241)→ RNF0391(ファイル名引数が使えない)が2件 -
%SUBST(ABAWREC:43:5) = N1USYOで ZONED 型を直接代入 → RNF7416(型不一致)が2件 -
%CHAR(*DATE:'*YMD0')のように日付フォーマット文字列を第2引数に指定 → RNF0621 - QPRINT/ABAWP42/OUTPUT へ
WRITE ファイル名 バッファ変数する際にファイルが RNF2109 で無視され → RNF7503(未定義オペランド)が多数発生 -
DFTACTGRP(*YES)のままコンパイルしており、CTL-OPT にDFTACTGRP(*NO)の指定なし
まとめ
ファイルからのレコード読み込みループ・IF/SELECT などの制御構造・KLIST 複合キーの変換・出力バッファへの %SUBST + %EDITC 変換など、ロジックの骨格部分は概ね正確に変換できている。
一方、固定長プログラム記述ファイル(F区分)への RECLN キーワード付与と OFLIND(*INOF) 未修正が致命傷で、3ファイルが全無視されコンパイルは失敗した。
DCL-DS の POS(n) 残存、%EOF 複合キー制限違反、%DEC(%TIME():6:0) の誤記など、フリーフォーマット固有の記法ルール違反も散在しており、「広範囲をカバーしているが、ファイル定義まわりと組み込み関数の細かい仕様を押さえ切れていない」という結果になった。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
- MYLIB/QPGMSRC(MBR_02) を、RPGⅣ の固定長形式から、
ソースコード先頭に "**FREE" を記述した完全フリーフォーマットの RPG に変換してください- 変換が終わったら下記の通り精査し、間違っていれば修正してください
- 確認方針
- コードの文法があっているか
- コンパイル時にエラーになる可能性が無いか
- 注意点
- "C:\Users\ユーザー名.bob\rules\Rule_Convert_FF.md" のルールに従うこと
- 最後に、変換タスクのサマリーを html ファイルにして、メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力してください
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
プロシージャー名・変数名に使用できる文字の制限
プロシージャー名・変数名・フィールド名には、英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字はフリーフォーマット RPG の識別子として使用できないため、
¥SB100 → SB100 のように変換すること。*DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
CRTBNDRPG のデフォルトは DFTACTGRP(*YES) であるため、プロシージャーが存在すると RNF1520 エラーになる。フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;%DATE() / %TIME() の戻り値は DATE / TIME 型であり、数値型変数へ直接代入できない
ZONED や PACKED の変数に年月日を格納する場合は、%YEARS / %MONTHS / %DAYS / %HOURS 等を使用した上で
%INT() 等で数値型に変換してから代入すること。
例:
誤) WTIYY = %YEARS(%DATE());
正) WTIYY = %INT(%YEARS(%DATE()));1行に複数ステートメントをセミコロンで連結しない
フリーフォーマットの1行は最大100桁だが、固定長ソース(SRCTYPE=RPGLE)では80桁制限が適用される場合がある。
複数の独立したステートメントは必ず別々の行に記述すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
DCL-F で外部記述ファイルを定義している場合、同名フィールドを RPG 内で異なる長さで再定義・使用すると
RNF6033 エラーになる。フィールド長は外部 DDS の定義と必ず一致させること。%EDITW の編集語はフィールド桁数分の置換文字が必要
%EDITW(フィールド: '編集語') の編集語には、対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールドには 4文字の編集語が必要 → %EDITW(NO: ' ')外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要
CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で
プロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型(ZONED / PACKED / INT 等)のフィールドに %TRIM を適用しないこと。
数値を文字として扱いたい場合は %CHAR() で変換してから %TRIM を適用すること。
例:
誤) %TRIM(W1MBMN) ← W1MBMNがZONED型
正) %TRIM(%CHAR(W1MBMN))PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
*PROCキーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる正当な RPG 名を使用すること。
¥ を含む名前(W¥PGM 等)や @@ で始まる名前は使用不可。ファイル仕様書のフラグ(入力、更新、追加など)を正確に変換すること
3-3. ソース③
コンパイル結果
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 1 | 464 |
うまく変換できたロジック
- DISK ファイル(NAIPP01、GADPL11)の DCL-F 定義、KEYED オプションの付与
- CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を指定(活動化グループ設定)
- 固定長 DS のバイト位置指定を OVERLAY キーワードに一括変換(日付・品番・背番号等)
- RPGサイクルの IP ファイルを
READ … WEOF99 / DOW NOT WEOF99 … ENDDOループに変換 - KLIST/KFLD の複合キー(得意先・納入先・工場・受入)を
(WTOKU:WNONY:FKOJ:WNUKE)形式に変換 - IFEQ/ANDEQ/OREQ の複合条件連鎖を
IF … AND/OR …構文に整理 - TIME 命令を
%INT(%DEC(%TIME()))に変換 - Z-ADD による代入・加算を
=演算子に変換(UYY2 = UYY1 + 1 等) - 出力仕様(O 仕様)を ABAWREC バッファ+%EDITC/%SUBST による固定長出力に変換
- PRINTER ヘッダー出力を QPRTREC バッファ+%SUBST で再現(6種ヘッダー行)
- *INLR = *ON / RETURN をループ外・サブルーチン前に正しく配置
変換に失敗したロジック(エラー原因になった可能性)
-
DCL-DS;に DS 名も*Nも指定されていない → RNF3368(これが連鎖崩壊の引き金) - ABAWP42 が外部記述として扱われ、同名レコード様式 ABAWP42 が衝突 → RNF2121→RNF2109 でファイルごと無視、後続 DCL-DS/DCL-S/DCL-PI が全滅
-
DCL-F QPRINT PRINTER OFLIND(*INOF);のパラメーター名誤り(*IN0Fが正) → RNF2014、さらに同名様式衝突でファイル無視 - 上記 RNF2109 の連鎖により、全 DCL-DS・DCL-S・DCL-PI が RNF0724/RNF5347 の嵐に(100件以上)
-
%YEARS(%DATE())/%MONTHS(%DATE())/%DAYS(%DATE())を日付分解に使用(Duration 関数の誤用) -
CHAIN (WTOKU:WNONY:FKOJ:WNUKE) GADPL11 *IN03;で結果標識を直接渡す形式 → RNF7030 -
%SUBST(QPRTREC:104:5) = %EDITC(PAGE:'Z');で RPG 予約語PAGEを変数として使用 -
READ NAIPP01 WEOF99;の結果標識渡し(WEOF99が IND 型変数なら可だが、定義が無視されて RNF7030)
まとめ
ファイル定義・DS のオーバーレイ変換・IF/ENDIF 制御構造・DOW ループへの置き換えなど、骨格部分の変換精度はかなり高い。
致命傷は DCL-DS; の DS 名省略という一点で、これが ABAWP42/QPRINT の同名レコード様式衝突と連鎖し、
後続の定義が全部演算命令として誤認されるドミノ倒し状態を引き起こした。
OFLIND(*INOF) のパラメーター名ミス、Duration 関数の誤用(%YEARS 等)、予約語 PAGE の変数使用といった
細かいルール違反も積み重なっており、「変換の方向性は正しいが、細部の詰めが甘い」という結果になった。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
- MYLIB/QPGMSRC(MBR_03) を、RPGⅣ の固定長形式から、
ソースコード先頭に "**FREE" を記述した完全フリーフォーマットの RPG に変換してください- 変換が終わったら下記の通り精査し、間違っていれば修正してください
- 確認方針
- コードの文法があっているか
- コンパイル時にエラーになる可能性が無いか
- 未使用変数の削除
- 注意点
- "C:\Users\ユーザー名.bob\rules\Rule_Convert_FF.md" のルールに従うこと
- 最後に、変換タスクのサマリーを html ファイルにして、メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力してください
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
プロシージャー名・変数名に使用できる文字の制限
プロシージャー名・変数名・フィールド名には、英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字はフリーフォーマット RPG の識別子として使用できないため、
¥SB100 → SB100 のように変換すること。*DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
CRTBNDRPG のデフォルトは DFTACTGRP(*YES) であるため、プロシージャーが存在すると RNF1520 エラーになる。フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;%DATE() / %TIME() の戻り値は DATE / TIME 型であり、数値型変数へ直接代入できない
ZONED や PACKED の変数に年月日を格納する場合は、%YEARS / %MONTHS / %DAYS / %HOURS 等を使用した上で
%INT() 等で数値型に変換してから代入すること。
例:
誤) WTIYY = %YEARS(%DATE());
正) WTIYY = %INT(%YEARS(%DATE()));1行に複数ステートメントをセミコロンで連結しない
フリーフォーマットの1行は最大100桁だが、固定長ソース(SRCTYPE=RPGLE)では80桁制限が適用される場合がある。
複数の独立したステートメントは必ず別々の行に記述すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
DCL-F で外部記述ファイルを定義している場合、同名フィールドを RPG 内で異なる長さで再定義・使用すると
RNF6033 エラーになる。フィールド長は外部 DDS の定義と必ず一致させること。%EDITW の編集語はフィールド桁数分の置換文字が必要
%EDITW(フィールド: '編集語') の編集語には、対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールドには 4文字の編集語が必要 → %EDITW(NO: ' ')外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要
CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で
プロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型(ZONED / PACKED / INT 等)のフィールドに %TRIM を適用しないこと。
数値を文字として扱いたい場合は %CHAR() で変換してから %TRIM を適用すること。
例:
誤) %TRIM(W1MBMN) ← W1MBMNがZONED型
正) %TRIM(%CHAR(W1MBMN))PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
*PROCキーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる正当な RPG 名を使用すること。
¥ を含む名前(W¥PGM 等)や @@ で始まる名前は使用不可。ファイル仕様書のフラグ(入力、更新、追加など)を正確に変換すること
DCL-F に RECLN キーワードは指定できない
フリーフォーマットのDCL-FではRECLNキーワードは認識されず、ファイル全体が無視される(RNF2023/RNF2109)。
固定長バッファ出力が必要な場合は、DCL-F ... DISK USAGE(*OUTPUT)のみ記述し、
バッファはDCL-S XXXXREC CHAR(nnn)で別途定義してWRITE ファイル名 バッファ変数で書き出すこと。
例:
誤) DCL-F ABAWP42 DISK RECLN(308) USAGE(*OUTPUT);
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;READE 後の %EOF は複合キー形式では使用できない場合がある
READE (キー1:キー2) ファイル名;の形式で読み込んだ後、%EOF(ファイル名)が RNF0391 エラーになる場合がある。
この場合はREADEの結果標識(例:*IN03)を直接使うか、%EOFをファイル名なしで使用すること。
例:
誤) READE (WTOKU:FSIKU) GADPL141;
*IN03 = %EOF(GADPL141); ← RNF0391
正) READE (WTOKU:FSIKU) GADPL141 *IN03;
IF *IN03;%DEC に TIME 型を渡す場合は精度・小数点パラメーターを指定できない
%DEC(%TIME():6:0)のように TIME 型変数に桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
TIME 型を数値に変換するには%INT(%DEC(%TIME()))または%INT(%CHAR(%TIME():'HHMMSS'))を使うこと。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
数値は%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO; ← N1USYO が ZONED 型
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない
%CHAR(*DATE:'*YMD0')のように日付フォーマットを第2パラメーターに渡すと RNF0621 エラーになる。
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うか、
DATE 型変数を%CHAR()でそのまま変換(デフォルト書式)すること。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式(編集コードY)
3-4. ソース④(1回目)
ここから作業方針を変更
同じ変換元ソースに対し、プロンプトを修正しながら繰り返し変換トライをしてみる
(記憶を引き継がせないように各回を別タスクとして実行した)
コンパイル結果
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 4 | 76 |
うまく変換できたロジック
- DISK・PRINTER ファイルの DCL-F 定義と
**FREE宣言・CTL-OPT への変換(NAIPP01、GADPL11) - 固定長の無名 DS を OVERLAY キーワード付きの DCL-DS *N に正しく変換(年月分解 DS、品番 DS など多数)
- KLIST/KFLD の複合キーを専用 DS(KFLDS)にまとめた CHAIN への変換
- IFxx/ANDxx/ORxx による複雑な条件分岐を IF〜ELSIF〜ENDIF 構造にすべて展開
- Z-ADD の連続代入を単純な代入式(
=)に変換(SN、S01〜S31 など 31 フィールド) - DO〜END ループを FOR〜ENDFOR に変換(配列 SNX の 9999999 ゼロ化)
- 固定長の TIME 命令を
%INT(%DEC(%TIME()))に変換 - GOTO/@END TAG を EXSR SREND(サブルーチン)に置換し、*INLR/*RETURN を適切に配置
- O 仕様のフィールド配置を %SUBST + %EDITC を使ったバッファ(ABAWREC)書き込みに変換
- CTDATA 定義(TB1 配列)と PERRCD キーワードを正しく引き継ぎ
変換に失敗したロジック(エラー原因になった可能性)
- ABAWP42 の DCL-F に
PGMDESCを付与 → RNF2023(認識されず)→ RNF2121/RNF2109 でファイルが丸ごと無視 - QPRINT の DCL-F に
PGMDESCを付与 → 同名レコード様式との衝突で RNF2017/RNF2121/RNF2109 連鎖 -
DCL-S WB5DATE DATE(*ISO0)の日付フォーマットにゼロサフィックス付き → RNF0619 -
CHAIN KFLDS GADPL11 *IN03;に結果標識を付加 → RNF0637 で仕様無視、後続で RNF7030(IN03 未定義) -
SN ZONED(217:0)およびSNPK PACKED(217:0)が 63 桁超 → RNF0503 で 63 桁に切り詰め(RNF7303 大量連鎖) - SN の OVERLAY サブフィールド(S01〜S31、SNX、SNCH)が全滅 → RNF7303 が 33 件発生し S01=N1N01S 等がすべて RNF7503
- GADPL11 のレコード様式 GADPL111 が使用されないと判定 → CHAIN の結果フィールドが未定義扱いに(RNF7031 が多数)
-
%DATE(%EDITC(B5SKH8:'Z') : *ISO0)で*ISO0を使用 → WB5DATE の定義エラーと相まって実行時リスク - DFTACTGRP(*YES) でコンパイル実行(コマンドライン指定が *YES のまま)→ CTL-OPT の *NO 設定が無効化される可能性
- FB1・FB2 が外部ファイルフィールドと名前衝突し RNF7031(参照のみで未使用扱い)
まとめ
IF 条件分岐・FOR ループ・DO ループ・EXSR/BEGSR などの制御構造と、OVERLAY を使った DS 定義は精度高く変換できていた。
一方でプログラム記述ファイル(ABAWP42、QPRINT)への PGMDESC 付与が逆効果となり、両ファイルが RNF2109 で無視される致命傷を招いた。
ZONED(217:0) の 63 桁制限オーバーは OVERLAY サブフィールド 33 件の連鎖エラーを引き起こし、S01〜S31 への代入がすべて未定義扱いになっている。
「構造変換の精度は高いが、ファイル定義まわりの細かいルールと ZONED の桁数上限を見落とした」という結果だ。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
- MYLIB/QPGMSRC(MBR_04) を、RPGⅣ の固定長形式から、
ソースコード先頭に "**FREE" を記述した完全フリーフォーマットの RPG に変換してください- 変換が終わったら下記の通り精査し、間違っていれば修正してください
- 確認方針
- コードの文法があっているか
- コンパイル時にエラーになる可能性が無いか
- 注意点
- "C:\Users\ユーザー名.bob\rules\Rule_Convert_FF.md" のルールに従うこと
- 最後に、変換タスクのサマリーを html ファイルにして、メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力してください
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
プロシージャー名・変数名に使用できる文字の制限
プロシージャー名・変数名・フィールド名には、英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字はフリーフォーマット RPG の識別子として使用できないため、
¥SB100 → SB100 のように変換すること。*DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
CRTBNDRPG のデフォルトは DFTACTGRP(*YES) であるため、プロシージャーが存在すると RNF1520 エラーになる。フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;%DATE() / %TIME() の戻り値は DATE / TIME 型であり、数値型変数へ直接代入できない
ZONED や PACKED の変数に年月日を格納する場合は、%YEARS / %MONTHS / %DAYS / %HOURS 等を使用した上で
%INT() 等で数値型に変換してから代入すること。
例:
誤) WTIYY = %YEARS(%DATE());
正) WTIYY = %INT(%YEARS(%DATE()));1行に複数ステートメントをセミコロンで連結しない
フリーフォーマットの1行は最大100桁だが、固定長ソース(SRCTYPE=RPGLE)では80桁制限が適用される場合がある。
複数の独立したステートメントは必ず別々の行に記述すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
DCL-F で外部記述ファイルを定義している場合、同名フィールドを RPG 内で異なる長さで再定義・使用すると
RNF6033 エラーになる。フィールド長は外部 DDS の定義と必ず一致させること。%EDITW の編集語はフィールド桁数分の置換文字が必要
%EDITW(フィールド: '編集語') の編集語には、対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールドには 4文字の編集語が必要 → %EDITW(NO: ' ')外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要
CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で
プロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型(ZONED / PACKED / INT 等)のフィールドに %TRIM を適用しないこと。
数値を文字として扱いたい場合は %CHAR() で変換してから %TRIM を適用すること。
例:
誤) %TRIM(W1MBMN) ← W1MBMNがZONED型
正) %TRIM(%CHAR(W1MBMN))PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
*PROCキーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる正当な RPG 名を使用すること。
¥ を含む名前(W¥PGM 等)や @@ で始まる名前は使用不可。ファイル仕様書のフラグ(入力、更新、追加など)を正確に変換すること
DCL-F に RECLN キーワードは指定できない
フリーフォーマットのDCL-FではRECLNキーワードは認識されず、ファイル全体が無視される(RNF2023/RNF2109)。
固定長バッファ出力が必要な場合は、DCL-F ... DISK USAGE(*OUTPUT)のみ記述し、
バッファはDCL-S XXXXREC CHAR(nnn)で別途定義してWRITE ファイル名 バッファ変数で書き出すこと。
例:
誤) DCL-F ABAWP42 DISK RECLN(308) USAGE(*OUTPUT);
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;READE 後の %EOF は複合キー形式では使用できない場合がある
READE (キー1:キー2) ファイル名;の形式で読み込んだ後、%EOF(ファイル名)が RNF0391 エラーになる場合がある。
この場合はREADEの結果標識(例:*IN03)を直接使うか、%EOFをファイル名なしで使用すること。
例:
誤) READE (WTOKU:FSIKU) GADPL141;
*IN03 = %EOF(GADPL141); ← RNF0391
正) READE (WTOKU:FSIKU) GADPL141 *IN03;
IF *IN03;%DEC に TIME 型を渡す場合は精度・小数点パラメーターを指定できない
%DEC(%TIME():6:0)のように TIME 型変数に桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
TIME 型を数値に変換するには%INT(%DEC(%TIME()))または%INT(%CHAR(%TIME():'HHMMSS'))を使うこと。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
数値は%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO; ← N1USYO が ZONED 型
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない
%CHAR(*DATE:'*YMD0')のように日付フォーマットを第2パラメーターに渡すと RNF0621 エラーになる。
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うか、
DATE 型変数を%CHAR()でそのまま変換(デフォルト書式)すること。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式(編集コードY)プリンターファイルの OFLIND には
*IN0Fを使用すること
固定長 RPG IV のOFLIND(*INOF)をフリーフォーマットに変換する場合、*INOFは不正なパラメーター
(RNF2014)になる。フリーフォーマットではOFLIND(*IN0F)と記述すること。
また、*INOFは標識参照として*IN0Fと書く(英字「O」ではなく数字「0」)。
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
正) DCL-F QPRINT PRINTER OFLIND(*IN0F);固定長プログラム記述ファイル(F指定)は
DCL-FにPGMDESCキーワードを付加すること
固定長 RPG IV でF指定(プログラム記述)のファイルをDCL-Fに変換する場合、
PGMDESCキーワードを付けないと RPG は外部記述ファイルとして扱い、
同名レコード様式が実在する場合に RNF2121(様式名重複)→ RNF2109(ファイル無視)が発生する。
RNF2109 でファイルが無視されると、後続のDCL-DS・DCL-S・DCL-PIがすべて演算仕様として
誤認され、RNF0724(ステートメントタイプ順序不正)や RNF5347(割り当て演算子が必要)が大量発生する。
固定長プログラム記述ファイルの場合、ルール12(RECLN 禁止)に従いバッファ変数方式と組み合わせること。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
誤) DCL-F ABAWP42 DISK USAGE(*OUTPUT); ← 外部記述として扱われる
正) DCL-F ABAWP42 DISK PGMDESC USAGE(*OUTPUT); ← プログラム記述として扱われる
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
※ 入力用プログラム記述ファイルも同様にPGMDESCを付けること。
3-5. ソース④(2回目)
この辺からルールファイルの縛りがガチガチになってきます
コンパイル結果
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 6 | 9 |
うまく変換できたロジック
- DISK ファイルの
DCL-F定義(NAIPP01、GADPL11)とEXTDESCによる外部ファイル指定 - 位置オーバーレイ DS の
OVERLAYキーワードへの変換(年月DS・品番DS・背番号DSなど) - 63桁超の
SN ZONED(217:0) DIM(31)をPACKED(7:0) OVERLAY+ CHAR バッファ方式に変換 -
KLIST/KFLDの複合キーをCHAIN (WTOKU:WNONY:FKOJ:WNUKE) GADPL11形式に変換 -
GOTO @END / TAG @ENDをEXSR @END+空サブルーチン化による構造化に変換 -
DO 1 TO 31ループをFOR A = 1 TO 31 / ENDFORに変換 - 大量の
IF/IFEQ/ANDEQ工場変換ロジックをIF/AND/ENDIF形式に正確に展開 -
SETOFF 0507→*IN05 = *OFF; *IN07 = *OFF;への標識初期化の変換 -
TIME命令を%INT(%DEC(%TIME()))に変換 -
DCL-PI *Nによるエントリーパラメーター定義とCTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER)の付加
変換に失敗したロジック(エラー原因になった可能性)
-
DCL-F ABAWP42 DISK USAGE(*OUTPUT)→ ファイル名とレコード様式名が同名で RNF2121 / RNF2109 が発生しファイル無視 -
DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('FILELIB/QPRINT')→ EXTDESC 先のファイルが存在せず RNF2120 でファイル無視 -
%YEAR(%DATE())/%MONTH(%DATE())/%DAY(%DATE())の使用 → RNF0604(不正なトークン)+ RNF0325 が3行連発 -
*INLR = *ON/RETURNをサブルーチン定義の後ろに記述 → RNF5005 が2行発生し終了処理が無視される -
%SUBST(N1KKUK:1:4)の第3引数が文字列長(2桁)を超える指定 → RNF0365(第3パラメーター過大)が発生 -
%EDITC(N1KKTN:'Z')で CHAR 型フィールドに編集コードを適用 → RNF7059(数値でないフィールド)が発生 -
WRITE ABAWP42 ABAWRECで ABAWP42 が無視済みのため → RNF7503(未定義オペランド)が発生 - GADPL11 の多数のフィールド(B5TOKU 等)が RPG 上で DCL-S 定義と衝突し RNF7031 が大量に警告
まとめ
ファイル定義・DS オーバーレイ・ループ・条件分岐など骨格部分の変換精度は高く、工場変換の大量 IF 連鎖も正確に展開できていた。
ただし ABAWP42 のようにファイル名とレコード様式名が同じケースへの対処が抜け落ちており、これが出力ファイル全体の無視につながった。
日付取得に %YEAR/%MONTH/%DAY という存在しない関数を使ったことと、*INLR = *ON / RETURN の配置ミスは定番の落とし穴で、「変換の大枠は正解、でも詰めが甘い」という結果になった。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
- MYLIB/QPGMSRC(MBR_04) を、RPGⅣ の固定長形式から、
ソースコード先頭に "**FREE" を記述した完全フリーフォーマットの RPG に変換してください- 変換が終わったら下記の通り精査し、間違っていれば修正してください
- 確認方針
- コンパイル時に重大度30以上のエラーが発生する可能性が無いか
- コードの文法があっているか
- 注意点
- "C:\Users\ユーザー名.bob\rules\Rule_Convert_FF.md" のルールに従うこと
- 最後に、変換タスクのサマリーを html ファイルにして、メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力してください
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
プロシージャー名・変数名に使用できる文字の制限
プロシージャー名・変数名・フィールド名には、英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字はフリーフォーマット RPG の識別子として使用できないため、
¥SB100 → SB100 のように変換すること。*DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
CRTBNDRPG のデフォルトは DFTACTGRP(*YES) であるため、プロシージャーが存在すると RNF1520 エラーになる。フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;%DATE() / %TIME() の戻り値は DATE / TIME 型であり、数値型変数へ直接代入できない
ZONED や PACKED の変数に年月日を格納する場合は、%YEARS / %MONTHS / %DAYS / %HOURS 等を使用した上で
%INT() 等で数値型に変換してから代入すること。
例:
誤) WTIYY = %YEARS(%DATE());
正) WTIYY = %INT(%YEARS(%DATE()));1行に複数ステートメントをセミコロンで連結しない
フリーフォーマットの1行は最大100桁だが、固定長ソース(SRCTYPE=RPGLE)では80桁制限が適用される場合がある。
複数の独立したステートメントは必ず別々の行に記述すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
DCL-F で外部記述ファイルを定義している場合、同名フィールドを RPG 内で異なる長さで再定義・使用すると
RNF6033 エラーになる。フィールド長は外部 DDS の定義と必ず一致させること。%EDITW の編集語はフィールド桁数分の置換文字が必要
%EDITW(フィールド: '編集語') の編集語には、対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールドには 4文字の編集語が必要 → %EDITW(NO: ' ')外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要
CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で
プロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型(ZONED / PACKED / INT 等)のフィールドに %TRIM を適用しないこと。
数値を文字として扱いたい場合は %CHAR() で変換してから %TRIM を適用すること。
例:
誤) %TRIM(W1MBMN) ← W1MBMNがZONED型
正) %TRIM(%CHAR(W1MBMN))PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
*PROCキーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる正当な RPG 名を使用すること。
¥ を含む名前(W¥PGM 等)や @@ で始まる名前は使用不可。ファイル仕様書のフラグ(入力、更新、追加など)を正確に変換すること
DCL-F に RECLN キーワードは指定できない
フリーフォーマットのDCL-FではRECLNキーワードは認識されず、ファイル全体が無視される(RNF2023/RNF2109)。
固定長バッファ出力が必要な場合は、DCL-F ... DISK USAGE(*OUTPUT)のみ記述し、
バッファはDCL-S XXXXREC CHAR(nnn)で別途定義してWRITE ファイル名 バッファ変数で書き出すこと。
例:
誤) DCL-F ABAWP42 DISK RECLN(308) USAGE(*OUTPUT);
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;READE 後の %EOF は複合キー形式では使用できない場合がある
READE (キー1:キー2) ファイル名;の形式で読み込んだ後、%EOF(ファイル名)が RNF0391 エラーになる場合がある。
この場合はREADEの結果標識(例:*IN03)を直接使うか、%EOFをファイル名なしで使用すること。
例:
誤) READE (WTOKU:FSIKU) GADPL141;
*IN03 = %EOF(GADPL141); ← RNF0391
正) READE (WTOKU:FSIKU) GADPL141 *IN03;
IF *IN03;%DEC に TIME 型を渡す場合は精度・小数点パラメーターを指定できない
%DEC(%TIME():6:0)のように TIME 型変数に桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
TIME 型を数値に変換するには%INT(%DEC(%TIME()))または%INT(%CHAR(%TIME():'HHMMSS'))を使うこと。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
数値は%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO; ← N1USYO が ZONED 型
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない
%CHAR(*DATE:'*YMD0')のように日付フォーマットを第2パラメーターに渡すと RNF0621 エラーになる。
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うか、
DATE 型変数を%CHAR()でそのまま変換(デフォルト書式)すること。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式(編集コードY)プリンターファイルの OFLIND には
*IN0Fを使用すること
固定長 RPG IV のOFLIND(*INOF)をフリーフォーマットに変換する場合、*INOFは不正なパラメーター
(RNF2014)になる。フリーフォーマットではOFLIND(*IN0F)と記述すること。
また、*INOFは標識参照として*IN0Fと書く(英字「O」ではなく数字「0」)。
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
正) DCL-F QPRINT PRINTER OFLIND(*IN0F);ファイル名と同名のレコード様式が実在すると
DCL-Fがファイルごと無視される
フリーフォーマットのDCL-FではPGMDESCキーワードは DISK / PRINTER のいずれにも使用できず
(RNF2023 エラーになる)、指定しても無視される。その結果 RPG は外部記述ファイルとして扱い、
ファイル名と同名のレコード様式が実ファイルに実在する場合に RNF2121(様式名重複)→ RNF2109(ファイル無視)が連鎖する。
RNF2109 でファイルが無視されると、後続のDCL-DS・DCL-S・DCL-PIがすべて演算仕様として
誤認され、RNF0724(ステートメントタイプ順序不正)や RNF5347(割り当て演算子が必要)が大量発生する。
この問題は DISK ファイルだけでなく PRINTER ファイルでも発生する。【DISK ファイルの対処】
固定長プログラム記述の出力ファイルは、ルール12(RECLN 禁止)に従いバッファ変数方式を使うこと。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
誤) DCL-F ABAWP42 DISK PGMDESC USAGE(*OUTPUT); ← PGMDESC は認識されず RNF2023
誤) DCL-F ABAWP42 DISK USAGE(*OUTPUT); ← 同名様式が存在するとファイル無視
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
※ バッファ変数方式自体はファイルが無視される問題の根本解決にはならない。
ABAWP42 のように実ファイルに同名様式が存在する場合は、実ファイル側のレコード様式名を
確認し、EXTDESC キーワードで別名の外部ファイルを指定するか、DDS 側でレコード様式名を
変更することを検討すること。【PRINTER ファイルの対処】
QPRINTのようにシステム側に同名の外部記述プリンターファイルが存在する場合も同様のエラーが発生する。
OFLINDがEXTINDと誤解釈され RNF2017 → RNF2121 → RNF2109 が連鎖する。
この場合はEXTDESCで実在しないダミー名を指定するか、プリンターファイルを独自 DDS で作成して
同名様式の衝突を回避すること。
例:
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F); ← QGPL/QPRINT に同名様式が存在すると RNF2017/RNF2109
正) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT'); ← 別名ファイルで様式衝突を回避CHAIN の結果(見つかった/見つからない)は
%FOUNDまたは%ERRORで判定すること
フリーフォーマットのCHAINでは、固定長の結果標識(NR標識)をCHAIN キー FILE *INxx;のように
付加することはできず、RNF0637(オペランドが必要)→ RNF7030(標識未定義)エラーになる。
CHAIN の後は%FOUNDまたは%FOUND(ファイル名)で結果を判定すること。
例:
誤) CHAIN KFLDS GADPL11 *IN03;
IF *IN03; ← RNF7030(IN03 未定義)正) CHAIN KFLDS GADPL11;
*IN03 = NOT %FOUND(GADPL11); ← 見つからなかった場合に ON
IF NOT %FOUND(GADPL11); ← 直接判定する場合ZONED / PACKED 数値型の桁数は最大63桁まで
ZONED(nnn:0)やPACKED(nnn:0)の桁数に 64 以上を指定すると RNF0503(数字項目の長さが63桁より大きい)
エラーになり、自動的に 63 桁に切り詰められる。
63桁を超えるデータ領域が必要な場合はCHAR型に変換し、数値演算が必要な部分のみ別途 ZONED/PACKED で定義すること。
例:
誤) SN ZONED(217:0); ← RNF0503(217桁 > 63桁制限)
正) SNBUF CHAR(217); ← バイト配列として定義
SNX ZONED(7:0) DIM(31); ← 必要な単位で個別定義
DATE型変数の日付フォーマットにゼロサフィックスは使用できない
DCL-S WB5DATE DATE(*ISO0);のように日付フォーマット名の末尾に0を付けると
RNF0619(日付形式の後のゼロは使用できない)エラーになる。
変数定義では*ISO・*YMD・*MDY・*DMY・*JULなどゼロなしのフォーマットを使うこと。
ゼロサフィックス(*ISO0・*YMD0等)は%DATEや%CHARの変換パラメーターとしても使用不可(ルール17参照)。
例:
誤) DCL-S WB5DATE DATE(*ISO0); ← RNF0619
正) DCL-S WB5DATE DATE(*ISO);フリーフォーマット
DCL-DSには必ず DS 名または*Nを指定すること
固定長 RPG IV では無名 DS(名前なし)が許容されたが、フリーフォーマットのDCL-DSでは
DS 名または*N(匿名)を必ず指定しなければならない。
DS 名も*Nも省略すると RNF3368(定義仕様が完全ではありません)エラーになる。
例:
誤) DCL-DS;
B5SKH8 ZONED(8:0) POS(1);
END-DS;
正) DCL-DS *N;
B5SKH8 ZONED(8:0);
END-DS;フリーフォーマット
DCL-DSのサブフィールドにPOSキーワードは使用できない
固定長 RPG IV の I 仕様(入力仕様)で使われていたバイト位置指定(POS(n))は、
フリーフォーマットのDCL-DSでは認識されない(RNF5347 / RNF0724 連鎖の原因)。
位置共有が必要な場合はOVERLAY(親フィールド:開始位置)キーワードで記述すること。
例:
誤) DCL-DS *N;
UYM1 ZONED(4:0) POS(1);
UYY1 ZONED(2:0) POS(1);
UMM1 ZONED(2:0) POS(3);
END-DS;
正) DCL-DS *N;
UYM1 ZONED(4:0);
UYY1 ZONED(2:0) OVERLAY(UYM1:1);
UMM1 ZONED(2:0) OVERLAY(UYM1:3);
END-DS;
3-6. ソース④(3回目)
内部記述プリンター・ファイルでつまづいたのでこのソースは一旦クローズ
コンパイル結果
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 7 | 186 |
うまく変換できたロジック
- DISK ファイルの DCL-F 定義(NAIPP01、GDDB51 相当)と DCL-PI によるパラメータ宣言
- 複数の無名 DS を OVERLAY キーワードを使った DCL-DS *N に正しく変換(UYM1/UYY1/UMM1 など)
- バイト位置指定(D仕様の
1 4 0等)を OVERLAY(親フィールド:開始位置) に変換 - KLIST/KFLD による複合キーを CHAIN (WTOKU:WNONY:FKOJ:WNUKE) の括弧コロン形式に変換
- IFEQ/ANDEQ/OREQ の複合条件を IF ... AND ... / IF ... OR ... の構文に変換
- GOTO @END + TAG を
IF ... *INLR = *ON; RETURN;による早期リターンに変換 - Z-ADD / MOVE / MOVEL を代入文(= 演算子)に変換
- 30本超の IF/END-IF 工場変換ブロックを全件フリーフォーマットに展開
- 出力仕様(O仕様)を BEGSR SRWRT 内の %SUBST + %EDITC による手動バッファ組み立てに変換
- CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を付与し、WTIME に %INT(%DEC(%TIME())) を使用
変換に失敗したロジック(エラー原因になった可能性)
- ABAWP42 の DCL-F 定義に RENAME 指定漏れ → 実ファイルと同名のレコード様式が衝突し RNF2121/RNF2109 が発生、ファイルが丸ごと無視された
- QPRINT の DCL-F 定義に EXTDESC 指定漏れ → QGPL/QPRINT の同名様式と衝突し RNF2017/RNF2109 が発生、こちらも無視された
- 上記2件の RNF2109 が引き金となり、後続の全 END-IF に RNF5347(EVAL に割り当て演算子が必要)が大量連鎖
- CRTBNDRPG に DFTACTGRP(*YES) を指定してコンパイル → CTL-OPT の
*NOが無視され RNF5347 がさらに全行で発生 -
*DATEを 8桁数値と比較するために %SUBDT(%DATE():*YEARS) 等を使用 → RNF0579(期間関数パラメーター不正)+ RNF0325 が連鎖 - N1KKUK(2桁 CHAR)に %SUBST(N1KKUK:1:4) で4桁を取り出そうとした → RNF0365(第3引数が大きすぎる)
- QPRINT の WRITE 命令でファイル名 QPRINT を参照 → ファイルが無視済みのため RNF7503(未定義オペランド)が WRITE 行すべてで発生
- IF条件ブロック内のネスト構造が崩れ、RNF5142(IF/ELSE の順序不正)と RNF5177(ENDxx 欠落)が連発
- 変換後ソースと実際のコンパイル対象ソースの間で WTIME の型が食い違い(ZONED(6:0) → CHAR(6) に変更されている)
- GADPL11 のキーフィールドが B5TOKU/B5NONY/B5NKOJ/B5NUKE なのに、CHAIN で WTOKU/WNONY/FKOJ/WNUKE を渡しており、型・フィールド名が一致しない可能性がある
まとめ
DISK ファイルの基本的な DCL-F 定義、DS の OVERLAY 変換、複合キーの括弧コロン形式、大量の IF 条件ブロックといった骨格部分の変換精度は高く、手直し箇所は少なそうだった。
ところが ABAWP42 と QPRINT の2ファイルで「実ファイルのレコード様式名とファイル名が同名」という地雷を踏んだことで RNF2109 が発生し、後続の END-IF が全滅する大連鎖を招いた。
さらに DFTACTGRP(*YES) のままコンパイルしたことでダメ押しの RNF5347 祭りになった。ファイル名衝突の確認と CRTBNDRPG のオプション指定が、次回への最大の教訓だ。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
対象メンバー
- 変換元
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_04
- 変換後
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_04_FF
タスク
- RPGⅣ の固定長形式から、ソースコード先頭に "**FREE" を記述した完全フリーフォーマットの RPG に変換する
- "C:\Users\ユーザー名.bob\rules\Rule_Convert_FF.md" のルールに従うこと
- 出力前にソースコードを精査し、重大度30以上のエラーの発生要因を特定する
- エラー要因箇所を修正し、修正が終わったらソースコード全体を読んで、修正個所とそれ以外の部分の整合性が取れているか確認する
- 新たなエラー原因となる箇所が見つかった場合は 2 に戻り修正を行うこと
- 変換後メンバーとして新規出力する
- 変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
- "C:\Users\A126552\Desktop\作業用フォルダ\AI\IBM Bob\CVTRPGSRCテスト"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
プロシージャー名・変数名に使用できる文字の制限
プロシージャー名・変数名・フィールド名には、英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字はフリーフォーマット RPG の識別子として使用できないため、
¥SB100 → SB100 のように変換すること。*DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
CRTBNDRPG のデフォルトは DFTACTGRP(*YES) であるため、プロシージャーが存在すると RNF1520 エラーになる。フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;%DATE() / %TIME() の戻り値は DATE / TIME 型であり、数値型変数へ直接代入できない
ZONED や PACKED の変数に年月日を格納する場合は、%YEARS/%MONTHS/%DAYS(複数形)を使用し、
%INT()等で数値型に変換してから代入すること。
%YEAR/%MONTH/%DAY(単数形)はフリーフォーマット RPG では組み込み関数として存在せず、
RNF0604(トークン不正)→ RNF0325(%INT パラメーター不正)エラーになる。
例:
誤) WTIYY = %YEARS(%DATE()); ← 数値への直接代入は不可
誤) WTODAY = %INT(%YEAR(%DATE())) * 10000
+ %INT(%MONTH(%DATE())) * 100
+ %INT(%DAY(%DATE())); ← %YEAR/%MONTH/%DAY は存在しない(RNF0604)
正) WTIYY = %INT(%YEARS(%DATE()));
正) WTODAY = %INT(%YEARS(%DATE())) * 10000
+ %INT(%MONTHS(%DATE())) * 100
+ %INT(%DAYS(%DATE()));1行に複数ステートメントをセミコロンで連結しない
フリーフォーマットの1行は最大100桁だが、固定長ソース(SRCTYPE=RPGLE)では80桁制限が適用される場合がある。
複数の独立したステートメントは必ず別々の行に記述すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
DCL-F で外部記述ファイルを定義している場合、同名フィールドを RPG 内で異なる長さで再定義・使用すると
RNF6033 エラーになる。フィールド長は外部 DDS の定義と必ず一致させること。%EDITW の編集語はフィールド桁数分の置換文字が必要
%EDITW(フィールド: '編集語') の編集語には、対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールドには 4文字の編集語が必要 → %EDITW(NO: ' ')外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要
CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で
プロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型(ZONED / PACKED / INT 等)のフィールドに %TRIM を適用しないこと。
数値を文字として扱いたい場合は %CHAR() で変換してから %TRIM を適用すること。
例:
誤) %TRIM(W1MBMN) ← W1MBMNがZONED型
正) %TRIM(%CHAR(W1MBMN))PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
*PROCキーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる正当な RPG 名を使用すること。
¥ を含む名前(W¥PGM 等)や @@ で始まる名前は使用不可。ファイル仕様書のフラグ(入力、更新、追加など)を正確に変換すること
DCL-F に RECLN キーワードは指定できない
フリーフォーマットのDCL-FではRECLNキーワードは認識されず、ファイル全体が無視される(RNF2023/RNF2109)。
固定長バッファ出力が必要な場合は、DCL-F ... DISK USAGE(*OUTPUT)のみ記述し、
バッファはDCL-S XXXXREC CHAR(nnn)で別途定義してWRITE ファイル名 バッファ変数で書き出すこと。
例:
誤) DCL-F ABAWP42 DISK RECLN(308) USAGE(*OUTPUT);
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;READE 後の %EOF は複合キー形式では使用できない場合がある
READE (キー1:キー2) ファイル名;の形式で読み込んだ後、%EOF(ファイル名)が RNF0391 エラーになる場合がある。
この場合はREADEの結果標識(例:*IN03)を直接使うか、%EOFをファイル名なしで使用すること。
例:
誤) READE (WTOKU:FSIKU) GADPL141;
*IN03 = %EOF(GADPL141); ← RNF0391
正) READE (WTOKU:FSIKU) GADPL141 *IN03;
IF *IN03;%DEC に TIME 型を渡す場合は精度・小数点パラメーターを指定できない
%DEC(%TIME():6:0)のように TIME 型変数に桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
TIME 型を数値に変換するには%INT(%DEC(%TIME()))または%INT(%CHAR(%TIME():'HHMMSS'))を使うこと。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
数値は%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO; ← N1USYO が ZONED 型
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない
%CHAR(*DATE:'*YMD0')のように日付フォーマットを第2パラメーターに渡すと RNF0621 エラーになる。
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うか、
DATE 型変数を%CHAR()でそのまま変換(デフォルト書式)すること。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式(編集コードY)プリンターファイルの OFLIND には
*IN0Fを使用すること
固定長 RPG IV のOFLIND(*INOF)をフリーフォーマットに変換する場合、*INOFは不正なパラメーター
(RNF2014)になる。フリーフォーマットではOFLIND(*IN0F)と記述すること。
また、*INOFは標識参照として*IN0Fと書く(英字「O」ではなく数字「0」)。
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
正) DCL-F QPRINT PRINTER OFLIND(*IN0F);ファイル名と同名のレコード様式が実在すると
DCL-Fがファイルごと無視される
フリーフォーマットのDCL-FではPGMDESCキーワードは DISK / PRINTER のいずれにも使用できず
(RNF2023 エラーになる)、指定しても無視される。その結果 RPG は外部記述ファイルとして扱い、
ファイル名と同名のレコード様式が実ファイルに実在する場合に RNF2121(様式名重複)→ RNF2109(ファイル無視)が連鎖する。
RNF2109 でファイルが無視されると、後続のDCL-DS・DCL-S・DCL-PIがすべて演算仕様として
誤認され、RNF0724(ステートメントタイプ順序不正)や RNF5347(割り当て演算子が必要)が大量発生する。
この問題は DISK ファイルだけでなく PRINTER ファイルでも発生する。【DISK ファイルの対処】
固定長プログラム記述の出力ファイルは、ルール12(RECLN 禁止)に従いバッファ変数方式を使うこと。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
誤) DCL-F ABAWP42 DISK PGMDESC USAGE(*OUTPUT); ← PGMDESC は認識されず RNF2023
誤) DCL-F ABAWP42 DISK USAGE(*OUTPUT); ← 同名様式が存在するとファイル無視
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
※ バッファ変数方式自体はファイルが無視される問題の根本解決にはならない。
ABAWP42 のように実ファイルに同名様式が存在する場合は、実ファイル側のレコード様式名を
確認し、EXTDESC キーワードで別名の外部ファイルを指定するか、DDS 側でレコード様式名を
変更することを検討すること。【PRINTER ファイルの対処】
QPRINTのようにシステム側に同名の外部記述プリンターファイルが存在する場合も同様のエラーが発生する。
OFLINDがEXTINDと誤解釈され RNF2017 → RNF2121 → RNF2109 が連鎖する。
この場合はEXTDESCで独自 DDS プリンターファイルの実在するライブラリ/ファイル名を指定して
同名様式の衝突を回避すること。
EXTDESCに実在しないファイル名を指定すると RNF2120(外部記述が見つからない)でファイルが無視される。
例:
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F); ← QGPL/QPRINT に同名様式が存在すると RNF2017/RNF2109
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('FILELIB/QPRINT'); ← 実在しない場合 RNF2120
正) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT'); ← 実在する独自DDS名を指定CHAIN の結果(見つかった/見つからない)は
%FOUNDまたは%ERRORで判定すること
フリーフォーマットのCHAINでは、固定長の結果標識(NR標識)をCHAIN キー FILE *INxx;のように
付加することはできず、RNF0637(オペランドが必要)→ RNF7030(標識未定義)エラーになる。
CHAIN の後は%FOUNDまたは%FOUND(ファイル名)で結果を判定すること。
例:
誤) CHAIN KFLDS GADPL11 *IN03;
IF *IN03; ← RNF7030(IN03 未定義)正) CHAIN KFLDS GADPL11;
*IN03 = NOT %FOUND(GADPL11); ← 見つからなかった場合に ON
IF NOT %FOUND(GADPL11); ← 直接判定する場合ZONED / PACKED 数値型の桁数は最大63桁まで
ZONED(nnn:0)やPACKED(nnn:0)の桁数に 64 以上を指定すると RNF0503(数字項目の長さが63桁より大きい)
エラーになり、自動的に 63 桁に切り詰められる。
63桁を超えるデータ領域が必要な場合はCHAR型に変換し、数値演算が必要な部分のみ別途 ZONED/PACKED で定義すること。
例:
誤) SN ZONED(217:0); ← RNF0503(217桁 > 63桁制限)
正) SNBUF CHAR(217); ← バイト配列として定義
SNX ZONED(7:0) DIM(31); ← 必要な単位で個別定義
DATE型変数の日付フォーマットにゼロサフィックスは使用できない
DCL-S WB5DATE DATE(*ISO0);のように日付フォーマット名の末尾に0を付けると
RNF0619(日付形式の後のゼロは使用できない)エラーになる。
変数定義では*ISO・*YMD・*MDY・*DMY・*JULなどゼロなしのフォーマットを使うこと。
ゼロサフィックス(*ISO0・*YMD0等)は%DATEや%CHARの変換パラメーターとしても使用不可(ルール17参照)。
例:
誤) DCL-S WB5DATE DATE(*ISO0); ← RNF0619
正) DCL-S WB5DATE DATE(*ISO);フリーフォーマット
DCL-DSには必ず DS 名または*Nを指定すること
固定長 RPG IV では無名 DS(名前なし)が許容されたが、フリーフォーマットのDCL-DSでは
DS 名または*N(匿名)を必ず指定しなければならない。
DS 名も*Nも省略すると RNF3368(定義仕様が完全ではありません)エラーになる。
例:
誤) DCL-DS;
B5SKH8 ZONED(8:0) POS(1);
END-DS;
正) DCL-DS *N;
B5SKH8 ZONED(8:0);
END-DS;フリーフォーマット
DCL-DSのサブフィールドにPOSキーワードは使用できない
固定長 RPG IV の I 仕様(入力仕様)で使われていたバイト位置指定(POS(n))は、
フリーフォーマットのDCL-DSでは認識されない(RNF5347 / RNF0724 連鎖の原因)。
位置共有が必要な場合はOVERLAY(親フィールド:開始位置)キーワードで記述すること。
例:
誤) DCL-DS *N;
UYM1 ZONED(4:0) POS(1);
UYY1 ZONED(2:0) POS(1);
UMM1 ZONED(2:0) POS(3);
END-DS;
正) DCL-DS *N;
UYM1 ZONED(4:0);
UYY1 ZONED(2:0) OVERLAY(UYM1:1);
UMM1 ZONED(2:0) OVERLAY(UYM1:3);
END-DS;
*INLR = *ONとRETURNはサブルーチン外(メイン処理の末尾)に記述すること
フリーフォーマットでは、BEGSR~ENDSRの直後にメインの演算命令(*INLR = *ON;やRETURN;等)を
記述すると RNF5005(ENDSR 演算命令の後の演算命令の指定が正しくない)エラーになり、その行は無視される。
プログラム終了処理は必ずサブルーチンブロックの前に記述するか、最後のサブルーチンの後に続けないこと。
例:
誤) BEGSR @END;
ENDSR;
*INLR = *ON; ← RNF5005(ENDSR 直後のため無視)
RETURN; ← RNF5005(同上)正) *INLR = *ON; ← サブルーチン定義の前に記述
RETURN;
BEGSR @END;
ENDSR;
3-7. ソース⑤(1回目)
プリンター・ファイルの無いソースでトライ
コンパイル結果
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 3 | 5 |
うまく変換できたロジック
- 3ファイル(入力・更新・出力)の DCL-F 定義と USAGE キーワードの対応が適切
- 無名 DS の OVERLAY 変換(WTIME 配下の時刻・日付分解フィールド群)が正確
- PSDS を DCL-DS *N PSDS + POS() キーワード形式に正しく変換(¥ 除去も完了)
- KLIST 12フィールドをコロン区切り複合キー形式の CHAIN に変換(#SB500・#SB530の両箇所)
-
%FOUND(ファイル名)を使った CHAIN 結果判定への変換(IN21 への代入) - DOWEQ '0' →
DOW NOT %EOF(ファイル名)への EOF ループ変換 - IFEQ/OREQ/ANDEQ → IF...OR/AND 形式への条件式の展開
- Z-ADD/MOVEL/SUB/MULT → 代入式・算術演算式への変換
- SELECT/WHENEQ → IF/ELSE/ENDIF 構造への書き換え
- CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を正しく付与
変換に失敗したロジック(エラー原因になった可能性)
-
%YEARS(%DATE())・%MONTHS(%DATE())・%DAYS(%DATE())を使用 → RNF0579/RNF0325 が6行分連発(期間関数の誤用。正しくは単数形%YEAR/%MONTH/%DAY) - 元ソースの無名 DS(A0SKHZ の集約ワーク)が変換されず未定義 → RNF7030(A0SKHZ が未定義)と RNF7503 が発生
- TIME 命令の変換が WTITM(時刻)と WTIHZ(日付)に分割されており、日付側に誤った期間関数を使用
- コンパイルコマンドに
DFTACTGRP(*YES)が残っており CTL-OPT と矛盾(今回は CTL-OPT 側が優先されたが要注意)
まとめ
今回のプログラムは比較的シンプルな構造だったこともあり、
ファイル定義・DS定義・CHAIN・ループ・条件分岐といった骨格部分の変換精度は高かった。
特に 12フィールドもある複合キーを正確なコロン区切り形式に変換できていたのは素直に◎。
一方で致命傷だったのは「期間関数の単数形・複数形の混同」で、
%YEARS / %MONTHS / %DAYS(複数形=期間演算用)を日付取り出しに使ってしまい、
関連6行が芋づる式にエラーになった。
また元ソースの集約ワーク DS(A0SKHZ)の変換漏れも未定義エラーを招いた。
変換カバレッジは広いものの、組み込み関数の細かい使い分けが甘く、その点を押さえれば一発コンパイルに近づける。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
対象メンバー
- 変換元
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_05
- 変換後
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_05_FF
タスク
- 【事前確認】変換を開始する前に、変換元ソース全体を読みこんで構成を把握する
- 【事前確認】変換を開始する前に、F仕様の全ファイルを対象に以下を確認する
1-1. DISK ファイルの確認
get_table_metadataで各 DISK ファイルの実レコード様式名を確認する- 外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述で同名様式あり →
EXTDESCで別名ファイルを指定(ユーザーに確認)- プログラム記述(F区分=F) → バッファ変数方式を採用(Rule_Convert_FF.md ルール3)
ただし実ファイルに同名様式が存在する場合はEXTDESCの要否もユーザーに確認すること1-2. PRINTER ファイルの確認
- 各 PRINTER ファイルが外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述 →
get_table_metadataでレコード様式名を確認し、同名様式があればEXTDESCで独自 DDS を指定- プログラム記述(F区分=F) → 対応する独自プリンター DDS ファイルをユーザーに確認する
DDS が特定できない場合はそのファイルの変換を保留し、ユーザーに判断を仰ぐことOFLIND(*INOF)は必ずOFLIND(*IN0F)に変換する(英字 O → 数字 0)1-3. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む
- 【変換】事前確認の結果を反映しながら、RPG IV 固定長形式を完全フリーフォーマットに変換する
- ソースコード先頭に
**FREEを記述する- "Rule_Convert_FF.md" の全ルールに従うこと
- 特に以下を重点確認すること
- ファイル定義(ルール1〜4):事前確認の対処方針を確実に反映する
- DCL-DS の POS → OVERLAY への変換(ルール7)
- 演算命令のオペランド順序(ルール13)
- 1行に複数ステートメントを書かない(ルール17):
IF X; Y=0; END-IF;も禁止- 【精査】出力前にソースコードを精査し、重大度20以上のエラー要因を除去する
- ファイル定義の問題(RNF2109 / RNF2121)が残っていないか確認する
- 1行に複数ステートメントが残っていないか全行スキャンする(RNF5508)
- ファイル定義エラーを起点とした連鎖エラー(RNF5347 / RNF0724 の大量発生)がないか確認する
- エラー要因を修正したらソースコード全体の整合性を再確認する
- 新たなエラー原因が見つかった場合は本ステップを繰り返す
- 【出力】変換後メンバーとして新規出力する
- 【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
- サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
- 【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
── ファイル定義(DCL-F)関連 ──
DISK/PRINTER ファイル変換前に「実ファイルのレコード様式名」を必ず確認すること
フリーフォーマットのDCL-Fでは、ファイル名と同名のレコード様式が実ファイルに存在すると
RNF2121(様式名重複)→ RNF2109(ファイル全体が無視)が発生する。
この問題は DISK / PRINTER / プログラム記述ファイルすべてに適用される。変換前に必ずやること:
get_table_metadataまたはread_ibmi_sourceで対象ファイルのレコード様式名を確認する- ファイル名とレコード様式名が同一の場合 → 必ず以下のいずれかで対処すること
- DISK 外部記述ファイル:
EXTDESC('ライブラリ/別名ファイル')で衝突を回避する- DISK プログラム記述ファイル(F区分=F):バッファ変数方式(後述ルール3)に変換する
- PRINTER ファイル:後述ルール2に従う
- 対処方法が不明な場合は処理を中断してユーザーに確認を求めること
RNF2109 が発生するとどうなるか:
ファイルが無視されると後続のすべての定義(DCL-S / DCL-DS / DCL-PI)や
演算命令(IF / END-IF 等)が演算仕様として誤認され、RNF5347 / RNF0724 が大量発生する。
この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。PRINTER ファイルの変換方針
固定長 RPG IV の PRINTER ファイルは以下の2パターンがあり、変換前に判定すること。【パターンA】外部記述 PRINTER ファイル(F仕様に E キーワードあり)
- 対応する独自 DDS が存在する →
EXTDESCでそのファイルを指定するOFLIND(*INOF)はOFLIND(*IN0F)に変換する(英字「O」ではなく数字「0」)QPRINTのようなシステム標準ファイルは QGPL/QPRINT に同名様式が存在するため必ずEXTDESCで独自 DDS を指定する
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F); ← 同名様式 → RNF2109
正) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');【パターンB】プログラム記述 PRINTER ファイル(F仕様に F 区分あり、E キーワードなし)
- 例:
FQPRINT O F 132 PRINTER OFLIND(*INOF)- フリーフォーマットには
PGMDESCキーワードが存在しないため、外部記述として扱われ RNF2109 が発生する- 対応する独自プリンター DDS がない場合は変換を中断してユーザーに確認を求めること
- 独自 DDS が用意できる場合のみ
EXTDESCで指定して変換する
例:
変換前) FQPRINT O F 132 PRINTER OFLIND(*INOF)
正) // 独自プリンターDDS(例: MYLIB/MYPRT)を事前に用意する
DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');
DCL-S QPREC CHAR(132);
// ...
WRITE QPRINT QPREC;DCL-F に RECLN キーワードは指定できない(DISK プログラム記述ファイルはバッファ変数方式を使う)
フリーフォーマットのDCL-FではRECLNキーワードは認識されず(RNF2023/RNF2109)。
固定長プログラム記述 DISK ファイル(F仕様のF区分)は、以下のバッファ変数方式に変換すること。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
注意: 実ファイルに同名レコード様式が存在する場合、DCL-F ABAWP42 DISK ...だけでは
RNF2121 → RNF2109 が発生してファイルごと無視される。バッファ変数方式だけでは解決しない。
この場合はEXTDESCで別名ファイルを指定するか、DDS 側のレコード様式名変更をユーザーに確認すること。ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
固定長 F 仕様の入出力区分(I/O/U/A)を DCL-F の USAGE キーワードに正しく対応させること。
固定長 フリーフォーマット I(入力) USAGE(*INPUT) O(出力) USAGE(*OUTPUT) U(更新) USAGE(*UPDATE) O+ADD(追加) USAGE(*OUTPUT)
── 定義仕様(DCL-S / DCL-DS / DCL-PI)関連 ──
プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;フリーフォーマット
DCL-DSには必ず DS 名または*Nを指定すること
固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットのDCL-DSでは
DS 名または*N(匿名)を必ず指定しなければならない(RNF3368)。
例:
誤) DCL-DS;
正) DCL-DS *N;フリーフォーマット
DCL-DSのサブフィールドにPOSキーワードは使用できない
固定長 I 仕様のバイト位置指定(POS(n))はフリーフォーマットでは認識されない(RNF5347 の原因)。
位置共有が必要な場合はOVERLAY(親フィールド:開始位置)キーワードを使うこと。
例:
誤) DCL-DS *N;
UYM1 ZONED(4:0) POS(1);
UYY1 ZONED(2:0) POS(1);
UMM1 ZONED(2:0) POS(3);
END-DS;
正) DCL-DS *N;
UYM1 ZONED(4:0);
UYY1 ZONED(2:0) OVERLAY(UYM1:1);
UMM1 ZONED(2:0) OVERLAY(UYM1:3);
END-DS;ZONED / PACKED 数値型の桁数は最大 63 桁まで
ZONED(nnn:0)やPACKED(nnn:0)の桁数に 64 以上を指定すると RNF0503 エラーになる。
63 桁を超えるデータ領域はCHAR型に変換すること。
DATE型変数の日付フォーマットにゼロサフィックスは使用できない
DATE(*ISO0)のようにゼロを付けると RNF0619 エラーになる。
変数定義では*ISO・*YMD・*MDY・*DMY・*JULなどゼロなしのフォーマットを使うこと。
例:
誤) DCL-S WB5DATE DATE(*ISO0);
正) DCL-S WB5DATE DATE(*ISO);プロシージャー名・変数名・フィールド名に使用できる文字の制限
英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字は使用できない。
¥SB100 → SB100 のように変換すること。PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
*PROCキーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる名前を使うこと。
¥ を含む名前(W¥PGM 等)は使用不可。
── 演算命令関連 ──
*DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
例:
正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;CHAIN の結果は
%FOUNDで判定すること
フリーフォーマットのCHAINに固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
CHAIN の後は%FOUNDまたは%FOUND(ファイル名)で判定すること。
例:
誤) CHAIN KFLDS GADPL11 *IN03;
正) CHAIN KFLDS GADPL11;
IF NOT %FOUND(GADPL11);READE 後の %EOF は複合キー形式では結果標識を使うこと
READE (キー1:キー2) ファイル名;の後に%EOF(ファイル名)を使うと RNF0391 エラーになる場合がある。
この場合は結果標識を直接使うこと。
例:
誤) READE (WTOKU:FSIKU) GADPL141;
*IN03 = %EOF(GADPL141);
正) READE (WTOKU:FSIKU) GADPL141 *IN03;
IF *IN03;
*INLR = *ONとRETURNはサブルーチン定義の前に記述すること
BEGSR~ENDSRブロックの直後に演算命令を記述すると RNF5005 エラーになる。
プログラム終了処理は必ずサブルーチン定義の前に記述すること。
例:
誤) BEGSR @END;
ENDSR;
*INLR = *ON; ← RNF5005
RETURN;
正) *INLR = *ON; ← サブルーチン定義の前
RETURN;
BEGSR @END;
ENDSR;1行に複数ステートメントをセミコロンで区切って記述しない(RNF5508)
フリーフォーマットでは1つの物理行に1つのステートメントのみ記述すること。
IF 条件; 処理; END-IF;のような「1行 IF」も RNF5508 エラーになるため禁止。
元ソースで固定長 CASxx / IFxx などの1行条件処理を変換する場合も必ず複数行に展開すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
誤) IF S01 = 9999999; S01 = 0; END-IF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;
正) IF S01 = 9999999;
S01 = 0;
END-IF;
── 組み込み関数・型変換関連 ──
%DATE() / %TIME() の戻り値は DATE / TIME 型であり、数値型変数へ直接代入できない
ZONED や PACKED の変数に年月日を格納する場合は、%YEARS/%MONTHS/%DAYS(複数形)を使い、
%INT()で数値型に変換してから代入すること。
%YEAR/%MONTH/%DAY(単数形)は存在しない(RNF0604)。
例:
誤) WTIYY = %YEARS(%DATE()); ← 数値への直接代入は不可
誤) WTODAY = %INT(%YEAR(%DATE())) * 10000 + ... ← %YEAR は不存在
正) WTIYY = %INT(%YEARS(%DATE()));
正) WTODAY = %INT(%YEARS(%DATE())) * 10000
+ %INT(%MONTHS(%DATE())) * 100
+ %INT(%DAYS(%DATE()));%DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
%DEC(%TIME():6:0)のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
例:
誤) %TRIM(W1MBMN) ← ZONED 型
正) %TRIM(%CHAR(W1MBMN))ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO;
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うこと。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式%EDITW の編集語はフィールド桁数分の置換文字が必要
対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールド → %EDITW(NO: ' ')
── 外部プログラム呼び出し関連 ──
外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要(RNF7030)
CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で宣言すること。ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
DCL-F で外部記述ファイルを定義している場合、同名フィールドを異なる長さで定義すると RNF6033 エラーになる。
3-8. ソース⑤(2回目)
順調にエラー数が減少している
コンパイル結果 → 失敗
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 0 | 3 |
- ちなみに、KLIST の形式と
USAGE(*UPDATE)の部分のみ手修正するとコンパイルに成功した
うまく変換できたロジック
- 3 つの DISK ファイルを
DCL-Fで正しく定義(入力・更新・出力の USAGE も一応区別) - 無名 DS のバイト位置参照を
OVERLAY(親フィールド:開始位置)形式に正しく変換 - タイムスタンプ DS(WTIME 14桁)を OVERLAY 付きで忠実に再現
- PSDS の
W\PGM・@@USER・W\JBNOをWPGM・XUSER・WJBNOに適切にリネーム -
TIME命令 →%INT(%DEC(%TIMESTAMP()))に変換し DS のサブフィールドも自動更新される構造を維持 -
DOWEQ *IN81 = '0'による EOF ループ →DOW NOT %EOF(AA001W0)に変換 -
MOVEL/Z-ADDによる多数のフィールド代入を単純な=代入に変換 -
SELECT / WHEN / ENDSLの条件分岐構造をそのまま正確に変換 -
IF … OR …/IF … AND …の複合条件をフリーフォーマット形式に変換 -
CLEAR AA001L01/WRITE/READなどの I/O 命令をそのまま維持
変換に失敗したロジック(エラー原因になった可能性)
-
KLIST/KFLDを DS 全体(KEYA01DS)渡しの CHAIN に変換 → RNF7078(キー長不一致)が 2 件- DS 先頭フィールド
#KKASI(7桁)とファイルの第1キーA0KASI(7桁)は同じ長さだが、RPG はファイルのキー合計長と DS サイズを比較するため不一致になる - 正しくは
CHAIN (#KKASI:#KTOKU:...:#KOIBN) AA001L01;のコロン区切り複合キー形式にする必要がある
- DS 先頭フィールド
-
AA001L0のファイル定義をUSAGE(*UPDATE)にしたが、元ソースはIF A(入力+追加)のためWRITE AA001L01が RNF5197(WRITE 不可なファイルタイプ)で失敗-
USAGE(*UPDATE:*OUTPUT)または追記可能な定義に変更が必要
-
- コンパイルコマンド側が
DFTACTGRP(*YES)のまま → CTL-OPT のDFTACTGRP(*NO)が無視される可能性(今回は実際にコマンドが*YES指定) - 元ソースの
A0SKHZ <= *DATEの日付比較をA0SKHZ <= WTIHZに変換しているが、*DATE(6桁 YMD)とWTIHZ(8桁 YYYYMMDD)で桁数・意味が異なり実行時に誤動作する可能性がある
まとめ
DS 定義・OVERLAY 変換・I/O 命令・制御構造(SELECT/WHEN、DOW ループ)など、
プログラムの骨格部分はかなり高い精度で変換できていた。
一方でコンパイルエラーの原因になったのは「KLIST を DS 全体渡しで CHAIN した」と「入力+追加ファイルの USAGE 指定ミス」の 2 点。
どちらも FFRPG 固有の文法知識が必要な箇所で、変換ツールが機械的に対応しにくいポイントだ。
コンパイルコマンド側の DFTACTGRP(*YES) 問題も見逃せず、ソース内の CTL-OPT だけ直しても実は意味がない、というトラップもある。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
対象メンバー
- 変換元
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_05
- 変換後
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_05_FF
タスク
【事前確認①】変換元ソース全体を読み込んで構成を把握する
- F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
【事前確認②】F仕様の全ファイルを対象に以下を確認する
2-1. DISK ファイルの確認
get_table_metadataで各 DISK ファイルの実レコード様式名を確認する- 外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述で同名様式あり →
EXTDESCで別名ファイルを指定(ユーザーに確認)- プログラム記述(F区分=F) → バッファ変数方式を採用(Rule_Convert_FF.md ルール3)
ただし実ファイルに同名様式が存在する場合はEXTDESCの要否もユーザーに確認すること- 入出力区分(I/O/U/A の組み合わせ)を確認し、ルール4の変換表に従って USAGE を決定する
特に U+A(更新+追加)はUSAGE(*UPDATE)のみとし、USAGE(*UPDATE:*ADD)は使わないこと(RNF2370)2-2. PRINTER ファイルの確認
- 各 PRINTER ファイルが外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述 →
get_table_metadataでレコード様式名を確認し、同名様式があればEXTDESCで独自 DDS を指定- プログラム記述(F区分=F) → 対応する独自プリンター DDS ファイルをユーザーに確認する
DDS が特定できない場合はそのファイルの変換を保留し、ユーザーに判断を仰ぐことOFLIND(*INOF)は必ずOFLIND(*IN0F)に変換する(英字 O → 数字 0)2-3. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む
【変換】事前確認の結果を反映しながら、RPG IV 固定長形式を完全フリーフォーマットに変換する
- ソースコード先頭に
**FREEを記述する- "Rule_Convert_FF.md" の全ルールに従うこと
- 元ソースの D 仕様(DCL-S / DCL-DS)を1件も漏らさず変換すること(ルール7の重要注記参照)
- 特に以下を重点確認すること
- ファイル定義(ルール1〜4):事前確認の対処方針を確実に反映する
- DCL-DS の POS → OVERLAY への変換(ルール7)
- PSDS(SDS)の変換(ルール11):
*PROCキーワードを除去し先頭 CHAR(10) として定義する- TIME 命令の変換(ルール18):DS の OVERLAY 構造を活かして
WTIME = %INT(%DEC(%TIMESTAMP()))に変換する- 演算命令のオペランド順序(ルール13)
- 1行に複数ステートメントを書かない(ルール17):
IF X; Y=0; END-IF;も禁止【精査】出力前にソースコードを精査し、重大度20以上のエラー要因を除去する
- ファイル定義の問題(RNF2109 / RNF2121)が残っていないか確認する
- 1行に複数ステートメントが残っていないか全行スキャンする(RNF5508)
- PSDS の *PROC キーワードが残っていないか確認する(RNF3308)
- USAGE(*UPDATE:*ADD) が使われていないか確認する(RNF2370)
- ファイル定義エラーを起点とした連鎖エラー(RNF5347 / RNF0724 の大量発生)がないか確認する
- エラー要因を修正したらソースコード全体の整合性を再確認する
- 新たなエラー原因が見つかった場合は本ステップを繰り返す
【出力】変換後メンバーとして新規出力する
【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
- サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
── ファイル定義(DCL-F)関連 ──
DISK/PRINTER ファイル変換前に「実ファイルのレコード様式名」を必ず確認すること
フリーフォーマットのDCL-Fでは、ファイル名と同名のレコード様式が実ファイルに存在すると
RNF2121(様式名重複)→ RNF2109(ファイル全体が無視)が発生する。
この問題は DISK / PRINTER / プログラム記述ファイルすべてに適用される。変換前に必ずやること:
get_table_metadataまたはread_ibmi_sourceで対象ファイルのレコード様式名を確認する- ファイル名とレコード様式名が同一の場合 → 必ず以下のいずれかで対処すること
- DISK 外部記述ファイル:
EXTDESC('ライブラリ/別名ファイル')で衝突を回避する- DISK プログラム記述ファイル(F区分=F):バッファ変数方式(後述ルール3)に変換する
- PRINTER ファイル:後述ルール2に従う
- 対処方法が不明な場合は処理を中断してユーザーに確認を求めること
RNF2109 が発生するとどうなるか:
ファイルが無視されると後続のすべての定義(DCL-S / DCL-DS / DCL-PI)や
演算命令(IF / END-IF 等)が演算仕様として誤認され、RNF5347 / RNF0724 が大量発生する。
この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。PRINTER ファイルの変換方針
固定長 RPG IV の PRINTER ファイルは以下の2パターンがあり、変換前に判定すること。【パターンA】外部記述 PRINTER ファイル(F仕様に E キーワードあり)
- 対応する独自 DDS が存在する →
EXTDESCでそのファイルを指定するOFLIND(*INOF)はOFLIND(*IN0F)に変換する(英字「O」ではなく数字「0」)QPRINTのようなシステム標準ファイルは QGPL/QPRINT に同名様式が存在するため必ずEXTDESCで独自 DDS を指定する
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F); ← 同名様式 → RNF2109
正) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');【パターンB】プログラム記述 PRINTER ファイル(F仕様に F 区分あり、E キーワードなし)
- 例:
FQPRINT O F 132 PRINTER OFLIND(*INOF)- フリーフォーマットには
PGMDESCキーワードが存在しないため、外部記述として扱われ RNF2109 が発生する- 対応する独自プリンター DDS がない場合は変換を中断してユーザーに確認を求めること
- 独自 DDS が用意できる場合のみ
EXTDESCで指定して変換する
例:
変換前) FQPRINT O F 132 PRINTER OFLIND(*INOF)
正) // 独自プリンターDDS(例: MYLIB/MYPRT)を事前に用意する
DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');
DCL-S QPREC CHAR(132);
// ...
WRITE QPRINT QPREC;DCL-F に RECLN キーワードは指定できない(DISK プログラム記述ファイルはバッファ変数方式を使う)
フリーフォーマットのDCL-FではRECLNキーワードは認識されず(RNF2023/RNF2109)。
固定長プログラム記述 DISK ファイル(F仕様のF区分)は、以下のバッファ変数方式に変換すること。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
注意: 実ファイルに同名レコード様式が存在する場合、DCL-F ABAWP42 DISK ...だけでは
RNF2121 → RNF2109 が発生してファイルごと無視される。バッファ変数方式だけでは解決しない。
この場合はEXTDESCで別名ファイルを指定するか、DDS 側のレコード様式名変更をユーザーに確認すること。ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
固定長 F 仕様の入出力区分(I/O/U/A)を DCL-F の USAGE キーワードに正しく対応させること。
固定長 フリーフォーマット I(入力) USAGE(*INPUT) O(出力) USAGE(*OUTPUT) U(更新) USAGE(*UPDATE) O+ADD(追加) USAGE(*OUTPUT) U+ADD(更新+追加) USAGE(*UPDATE) **【重要】USAGE(UPDATE:ADD) は無効(RNF2370 エラー)
固定長のF仕様に U(更新)と A(追加)の両方が指定されている場合(例:FAA001L0 IF A E K DISK)、
フリーフォーマットでUSAGE(*UPDATE:*ADD)と書くと RNF2370 エラーになる。
更新と追加の両方が必要な場合はUSAGE(*UPDATE)のみ指定すること。
更新ファイルにWRITE命令を使えば追加も可能。
例:
変換前) FAA001L0 IF A E K DISK ← U(更新)+A(追加)
誤) DCL-F AA001L0 DISK KEYED USAGE(*UPDATE:*ADD); ← RNF2370
正) DCL-F AA001L0 DISK KEYED USAGE(*UPDATE);
── 定義仕様(DCL-S / DCL-DS / DCL-PI)関連 ──
プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;フリーフォーマット
DCL-DSには必ず DS 名または*Nを指定すること
固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットのDCL-DSでは
DS 名または*N(匿名)を必ず指定しなければならない(RNF3368)。
例:
誤) DCL-DS;
正) DCL-DS *N;フリーフォーマット
DCL-DSのサブフィールドにPOSキーワードは使用できない
固定長 I 仕様のバイト位置指定(POS(n))はフリーフォーマットでは認識されない(RNF5347 の原因)。
位置共有が必要な場合はOVERLAY(親フィールド:開始位置)キーワードを使うこと。
例:
誤) DCL-DS *N;
UYM1 ZONED(4:0) POS(1);
UYY1 ZONED(2:0) POS(1);
UMM1 ZONED(2:0) POS(3);
END-DS;
正) DCL-DS *N;
UYM1 ZONED(4:0);
UYY1 ZONED(2:0) OVERLAY(UYM1:1);
UMM1 ZONED(2:0) OVERLAY(UYM1:3);
END-DS;【重要】外部ファイルフィールドと OVERLAY を組み合わせた DS は変換漏れに注意
固定長 RPG IV では、外部記述ファイルのフィールドをバイト位置で参照する無名 DS を定義し、
複数フィールドを1つの集約変数(例:年月日を YYYYMMDD の8桁に合算)として扱うパターンがある。
このような DS は変換時に丸ごと抜け落ちやすいため、元ソースの D 仕様を全件確認し必ず変換すること。
例(元ソース固定長):
D DS
D A0SKHZ 1 8 0 ← 削除予定日8桁(集約)
D A0SKYY 1 4 0 ← 年(A0SKHZ と同位置でオーバーレイ)
D A0SKMM 5 6 0
D A0SKDD 7 8 0
変換後(フリーフォーマット):
DCL-DS *N;
A0SKHZ ZONED(8:0);
A0SKYY ZONED(4:0) OVERLAY(A0SKHZ:1);
A0SKMM ZONED(2:0) OVERLAY(A0SKHZ:5);
A0SKDD ZONED(2:0) OVERLAY(A0SKHZ:7);
END-DS;
※ この DS が抜けると「A0SKHZ が未定義」(RNF7030)となり、演算命令でコンパイルエラーになる。ZONED / PACKED 数値型の桁数は最大 63 桁まで
ZONED(nnn:0)やPACKED(nnn:0)の桁数に 64 以上を指定すると RNF0503 エラーになる。
63 桁を超えるデータ領域はCHAR型に変換すること。
DATE型変数の日付フォーマットにゼロサフィックスは使用できない
DATE(*ISO0)のようにゼロを付けると RNF0619 エラーになる。
変数定義では*ISO・*YMD・*MDY・*DMY・*JULなどゼロなしのフォーマットを使うこと。
例:
誤) DCL-S WB5DATE DATE(*ISO0);
正) DCL-S WB5DATE DATE(*ISO);プロシージャー名・変数名・フィールド名に使用できる文字の制限
英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字は使用できない。
¥SB100 → SB100 のように変換すること。PSDS のサブフィールド定義はフリーフォーマットの記法に正しく変換すること
固定長のSDS(プログラム状況 DS)はフリーフォーマットでDCL-DS *N PSDSに変換する。
各サブフィールドの変換ルールは以下の通り。*【PROC フィールド】
固定長で*PROC特殊語を使ったサブフィールド定義(現行プロシージャー名)は、
フリーフォーマットでは*PROCキーワード自体が RNF3308 エラーになる。
PSDS の先頭 10 バイトが自動的に現行プロシージャー名に設定されるため、
*PROCキーワードを付けずに先頭のCHAR(10)フィールドとして定義すること。
例:
変換前) D W¥PGM *PROC
誤) WPGM CHAR(10) *PROC; ← RNF3308
正) WPGM CHAR(10); ← 先頭10バイトが自動的に現行PGM名になる【バイト位置指定フィールド(POS)】
PSDS のサブフィールドではPOS(n)キーワードは使用可能(通常 DS のルール7とは異なる)。
固定長の位置指定はそのままPOS(n)で変換してよい。
例:
変換前) D W¥WSID 244 253
正) WWSID CHAR(10) POS(244);【フィールド名の制限】
英大文字・数字・#・@・$ のみ使用可能。¥ を含む名前は変換する。
例:W¥PGM → WPGM、W¥WSID → WWSID、@@USER → XUSER(@ は2個連続不可のため変更)
── 演算命令関連 ──
*DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
例:
正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;CHAIN の結果は
%FOUNDで判定すること
フリーフォーマットのCHAINに固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
CHAIN の後は%FOUNDまたは%FOUND(ファイル名)で判定すること。
例:
誤) CHAIN KFLDS GADPL11 *IN03;
正) CHAIN KFLDS GADPL11;
IF NOT %FOUND(GADPL11);READE 後の %EOF は複合キー形式では結果標識を使うこと
READE (キー1:キー2) ファイル名;の後に%EOF(ファイル名)を使うと RNF0391 エラーになる場合がある。
この場合は結果標識を直接使うこと。
例:
誤) READE (WTOKU:FSIKU) GADPL141;
*IN03 = %EOF(GADPL141);
正) READE (WTOKU:FSIKU) GADPL141 *IN03;
IF *IN03;
*INLR = *ONとRETURNはサブルーチン定義の前に記述すること
BEGSR~ENDSRブロックの直後に演算命令を記述すると RNF5005 エラーになる。
プログラム終了処理は必ずサブルーチン定義の前に記述すること。
例:
誤) BEGSR @END;
ENDSR;
*INLR = *ON; ← RNF5005
RETURN;
正) *INLR = *ON; ← サブルーチン定義の前
RETURN;
BEGSR @END;
ENDSR;1行に複数ステートメントをセミコロンで区切って記述しない(RNF5508)
フリーフォーマットでは1つの物理行に1つのステートメントのみ記述すること。
IF 条件; 処理; END-IF;のような「1行 IF」も RNF5508 エラーになるため禁止。
元ソースで固定長 CASxx / IFxx などの1行条件処理を変換する場合も必ず複数行に展開すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
誤) IF S01 = 9999999; S01 = 0; END-IF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;
正) IF S01 = 9999999;
S01 = 0;
END-IF;
── 組み込み関数・型変換関連 ──
固定長の
TIME命令は%INT(%DEC(%TIMESTAMP()))で変換すること
固定長 RPG IV のTIME命令は、14桁の ZONED 型 DS(WTIME等)に現在の日時を
YYYYMMDDHHMMSS形式の数値として格納する。
フリーフォーマットではTIME命令が使えないため、以下のように変換すること。
例:
変換前) C TIME WTIME ← WTIME は ZONED(14:0) DS
正) WTIME = %INT(%DEC(%TIMESTAMP()));これにより WTIME(14桁 ZONED DS)に日時数値が入り、OVERLAY 定義されたサブフィールド
(WTIYY/WTIMM/WTIDD 等)も自動的に更新される。
%YEAR/%MONTH/%DAYを使った個別代入は不要であり、使用を避けること。
%YEAR(%DATE())等は RNF0604/RNF0325 が連鎖して発生する環境があるため信頼しないこと。年月日の8桁数値(例:WTODAY)が個別に必要な場合は、
%TIMESTAMP()の数値変換から
%INT(%DEC(%TIMESTAMP()))の上位8桁を取得する方法を使うこと。
例:
// %TIMESTAMP() → "YYYY-MM-DD-HH.MM.SS.NNNNNN" 形式
// %DEC(%TIMESTAMP()) → 14桁数値(YYYYMMDDHHMMSS に近い形)
// WTIME DS の OVERLAY を活用して年月日を得る方法が最も安全:
WTIME = %INT(%DEC(%TIMESTAMP()));
WTODAY = (WTIYY * 10000) + (WTIMM * 100) + WTIDD;【参考】単独で日付数値(YYYYMMDD)が必要な場合
%INT(%DEC(%DATE()))は DATE 型なので精度指定なしで使用可能(ルール19参照)。
ただし戻り値のフォーマットはジョブの日付書式に依存するため、%TIMESTAMP 経由の方が確実。%DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
%DEC(%TIME():6:0)のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
例:
誤) %TRIM(W1MBMN) ← ZONED 型
正) %TRIM(%CHAR(W1MBMN))ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO;
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うこと。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式%EDITW の編集語はフィールド桁数分の置換文字が必要
対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールド → %EDITW(NO: ' ')
── 外部プログラム呼び出し関連 ──
外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要(RNF7030)
CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で宣言すること。ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
DCL-F で外部記述ファイルを定義している場合、同名フィールドを異なる長さで定義すると RNF6033 エラーになる。
3-9. ソース⑥(1回目)
ソース⑤と同様にプリンター・ファイルの無いものを選定
ルールファイルが効いているのか、1回目としてはエラー数が少ない
コンパイル結果 → 失敗
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 0 | 4 |
うまく変換できたロジック
- WORKSTN / DISK / PRINTER の DCL-F 定義(XY003D0・XY001L0・XYAPL14・XY003V0)
- GOTO/TAG によるループを DOW *ON〜ENDDO + ITER に構造化
- KLIST/KFLD の複合キーを
(KFKKJC:KFNKJC)形式に変換(SETLL/READE 両対応) - バイト位置参照の DS を OVERLAY キーワード形式に変換(日時 DS・ページ番号 DS 等)
- PSDS の
¥を含むフィールド名を除去(W¥PGM → WPGM、@@USER → XUSER) -
TIME命令を%INT(%DEC(%TIMESTAMP()))に変換し OVERLAY サブフィールドで年月日取得 -
CALL 'XY001R'をCALLP XY001R()+DCL-PR EXTPGM('XY001R')に変換 - CTL-OPT に
DFTACTGRP(*NO) ACTGRP(*CALLER)を正しく追加 - DIV 命令を
%INT(PRKEN / 27)形式の整数除算に変換 - CTDATA 配列(
DIM(10) CTDATA PERRCD(1))を DCL-S で正しく定義
変換に失敗したロジック(エラー原因になった可能性)
-
READ XY001L0 *IN60;の形式で EOF 標識を直接渡している → RNF0637(仕様無視) -
READE (KFKKJC:KFNKJC) XYAPL14 *IN70;でも同様の標識直渡し → RNF0637(仕様無視) - 上記 RNF0637 の副作用として IN60/IN70 が未定義扱いになり → RNF7030(× 2件)
-
READ/READE後の EOF 判定は結果標識でなく%EOFを使う必要があった - コンパイルコマンドが
DFTACTGRP(*YES)のまま実行されており、ソースの CTL-OPT 指定が活かされなかった
まとめ
ファイル定義・DS の OVERLAY 変換・GOTO 除去・KLIST の複合キー化など、構造的に難度が高い部分は
おおむね正確に変換できており、完成度は高い。致命傷になったのは READ と READE の結果標識直渡し
(READ ファイル名 *IN60; 形式)で、フリーフォーマットでは RNF0637 で仕様ごと無視されるため
EOF ループが機能しない。エラー件数自体は重大 4 件と少なく、ピンポイントの修正で完成できる水準だった。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
対象メンバー
- 変換元
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_06
- 変換後
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_06_FF
タスク
【事前確認①】変換元ソース全体を読み込んで構成を把握する
- F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
- KLIST / KFLD 定義が存在する場合は使用箇所(CHAIN/SETLL/SETGT/READE)とキーフィールドを全件メモする
【事前確認②】F仕様の全ファイルを対象に以下を確認する
2-1. DISK ファイルの確認
get_table_metadataで各 DISK ファイルの実レコード様式名を確認する- 外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述で同名様式あり →
EXTDESCで別名ファイルを指定(ユーザーに確認)- プログラム記述(F区分=F) → バッファ変数方式を採用(Rule_Convert_FF.md ルール3)
ただし実ファイルに同名様式が存在する場合はEXTDESCの要否もユーザーに確認すること- 入出力区分(I/O/U/A の組み合わせ)を確認し、ルール4の変換表に従って USAGE を決定する
特に I+A(入力+追加)はUSAGE(*UPDATE:*OUTPUT)を使うこと(USAGE(*INPUT) では WRITE が RNF5197)
U+A(更新+追加)もUSAGE(*UPDATE:*OUTPUT)のみ(USAGE(*UPDATE:*ADD) は RNF2370)2-2. PRINTER ファイルの確認
- 各 PRINTER ファイルが外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述 →
get_table_metadataでレコード様式名を確認し、同名様式があればEXTDESCで独自 DDS を指定- プログラム記述(F区分=F) → 対応する独自プリンター DDS ファイルをユーザーに確認する
DDS が特定できない場合はそのファイルの変換を保留し、ユーザーに判断を仰ぐことOFLIND(*INOF)は必ずOFLIND(*IN0F)に変換する(英字 O → 数字 0)2-3. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む
【変換】事前確認の結果を反映しながら、RPG IV 固定長形式を完全フリーフォーマットに変換する
- ソースコード先頭に
**FREEを記述する- "Rule_Convert_FF.md" の全ルールに従うこと
- 元ソースの D 仕様(DCL-S / DCL-DS)を1件も漏らさず変換すること(ルール7の重要注記参照)
- 特に以下を重点確認すること
- ファイル定義(ルール1〜4):事前確認の対処方針を確実に反映する
- DCL-DS の POS → OVERLAY への変換(ルール7)
- PSDS(SDS)の変換(ルール11):
*PROCキーワードを除去し先頭 CHAR(10) として定義する- TIME 命令の変換(ルール19):DS の OVERLAY 構造を活かして
WTIME = %INT(%DEC(%TIMESTAMP()))に変換する- KLIST / KFLD の変換(ルール18):
CHAIN/SETLL/SETGT/READEでは(key1:key2:...)の複合キー形式を使う。DS 名を Factor1 に渡さないこと(RNF7078)- 演算命令のオペランド順序(ルール13)
- 1行に複数ステートメントを書かない(ルール17):
IF X; Y=0; END-IF;も禁止【精査】出力前にソースコードを精査し、重大度20以上のエラー要因を除去する
- ファイル定義の問題(RNF2109 / RNF2121)が残っていないか確認する
- 1行に複数ステートメントが残っていないか全行スキャンする(RNF5508)
- PSDS の *PROC キーワードが残っていないか確認する(RNF3308)
- USAGE(*UPDATE:*ADD) / USAGE(*INPUT) でWRITEしている箇所がないか確認する(RNF2370/RNF5197)
- CHAIN / SETLL / SETGT / READE の Factor1 に DS 名が使われていないか確認する(RNF7078)
- ファイル定義エラーを起点とした連鎖エラー(RNF5347 / RNF0724 の大量発生)がないか確認する
- エラー要因を修正したらソースコード全体の整合性を再確認する
- 新たなエラー原因が見つかった場合は本ステップを繰り返す
【出力】変換後メンバーとして新規出力する
【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
- サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
── ファイル定義(DCL-F)関連 ──
DISK/PRINTER ファイル変換前に「実ファイルのレコード様式名」を必ず確認すること
フリーフォーマットのDCL-Fでは、ファイル名と同名のレコード様式が実ファイルに存在すると
RNF2121(様式名重複)→ RNF2109(ファイル全体が無視)が発生する。
この問題は DISK / PRINTER / プログラム記述ファイルすべてに適用される。変換前に必ずやること:
get_table_metadataまたはread_ibmi_sourceで対象ファイルのレコード様式名を確認する- ファイル名とレコード様式名が同一の場合 → 必ず以下のいずれかで対処すること
- DISK 外部記述ファイル:
EXTDESC('ライブラリ/別名ファイル')で衝突を回避する- DISK プログラム記述ファイル(F区分=F):バッファ変数方式(後述ルール3)に変換する
- PRINTER ファイル:後述ルール2に従う
- 対処方法が不明な場合は処理を中断してユーザーに確認を求めること
RNF2109 が発生するとどうなるか:
ファイルが無視されると後続のすべての定義(DCL-S / DCL-DS / DCL-PI)や
演算命令(IF / END-IF 等)が演算仕様として誤認され、RNF5347 / RNF0724 が大量発生する。
この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。PRINTER ファイルの変換方針
固定長 RPG IV の PRINTER ファイルは以下の2パターンがあり、変換前に判定すること。【パターンA】外部記述 PRINTER ファイル(F仕様に E キーワードあり)
- 対応する独自 DDS が存在する →
EXTDESCでそのファイルを指定するOFLIND(*INOF)はOFLIND(*IN0F)に変換する(英字「O」ではなく数字「0」)QPRINTのようなシステム標準ファイルは QGPL/QPRINT に同名様式が存在するため必ずEXTDESCで独自 DDS を指定する
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F); ← 同名様式 → RNF2109
正) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');【パターンB】プログラム記述 PRINTER ファイル(F仕様に F 区分あり、E キーワードなし)
- 例:
FQPRINT O F 132 PRINTER OFLIND(*INOF)- フリーフォーマットには
PGMDESCキーワードが存在しないため、外部記述として扱われ RNF2109 が発生する- 対応する独自プリンター DDS がない場合は変換を中断してユーザーに確認を求めること
- 独自 DDS が用意できる場合のみ
EXTDESCで指定して変換する
例:
変換前) FQPRINT O F 132 PRINTER OFLIND(*INOF)
正) // 独自プリンターDDS(例: MYLIB/MYPRT)を事前に用意する
DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');
DCL-S QPREC CHAR(132);
// ...
WRITE QPRINT QPREC;DCL-F に RECLN キーワードは指定できない(DISK プログラム記述ファイルはバッファ変数方式を使う)
フリーフォーマットのDCL-FではRECLNキーワードは認識されず(RNF2023/RNF2109)。
固定長プログラム記述 DISK ファイル(F仕様のF区分)は、以下のバッファ変数方式に変換すること。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
注意: 実ファイルに同名レコード様式が存在する場合、DCL-F ABAWP42 DISK ...だけでは
RNF2121 → RNF2109 が発生してファイルごと無視される。バッファ変数方式だけでは解決しない。
この場合はEXTDESCで別名ファイルを指定するか、DDS 側のレコード様式名変更をユーザーに確認すること。ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
固定長 F 仕様の入出力区分(I/O/U/A)を DCL-F の USAGE キーワードに正しく対応させること。
固定長の組み合わせ フリーフォーマット 備考 I のみ USAGE(*INPUT) READ/CHAIN のみ O のみ USAGE(*OUTPUT) WRITE のみ U のみ USAGE(*UPDATE) READ/CHAIN/WRITE/UPDATE/DELETE I+A USAGE(*UPDATE) CHAIN+WRITE が必要なため *UPDATE を使う(RNF5197 防止) O+A USAGE(*OUTPUT) WRITE のみ U+A USAGE(*UPDATE) WRITE も可(USAGE(*UPDATE:*ADD) は RNF2370 エラー) *【重要①】I+A(入力+追加)は USAGE(UPDATE) を使うこと
固定長でI(入力)とA(追加)の両方が指定されている場合(例:FAA001L0 IF A E K DISK)、
CHAIN と WRITE の両方を使うためUSAGE(*INPUT)では WRITE 時に RNF5197 エラーになる。
必ずUSAGE(*UPDATE)を指定すること。
例:
変換前) FAA001L0 IF A E K DISK ← I(入力)+A(追加)
誤) DCL-F AA001L0 DISK KEYED USAGE(*INPUT); ← WRITE が RNF5197
正) DCL-F AA001L0 DISK KEYED USAGE(*UPDATE);**【重要②】USAGE(UPDATE:ADD) は無効(RNF2370 エラー)
U(更新)と A(追加)の両方が指定されている場合でもUSAGE(*UPDATE:*ADD)は使えない。
USAGE(*UPDATE)のみ指定すること。更新ファイルに WRITE 命令を使えば追加も可能。
例:
変換前) FXXXFILE UF A E K DISK ← U(更新)+A(追加)
誤) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*ADD); ← RNF2370
正) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE);
── 定義仕様(DCL-S / DCL-DS / DCL-PI)関連 ──
プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;フリーフォーマット
DCL-DSには必ず DS 名または*Nを指定すること
固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットのDCL-DSでは
DS 名または*N(匿名)を必ず指定しなければならない(RNF3368)。
例:
誤) DCL-DS;
正) DCL-DS *N;フリーフォーマット
DCL-DSのサブフィールドにPOSキーワードは使用できない
固定長 I 仕様のバイト位置指定(POS(n))はフリーフォーマットでは認識されない(RNF5347 の原因)。
位置共有が必要な場合はOVERLAY(親フィールド:開始位置)キーワードを使うこと。
例:
誤) DCL-DS *N;
UYM1 ZONED(4:0) POS(1);
UYY1 ZONED(2:0) POS(1);
UMM1 ZONED(2:0) POS(3);
END-DS;
正) DCL-DS *N;
UYM1 ZONED(4:0);
UYY1 ZONED(2:0) OVERLAY(UYM1:1);
UMM1 ZONED(2:0) OVERLAY(UYM1:3);
END-DS;【重要】外部ファイルフィールドと OVERLAY を組み合わせた DS は変換漏れに注意
固定長 RPG IV では、外部記述ファイルのフィールドをバイト位置で参照する無名 DS を定義し、
複数フィールドを1つの集約変数(例:年月日を YYYYMMDD の8桁に合算)として扱うパターンがある。
このような DS は変換時に丸ごと抜け落ちやすいため、元ソースの D 仕様を全件確認し必ず変換すること。
例(元ソース固定長):
D DS
D A0SKHZ 1 8 0 ← 削除予定日8桁(集約)
D A0SKYY 1 4 0 ← 年(A0SKHZ と同位置でオーバーレイ)
D A0SKMM 5 6 0
D A0SKDD 7 8 0
変換後(フリーフォーマット):
DCL-DS *N;
A0SKHZ ZONED(8:0);
A0SKYY ZONED(4:0) OVERLAY(A0SKHZ:1);
A0SKMM ZONED(2:0) OVERLAY(A0SKHZ:5);
A0SKDD ZONED(2:0) OVERLAY(A0SKHZ:7);
END-DS;
※ この DS が抜けると「A0SKHZ が未定義」(RNF7030)となり、演算命令でコンパイルエラーになる。ZONED / PACKED 数値型の桁数は最大 63 桁まで
ZONED(nnn:0)やPACKED(nnn:0)の桁数に 64 以上を指定すると RNF0503 エラーになる。
63 桁を超えるデータ領域はCHAR型に変換すること。
DATE型変数の日付フォーマットにゼロサフィックスは使用できない
DATE(*ISO0)のようにゼロを付けると RNF0619 エラーになる。
変数定義では*ISO・*YMD・*MDY・*DMY・*JULなどゼロなしのフォーマットを使うこと。
例:
誤) DCL-S WB5DATE DATE(*ISO0);
正) DCL-S WB5DATE DATE(*ISO);プロシージャー名・変数名・フィールド名に使用できる文字の制限
英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字は使用できない。
¥SB100 → SB100 のように変換すること。PSDS のサブフィールド定義はフリーフォーマットの記法に正しく変換すること
固定長のSDS(プログラム状況 DS)はフリーフォーマットでDCL-DS *N PSDSに変換する。
各サブフィールドの変換ルールは以下の通り。*【PROC フィールド】
固定長で*PROC特殊語を使ったサブフィールド定義(現行プロシージャー名)は、
フリーフォーマットでは*PROCキーワード自体が RNF3308 エラーになる。
PSDS の先頭 10 バイトが自動的に現行プロシージャー名に設定されるため、
*PROCキーワードを付けずに先頭のCHAR(10)フィールドとして定義すること。
例:
変換前) D W¥PGM *PROC
誤) WPGM CHAR(10) *PROC; ← RNF3308
正) WPGM CHAR(10); ← 先頭10バイトが自動的に現行PGM名になる【バイト位置指定フィールド(POS)】
PSDS のサブフィールドではPOS(n)キーワードは使用可能(通常 DS のルール7とは異なる)。
固定長の位置指定はそのままPOS(n)で変換してよい。
例:
変換前) D W¥WSID 244 253
正) WWSID CHAR(10) POS(244);【フィールド名の制限】
英大文字・数字・#・@・$ のみ使用可能。¥ を含む名前は変換する。
例:W¥PGM → WPGM、W¥WSID → WWSID、@@USER → XUSER(@ は2個連続不可のため変更)
── 演算命令関連 ──
*DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
例:
正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;CHAIN の結果は
%FOUNDで判定すること
フリーフォーマットのCHAINに固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
CHAIN の後は%FOUNDまたは%FOUND(ファイル名)で判定すること。
例:
誤) CHAIN KFLDS GADPL11 *IN03;
正) CHAIN KFLDS GADPL11;
IF NOT %FOUND(GADPL11);READE 後の %EOF は複合キー形式では結果標識を使うこと
READE (キー1:キー2) ファイル名;の後に%EOF(ファイル名)を使うと RNF0391 エラーになる場合がある。
この場合は結果標識を直接使うこと。
例:
誤) READE (WTOKU:FSIKU) GADPL141;
*IN03 = %EOF(GADPL141);
正) READE (WTOKU:FSIKU) GADPL141 *IN03;
IF *IN03;
*INLR = *ONとRETURNはサブルーチン定義の前に記述すること
BEGSR~ENDSRブロックの直後に演算命令を記述すると RNF5005 エラーになる。
プログラム終了処理は必ずサブルーチン定義の前に記述すること。
例:
誤) BEGSR @END;
ENDSR;
*INLR = *ON; ← RNF5005
RETURN;
正) *INLR = *ON; ← サブルーチン定義の前
RETURN;
BEGSR @END;
ENDSR;1行に複数ステートメントをセミコロンで区切って記述しない(RNF5508)
フリーフォーマットでは1つの物理行に1つのステートメントのみ記述すること。
IF 条件; 処理; END-IF;のような「1行 IF」も RNF5508 エラーになるため禁止。
元ソースで固定長 CASxx / IFxx などの1行条件処理を変換する場合も必ず複数行に展開すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
誤) IF S01 = 9999999; S01 = 0; END-IF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;
正) IF S01 = 9999999;
S01 = 0;
END-IF;KLIST / KFLD は複合キー形式
(key1:key2:...)に変換すること
固定長 RPG IV のKLIST/KFLDはフリーフォーマットに変換できない命令である。
CHAIN / SETLL / SETGT / READE / READPE での複合キー指定は、カッコで囲んだコロン区切り形式
(key1:key2:...)に変換すること。【禁止】DS 全体をキーとして渡す方法(RNF7078 エラー)
KLIST の代替として全キーフィールドを DS にまとめCHAIN KEYDS FILNAME;と記述すると、
RPG は DS 先頭のフィールドの長さとファイルの最初のキーフィールドの長さを比較するため
RNF7078(長さ不一致)が発生する。DS 名を CHAIN の Factor1 に渡してはいけない。
例:
変換前) C KEYA01 CHAIN AA001L01
← KLIST KEYA01 は #KKASI(7):#KTOKU(4):#KNONY(4):... の12フィールド
誤) CHAIN KEYA01DS AA001L01; ← DS全体(53バイト)→ RNF7078
正) CHAIN (#KKASI:#KTOKU:#KNONY:#KNKOJ:#KNUKE
:#KMEHZ:#KMEBB:#KHINB:#KBUHI:#KSHUY
:#KKNRI:#KOIBN) AA001L01;SETLL / SETGT / READE でも同様にコロン区切り複合キー形式を使うこと。
例:
変換前) C KEYA01 SETLL AA001L01
正) SETLL (#KKASI:#KTOKU:...) AA001L01;
── 組み込み関数・型変換関連 ──
固定長の
TIME命令は%INT(%DEC(%TIMESTAMP()))で変換すること
固定長 RPG IV のTIME命令は、14桁の ZONED 型 DS(WTIME等)に現在の日時を
YYYYMMDDHHMMSS形式の数値として格納する。
フリーフォーマットではTIME命令が使えないため、以下のように変換すること。
例:
変換前) C TIME WTIME ← WTIME は ZONED(14:0) DS
正) WTIME = %INT(%DEC(%TIMESTAMP()));これにより WTIME(14桁 ZONED DS)に日時数値が入り、OVERLAY 定義されたサブフィールド
(WTIYY/WTIMM/WTIDD 等)も自動的に更新される。
%YEAR/%MONTH/%DAYを使った個別代入は不要であり、使用を避けること。
%YEAR(%DATE())等は RNF0604/RNF0325 が連鎖して発生する環境があるため信頼しないこと。年月日の8桁数値(例:WTODAY)が個別に必要な場合は、
%TIMESTAMP()の数値変換から
%INT(%DEC(%TIMESTAMP()))の上位8桁を取得する方法を使うこと。
例:
// %TIMESTAMP() → "YYYY-MM-DD-HH.MM.SS.NNNNNN" 形式
// %DEC(%TIMESTAMP()) → 14桁数値(YYYYMMDDHHMMSS に近い形)
// WTIME DS の OVERLAY を活用して年月日を得る方法が最も安全:
WTIME = %INT(%DEC(%TIMESTAMP()));
WTODAY = (WTIYY * 10000) + (WTIMM * 100) + WTIDD;【参考】単独で日付数値(YYYYMMDD)が必要な場合
%INT(%DEC(%DATE()))は DATE 型なので精度指定なしで使用可能(ルール19参照)。
ただし戻り値のフォーマットはジョブの日付書式に依存するため、%TIMESTAMP 経由の方が確実。%DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
%DEC(%TIME():6:0)のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
例:
誤) %TRIM(W1MBMN) ← ZONED 型
正) %TRIM(%CHAR(W1MBMN))ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO;
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うこと。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式%EDITW の編集語はフィールド桁数分の置換文字が必要
対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールド → %EDITW(NO: ' ')
── 外部プログラム呼び出し関連 ──
外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要(RNF7030)
CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で宣言すること。ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
DCL-F で外部記述ファイルを定義している場合、同名フィールドを異なる長さで定義すると RNF6033 エラーになる。
3-10. ソース⑥(2回目)
DCL-F BD003D0 CF E WORKSTN; (DSPF にキーワードは使用不可) 等、
1回目では見られなかった変換ミスが散見された
コンパイル結果 → 失敗
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 1 | 3 |
うまく変換できたロジック
- GOTO/TAG によるループを
DOW *ON+ITER・RETURNによる構造化ループに変換 -
TIME命令をWTIME = %INT(%DEC(%TIMESTAMP()))に変換し、OVERLAY DS で年月日を分解 - KLIST/KFLD の複合キーを
(KFKKJC:KFNKJC)形式の SETLL/READE に変換 - 固定長 DS の
POS指定をOVERLAY(親フィールド:開始バイト)形式に正しく変換 - PSDS の
W¥PGM@@USERをWPGM・XUSERに改名し、*PROCキーワードも除去 -
CTL-OPTにDFTACTGRP(*NO) ACTGRP(*CALLER)を正しく追加 -
CALL 'BD001R'→DCL-PR BD001R EXTPGM('BD001R'); END-PR;+CALLP BD001R()に変換 - 標識の SETOFF を
*IN01 = *OFF;など1行ずつ独立したステートメントに分解 - CTDATA 配列
@ERの定義(DCL-S @ER CHAR(60) DIM(10) CTDATA PERRCD(1))を正しく変換 -
*INLR = *ON; RETURN;をサブルーチン定義より前に配置(RNF5005 を回避)
変換に失敗したロジック(エラー原因になった可能性)
-
DCL-F BD003D0 CF E WORKSTN;にCF・Eが残存 → RNF2023 でキーワード無視、DISK 扱いに - DISK 扱いになった結果、
EXFMT BD003D01;が RNF5199(演算項目オペランド不正)で重大エラー - PRINTER ファイル
BD003V0にEXTDESC未指定 → 同名様式が存在する場合に RNF2121 のリスク残存 - 複合キー
READE (KFKKJC:KFNKJC) BDAPL14;の後に%EOF(BDAPL14)を使用 → RNF0391 の潜在リスク - コンパイルコマンド側は
DFTACTGRP(*YES)のまま(CTL-OPT の設定が上書きされるリスク)
まとめ
DS 定義・ループ構造・KLIST/KFLD の複合キー変換・TIME 命令・PSDS のフィールド名整理など、
骨格部分の変換精度は高く、修正点は限られていた。
しかし WORKSTN ファイルの DCL-F に CF・E が残ったままという一点が致命傷で、
ファイルが DISK 扱いになり EXFMT 命令が重大エラーとなってコンパイル失敗。
フリーフォーマット固有の DCL-F 記法ルールの詰めが甘い点が改善課題として残る。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
対象メンバー
- 変換元
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_06
- 変換後
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_06_FF
タスク
【事前確認①】変換元ソース全体を読み込んで構成を把握する
- F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
- KLIST / KFLD 定義が存在する場合は使用箇所(CHAIN/SETLL/SETGT/READE)とキーフィールドを全件メモする
- READ / READE / READP の使用箇所を全件メモし、固定長の結果標識(*INxx)を使っているか確認する
【事前確認②】F仕様の全ファイルを対象に以下を確認する
2-1. DISK ファイルの確認
get_table_metadataで各 DISK ファイルの実レコード様式名を確認する- 外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述で同名様式あり →
EXTDESCで別名ファイルを指定(ユーザーに確認)- プログラム記述(F区分=F) → バッファ変数方式を採用(Rule_Convert_FF.md ルール3)
ただし実ファイルに同名様式が存在する場合はEXTDESCの要否もユーザーに確認すること- 入出力区分(I/O/U/A の組み合わせ)を確認し、ルール4の変換表に従って USAGE を決定する
特に I+A(入力+追加)はUSAGE(*UPDATE:*OUTPUT)を使うこと(USAGE(*INPUT) では WRITE が RNF5197)
U+A(更新+追加)もUSAGE(*UPDATE:*OUTPUT)のみ(USAGE(*UPDATE:*ADD) は RNF2370)2-2. PRINTER ファイルの確認
- 各 PRINTER ファイルが外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述 →
get_table_metadataでレコード様式名を確認し、同名様式があればEXTDESCで独自 DDS を指定- プログラム記述(F区分=F) → 対応する独自プリンター DDS ファイルをユーザーに確認する
DDS が特定できない場合はそのファイルの変換を保留し、ユーザーに判断を仰ぐことOFLIND(*INOF)は必ずOFLIND(*IN0F)に変換する(英字 O → 数字 0)2-3. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む
【変換】事前確認の結果を反映しながら、RPG IV 固定長形式を完全フリーフォーマットに変換する
- ソースコード先頭に
**FREEを記述する- "Rule_Convert_FF.md" の全ルールに従うこと
- 元ソースの D 仕様(DCL-S / DCL-DS)を1件も漏らさず変換すること(ルール7の重要注記参照)
- 特に以下を重点確認すること
- ファイル定義(ルール1〜4):事前確認の対処方針を確実に反映する
- DCL-DS の POS → OVERLAY への変換(ルール7)
- PSDS(SDS)の変換(ルール11):
*PROCキーワードを除去し先頭 CHAR(10) として定義する- TIME 命令の変換(ルール19):DS の OVERLAY 構造を活かして
WTIME = %INT(%DEC(%TIMESTAMP()))に変換する- KLIST / KFLD の変換(ルール18):
CHAIN/SETLL/SETGT/READEでは(key1:key2:...)の複合キー形式を使う。DS 名を Factor1 に渡さないこと(RNF7078)- READ / READE / READP の EOF 判定(ルール15):
READ ファイル名 *INxx;形式はフリーフォーマットでは RNF0637 になる。必ずREAD ファイル名; *INxx = %EOF(ファイル名);またはIF %EOF(ファイル名);形式に変換すること- 演算命令のオペランド順序(ルール13)
- 1行に複数ステートメントを書かない(ルール17):
IF X; Y=0; END-IF;も禁止【精査】出力前にソースコードを精査し、重大度20以上のエラー要因を除去する
- ファイル定義の問題(RNF2109 / RNF2121)が残っていないか確認する
- 1行に複数ステートメントが残っていないか全行スキャンする(RNF5508)
- PSDS の *PROC キーワードが残っていないか確認する(RNF3308)
- USAGE(*UPDATE:*ADD) / USAGE(*INPUT) でWRITEしている箇所がないか確認する(RNF2370/RNF5197)
- CHAIN / SETLL / SETGT / READE の Factor1 に DS 名が使われていないか確認する(RNF7078)
- READ / READE / READP の命令の直後に
*INxxが直接記述されていないか全行スキャンする(RNF0637)*INLR = *ON/RETURNが BEGSR ブロックより後ろに記述されていないか確認する(RNF5005)- ファイル定義エラーを起点とした連鎖エラー(RNF5347 / RNF0724 の大量発生)がないか確認する
- エラー要因を修正したらソースコード全体の整合性を再確認する
- 新たなエラー原因が見つかった場合は本ステップを繰り返す
【出力】変換後メンバーとして新規出力する
【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
- サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
── ファイル定義(DCL-F)関連 ──
DISK/PRINTER ファイル変換前に「実ファイルのレコード様式名」を必ず確認すること
フリーフォーマットのDCL-Fでは、ファイル名と同名のレコード様式が実ファイルに存在すると
RNF2121(様式名重複)→ RNF2109(ファイル全体が無視)が発生する。
この問題は DISK / PRINTER / プログラム記述ファイルすべてに適用される。変換前に必ずやること:
get_table_metadataまたはread_ibmi_sourceで対象ファイルのレコード様式名を確認する- ファイル名とレコード様式名が同一の場合 → 必ず以下のいずれかで対処すること
- DISK 外部記述ファイル:
EXTDESC('ライブラリ/別名ファイル')で衝突を回避する- DISK プログラム記述ファイル(F区分=F):バッファ変数方式(後述ルール3)に変換する
- PRINTER ファイル:後述ルール2に従う
- 対処方法が不明な場合は処理を中断してユーザーに確認を求めること
RNF2109 が発生するとどうなるか:
ファイルが無視されると後続のすべての定義(DCL-S / DCL-DS / DCL-PI)や
演算命令(IF / ENDIF 等)が演算仕様として誤認され、RNF5347 / RNF0724 が大量発生する。
この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。PRINTER ファイルの変換方針
固定長 RPG IV の PRINTER ファイルは以下の2パターンがあり、変換前に判定すること。【パターンA】外部記述 PRINTER ファイル(F仕様に E キーワードあり)
- 対応する独自 DDS が存在する →
EXTDESCでそのファイルを指定するOFLIND(*INOF)はOFLIND(*IN0F)に変換する(英字「O」ではなく数字「0」)QPRINTのようなシステム標準ファイルは QGPL/QPRINT に同名様式が存在するため必ずEXTDESCで独自 DDS を指定する
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F); ← 同名様式 → RNF2109
正) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');【パターンB】プログラム記述 PRINTER ファイル(F仕様に F 区分あり、E キーワードなし)
- 例:
FQPRINT O F 132 PRINTER OFLIND(*INOF)- フリーフォーマットには
PGMDESCキーワードが存在しないため、外部記述として扱われ RNF2109 が発生する- 対応する独自プリンター DDS がない場合は変換を中断してユーザーに確認を求めること
- 独自 DDS が用意できる場合のみ
EXTDESCで指定して変換する
例:
変換前) FQPRINT O F 132 PRINTER OFLIND(*INOF)
正) // 独自プリンターDDS(例: MYLIB/MYPRT)を事前に用意する
DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');
DCL-S QPREC CHAR(132);
// ...
WRITE QPRINT QPREC;DCL-F に RECLN キーワードは指定できない(DISK プログラム記述ファイルはバッファ変数方式を使う)
フリーフォーマットのDCL-FではRECLNキーワードは認識されず(RNF2023/RNF2109)。
固定長プログラム記述 DISK ファイル(F仕様のF区分)は、以下のバッファ変数方式に変換すること。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
注意: 実ファイルに同名レコード様式が存在する場合、DCL-F ABAWP42 DISK ...だけでは
RNF2121 → RNF2109 が発生してファイルごと無視される。バッファ変数方式だけでは解決しない。
この場合はEXTDESCで別名ファイルを指定するか、DDS 側のレコード様式名変更をユーザーに確認すること。WORKSTN ファイルは
DCL-F ファイル名 WORKSTN;のみで定義すること(RNF2023/RNF2401)
固定長 F 仕様の WORKSTN ファイルはCF(Combined)とE(外部記述)を組み合わせて記述するが、
フリーフォーマットのDCL-FではCFとEは認識されないキーワードのため RNF2023 で無視される。
その結果ファイルが DISK として扱われ、EXFMT命令が RNF5199(オペランドが正しくない)エラーになる。
フリーフォーマットではWORKSTNキーワードだけで「外部記述・双方向入出力」の意味を持つため、
CF/Eは不要。INFDSやSFILEキーワードが必要な場合はそれぞれ追記すること。
例:
変換前) FBD003D0 CF E WORKSTN
誤) DCL-F BD003D0 CF E WORKSTN; ← CF・E が RNF2023 → DISK 扱い → EXFMT が RNF5199
正) DCL-F BD003D0 WORKSTN;INFDS(情報 DS)が必要な場合:
正) DCL-F BD003D0 WORKSTN INFDS(WS_INFDS);ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
固定長 F 仕様の入出力区分(I/O/U/A)を DCL-F の USAGE キーワードに正しく対応させること。
固定長の組み合わせ フリーフォーマット 備考 I のみ USAGE(*INPUT) READ/CHAIN のみ O のみ USAGE(*OUTPUT) WRITE のみ U のみ USAGE(*UPDATE) READ/CHAIN/WRITE/UPDATE/DELETE I+A USAGE(*UPDATE:*OUTPUT) CHAIN+WRITE が必要なため *UPDATE を使う(RNF5197 防止) O+A USAGE(*OUTPUT) WRITE のみ U+A USAGE(*UPDATE:*OUTPUT) WRITE も可(USAGE(*UPDATE:*ADD) は RNF2370 エラー) **【重要①】I+A(入力+追加)は USAGE(UPDATE:OUTPUT) を使うこと
固定長でI(入力)とA(追加)の両方が指定されている場合(例:FAA001L0 IF A E K DISK)、
CHAIN と WRITE の両方を使うためUSAGE(*INPUT)では WRITE 時に RNF5197 エラーになる。
必ずUSAGE(*UPDATE:*OUTPUT)を指定すること。
例:
変換前) FAA001L0 IF A E K DISK ← I(入力)+A(追加)
誤) DCL-F AA001L0 DISK KEYED USAGE(*INPUT); ← WRITE が RNF5197
正) DCL-F AA001L0 DISK KEYED USAGE(*UPDATE:*OUTPUT);**【重要②】USAGE(UPDATE:ADD) は無効(RNF2370 エラー)
U(更新)と A(追加)の両方が指定されている場合でもUSAGE(*UPDATE:*ADD)は使えない。
USAGE(*UPDATE:*OUTPUT)を指定すること。更新ファイルに WRITE 命令を使えば追加も可能。
例:
変換前) FXXXFILE UF A E K DISK ← U(更新)+A(追加)
誤) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*ADD); ← RNF2370
正) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*OUTPUT);
── 定義仕様(DCL-S / DCL-DS / DCL-PI)関連 ──
プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;フリーフォーマット
DCL-DSには必ず DS 名または*Nを指定すること
固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットのDCL-DSでは
DS 名または*N(匿名)を必ず指定しなければならない(RNF3368)。
例:
誤) DCL-DS;
正) DCL-DS *N;フリーフォーマット
DCL-DSのサブフィールドにPOSキーワードは使用できない
固定長 I 仕様のバイト位置指定(POS(n))はフリーフォーマットでは認識されない(RNF5347 の原因)。
位置共有が必要な場合はOVERLAY(親フィールド:開始位置)キーワードを使うこと。
例:
誤) DCL-DS *N;
UYM1 ZONED(4:0) POS(1);
UYY1 ZONED(2:0) POS(1);
UMM1 ZONED(2:0) POS(3);
END-DS;
正) DCL-DS *N;
UYM1 ZONED(4:0);
UYY1 ZONED(2:0) OVERLAY(UYM1:1);
UMM1 ZONED(2:0) OVERLAY(UYM1:3);
END-DS;【重要】外部ファイルフィールドと OVERLAY を組み合わせた DS は変換漏れに注意
固定長 RPG IV では、外部記述ファイルのフィールドをバイト位置で参照する無名 DS を定義し、
複数フィールドを1つの集約変数(例:年月日を YYYYMMDD の8桁に合算)として扱うパターンがある。
このような DS は変換時に丸ごと抜け落ちやすいため、元ソースの D 仕様を全件確認し必ず変換すること。
例(元ソース固定長):
D DS
D A0SKHZ 1 8 0 ← 削除予定日8桁(集約)
D A0SKYY 1 4 0 ← 年(A0SKHZ と同位置でオーバーレイ)
D A0SKMM 5 6 0
D A0SKDD 7 8 0
変換後(フリーフォーマット):
DCL-DS *N;
A0SKHZ ZONED(8:0);
A0SKYY ZONED(4:0) OVERLAY(A0SKHZ:1);
A0SKMM ZONED(2:0) OVERLAY(A0SKHZ:5);
A0SKDD ZONED(2:0) OVERLAY(A0SKHZ:7);
END-DS;
※ この DS が抜けると「A0SKHZ が未定義」(RNF7030)となり、演算命令でコンパイルエラーになる。ZONED / PACKED 数値型の桁数は最大 63 桁まで
ZONED(nnn:0)やPACKED(nnn:0)の桁数に 64 以上を指定すると RNF0503 エラーになる。
63 桁を超えるデータ領域はCHAR型に変換すること。
DATE型変数の日付フォーマットにゼロサフィックスは使用できない
DATE(*ISO0)のようにゼロを付けると RNF0619 エラーになる。
変数定義では*ISO・*YMD・*MDY・*DMY・*JULなどゼロなしのフォーマットを使うこと。
例:
誤) DCL-S WB5DATE DATE(*ISO0);
正) DCL-S WB5DATE DATE(*ISO);プロシージャー名・変数名・フィールド名に使用できる文字の制限
英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字は使用できない。
¥SB100 → SB100 のように変換すること。PSDS のサブフィールド定義はフリーフォーマットの記法に正しく変換すること
固定長のSDS(プログラム状況 DS)はフリーフォーマットでDCL-DS *N PSDSに変換する。
各サブフィールドの変換ルールは以下の通り。*【PROC フィールド】
固定長で*PROC特殊語を使ったサブフィールド定義(現行プロシージャー名)は、
フリーフォーマットでは*PROCキーワード自体が RNF3308 エラーになる。
PSDS の先頭 10 バイトが自動的に現行プロシージャー名に設定されるため、
*PROCキーワードを付けずに先頭のCHAR(10)フィールドとして定義すること。
例:
変換前) D W¥PGM *PROC
誤) WPGM CHAR(10) *PROC; ← RNF3308
正) WPGM CHAR(10); ← 先頭10バイトが自動的に現行PGM名になる【バイト位置指定フィールド(POS)】
PSDS のサブフィールドではPOS(n)キーワードは使用可能(通常 DS のルール8とは異なる)。
固定長の位置指定はそのままPOS(n)で変換してよい。
例:
変換前) D W¥WSID 244 253
正) WWSID CHAR(10) POS(244);【フィールド名の制限】
英大文字・数字・#・@・$ のみ使用可能。¥ を含む名前は変換する。
例:W¥PGM → WPGM、W¥WSID → WWSID、@@USER → XUSER(@ は2個連続不可のため変更)
── 演算命令関連 ──
DFTACTGRP(YES) ではフリーフォーマット RPG は正しくコンパイルできない
フリーフォーマット RPG ではCTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);を必ず先頭に記述する*こと。
さらに重要:CTL-OPT にいくらDFTACTGRP(*NO)と書いても、コンパイルコマンド(CRTBNDRPG)側が
DFTACTGRP(*YES)だと CTL-OPT が無視される。 その場合、ENDIF/ENDDOがすべて演算命令として
誤認され RNF5347(割り当て演算子が必要)が大量連鎖する。コンパイル時は必ず
DFTACTGRP(*NO)を指定すること(ルール27参照)。
例:
正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER); ← ソース先頭
正) CRTBNDRPG PGM(LIB/PGM) SRCFILE(LIB/SRC) DFTACTGRP(*NO) ← コンパイルコマンドフリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;CHAIN の結果は
%FOUNDで判定すること
フリーフォーマットのCHAINに固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
CHAIN の後は%FOUNDまたは%FOUND(ファイル名)で判定すること。
例:
誤) CHAIN KFLDS GADPL11 *IN03;
正) CHAIN KFLDS GADPL11;
IF NOT %FOUND(GADPL11);READ / READE / READP 命令に結果標識を直接付加してはいけない(RNF0637 → RNF7030 連鎖)
フリーフォーマットではREAD ファイル名 *INxx;のように結果標識をオペランドとして渡す書き方は
RNF0637(オペランドが必要であるが見つからなかった)になり、その仕様は無視される。
さらに*INxxが定義されなかったものとして RNF7030 も連鎖する。
これは 単一キー・複合キーを問わず、READ / READE / READP すべてに適用される。【READ の EOF 判定】
READ の後で%EOF(ファイル名)を使うか、先に標識を*OFFに初期化して%EOFを代入すること。
例:
誤) READ BD001L0 *IN60; ← RNF0637 → 仕様無視 → RNF7030(IN60 未定義)
正) READ BD001L0;
*IN60 = %EOF(BD001L0); ← 必要なら標識に保存
IF %EOF(BD001L0); ← 直接判定する場合【READE の EOF 判定(単一キー)】
例:
誤) READE KFLD FILNAME *IN70; ← RNF0637 → 仕様無視 → RNF7030(IN70 未定義)
正) READE KFLD FILNAME;
IF %EOF(FILNAME);【READE の EOF 判定(複合キー)】
複合キー形式の READE の後に%EOF(ファイル名)を使うと RNF0391 が発生する場合がある。
その場合はファイル名なしの%EOFを使うこと。
例:
誤) READE (KFKKJC:KFNKJC) BDAPL14 *IN70; ← RNF0637 → 仕様無視 → RNF7030
誤) READE (KFKKJC:KFNKJC) BDAPL14;
*IN70 = %EOF(BDAPL14); ← RNF0391 の可能性あり
正) *IN70 = *OFF;
READE (KFKKJC:KFNKJC) BDAPL14;
*IN70 = %EOF; ← ファイル名なしなら可
IF *IN70;
*INLR = *ONとRETURNはサブルーチン定義の前に記述すること
BEGSR~ENDSRブロックの直後に演算命令を記述すると RNF5005 エラーになる。
プログラム終了処理は必ずサブルーチン定義の前に記述すること。
例:
誤) BEGSR @END;
ENDSR;
*INLR = *ON; ← RNF5005
RETURN;
正) *INLR = *ON; ← サブルーチン定義の前
RETURN;
BEGSR @END;
ENDSR;1行に複数ステートメントをセミコロンで区切って記述しない(RNF5508)
フリーフォーマットでは1つの物理行に1つのステートメントのみ記述すること。
IF 条件; 処理; ENDIF;のような「1行 IF」も RNF5508 エラーになるため禁止。
元ソースで固定長 CASxx / IFxx などの1行条件処理を変換する場合も必ず複数行に展開すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
誤) IF S01 = 9999999; S01 = 0; ENDIF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;
正) IF S01 = 9999999;
S01 = 0;
ENDIF;KLIST / KFLD は複合キー形式
(key1:key2:...)に変換すること
固定長 RPG IV のKLIST/KFLDはフリーフォーマットに変換できない命令である。
CHAIN / SETLL / SETGT / READE / READPE での複合キー指定は、カッコで囲んだコロン区切り形式
(key1:key2:...)に変換すること。【禁止】DS 全体をキーとして渡す方法(RNF7078 エラー)
KLIST の代替として全キーフィールドを DS にまとめCHAIN KEYDS FILNAME;と記述すると、
RPG は DS 先頭のフィールドの長さとファイルの最初のキーフィールドの長さを比較するため
RNF7078(長さ不一致)が発生する。DS 名を CHAIN の Factor1 に渡してはいけない。
例:
変換前) C KEYA01 CHAIN AA001L01
← KLIST KEYA01 は #KKASI(7):#KTOKU(4):#KNONY(4):... の12フィールド
誤) CHAIN KEYA01DS AA001L01; ← DS全体(53バイト)→ RNF7078
正) CHAIN (#KKASI:#KTOKU:#KNONY:#KNKOJ:#KNUKE
:#KMEHZ:#KMEBB:#KHINB:#KBUHI:#KSHUY
:#KKNRI:#KOIBN) AA001L01;SETLL / SETGT / READE でも同様にコロン区切り複合キー形式を使うこと。
例:
変換前) C KEYA01 SETLL AA001L01
正) SETLL (#KKASI:#KTOKU:...) AA001L01;
── 組み込み関数・型変換関連 ──
固定長の
TIME命令は%INT(%DEC(%TIMESTAMP()))で変換すること
固定長 RPG IV のTIME命令は、14桁の ZONED 型 DS(WTIME等)に現在の日時を
YYYYMMDDHHMMSS形式の数値として格納する。
フリーフォーマットではTIME命令が使えないため、以下のように変換すること。
例:
変換前) C TIME WTIME ← WTIME は ZONED(14:0) DS
正) WTIME = %INT(%DEC(%TIMESTAMP()));これにより WTIME(14桁 ZONED DS)に日時数値が入り、OVERLAY 定義されたサブフィールド
(WTIYY/WTIMM/WTIDD 等)も自動的に更新される。
%YEAR/%MONTH/%DAYを使った個別代入は不要であり、使用を避けること。
%YEAR(%DATE())等は RNF0604/RNF0325 が連鎖して発生する環境があるため信頼しないこと。年月日の8桁数値(例:WTODAY)が個別に必要な場合は、WTIME DS の OVERLAY を活用すること。
例:
WTIME = %INT(%DEC(%TIMESTAMP()));
WTODAY = (WTIYY * 10000) + (WTIMM * 100) + WTIDD;%DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
%DEC(%TIME():6:0)のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
例:
誤) %TRIM(W1MBMN) ← ZONED 型
正) %TRIM(%CHAR(W1MBMN))ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO;
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うこと。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式%EDITW の編集語はフィールド桁数分の置換文字が必要
対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールド → %EDITW(NO: ' ')
── 外部プログラム呼び出し関連 ──
固定長の
CALL命令は必ずCALLP+ プロトタイプ宣言に変換すること(RNF7030/RNF5502/バインドエラー)
固定長 RPG IV のCALL '外部プログラム名'はフリーフォーマットでは使用できない。
フリーフォーマットで外部プログラムを呼び出す場合は、以下のすべてを守ること。【重要①】呼び出し先が
*PGMの場合はEXTPGMキーワードが必須(バインドエラー防止)
EXTPGMを省略したDCL-PRはサービスプログラム(*SRVPGM)のプロシージャーとして解決しようとするため、
*PGMを呼び出す場合にバインドステップでCPD5D02(記号の定義が見つからない)が発生する。
呼び出し先が*PGMか*SRVPGMかを必ず確認し、*PGMの場合はEXTPGM('プログラム名')を付けること。
例:
誤) DCL-PR BD001R; ← EXTPGM なし → バインド時に CPD5D02
END-PR;
正) DCL-PR BD001R EXTPGM('BD001R'); ← *PGM 呼び出し
END-PR;【重要②】プロトタイプ宣言は必須(RNF7030 防止)
必ずDCL-PR ~ END-PRでプロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。【重要③】呼び出し時は括弧を付けること(RNF5502 防止)
CALLP プログラム名();と 括弧を付けること。パラメーターがなくても括弧は必須。例(総合):
変換前) CALL 'BD001R' ← 固定長の CALL 命令
誤) CALLP BD001R; ← RNF5502(括弧が必要)
誤) DCL-PR BD001R; END-PR; ← EXTPGM なし → バインドエラー
正) DCL-PR BD001R EXTPGM('BD001R'); ← *PGM 呼び出しには EXTPGM 必須
END-PR;
// ...
CALLP BD001R(); ← パラメーターなしでも括弧は必須
正) CALLP BD001R(ARG1:ARG2); ← パラメーターあり外部記述ファイルのフィールドと同名の変数を定義する場合は桁数を一致させること(RNF6033)
DCL-F で外部記述ファイルを定義している場合、ファイルのフィールドと同名の変数を
RPG 内で異なる桁数・型で再定義すると RNF6033(外部記述フィールドの長さが前の定義と同じでない)
エラーになり、その仕様が無視される。この確認は DISK ファイルだけでなく PRINTER ファイルにも適用される。
PRINTER ファイルの DDS に定義されたフィールドと同名の作業変数を RPG 内で定義すると
桁数・型の一致が必要になる。変換前に必ず DDS ソースを読み込んで各フィールドの桁数・型を把握すること。
例:
外部フィールド @DATE が ZONE(8,0) の場合:
誤) DCL-S @DATE ZONED(6:0); ← 桁数が異なる → RNF6033
正) DCL-S @DATE ZONED(8:0); ← 外部定義と一致させる
※ 外部定義と異なる桁数で作業変数が必要な場合は別名(例:W@DATE)を使うこと。
── コンパイルコマンド関連 ──
コンパイルコマンド(CRTBNDRPG)は必ず
DFTACTGRP(*NO)を指定すること
フリーフォーマット RPG はコンパイル時にDFTACTGRP(*NO)を指定しないと、
CTL-OPT の記述に関わらずDFTACTGRP(*YES)として扱われる場合がある。
DFTACTGRP(*YES)のままコンパイルするとENDIF/ENDDOが演算命令として誤認され、
RNF5347(EVAL に割り当て演算子が必要)が全ブロック終端行で大量発生する。変換後のソースを書き込んだら、必ず以下のコマンドでコンパイルするようユーザーに伝えること:
CRTBNDRPG PGM(ライブラリ/プログラム名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)また、CTL-OPT に
DFTACTGRP(*NO)を記述することと、コンパイルコマンドで指定することは
両方必要であり、どちらか片方だけでは不十分な場合がある(ルール13参照)。
3-11. ソース⑥(3回目)
IF … ENDIF が正しいところ、なぜか軒並み IF … END-IF に変換されていた
真因ではない部分のルールを修正されるのを防ぐため、このソースは 3回でトライ中止とした
コンパイル結果 → 失敗
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 3 | 54 |
うまく変換できたロジック
- WORKSTN / DISK / PRINTER ファイルの DCL-F 定義(BD003D0、BD001L0、BDAPL14、BD003V0 相当)
- PSDS(プログラム状況 DS)を
DCL-DS *N PSDS形式に変換し、@@USER → XUSERに改名 - 固定長の無名 DS を
DCL-DS *N … END-DS+OVERLAYで正しく変換(時刻 DS など) -
TIME命令を%INT(%DEC(%TIMESTAMP()))に変換し、OVERLAY サブフィールドで年月日を取得 -
*DATE→%INT(%DEC(*DATE))の数値取得変換 -
KLIST/KFLDの複合キーを(KFKKJC:KFNKJC)形式のコロン区切りに変換(SETLL / READE) -
DO *HIVAL … READ … *IN60 … LEAVEをDOW *IN60 = *OFF … ENDDOループに変換 -
CALL 'BD001R'をDCL-PR BD001R EXTPGM('BD001R'); END-PR;+CALLP BD001Rに変換 - CTDATA 配列(
@ER)の定義と**CTDATAセクションへの移植 - IF/ELSE/END-IF、ITER、LEAVE、EXSR、EXFMT などの制御構造・命令の変換
変換に失敗したロジック(エラー原因になった可能性)
-
@STR:のラベル行が GOTO のジャンプ先として残存 → RNF5347(@STRを EVAL 左辺と誤認)が根本原因 -
GOTO @STR;が残ったままで構造化されていない → RNF7030(GOTO・@STR が未定義扱い)が連発 - GOTO の残存が引き金となり、後続の
END-IF;/ENDDO;すべてが RNF5347 に連鎖(20 件以上) -
CALLP BD001R;に括弧がない → RNF5502(プロシージャー名の後に括弧が必要) - DFTACTGRP(*YES) のままコンパイル → CTL-OPT に
DFTACTGRP(*NO)を書いても無効になる -
@DATEが PRINTER ファイルの外部フィールドと桁数不一致(6 桁 vs 8 桁)→ RNF6033 -
%EOF(BDAPL14)を複合キー READE の直後に使用 → RNF0391 が発生する可能性(今回は連鎖で不明瞭) -
BD001L01/BDAPL141のレコード様式が入出力で未使用 → RNF7066(影響は軽微だが未整理)
まとめ
ファイル定義・DS 定義・OVERLAY 変換・TIME 命令・KLIST/KFLD の複合キー化など、手間のかかる部分の変換精度は高い。
ただし GOTO / TAG を構造化ループに置き換えず、ラベル行(@STR:)と GOTO @STR; がそのまま残ったのが致命傷だ。
このラベル行をコンパイラが EVAL 左辺と誤認したことで RNF5347 が連鎖し、後続の IF / DOW ブロック全体を道連れにした。
CALLP の括弧抜けや @DATE の桁数ズレなど細かいミスも重なっており、「広い範囲をカバーしつつも、GOTO 除去という最重要ポイントを取りこぼした」という結果になった。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
対象メンバー
- 変換元
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_06
- 変換後
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_06_FF
タスク
【事前確認①】変換元ソース全体を読み込んで構成を把握する
- F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
- KLIST / KFLD 定義が存在する場合は使用箇所(CHAIN/SETLL/SETGT/READE)とキーフィールドを全件メモする
- READ / READE / READP の使用箇所を全件メモし、固定長の結果標識(*INxx)を使っているか確認する
【事前確認②】F仕様の全ファイルを対象に以下を確認する
2-1. WORKSTN ファイルの確認
- WORKSTN ファイルは
DCL-F ファイル名 WORKSTN;のみで定義する(Rule_Convert_FF.md ルール4)- 固定長の
CF/Eキーワードはフリーフォーマットでは 認識されず RNF2023 になるため、必ず除去することCF Eが残ったままだとファイルが DISK として扱われ、EXFMTが RNF5199 になる2-2. DISK ファイルの確認
get_table_metadataで各 DISK ファイルの実レコード様式名を確認する- 外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述で同名様式あり →
EXTDESCで別名ファイルを指定(ユーザーに確認)- プログラム記述(F区分=F) → バッファ変数方式を採用(Rule_Convert_FF.md ルール3)
ただし実ファイルに同名様式が存在する場合はEXTDESCの要否もユーザーに確認すること- 入出力区分(I/O/U/A の組み合わせ)を確認し、ルール5の変換表に従って USAGE を決定する
特に I+A(入力+追加)はUSAGE(*UPDATE:*OUTPUT)を使うこと(USAGE(*INPUT) では WRITE が RNF5197)
U+A(更新+追加)もUSAGE(*UPDATE:*OUTPUT)のみ(USAGE(*UPDATE:*ADD) は RNF2370)2-3. PRINTER ファイルの確認
- 各 PRINTER ファイルが外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述 →
get_table_metadataでレコード様式名を確認し、同名様式があればEXTDESCで独自 DDS を指定- プログラム記述(F区分=F) → 対応する独自プリンター DDS ファイルをユーザーに確認する
DDS が特定できない場合はそのファイルの変換を保留し、ユーザーに判断を仰ぐことOFLIND(*INOF)は必ずOFLIND(*IN0F)に変換する(英字 O → 数字 0)2-4. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む
【変換】事前確認の結果を反映しながら、RPG IV 固定長形式を完全フリーフォーマットに変換する
- ソースコード先頭に
**FREEを記述する- "Rule_Convert_FF.md" の全ルールに従うこと
- 元ソースの D 仕様(DCL-S / DCL-DS)を1件も漏らさず変換すること(ルール8の重要注記参照)
- 特に以下を重点確認すること
- ファイル定義(ルール1〜5):事前確認の対処方針を確実に反映する
- WORKSTN ファイル(ルール4):
DCL-F ファイル名 WORKSTN;のみ。CF/Eを残さないこと(RNF2023 → RNF5199)- DCL-DS の POS → OVERLAY への変換(ルール8)
- PSDS(SDS)の変換(ルール12):
*PROCキーワードを除去し先頭 CHAR(10) として定義する- TIME 命令の変換(ルール20):DS の OVERLAY 構造を活かして
WTIME = %INT(%DEC(%TIMESTAMP()))に変換する- KLIST / KFLD の変換(ルール19):
CHAIN/SETLL/SETGT/READEでは(key1:key2:...)の複合キー形式を使う。DS 名を Factor1 に渡さないこと(RNF7078)- READ / READE / READP の EOF 判定(ルール16):
READ ファイル名 *INxx;形式はフリーフォーマットでは RNF0637 になる。必ずREAD ファイル名; *INxx = %EOF(ファイル名);またはIF %EOF(ファイル名);形式に変換すること- 演算命令のオペランド順序(ルール14)
- 1行に複数ステートメントを書かない(ルール18):
IF X; Y=0; END-IF;も禁止【精査】出力前にソースコードを精査し、重大度20以上のエラー要因を除去する
- WORKSTN ファイルの
DCL-FにCF/Eが残っていないか確認する(RNF2023 → RNF5199)- ファイル定義の問題(RNF2109 / RNF2121)が残っていないか確認する
- 1行に複数ステートメントが残っていないか全行スキャンする(RNF5508)
- PSDS の *PROC キーワードが残っていないか確認する(RNF3308)
- USAGE(*UPDATE:*ADD) / USAGE(*INPUT) でWRITEしている箇所がないか確認する(RNF2370/RNF5197)
- CHAIN / SETLL / SETGT / READE の Factor1 に DS 名が使われていないか確認する(RNF7078)
- READ / READE / READP の命令の直後に
*INxxが直接記述されていないか全行スキャンする(RNF0637)*INLR = *ON/RETURNが BEGSR ブロックより後ろに記述されていないか確認する(RNF5005)- ファイル定義エラーを起点とした連鎖エラー(RNF5347 / RNF0724 の大量発生)がないか確認する
- エラー要因を修正したらソースコード全体の整合性を再確認する
- 新たなエラー原因が見つかった場合は本ステップを繰り返す
【出力】変換後メンバーとして新規出力する
【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
- サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
── ファイル定義(DCL-F)関連 ──
DISK/PRINTER ファイル変換前に「実ファイルのレコード様式名」を必ず確認すること
フリーフォーマットのDCL-Fでは、ファイル名と同名のレコード様式が実ファイルに存在すると
RNF2121(様式名重複)→ RNF2109(ファイル全体が無視)が発生する。
この問題は DISK / PRINTER / プログラム記述ファイルすべてに適用される。変換前に必ずやること:
get_table_metadataまたはread_ibmi_sourceで対象ファイルのレコード様式名を確認する- ファイル名とレコード様式名が同一の場合 → 必ず以下のいずれかで対処すること
- DISK 外部記述ファイル:
EXTDESC('ライブラリ/別名ファイル')で衝突を回避する- DISK プログラム記述ファイル(F区分=F):バッファ変数方式(後述ルール3)に変換する
- PRINTER ファイル:後述ルール2に従う
- 対処方法が不明な場合は処理を中断してユーザーに確認を求めること
RNF2109 が発生するとどうなるか:
ファイルが無視されると後続のすべての定義(DCL-S / DCL-DS / DCL-PI)や
演算命令(IF / ENDIF 等)が演算仕様として誤認され、RNF5347 / RNF0724 が大量発生する。
この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。PRINTER ファイルの変換方針
固定長 RPG IV の PRINTER ファイルは以下の2パターンがあり、変換前に判定すること。【パターンA】外部記述 PRINTER ファイル(F仕様に E キーワードあり)
- 対応する独自 DDS が存在する →
EXTDESCでそのファイルを指定するOFLIND(*INOF)はOFLIND(*IN0F)に変換する(英字「O」ではなく数字「0」)QPRINTのようなシステム標準ファイルは QGPL/QPRINT に同名様式が存在するため必ずEXTDESCで独自 DDS を指定する
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F); ← 同名様式 → RNF2109
正) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');【パターンB】プログラム記述 PRINTER ファイル(F仕様に F 区分あり、E キーワードなし)
- 例:
FQPRINT O F 132 PRINTER OFLIND(*INOF)- フリーフォーマットには
PGMDESCキーワードが存在しないため、外部記述として扱われ RNF2109 が発生する- 対応する独自プリンター DDS がない場合は変換を中断してユーザーに確認を求めること
- 独自 DDS が用意できる場合のみ
EXTDESCで指定して変換する
例:
変換前) FQPRINT O F 132 PRINTER OFLIND(*INOF)
正) // 独自プリンターDDS(例: MYLIB/MYPRT)を事前に用意する
DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');
DCL-S QPREC CHAR(132);
// ...
WRITE QPRINT QPREC;DCL-F に RECLN キーワードは指定できない(DISK プログラム記述ファイルはバッファ変数方式を使う)
フリーフォーマットのDCL-FではRECLNキーワードは認識されず(RNF2023/RNF2109)。
固定長プログラム記述 DISK ファイル(F仕様のF区分)は、以下のバッファ変数方式に変換すること。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
注意: 実ファイルに同名レコード様式が存在する場合、DCL-F ABAWP42 DISK ...だけでは
RNF2121 → RNF2109 が発生してファイルごと無視される。バッファ変数方式だけでは解決しない。
この場合はEXTDESCで別名ファイルを指定するか、DDS 側のレコード様式名変更をユーザーに確認すること。WORKSTN ファイルは
DCL-F ファイル名 WORKSTN;のみで定義すること(RNF2023/RNF2401/RNF5199)
固定長 F 仕様の WORKSTN ファイルはCF(Combined)とE(外部記述)を組み合わせて記述するが、
フリーフォーマットのDCL-FではCFとEは認識されないキーワードのため RNF2023 で無視される。
その結果ファイルが DISK として扱われ、EXFMT命令が RNF5199(オペランドが正しくない)エラーになる。
フリーフォーマットではWORKSTNキーワードだけで「外部記述・双方向入出力」の意味を持つため、
CF/Eは不要。INFDSやSFILEキーワードが必要な場合はそれぞれ追記すること。
例:
変換前) FBD003D0 CF E WORKSTN
誤) DCL-F BD003D0 CF E WORKSTN; ← CF・E が RNF2023 → DISK 扱い → EXFMT が RNF5199
正) DCL-F BD003D0 WORKSTN;INFDS(情報 DS)が必要な場合:
正) DCL-F BD003D0 WORKSTN INFDS(WS_INFDS);【精査チェック】変換後ソース全行を対象に
DCL-F行にCFまたはEが残っていないかスキャンすること。
このキーワードが1つでも残っているとファイルが DISK 扱いになり、EXFMTが RNF5199 で失敗する。ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
固定長 F 仕様の入出力区分(I/O/U/A)を DCL-F の USAGE キーワードに正しく対応させること。
固定長の組み合わせ フリーフォーマット 備考 I のみ USAGE(*INPUT) READ/CHAIN のみ O のみ USAGE(*OUTPUT) WRITE のみ U のみ USAGE(*UPDATE) READ/CHAIN/WRITE/UPDATE/DELETE I+A USAGE(*UPDATE:*OUTPUT) CHAIN+WRITE が必要なため *UPDATE を使う(RNF5197 防止) O+A USAGE(*OUTPUT) WRITE のみ U+A USAGE(*UPDATE:*OUTPUT) WRITE も可(USAGE(*UPDATE:*ADD) は RNF2370 エラー) **【重要①】I+A(入力+追加)は USAGE(UPDATE:OUTPUT) を使うこと
固定長でI(入力)とA(追加)の両方が指定されている場合(例:FAA001L0 IF A E K DISK)、
CHAIN と WRITE の両方を使うためUSAGE(*INPUT)では WRITE 時に RNF5197 エラーになる。
必ずUSAGE(*UPDATE:*OUTPUT)を指定すること。
例:
変換前) FAA001L0 IF A E K DISK ← I(入力)+A(追加)
誤) DCL-F AA001L0 DISK KEYED USAGE(*INPUT); ← WRITE が RNF5197
正) DCL-F AA001L0 DISK KEYED USAGE(*UPDATE:*OUTPUT);**【重要②】USAGE(UPDATE:ADD) は無効(RNF2370 エラー)
U(更新)と A(追加)の両方が指定されている場合でもUSAGE(*UPDATE:*ADD)は使えない。
USAGE(*UPDATE:*OUTPUT)を指定すること。更新ファイルに WRITE 命令を使えば追加も可能。
例:
変換前) FXXXFILE UF A E K DISK ← U(更新)+A(追加)
誤) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*ADD); ← RNF2370
正) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*OUTPUT);
── 定義仕様(DCL-S / DCL-DS / DCL-PI)関連 ──
プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;フリーフォーマット
DCL-DSには必ず DS 名または*Nを指定すること
固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットのDCL-DSでは
DS 名または*N(匿名)を必ず指定しなければならない(RNF3368)。
例:
誤) DCL-DS;
正) DCL-DS *N;フリーフォーマット
DCL-DSのサブフィールドにPOSキーワードは使用できない
固定長 I 仕様のバイト位置指定(POS(n))はフリーフォーマットでは認識されない(RNF5347 の原因)。
位置共有が必要な場合はOVERLAY(親フィールド:開始位置)キーワードを使うこと。
例:
誤) DCL-DS *N;
UYM1 ZONED(4:0) POS(1);
UYY1 ZONED(2:0) POS(1);
UMM1 ZONED(2:0) POS(3);
END-DS;
正) DCL-DS *N;
UYM1 ZONED(4:0);
UYY1 ZONED(2:0) OVERLAY(UYM1:1);
UMM1 ZONED(2:0) OVERLAY(UYM1:3);
END-DS;【重要】外部ファイルフィールドと OVERLAY を組み合わせた DS は変換漏れに注意
固定長 RPG IV では、外部記述ファイルのフィールドをバイト位置で参照する無名 DS を定義し、
複数フィールドを1つの集約変数(例:年月日を YYYYMMDD の8桁に合算)として扱うパターンがある。
このような DS は変換時に丸ごと抜け落ちやすいため、元ソースの D 仕様を全件確認し必ず変換すること。
例(元ソース固定長):
D DS
D A0SKHZ 1 8 0 ← 削除予定日8桁(集約)
D A0SKYY 1 4 0 ← 年(A0SKHZ と同位置でオーバーレイ)
D A0SKMM 5 6 0
D A0SKDD 7 8 0
変換後(フリーフォーマット):
DCL-DS *N;
A0SKHZ ZONED(8:0);
A0SKYY ZONED(4:0) OVERLAY(A0SKHZ:1);
A0SKMM ZONED(2:0) OVERLAY(A0SKHZ:5);
A0SKDD ZONED(2:0) OVERLAY(A0SKHZ:7);
END-DS;
※ この DS が抜けると「A0SKHZ が未定義」(RNF7030)となり、演算命令でコンパイルエラーになる。ZONED / PACKED 数値型の桁数は最大 63 桁まで
ZONED(nnn:0)やPACKED(nnn:0)の桁数に 64 以上を指定すると RNF0503 エラーになる。
63 桁を超えるデータ領域はCHAR型に変換すること。
DATE型変数の日付フォーマットにゼロサフィックスは使用できない
DATE(*ISO0)のようにゼロを付けると RNF0619 エラーになる。
変数定義では*ISO・*YMD・*MDY・*DMY・*JULなどゼロなしのフォーマットを使うこと。
例:
誤) DCL-S WB5DATE DATE(*ISO0);
正) DCL-S WB5DATE DATE(*ISO);プロシージャー名・変数名・フィールド名に使用できる文字の制限
英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字は使用できない。
¥SB100 → SB100 のように変換すること。PSDS のサブフィールド定義はフリーフォーマットの記法に正しく変換すること
固定長のSDS(プログラム状況 DS)はフリーフォーマットでDCL-DS *N PSDSに変換する。
各サブフィールドの変換ルールは以下の通り。*【PROC フィールド】
固定長で*PROC特殊語を使ったサブフィールド定義(現行プロシージャー名)は、
フリーフォーマットでは*PROCキーワード自体が RNF3308 エラーになる。
PSDS の先頭 10 バイトが自動的に現行プロシージャー名に設定されるため、
*PROCキーワードを付けずに先頭のCHAR(10)フィールドとして定義すること。
例:
変換前) D W¥PGM *PROC
誤) WPGM CHAR(10) *PROC; ← RNF3308
正) WPGM CHAR(10); ← 先頭10バイトが自動的に現行PGM名になる【バイト位置指定フィールド(POS)】
PSDS のサブフィールドではPOS(n)キーワードは使用可能(通常 DS のルール8とは異なる)。
固定長の位置指定はそのままPOS(n)で変換してよい。
例:
変換前) D W¥WSID 244 253
正) WWSID CHAR(10) POS(244);【フィールド名の制限】
英大文字・数字・#・@・$ のみ使用可能。¥ を含む名前は変換する。
例:W¥PGM → WPGM、W¥WSID → WWSID、@@USER → XUSER(@ は2個連続不可のため変更)
── 演算命令関連 ──
DFTACTGRP(YES) ではフリーフォーマット RPG は正しくコンパイルできない
フリーフォーマット RPG ではCTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);を必ず先頭に記述する*こと。
さらに重要:CTL-OPT にいくらDFTACTGRP(*NO)と書いても、コンパイルコマンド(CRTBNDRPG)側が
DFTACTGRP(*YES)だと CTL-OPT が無視される。 その場合、ENDIF/ENDDOがすべて演算命令として
誤認され RNF5347(割り当て演算子が必要)が大量連鎖する。コンパイル時は必ず
DFTACTGRP(*NO)を指定すること(ルール28参照)。
例:
正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER); ← ソース先頭
正) CRTBNDRPG PGM(LIB/PGM) SRCFILE(LIB/SRC) DFTACTGRP(*NO) ← コンパイルコマンドフリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;CHAIN の結果は
%FOUNDで判定すること
フリーフォーマットのCHAINに固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
CHAIN の後は%FOUNDまたは%FOUND(ファイル名)で判定すること。
例:
誤) CHAIN KFLDS GADPL11 *IN03;
正) CHAIN KFLDS GADPL11;
IF NOT %FOUND(GADPL11);READ / READE / READP 命令に結果標識を直接付加してはいけない(RNF0637 → RNF7030 連鎖)
フリーフォーマットではREAD ファイル名 *INxx;のように結果標識をオペランドとして渡す書き方は
RNF0637(オペランドが必要であるが見つからなかった)になり、その仕様は無視される。
さらに*INxxが定義されなかったものとして RNF7030 も連鎖する。
これは 単一キー・複合キーを問わず、READ / READE / READP すべてに適用される。【READ の EOF 判定】
READ の後で%EOF(ファイル名)を使うか、先に標識を*OFFに初期化して%EOFを代入すること。
例:
誤) READ BD001L0 *IN60; ← RNF0637 → 仕様無視 → RNF7030(IN60 未定義)
正) READ BD001L0;
*IN60 = %EOF(BD001L0); ← 必要なら標識に保存
IF %EOF(BD001L0); ← 直接判定する場合【READE の EOF 判定(単一キー)】
例:
誤) READE KFLD FILNAME *IN70; ← RNF0637 → 仕様無視 → RNF7030(IN70 未定義)
正) READE KFLD FILNAME;
IF %EOF(FILNAME);【READE の EOF 判定(複合キー)】
複合キー形式のREADE (key1:key2) FILNAME;の後に%EOF(ファイル名)を使うと
RNF0391 が発生する場合がある。ファイル名なしの%EOFを使うこと。
*INxx = *OFF;で初期化してから%EOFを代入するパターンが最も安全。
例:
誤) READE (KFKKJC:KFNKJC) BDAPL14;
*IN70 = %EOF(BDAPL14); ← RNF0391 の可能性あり
正) *IN70 = *OFF;
READE (KFKKJC:KFNKJC) BDAPL14;
*IN70 = %EOF; ← ファイル名なしなら可
IF *IN70;
*INLR = *ONとRETURNはサブルーチン定義の前に記述すること
BEGSR~ENDSRブロックの直後に演算命令を記述すると RNF5005 エラーになる。
プログラム終了処理は必ずサブルーチン定義の前に記述すること。
例:
誤) BEGSR @END;
ENDSR;
*INLR = *ON; ← RNF5005
RETURN;
正) *INLR = *ON; ← サブルーチン定義の前
RETURN;
BEGSR @END;
ENDSR;1行に複数ステートメントをセミコロンで区切って記述しない(RNF5508)
フリーフォーマットでは1つの物理行に1つのステートメントのみ記述すること。
IF 条件; 処理; ENDIF;のような「1行 IF」も RNF5508 エラーになるため禁止。
元ソースで固定長 CASxx / IFxx などの1行条件処理を変換する場合も必ず複数行に展開すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
誤) IF S01 = 9999999; S01 = 0; ENDIF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;
正) IF S01 = 9999999;
S01 = 0;
ENDIF;KLIST / KFLD は複合キー形式
(key1:key2:...)に変換すること
固定長 RPG IV のKLIST/KFLDはフリーフォーマットに変換できない命令である。
CHAIN / SETLL / SETGT / READE / READPE での複合キー指定は、カッコで囲んだコロン区切り形式
(key1:key2:...)に変換すること。【禁止】DS 全体をキーとして渡す方法(RNF7078 エラー)
KLIST の代替として全キーフィールドを DS にまとめCHAIN KEYDS FILNAME;と記述すると、
RPG は DS 先頭のフィールドの長さとファイルの最初のキーフィールドの長さを比較するため
RNF7078(長さ不一致)が発生する。DS 名を CHAIN の Factor1 に渡してはいけない。
例:
変換前) C KEYA01 CHAIN AA001L01
← KLIST KEYA01 は #KKASI(7):#KTOKU(4):#KNONY(4):... の12フィールド
誤) CHAIN KEYA01DS AA001L01; ← DS全体(53バイト)→ RNF7078
正) CHAIN (#KKASI:#KTOKU:#KNONY:#KNKOJ:#KNUKE
:#KMEHZ:#KMEBB:#KHINB:#KBUHI:#KSHUY
:#KKNRI:#KOIBN) AA001L01;SETLL / SETGT / READE でも同様にコロン区切り複合キー形式を使うこと。
例:
変換前) C KEYA01 SETLL AA001L01
正) SETLL (#KKASI:#KTOKU:...) AA001L01;
── 組み込み関数・型変換関連 ──
固定長の
TIME命令は%INT(%DEC(%TIMESTAMP()))で変換すること
固定長 RPG IV のTIME命令は、14桁の ZONED 型 DS(WTIME等)に現在の日時を
YYYYMMDDHHMMSS形式の数値として格納する。
フリーフォーマットではTIME命令が使えないため、以下のように変換すること。
例:
変換前) C TIME WTIME ← WTIME は ZONED(14:0) DS
正) WTIME = %INT(%DEC(%TIMESTAMP()));これにより WTIME(14桁 ZONED DS)に日時数値が入り、OVERLAY 定義されたサブフィールド
(WTIYY/WTIMM/WTIDD 等)も自動的に更新される。
%YEAR/%MONTH/%DAYを使った個別代入は不要であり、使用を避けること。
%YEAR(%DATE())等は RNF0604/RNF0325 が連鎖して発生する環境があるため信頼しないこと。年月日の8桁数値(例:WTODAY)が個別に必要な場合は、WTIME DS の OVERLAY を活用すること。
例:
WTIME = %INT(%DEC(%TIMESTAMP()));
WTODAY = (WTIYY * 10000) + (WTIMM * 100) + WTIDD;%DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
%DEC(%TIME():6:0)のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
例:
誤) %TRIM(W1MBMN) ← ZONED 型
正) %TRIM(%CHAR(W1MBMN))ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO;
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うこと。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式%EDITW の編集語はフィールド桁数分の置換文字が必要
対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールド → %EDITW(NO: ' ')
── 外部プログラム呼び出し関連 ──
固定長の
CALL命令は必ずCALLP+ プロトタイプ宣言に変換すること(RNF7030/RNF5502/バインドエラー)
固定長 RPG IV のCALL '外部プログラム名'はフリーフォーマットでは使用できない。
フリーフォーマットで外部プログラムを呼び出す場合は、以下のすべてを守ること。【重要①】呼び出し先が
*PGMの場合はEXTPGMキーワードが必須(バインドエラー防止)
EXTPGMを省略したDCL-PRはサービスプログラム(*SRVPGM)のプロシージャーとして解決しようとするため、
*PGMを呼び出す場合にバインドステップでCPD5D02(記号の定義が見つからない)が発生する。
呼び出し先が*PGMか*SRVPGMかを必ず確認し、*PGMの場合はEXTPGM('プログラム名')を付けること。
例:
誤) DCL-PR BD001R; ← EXTPGM なし → バインド時に CPD5D02
END-PR;
正) DCL-PR BD001R EXTPGM('BD001R'); ← *PGM 呼び出し
END-PR;【重要②】プロトタイプ宣言は必須(RNF7030 防止)
必ずDCL-PR ~ END-PRでプロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。【重要③】呼び出し時は括弧を付けること(RNF5502 防止)
CALLP プログラム名();と 括弧を付けること。パラメーターがなくても括弧は必須。例(総合):
変換前) CALL 'BD001R' ← 固定長の CALL 命令
誤) CALLP BD001R; ← RNF5502(括弧が必要)
誤) DCL-PR BD001R; END-PR; ← EXTPGM なし → バインドエラー
正) DCL-PR BD001R EXTPGM('BD001R'); ← *PGM 呼び出しには EXTPGM 必須
END-PR;
// ...
CALLP BD001R(); ← パラメーターなしでも括弧は必須
正) CALLP BD001R(ARG1:ARG2); ← パラメーターあり外部記述ファイルのフィールドと同名の変数を定義する場合は桁数を一致させること(RNF6033)
DCL-F で外部記述ファイルを定義している場合、ファイルのフィールドと同名の変数を
RPG 内で異なる桁数・型で再定義すると RNF6033(外部記述フィールドの長さが前の定義と同じでない)
エラーになり、その仕様が無視される。この確認は DISK ファイルだけでなく PRINTER ファイルにも適用される。
PRINTER ファイルの DDS に定義されたフィールドと同名の作業変数を RPG 内で定義すると
桁数・型の一致が必要になる。変換前に必ず DDS ソースを読み込んで各フィールドの桁数・型を把握すること。
例:
外部フィールド @DATE が ZONE(8,0) の場合:
誤) DCL-S @DATE ZONED(6:0); ← 桁数が異なる → RNF6033
正) DCL-S @DATE ZONED(8:0); ← 外部定義と一致させる
※ 外部定義と異なる桁数で作業変数が必要な場合は別名(例:W@DATE)を使うこと。
── コンパイルコマンド関連 ──
コンパイルコマンド(CRTBNDRPG)は必ず
DFTACTGRP(*NO)を指定すること
フリーフォーマット RPG はコンパイル時にDFTACTGRP(*NO)を指定しないと、
CTL-OPT の記述に関わらずDFTACTGRP(*YES)として扱われる場合がある。
DFTACTGRP(*YES)のままコンパイルするとENDIF/ENDDOが演算命令として誤認され、
RNF5347(EVAL に割り当て演算子が必要)が全ブロック終端行で大量発生する。変換後のソースを書き込んだら、必ず以下のコマンドでコンパイルするようユーザーに伝えること:
CRTBNDRPG PGM(ライブラリ/プログラム名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)また、CTL-OPT に
DFTACTGRP(*NO)を記述することと、コンパイルコマンドで指定することは
両方必要であり、どちらか片方だけでは不十分な場合がある(ルール13参照)。
── 出力前の精査チェックリスト ──
変換後ソースを出力する前に以下の全項目をスキャンして重大度20以上のエラー要因を除去すること
出力前に変換後ソース全行を対象として以下を順番に確認すること。
1件でも該当があれば修正してから再度全項目をスキャンし直すこと。【ファイル定義チェック】
DCL-F行にCFまたはEキーワードが残っていないか(RNF2023 → DISK 扱い → RNF5199)
→WORKSTNファイルはDCL-F ファイル名 WORKSTN;のみで定義すること(ルール4)- DISK/PRINTER ファイルでファイル名と同名のレコード様式が存在するものに
EXTDESCが指定されているか(ルール1)- USAGE(*UPDATE:*ADD) が使われていないか(RNF2370)→
USAGE(*UPDATE:*OUTPUT)に変換すること(ルール5)- I+A ファイルに
USAGE(*INPUT)が使われていないか(RNF5197)→USAGE(*UPDATE:*OUTPUT)に変換すること(ルール5)【定義仕様チェック】
- PSDS の
*PROCキーワードが残っていないか(RNF3308)→ 除去して先頭CHAR(10)として定義すること(ルール12)DCL-DSに名前も*Nも指定されていない無名 DS が残っていないか(RNF3368)(ルール7)- 通常 DS のサブフィールドに
POS(n)が使われていないか(RNF5347)→OVERLAYに変換すること(ルール8)
※ PSDS のサブフィールドのPOSは使用可(ルール12)【演算命令チェック】
READ/READE/READPの直後に*INxxが直接記述されていないか(RNF0637)(ルール16)- 複合キー
READE (k1:k2) FILE;の後に%EOF(ファイル名)が使われていないか(RNF0391)
→%EOF(ファイル名なし)を使うこと(ルール16)CHAIN/SETLL/SETGT/READEの Factor1 に DS 名が使われていないか(RNF7078)(ルール19)*INLR = *ON/RETURNがBEGSRブロックより後ろに記述されていないか(RNF5005)(ルール17)- 1行に複数ステートメントが残っていないか(RNF5508)(ルール18)
SETGT/SETLL/READE/READPのオペランド順序が「キー → ファイル名」になっているか(ルール14)【コンパイル設定チェック】
CTL-OPTにDFTACTGRP(*NO) ACTGRP(*CALLER)が含まれているか(ルール13)- コンパイルコマンドに
DFTACTGRP(*NO)を指定するようユーザーに伝えたか(ルール28)
3-12. ソース⑦(1回目)
入力値のエラーチェックをする対話式のプログラム
1回目にして重大度20のエラー1件のみという好成績
コンパイル結果 → 失敗
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 1 | 0 |
うまく変換できたロジック
- WORKSTN ファイル(ZX320D0)や DISK ファイル(ZH301L1、ZH301L3)を
DCL-Fに正しく変換 -
DO *HIVAL+GOTO ECHKの組み合わせをERRSWフラグ +IF ERRSW = '0'の連鎖チェックに構造化 -
KLIST/KFLD(K#SHN、K#HNHZ)を(K#SHN1:K#SHN2:K#SHN3)形式の複合キーに変換 -
CALL 'DATR11'+PARMをDCL-PR DATR11 EXTPGM('DATR11')+CALLP DATR11(...)に変換 -
TIME命令を%INT(%DEC(%TIMESTAMP()))に変換し、OVERLAY DS の WYMD サブフィールドも活用 - バイト位置指定の日時 DS を
OVERLAY(WTIME:n)形式のDCL-DSに変換 -
MOVEL *BLANK/Z-ADDなどの固定長代入命令を直接代入(= *BLANK、= 値)に変換 -
DOWEQループやDO *HIVALをDOW/DOW *ONに、SETOFFを個別の*INxx = *OFFに変換 -
DCL-PI *Nでプログラムパラメータを正しく定義し、PLIST/PARMを除去 -
IFEQ/IFGT/IFLE/ELSE/ENDIFの条件分岐をIF/ELSE/ENDIFに正しく変換
変換に失敗したロジック(エラー原因になった可能性)
-
%FOUND(DH301L11)にレコード様式名を渡している(ファイル名ZH301L1が正しい)→ RNF0394(重大度20)でプログラム未作成 -
CHAIN (K#SHN1:K#SHN2:K#SHN3) DH301L11のファイル指定はレコード様式名になっている(ファイル名と混在) - CTDATA 配列
ERの定義がDIM(99)なのに実データが5件しかなく、RNF8042(ソースレコード不足)が発生 - DH301L1 / DH301L3 の外部フィールドが未参照扱い(RNF7031 が52件)→ 実害はないが、定義整理の余地あり
-
DOWEQ '99'ループで#SB999を呼ぶ構造は、終了後に無限ループになる可能性がある設計上の懸念
まとめ
ファイル定義・DS 定義・外部プログラム呼び出し・複合キー変換・TIME 命令の代替など、プログラムの骨格となる部分の変換精度は高く仕上がっている。
コンパイルを止めた直接原因はたった1件——%FOUND() の引数にレコード様式名(ZH301L11)を渡すというミスだ。ファイル名と様式名が同じ8文字で末尾1文字違いという紛らわしさもあるが、ここだけ直せばビルドが通る状態だった。
CTDATA の件数不足(DIM(99) に対してデータ5件)も通知扱いで済んでいるとはいえ、実行時に未初期化要素を参照するとノイズが出る恐れがある。変換ツールが DIM 値を固定で生成している可能性があるため、要確認。
全体的には「ほぼ動く状態まで持ってきたが、ファイル名/様式名の使い分けという細かい点で引っかかった」という結果。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
対象メンバー
- 変換元
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_07
- 変換後
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_07_FF
タスク
【事前確認①】変換元ソース全体を読み込んで構成を把握する
- F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
- KLIST / KFLD 定義が存在する場合は使用箇所(CHAIN/SETLL/SETGT/READE)とキーフィールドを全件メモする
- READ / READE / READP の使用箇所を全件メモし、固定長の結果標識(*INxx)を使っているか確認する
- GOTO / TAG の使用箇所を全件メモする(フリーフォーマットでは使用不可 → ルール29)
GOTO が存在する場合、対応する TAG(ラベル)とジャンプ先の文脈を把握し、変換方針(DOW/LEAVE/ITER/IF)を決定する*で始まるコメント行の使用箇所を全件確認する(フリーフォーマットでは乗算演算子として誤認 → ルール32)
区切り線(*----...)やサブルーチン直後の*行が残存するだけでプログラム全体のコンパイルエラーになる- CALLP / CALL で外部プログラムを呼び出している箇所を全件メモする
- 外部記述ファイルのフィールドと同名の DCL-S / DCL-DS サブフィールドを定義している箇所を確認する
- D仕様の全フィールド名を RPG 予約語リストと照合する(ルール31)
PAGE/PAGE1~PAGE7は印刷プログラムに頻出するため特に注意すること
予約語と一致するフィールド名があれば、先頭にWを付けた別名(例:WPAGE)に置き換える計画を立てる【事前確認②】F仕様の全ファイルを対象に以下を確認する
2-1. WORKSTN ファイルの確認
- WORKSTN ファイルは
DCL-F ファイル名 WORKSTN;のみで定義する(ルール4)- 固定長の
CF/Eキーワードはフリーフォーマットでは 認識されず RNF2023 になるため、必ず除去することCF Eが残ったままだとファイルが DISK として扱われ、EXFMTが RNF5199 になる2-2. DISK ファイルの確認
get_table_metadataで各 DISK ファイルの実レコード様式名を確認する- 外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述で同名様式あり →
EXTDESCで別名ファイルを指定(ユーザーに確認)- プログラム記述(F区分=F) → バッファ変数方式を採用(ルール3)
ただし実ファイルに同名様式が存在する場合はEXTDESCの要否もユーザーに確認すること- 入出力区分(I/O/U/A の組み合わせ)を確認し、ルール6の変換表に従って USAGE を決定する
特に I+A(入力+追加)はUSAGE(*UPDATE:*OUTPUT)を使うこと(USAGE(*INPUT) では WRITE が RNF5197)
U+A(更新+追加)もUSAGE(*UPDATE:*OUTPUT)のみ(USAGE(*UPDATE:*ADD) は RNF2370)get_column_metadataで外部記述フィールドの桁数・型を確認し、同名変数を定義する場合は一致させる(ルール28 / RNF6033)2-3. PRINTER ファイルの確認
- 各 PRINTER ファイルが外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述 →
get_table_metadataでレコード様式名を確認し、同名様式があればEXTDESCで独自 DDS を指定- 外部記述 PRINTER ファイルの DDS ソースを
read_ibmi_sourceで読み込み、各様式のフィールド名と桁数・型を把握すること(RNF6033 防止 / ルール28)
- DDS で定義されているフィールド(
@DATE・@TIME・@@USER等)は、同名の作業変数を RPG 内で定義する際に桁数・型を一致させること- 例)DDS に
@DATE 8S 0(ZONED 8桁)があれば、RPG 変数も@DATE ZONED(8:0)にする- プログラム記述(F区分=F) → 対応する独自プリンター DDS ファイルをユーザーに確認する
DDS が特定できない場合はそのファイルの変換を保留し、ユーザーに判断を仰ぐことOFLIND(*INOF)は必ずOFLIND(*IN0F)に変換する(英字 O → 数字 0)2-4. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む
【変換】事前確認の結果を反映しながら、RPG IV 固定長形式を完全フリーフォーマットに変換する
- ソースコード先頭に
**FREEを記述する- "Rule_Convert_FF.md" の全ルールに従うこと
- 元ソースの D 仕様(DCL-S / DCL-DS)を1件も漏らさず変換すること(ルール9の重要注記参照)
- 特に以下を重点確認すること
- ファイル定義(ルール1〜6):事前確認の対処方針を確実に反映する
- WORKSTN ファイル(ルール4):
DCL-F ファイル名 WORKSTN;のみ。CF/Eを残さないこと(RNF2023 → RNF5199)- 予約語の変数名(ルール31):事前確認で判明した予約語フィールド(
PAGE等)を別名に変換し、演算命令内の全参照箇所も置き換えること- DCL-DS の POS → OVERLAY への変換(ルール9)
- PSDS(SDS)の変換(ルール13):
*PROCキーワードを除去し先頭 CHAR(10) として定義する- TIME 命令の変換(ルール21):DS の OVERLAY 構造を活かして
WTIME = %INT(%DEC(%TIMESTAMP()))に変換する- GOTO / TAG の変換(ルール29):
GOTOと対応するラベル行をすべて除去しDOW *ON/LEAVE/ITER/IFに置き換える
ラベル行(@STR:等)が1行でも残るとコンパイラが演算命令として誤認し RNF5347 が大量連鎖する- 固定長コメント行の変換(ルール32):
*で始まるすべての行を//コメントに変換するか削除すること
ENDSRの後ろや区切り線(*----...、* * * * * *)が残りやすいため全行スキャンすること
**FREEのみ例外として除外する- KLIST / KFLD の変換(ルール20):
CHAIN/SETLL/SETGT/READEでは(key1:key2:...)の複合キー形式を使う。DS 名を Factor1 に渡さないこと(RNF7078)- READ / READE / READP の EOF 判定(ルール17):
READ ファイル名 *INxx;形式はフリーフォーマットでは RNF0637 になる。必ずREAD ファイル名; *INxx = %EOF(ファイル名);またはIF %EOF(ファイル名);形式に変換すること- CALLP の括弧(ルール27):
CALLP プログラム名();と括弧を付けること。パラメーターなしでも括弧は必須(RNF5502)- CALL 命令は必ず CALLP + プロトタイプ宣言に変換すること(ルール27)
- 演算命令のオペランド順序(ルール15)
- 1行に複数ステートメントを書かない(ルール19):
IF X; Y=0; ENDIF;も禁止【精査】出力前にソースコードを精査し、重大度20以上のエラー要因を除去する
- 予約語チェック(ルール31 / RNF3314 → RNF5347/RNF7030 大量連鎖の防止):全 DCL-S / DCL-DS サブフィールドの名前を予約語リストと照合する
PAGE/PAGE1~PAGE7が変数名・フィールド名として残っていないか全定義をスキャンする- 予約語が残っていた場合は
WPAGEなどの別名に変更し、演算命令内の参照箇所もすべて置き換える*で始まる行(**FREEを除く)が1行も残っていないか全行スキャンする(ルール32 / RNF5347 大量連鎖の根本原因)
区切り線・サブルーチン後の*行1行でプログラム全体のコンパイルエラーになる- GOTO 文およびラベル行(
ラベル名:の行)が1行も残っていないか全行スキャンする(ルール29 / RNF5347 連鎖)- CALLP の呼び出しに括弧があるか全件確認する(
CALLP PGM;→CALLP PGM();/ RNF5502)- 外部記述フィールドと同名の変数定義で桁数・型が一致しているか確認する(ルール28 / RNF6033)
- PRINTER ファイルの DDS で定義されたフィールド(
@DATE・@TIME・@@USER等)についても同様に確認すること- WORKSTN ファイルの
DCL-FにCF/Eが残っていないか確認する(RNF2023 → RNF5199)- ファイル定義の問題(RNF2109 / RNF2121)が残っていないか確認する
- 1行に複数ステートメントが残っていないか全行スキャンする(RNF5508)
- PSDS の *PROC キーワードが残っていないか確認する(RNF3308)
- USAGE(*UPDATE:*ADD) / USAGE(*INPUT) でWRITEしている箇所がないか確認する(RNF2370/RNF5197)
- CHAIN / SETLL / SETGT / READE の Factor1 に DS 名が使われていないか確認する(RNF7078)
- READ / READE / READP の命令の直後に
*INxxが直接記述されていないか全行スキャンする(RNF0637)*INLR = *ON/RETURNが BEGSR ブロックより後ろに記述されていないか確認する(RNF5005)- ファイル定義エラーを起点とした連鎖エラー(RNF5347 / RNF0724 の大量発生)がないか確認する
- エラー要因を修正したらソースコード全体の整合性を再確認する
- 新たなエラー原因が見つかった場合は本ステップを繰り返す
【出力】変換後メンバーとして新規出力する
write_ibmi_sourceで書き込んだ後、コンパイルする場合は必ずDFTACTGRP(*NO)を指定すること(ルール30)- CTL-OPT に
DFTACTGRP(*NO) ACTGRP(*CALLER)を記述していても、コンパイルコマンド側がDFTACTGRP(*YES)だと CTL-OPT が無視されENDIF/ENDDOが演算命令として誤認される(RNF5347 大量発生)- ユーザーに対して、以下のコンパイルコマンドを提示すること:
CRTBNDRPG PGM(ライブラリ/メンバー名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
- サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
── ファイル定義(DCL-F)関連 ──
DISK/PRINTER ファイル変換前に「実ファイルのレコード様式名」を必ず確認すること
フリーフォーマットのDCL-Fでは、ファイル名と同名のレコード様式が実ファイルに存在すると
RNF2121(様式名重複)→ RNF2109(ファイル全体が無視)が発生する。
この問題は DISK / PRINTER / プログラム記述ファイルすべてに適用される。変換前に必ずやること:
get_table_metadataまたはread_ibmi_sourceで対象ファイルのレコード様式名を確認する- ファイル名とレコード様式名が同一の場合 → 必ず以下のいずれかで対処すること
- DISK 外部記述ファイル:
EXTDESC('ライブラリ/別名ファイル')で衝突を回避する- DISK プログラム記述ファイル(F区分=F):バッファ変数方式(後述ルール3)に変換する
- PRINTER ファイル:後述ルール2に従う
- 対処方法が不明な場合は処理を中断してユーザーに確認を求めること
RNF2109 が発生するとどうなるか:
ファイルが無視されると後続のすべての定義(DCL-S / DCL-DS / DCL-PI)や
演算命令(IF / ENDIF 等)が演算仕様として誤認され、RNF5347 / RNF0724 が大量発生する。
この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。PRINTER ファイルの変換方針
固定長 RPG IV の PRINTER ファイルは以下の2パターンがあり、変換前に判定すること。【パターンA】外部記述 PRINTER ファイル(F仕様に E キーワードあり)
- 対応する独自 DDS が存在する →
EXTDESCでそのファイルを指定するOFLIND(*INOF)はOFLIND(*IN0F)に変換する(英字「O」ではなく数字「0」)QPRINTのようなシステム標準ファイルは QGPL/QPRINT に同名様式が存在するため必ずEXTDESCで独自 DDS を指定する
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F); ← 同名様式 → RNF2109
正) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');【パターンB】プログラム記述 PRINTER ファイル(F仕様に F 区分あり、E キーワードなし)
- 例:
FQPRINT O F 132 PRINTER OFLIND(*INOF)- フリーフォーマットには
PGMDESCキーワードが存在しないため、外部記述として扱われ RNF2109 が発生する- 対応する独自プリンター DDS がない場合は変換を中断してユーザーに確認を求めること
- 独自 DDS が用意できる場合のみ
EXTDESCで指定して変換する
例:
変換前) FQPRINT O F 132 PRINTER OFLIND(*INOF)
正) // 独自プリンターDDS(例: MYLIB/MYPRT)を事前に用意する
DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');
DCL-S QPREC CHAR(132);
// ...
WRITE QPRINT QPREC;DCL-F に RECLN キーワードは指定できない(DISK プログラム記述ファイルはバッファ変数方式を使う)
フリーフォーマットのDCL-FではRECLNキーワードは認識されず(RNF2023/RNF2109)。
固定長プログラム記述 DISK ファイル(F仕様のF区分)は、以下のバッファ変数方式に変換すること。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
注意: 実ファイルに同名レコード様式が存在する場合、DCL-F ABAWP42 DISK ...だけでは
RNF2121 → RNF2109 が発生してファイルごと無視される。バッファ変数方式だけでは解決しない。
この場合はEXTDESCで別名ファイルを指定するか、DDS 側のレコード様式名変更をユーザーに確認すること。WORKSTN ファイルは
DCL-F ファイル名 WORKSTN;のみで定義すること(RNF2023/RNF2401)
固定長 F 仕様の WORKSTN ファイルはCF(Combined)とE(外部記述)を組み合わせて記述するが、
フリーフォーマットのDCL-FではCFとEは認識されないキーワードのため RNF2023 で無視される。
その結果ファイルが DISK として扱われ、EXFMT命令が RNF5199(オペランドが正しくない)エラーになる。
フリーフォーマットではWORKSTNキーワードだけで「外部記述・双方向入出力」の意味を持つため、
CF/Eは不要。INFDSやSFILEキーワードが必要な場合はそれぞれ追記すること。
例:
変換前) FBD003D0 CF E WORKSTN
誤) DCL-F BD003D0 CF E WORKSTN; ← CF・E が RNF2023 → DISK 扱い → EXFMT が RNF5199
正) DCL-F BD003D0 WORKSTN;INFDS(情報 DS)が必要な場合:
正) DCL-F BD003D0 WORKSTN INFDS(WS_INFDS);ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
固定長 F 仕様の入出力区分(I/O/U/A)を DCL-F の USAGE キーワードに正しく対応させること。
固定長の組み合わせ フリーフォーマット 備考 I のみ USAGE(*INPUT) READ/CHAIN のみ O のみ USAGE(*OUTPUT) WRITE のみ U のみ USAGE(*UPDATE) READ/CHAIN/WRITE/UPDATE/DELETE I+A USAGE(*UPDATE:*OUTPUT) CHAIN+WRITE が必要なため *UPDATE を使う(RNF5197 防止) O+A USAGE(*OUTPUT) WRITE のみ U+A USAGE(*UPDATE:*OUTPUT) WRITE も可(USAGE(*UPDATE:*ADD) は RNF2370 エラー) **【重要①】I+A(入力+追加)は USAGE(UPDATE:OUTPUT) を使うこと
固定長でI(入力)とA(追加)の両方が指定されている場合(例:FAA001L0 IF A E K DISK)、
CHAIN と WRITE の両方を使うためUSAGE(*INPUT)では WRITE 時に RNF5197 エラーになる。
必ずUSAGE(*UPDATE:*OUTPUT)を指定すること。
例:
変換前) FAA001L0 IF A E K DISK ← I(入力)+A(追加)
誤) DCL-F AA001L0 DISK KEYED USAGE(*INPUT); ← WRITE が RNF5197
正) DCL-F AA001L0 DISK KEYED USAGE(**UPDATE:*OUTPUT);**【重要②】USAGE(UPDATE:ADD) は無効(RNF2370 エラー)
U(更新)と A(追加)の両方が指定されている場合でもUSAGE(*UPDATE:*ADD)は使えない。
USAGE(*UPDATE:*OUTPUT)を指定すること。更新ファイルに WRITE 命令を使えば追加も可能。
例:
変換前) FXXXFILE UF A E K DISK ← U(更新)+A(追加)
誤) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*ADD); ← RNF2370
正) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*OUTPUT);
── 定義仕様(DCL-S / DCL-DS / DCL-PI)関連 ──
プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;フリーフォーマット
DCL-DSには必ず DS 名または*Nを指定すること
固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットのDCL-DSでは
DS 名または*N(匿名)を必ず指定しなければならない(RNF3368)。
例:
誤) DCL-DS;
正) DCL-DS *N;フリーフォーマット
DCL-DSのサブフィールドにPOSキーワードは使用できない
固定長 I 仕様のバイト位置指定(POS(n))はフリーフォーマットでは認識されない(RNF5347 の原因)。
位置共有が必要な場合はOVERLAY(親フィールド:開始位置)キーワードを使うこと。
例:
誤) DCL-DS *N;
UYM1 ZONED(4:0) POS(1);
UYY1 ZONED(2:0) POS(1);
UMM1 ZONED(2:0) POS(3);
END-DS;
正) DCL-DS *N;
UYM1 ZONED(4:0);
UYY1 ZONED(2:0) OVERLAY(UYM1:1);
UMM1 ZONED(2:0) OVERLAY(UYM1:3);
END-DS;【重要】外部ファイルフィールドと OVERLAY を組み合わせた DS は変換漏れに注意
固定長 RPG IV では、外部記述ファイルのフィールドをバイト位置で参照する無名 DS を定義し、
複数フィールドを1つの集約変数(例:年月日を YYYYMMDD の8桁に合算)として扱うパターンがある。
このような DS は変換時に丸ごと抜け落ちやすいため、元ソースの D 仕様を全件確認し必ず変換すること。
例(元ソース固定長):
D DS
D A0SKHZ 1 8 0 ← 削除予定日8桁(集約)
D A0SKYY 1 4 0 ← 年(A0SKHZ と同位置でオーバーレイ)
D A0SKMM 5 6 0
D A0SKDD 7 8 0
変換後(フリーフォーマット):
DCL-DS *N;
A0SKHZ ZONED(8:0);
A0SKYY ZONED(4:0) OVERLAY(A0SKHZ:1);
A0SKMM ZONED(2:0) OVERLAY(A0SKHZ:5);
A0SKDD ZONED(2:0) OVERLAY(A0SKHZ:7);
END-DS;
※ この DS が抜けると「A0SKHZ が未定義」(RNF7030)となり、演算命令でコンパイルエラーになる。ZONED / PACKED 数値型の桁数は最大 63 桁まで
ZONED(nnn:0)やPACKED(nnn:0)の桁数に 64 以上を指定すると RNF0503 エラーになる。
63 桁を超えるデータ領域はCHAR型に変換すること。
DATE型変数の日付フォーマットにゼロサフィックスは使用できない
DATE(*ISO0)のようにゼロを付けると RNF0619 エラーになる。
変数定義では*ISO・*YMD・*MDY・*DMY・*JULなどゼロなしのフォーマットを使うこと。
例:
誤) DCL-S WB5DATE DATE(*ISO0);
正) DCL-S WB5DATE DATE(*ISO);プロシージャー名・変数名・フィールド名に使用できる文字の制限
英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字は使用できない。
¥SB100 → SB100 のように変換すること。フリーフォーマット RPG の予約語を変数名・フィールド名に使用しないこと(RNF3314 → RNF5347/RNF7030 連鎖の原因)
RPG の特殊語(予約語)と同一の名前を変数名・フィールド名に使用すると RNF3314(名前の指定が予約語である)
エラーになり、その変数を参照する演算命令が正しく解釈されなくなる。
さらに RNF3314 が発生すると、コンパイラの内部状態が崩れ、後続のENDIF/ENDDOのENDが
未定義名として RNF7030 → RNF5347 / RNF5177 / RNF5248 が大量に連鎖する。使用禁止の主な予約語(変数名・フィールド名として使えない):
予約語 説明 PAGEプリンター出力の現行ページ番号(特殊語) PAGE1~PAGE7プリンター出力用ページ番号(特殊語) *DATEプログラム実行日付(固定長では変数名としても使われるが FF では不可) *TIMEプログラム実行時刻 *IN標識配列 *INLR*IN01等標識名 *ON*OFF*HIVAL*LOVAL*BLANK*ZERO*NULL等特殊値 変換方針: 固定長 RPG IV のフィールド名が予約語と一致する場合、先頭に
WやXを付けて別名にする。
例:
変換前) D PAGE 2S 0 ← ZONED 2桁のフィールド名が PAGE
誤) DCL-S PAGE ZONED(2:0); ← RNF3314 → ENDIF/ENDDO が大量 RNF5347 になる連鎖
正) DCL-S WPAGE ZONED(2:0); ← 先頭に W を付けて回避【精査チェック】変換後に予約語が変数名・フィールド名として使われていないか全定義をスキャンすること。
特にPAGE/PAGE1~PAGE7は印刷プログラムに頻出するため注意すること。PSDS のサブフィールド定義はフリーフォーマットの記法に正しく変換すること
固定長のSDS(プログラム状況 DS)はフリーフォーマットでDCL-DS *N PSDSに変換する。
各サブフィールドの変換ルールは以下の通り。*【PROC フィールド】
固定長で*PROC特殊語を使ったサブフィールド定義(現行プロシージャー名)は、
フリーフォーマットでは*PROCキーワード自体が RNF3308 エラーになる。
PSDS の先頭 10 バイトが自動的に現行プロシージャー名に設定されるため、
*PROCキーワードを付けずに先頭のCHAR(10)フィールドとして定義すること。
例:
変換前) D W¥PGM *PROC
誤) WPGM CHAR(10) *PROC; ← RNF3308
正) WPGM CHAR(10); ← 先頭10バイトが自動的に現行PGM名になる【バイト位置指定フィールド(POS)】
PSDS のサブフィールドではPOS(n)キーワードは使用可能(通常 DS のルール7とは異なる)。
固定長の位置指定はそのままPOS(n)で変換してよい。
例:
変換前) D W¥WSID 244 253
正) WWSID CHAR(10) POS(244);【フィールド名の制限】
英大文字・数字・#・@・$ のみ使用可能。¥ を含む名前は変換する。
例:W¥PGM → WPGM、W¥WSID → WWSID、@@USER → XUSER(@ は2個連続不可のため変更)
── 演算命令関連 ──
DFTACTGRP(YES) ではフリーフォーマット RPG は正しくコンパイルできない
フリーフォーマット RPG ではCTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);を必ず先頭に記述する*こと。
さらに重要:CTL-OPT にいくらDFTACTGRP(*NO)と書いても、コンパイルコマンド(CRTBNDRPG)側が
DFTACTGRP(*YES)だと CTL-OPT が無視される。 その場合、ENDIF/ENDDOがすべて演算命令として
誤認され RNF5347(割り当て演算子が必要)が大量連鎖する。コンパイル時は必ず
DFTACTGRP(*NO)を指定すること(ルール30参照)。
例:
正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER); ← ソース先頭
正) CRTBNDRPG PGM(LIB/PGM) SRCFILE(LIB/SRC) DFTACTGRP(*NO) ← コンパイルコマンドフリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;CHAIN の結果は
%FOUNDで判定すること
フリーフォーマットのCHAINに固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
CHAIN の後は%FOUNDまたは%FOUND(ファイル名)で判定すること。
例:
誤) CHAIN KFLDS GADPL11 *IN03;
正) CHAIN KFLDS GADPL11;
IF NOT %FOUND(GADPL11);READ / READE / READP 命令の結果(EOF)判定
【READ の EOF 判定】
フリーフォーマットのREAD命令では、結果標識をオペランドとして直接渡す
READ ファイル名 *INxx;の形式は RNF0637(オペランドが必要)エラーになる。
EOF 判定はREADの後で%EOF(ファイル名)を使うこと。
例:
誤) READ BD001L0 *IN60; ← RNF0637 + RNF7030(IN60 未定義)
正) READ BD001L0;
*IN60 = %EOF(BD001L0); ← 必要なら標識に保存
IF %EOF(BD001L0); ← 直接判定する場合【READE の EOF 判定(単一キー)】
単一キーのREADEは同様に結果標識を直接渡す形式が不可。%EOFで判定すること。
例:
誤) READE KFLD FILNAME *IN70;
正) READE KFLD FILNAME;
IF %EOF(FILNAME);【READE の EOF 判定(複合キー)】
READE (キー1:キー2) ファイル名;の後に%EOF(ファイル名)を使うと RNF0391 エラーになる場合がある。
この場合はREADEに結果標識パラメーターとして渡さず、%EOFをファイル名なしで使うか、
READE後に別途標識を参照する方法を採ること。
例:
誤) READE (WTOKU:FSIKU) GADPL141;
*IN03 = %EOF(GADPL141); ← RNF0391
正) READE (WTOKU:FSIKU) GADPL141;
IF %EOF; ← ファイル名なしなら可
または)
// READ/READE に先立ち *IN70 = *OFF; でリセット、
// %EOF 判定で代入
READE (WTOKU:FSIKU) GADPL141;
*IN70 = %EOF;
IF *IN70;
*INLR = *ONとRETURNはサブルーチン定義の前に記述すること
BEGSR~ENDSRブロックの直後に演算命令を記述すると RNF5005 エラーになる。
プログラム終了処理は必ずサブルーチン定義の前に記述すること。
例:
誤) BEGSR @END;
ENDSR;
*INLR = *ON; ← RNF5005
RETURN;
正) *INLR = *ON; ← サブルーチン定義の前
RETURN;
BEGSR @END;
ENDSR;1行に複数ステートメントをセミコロンで区切って記述しない(RNF5508)
フリーフォーマットでは1つの物理行に1つのステートメントのみ記述すること。
IF 条件; 処理; ENDIF;のような「1行 IF」も RNF5508 エラーになるため禁止。
元ソースで固定長 CASxx / IFxx などの1行条件処理を変換する場合も必ず複数行に展開すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
誤) IF S01 = 9999999; S01 = 0; ENDIF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;
正) IF S01 = 9999999;
S01 = 0;
ENDIF;KLIST / KFLD は複合キー形式
(key1:key2:...)に変換すること
固定長 RPG IV のKLIST/KFLDはフリーフォーマットに変換できない命令である。
CHAIN / SETLL / SETGT / READE / READPE での複合キー指定は、カッコで囲んだコロン区切り形式
(key1:key2:...)に変換すること。【禁止】DS 全体をキーとして渡す方法(RNF7078 エラー)
KLIST の代替として全キーフィールドを DS にまとめCHAIN KEYDS FILNAME;と記述すると、
RPG は DS 先頭のフィールドの長さとファイルの最初のキーフィールドの長さを比較するため
RNF7078(長さ不一致)が発生する。DS 名を CHAIN の Factor1 に渡してはいけない。
例:
変換前) C KEYA01 CHAIN AA001L01
← KLIST KEYA01 は #KKASI(7):#KTOKU(4):#KNONY(4):... の12フィールド
誤) CHAIN KEYA01DS AA001L01; ← DS全体(53バイト)→ RNF7078
正) CHAIN (#KKASI:#KTOKU:#KNONY:#KNKOJ:#KNUKE
:#KMEHZ:#KMEBB:#KHINB:#KBUHI:#KSHUY
:#KKNRI:#KOIBN) AA001L01;SETLL / SETGT / READE でも同様にコロン区切り複合キー形式を使うこと。
例:
変換前) C KEYA01 SETLL AA001L01
正) SETLL (#KKASI:#KTOKU:...) AA001L01;固定長形式のコメント行(
*で始まる行)はフリーフォーマットでは乗算演算子として誤認される(RNF5347 連鎖の根本原因)
固定長 RPG IV では桁1に*を記述することでコメント行として扱われるが、
フリーフォーマットでは*が乗算演算子として解釈される。
その結果 RNF0955(EVAL左辺として無効)→ RNF5347(割り当て演算子が必要)が発生し、
さらにコンパイラの内部状態が崩壊して後続のENDIF/ENDDO/ENDSRが
すべて演算命令として誤認され、RNF5177 / RNF5248 / RNF7030 が大量に連鎖する。
この1行の変換漏れがプログラム全体のコンパイルエラーを引き起こす。変換方針:
*で始まるすべてのコメント行を//コメント行に変換するか、不要であれば削除すること- 特に
BEGSR~ENDSRの後ろや、サブルーチン区切り線として使われる
* * * * * *や*----...のような行が残りやすいため重点的にチェックすること
例:
変換前) * サブルーチン SB210
*---------------------------------------
誤) * サブルーチン SB210 ← フリーフォーマットでは乗算演算子として誤認
正) // サブルーチン SB210
// ---------------------------------------【精査チェック】変換後ソース全行を対象に
*で始まる行(ただし**FREEを除く)が
残っていないかスキャンすること。
**FREEはフリーフォーマット宣言なので除外する。
- フリーフォーマットでは
GOTO/TAG命令は使用できない(RNF7030/RNF5347 連鎖の原因)
固定長 RPG IV のGOTO ラベル名と対応するTAG ラベル名は、フリーフォーマットでは
コンパイラに演算命令として誤認され、RNF7030(名前未定義)→ RNF5347(割り当て演算子が必要)
が大量に連鎖する。フリーフォーマットにはTAG命令に相当する構文が存在しない。変換方針:
GOTOを使ったループはDOW *ONループに置き換え、終了条件はLEAVEで抜けるGOTOを使ったループ先頭へのITER相当はITERに置き換える- それ以外の
GOTO(前方ジャンプ等)は構造化された IF/SELECT に書き直す例(メインループを GOTO + TAG で実装していた場合):
変換前) C TAG @STR
C EXFMT BD003D01
...
C GOTO @STR
正) DOW *ON;
EXFMT BD003D01;
...
IF 終了条件;
LEAVE;
ENDIF;
ENDDO;注意:
ラベル名:の行(フリーフォーマットでの TAG 相当)がソース中に残ったままだと
コンパイラが演算命令として解釈し、RNF5347 が大量発生する。
必ずすべてのGOTO文と対応するラベル行を除去・変換すること。
── 組み込み関数・型変換関連 ──
固定長の
TIME命令は%INT(%DEC(%TIMESTAMP()))で変換すること
固定長 RPG IV のTIME命令は、14桁の ZONED 型 DS(WTIME等)に現在の日時を
YYYYMMDDHHMMSS形式の数値として格納する。
フリーフォーマットではTIME命令が使えないため、以下のように変換すること。
例:
変換前) C TIME WTIME ← WTIME は ZONED(14:0) DS
正) WTIME = %INT(%DEC(%TIMESTAMP()));これにより WTIME(14桁 ZONED DS)に日時数値が入り、OVERLAY 定義されたサブフィールド
(WTIYY/WTIMM/WTIDD 等)も自動的に更新される。
%YEAR/%MONTH/%DAYを使った個別代入は不要であり、使用を避けること。
%YEAR(%DATE())等は RNF0604/RNF0325 が連鎖して発生する環境があるため信頼しないこと。年月日の8桁数値(例:WTODAY)が個別に必要な場合は、
%TIMESTAMP()の数値変換から
%INT(%DEC(%TIMESTAMP()))の上位8桁を取得する方法を使うこと。
例:
// %TIMESTAMP() → "YYYY-MM-DD-HH.MM.SS.NNNNNN" 形式
// %DEC(%TIMESTAMP()) → 14桁数値(YYYYMMDDHHMMSS に近い形)
// WTIME DS の OVERLAY を活用して年月日を得る方法が最も安全:
WTIME = %INT(%DEC(%TIMESTAMP()));
WTODAY = (WTIYY * 10000) + (WTIMM * 100) + WTIDD;【参考】単独で日付数値(YYYYMMDD)が必要な場合
%INT(%DEC(%DATE()))は DATE 型なので精度指定なしで使用可能(ルール22参照)。
ただし戻り値のフォーマットはジョブの日付書式に依存するため、%TIMESTAMP 経由の方が確実。%DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
%DEC(%TIME():6:0)のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
例:
誤) %TRIM(W1MBMN) ← ZONED 型
正) %TRIM(%CHAR(W1MBMN))ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO;
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うこと。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式%EDITW の編集語はフィールド桁数分の置換文字が必要
対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールド → %EDITW(NO: ' ')
── 外部プログラム呼び出し関連 ──
固定長の
CALL命令は必ずCALLP+ プロトタイプ宣言に変換すること(RNF7030/RNF5502)
固定長 RPG IV のCALL '外部プログラム名'はフリーフォーマットでは使用できない。
フリーフォーマットで外部プログラムを呼び出す場合は、以下の両方を守ること。
- 必ず
DCL-PR ~ END-PRでプロトタイプを事前宣言すること(RNF7030 防止)- 呼び出し時は
CALLP プログラム名();と 括弧を付けること(RNF5502 防止)
パラメーターがなくても括弧は必須。
例:
変換前) CALL 'BD001R' ← 固定長の CALL 命令
誤) CALLP BD001R; ← RNF5502(括弧が必要)
正) DCL-PR BD001R; ← プロトタイプ宣言
END-PR;
// ...
CALLP BD001R(); ← パラメーターなしでも括弧は必須
正) CALLP BD001R(ARG1:ARG2); ← パラメーターあり外部記述ファイルのフィールドと同名の変数を定義する場合は桁数を一致させること(RNF6033)
DCL-F で外部記述ファイルを定義している場合、ファイルのフィールドと同名の変数を
RPG 内で異なる桁数・型で再定義すると RNF6033(外部記述フィールドの長さが前の定義と同じでない)
エラーになり、その仕様が無視される。この確認は DISK ファイルだけでなく PRINTER ファイルにも適用される。
PRINTER ファイルの DDS に定義されたフィールド(@DATE・@TIME・@@USER等)は、
RPG 内で同名の作業変数を定義すると桁数・型の一致が必要になる。
変換前に必ず DDS ソースを読み込んで各フィールドの桁数・型を把握すること。外部記述フィールドと同名の変数が必要な場合は、
get_column_metadata(DISK)または
read_ibmi_source(PRINTER の DDS ソース)でフィールドの桁数・型を確認し、RPG 変数と一致させること。
例(DISK ファイルの場合):
外部フィールド @DATE が ZONE(8,0) の場合:
誤) DCL-S @DATE ZONED(6:0); ← 桁数が異なる → RNF6033
正) DCL-S @DATE ZONED(8:0); ← 外部定義と一致させる
例(PRINTER ファイルの DDS の場合):
DDS:@DATE 8S 0(ZONED 8桁)
誤) DCL-S @DATE ZONED(6:0); ← 桁数が異なる → RNF6033
正) DCL-S @DATE ZONED(8:0); ← DDS 定義と一致させる
※ 外部定義と異なる桁数で作業変数が必要な場合は別名(例:W@DATE)を使うこと。コンパイルコマンド(CRTBNDRPG)は必ず
DFTACTGRP(*NO)を指定すること
フリーフォーマット RPG はコンパイル時にDFTACTGRP(*NO)を指定しないと、
CTL-OPT の記述に関わらずDFTACTGRP(*YES)として扱われる場合がある。
DFTACTGRP(*YES)のままコンパイルするとENDIF/ENDDOが演算命令として誤認され、
RNF5347(EVAL に割り当て演算子が必要)が全ブロック終端行で大量発生する。変換後のソースを書き込んだら、必ず以下のコマンドでコンパイルするようユーザーに伝えること:
CRTBNDRPG PGM(ライブラリ/プログラム名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)また、CTL-OPT に
DFTACTGRP(*NO)を記述することと、コンパイルコマンドで指定することは
両方必要であり、どちらか片方だけでは不十分な場合がある(ルール14参照)。
3-13. ソース⑦(2回目)
エラー0件にも関わらずコンパイルに失敗した
DCL-PR への EXTPGM キーワード漏れが原因
コンパイル結果 → 失敗
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 0 | 0 |
うまく変換できたロジック
- WORKSTN / DISK ファイルの
DCL-F定義(DH320D0、DH301L1、DH301L3)が正しく変換された -
DOWEQ '01'/DOWEQ '99'をDOW DSPSW = '01';/DOW DSPSW = '99';形式に変換 -
IFEQ/ELSE/ENDIF等の制御構造をIF/ELSE/ENDIFへ正確に変換 -
DO *HIVALループ内のGOTO ECHK/LEAVE/ITERをDOW *ON;+LEAVE/ITER構造に置換 -
KLIST/KFLDを個別変数(K#SHN1:K#SHN2:K#SHN3)に分解し、CHAIN (K#SHN1:K#SHN2:K#SHN3) DH301L1;形式に変換 -
CHAINの NR 標識(*IN80)をIF NOT %FOUND(DH301L1);に変換 - 複合キーの
SETLL/READEを(K#SHN1:K#SHN2:K#SHN3:K#STHZ)コロン区切り形式に変換 -
TIME命令を%INT(%DEC(%TIMESTAMP()))に変換 -
CALL 'DATR11'/PARMをCALLP DATR11(P@DATE:P@PLMI:P@DAYS:PODATE:PORTN)+DCL-PRに変換 - 無名 DS のバイト位置指定(
WTIME 1 14 0等)をOVERLAY(WTIME:n)形式に変換
変換に失敗したロジック(エラー原因になった可能性)
-
DCL-PR DATR11にEXTPGM('DATR11')がない → バインドステップでCPD5D02が発生しプログラム未作成 -
READE (K#SHN1:K#SHN2:K#SHN3) DH301L3;後の EOF 判定が%EOF単体(ファイル名なし)であり、意図が正しいか要確認 - 外部 2 ファイル(
DH301L1、DH301L3)のレコード様式名(DH301L11、DH301L31)が未使用 →RNF7066(影響は軽微だが様式名の誤参照リスクあり) -
CTDATAの全角文字メッセージがRNF8267(DBCS 指定不正)を全 4 件で発生 → 実行時にメッセージが正しく表示されない可能性 -
RNF8042:E-05のメッセージ行の桁数が 60 バイトに満たず、CTDATA のレコード数不足として警告 - 相互参照表で
RNF7031が 52 件発生(DH301L1/DH301L3のほぼ全フィールドが未参照) → 変換後ロジックでファイルフィールドを一切直接参照していないことが露わに - 変換元の
GOTO ECHKは構造化に変換されたが、#CHKサブルーチンの入れ子 IF が深くなり可読性が低下している - 変換元の
MOVEL PODATE @STHZ(文字→数値への転送)が@STHZ = %DEC(PODATE:8:0);に変換されたが、型変換の整合性は実行時まで確認不可
まとめ
ファイル定義・DS の OVERLAY 変換・KLIST の複合キー化・GOTO の構造化など、骨格部分の変換精度は高く、コンパイルエラー自体はゼロだった。
唯一の失敗は DCL-PR への EXTPGM キーワード漏れで、これがバインドエラーを引き起こしてプログラム未作成という結果に。
CTDATA の全角文字まわりの RNF8267 は実害になりうる警告で、実行時にメッセージが化ける可能性がある。
「ほぼ変換できているのに最後の一手が惜しい」という、なかなか悔しい結果になった。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
対象メンバー
- 変換元
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_07
- 変換後
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_07_FF
タスク
【事前確認①】変換元ソース全体を読み込んで構成を把握する
- F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
- KLIST / KFLD 定義が存在する場合は使用箇所(CHAIN/SETLL/SETGT/READE)とキーフィールドを全件メモする
- READ / READE / READP の使用箇所を全件メモし、固定長の結果標識(*INxx)を使っているか確認する
- GOTO / TAG の使用箇所を全件メモする(フリーフォーマットでは使用不可 → ルール29)
GOTO が存在する場合、対応する TAG(ラベル)とジャンプ先の文脈を把握し、変換方針(DOW/LEAVE/ITER/IF)を決定する*で始まるコメント行の使用箇所を全件確認する(フリーフォーマットでは乗算演算子として誤認 → ルール32)
区切り線(*----...)やサブルーチン直後の*行が残存するだけでプログラム全体のコンパイルエラーになる- CALLP / CALL で外部プログラムを呼び出している箇所を全件メモする
- 外部記述ファイルのフィールドと同名の DCL-S / DCL-DS サブフィールドを定義している箇所を確認する
- D仕様の全フィールド名を RPG 予約語リストと照合する(ルール31)
PAGE/PAGE1~PAGE7は印刷プログラムに頻出するため特に注意すること
予約語と一致するフィールド名があれば、先頭にWを付けた別名(例:WPAGE)に置き換える計画を立てる【事前確認②】F仕様の全ファイルを対象に以下を確認する
2-1. WORKSTN ファイルの確認
- WORKSTN ファイルは
DCL-F ファイル名 WORKSTN;のみで定義する(ルール4)- 固定長の
CF/Eキーワードはフリーフォーマットでは 認識されず RNF2023 になるため、必ず除去することCF Eが残ったままだとファイルが DISK として扱われ、EXFMTが RNF5199 になる2-2. DISK ファイルの確認
get_table_metadataで各 DISK ファイルの実レコード様式名を確認する- 外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述で同名様式あり →
EXTDESCで別名ファイルを指定(ユーザーに確認)- プログラム記述(F区分=F) → バッファ変数方式を採用(ルール3)
ただし実ファイルに同名様式が存在する場合はEXTDESCの要否もユーザーに確認すること- 入出力区分(I/O/U/A の組み合わせ)を確認し、ルール6の変換表に従って USAGE を決定する
特に I+A(入力+追加)はUSAGE(*UPDATE:*OUTPUT)を使うこと(USAGE(*INPUT) では WRITE が RNF5197)
U+A(更新+追加)もUSAGE(*UPDATE:*OUTPUT)のみ(USAGE(*UPDATE:*ADD) は RNF2370)get_column_metadataで外部記述フィールドの桁数・型を確認し、同名変数を定義する場合は一致させる(ルール28 / RNF6033)2-3. PRINTER ファイルの確認
- 各 PRINTER ファイルが外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述 →
get_table_metadataでレコード様式名を確認し、同名様式があればEXTDESCで独自 DDS を指定- 外部記述 PRINTER ファイルの DDS ソースを
read_ibmi_sourceで読み込み、各様式のフィールド名と桁数・型を把握すること(RNF6033 防止 / ルール28)
- DDS で定義されているフィールド(
@DATE・@TIME・@@USER等)は、同名の作業変数を RPG 内で定義する際に桁数・型を一致させること- 例)DDS に
@DATE 8S 0(ZONED 8桁)があれば、RPG 変数も@DATE ZONED(8:0)にする- プログラム記述(F区分=F) → 対応する独自プリンター DDS ファイルをユーザーに確認する
DDS が特定できない場合はそのファイルの変換を保留し、ユーザーに判断を仰ぐことOFLIND(*INOF)は必ずOFLIND(*IN0F)に変換する(英字 O → 数字 0)2-4. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む
【変換】事前確認の結果を反映しながら、RPG IV 固定長形式を完全フリーフォーマットに変換する
- ソースコード先頭に
**FREEを記述する- "Rule_Convert_FF.md" の全ルールに従うこと
- 元ソースの D 仕様(DCL-S / DCL-DS)を1件も漏らさず変換すること(ルール9の重要注記参照)
- 特に以下を重点確認すること
- ファイル定義(ルール1〜6):事前確認の対処方針を確実に反映する
- WORKSTN ファイル(ルール4):
DCL-F ファイル名 WORKSTN;のみ。CF/Eを残さないこと(RNF2023 → RNF5199)- 予約語の変数名(ルール31):事前確認で判明した予約語フィールド(
PAGE等)を別名に変換し、演算命令内の全参照箇所も置き換えること- DCL-DS の POS → OVERLAY への変換(ルール9)
- PSDS(SDS)の変換(ルール13):
*PROCキーワードを除去し先頭 CHAR(10) として定義する- TIME 命令の変換(ルール21):DS の OVERLAY 構造を活かして
WTIME = %INT(%DEC(%TIMESTAMP()))に変換する- GOTO / TAG の変換(ルール29):
GOTOと対応するラベル行をすべて除去しDOW *ON/LEAVE/ITER/IFに置き換える
ラベル行(@STR:等)が1行でも残るとコンパイラが演算命令として誤認し RNF5347 が大量連鎖する- 固定長コメント行の変換(ルール32):
*で始まるすべての行を//コメントに変換するか削除すること
ENDSRの後ろや区切り線(*----...、* * * * * *)が残りやすいため全行スキャンすること
**FREEのみ例外として除外する- KLIST / KFLD の変換(ルール20):
CHAIN/SETLL/SETGT/READEでは(key1:key2:...)の複合キー形式を使う。DS 名を Factor1 に渡さないこと(RNF7078)- READ / READE / READP の EOF 判定(ルール17):
READ ファイル名 *INxx;形式はフリーフォーマットでは RNF0637 になる。必ずREAD ファイル名; *INxx = %EOF(ファイル名);またはIF %EOF(ファイル名);形式に変換すること- CALLP の括弧(ルール27):
CALLP プログラム名();と括弧を付けること。パラメーターなしでも括弧は必須(RNF5502)- CALL 命令は必ず CALLP + プロトタイプ宣言に変換すること(ルール27)
- 演算命令のオペランド順序(ルール15)
- 1行に複数ステートメントを書かない(ルール19):
IF X; Y=0; ENDIF;も禁止【精査】出力前にソースコードを精査し、重大度20以上のエラー要因を除去する
- 予約語チェック(ルール31 / RNF3314 → RNF5347/RNF7030 大量連鎖の防止):全 DCL-S / DCL-DS サブフィールドの名前を予約語リストと照合する
PAGE/PAGE1~PAGE7が変数名・フィールド名として残っていないか全定義をスキャンする- 予約語が残っていた場合は
WPAGEなどの別名に変更し、演算命令内の参照箇所もすべて置き換える*で始まる行(**FREEを除く)が1行も残っていないか全行スキャンする(ルール32 / RNF5347 大量連鎖の根本原因)
区切り線・サブルーチン後の*行1行でプログラム全体のコンパイルエラーになる- GOTO 文およびラベル行(
ラベル名:の行)が1行も残っていないか全行スキャンする(ルール29 / RNF5347 連鎖)- CALLP の呼び出しに括弧があるか全件確認する(
CALLP PGM;→CALLP PGM();/ RNF5502)- 外部記述フィールドと同名の変数定義で桁数・型が一致しているか確認する(ルール28 / RNF6033)
- PRINTER ファイルの DDS で定義されたフィールド(
@DATE・@TIME・@@USER等)についても同様に確認すること- WORKSTN ファイルの
DCL-FにCF/Eが残っていないか確認する(RNF2023 → RNF5199)- ファイル定義の問題(RNF2109 / RNF2121)が残っていないか確認する
- 1行に複数ステートメントが残っていないか全行スキャンする(RNF5508)
- PSDS の *PROC キーワードが残っていないか確認する(RNF3308)
- USAGE(*UPDATE:*ADD) / USAGE(*INPUT) でWRITEしている箇所がないか確認する(RNF2370/RNF5197)
- CHAIN / SETLL / SETGT / READE の Factor1 に DS 名が使われていないか確認する(RNF7078)
- READ / READE / READP の命令の直後に
*INxxが直接記述されていないか全行スキャンする(RNF0637)*INLR = *ON/RETURNが BEGSR ブロックより後ろに記述されていないか確認する(RNF5005)- ファイル定義エラーを起点とした連鎖エラー(RNF5347 / RNF0724 の大量発生)がないか確認する
- エラー要因を修正したらソースコード全体の整合性を再確認する
- 新たなエラー原因が見つかった場合は本ステップを繰り返す
【出力】変換後メンバーとして新規出力する
write_ibmi_sourceで書き込んだ後、コンパイルする場合は必ずDFTACTGRP(*NO)を指定すること(ルール30)- CTL-OPT に
DFTACTGRP(*NO) ACTGRP(*CALLER)を記述していても、コンパイルコマンド側がDFTACTGRP(*YES)だと CTL-OPT が無視されENDIF/ENDDOが演算命令として誤認される(RNF5347 大量発生)- ユーザーに対して、以下のコンパイルコマンドを提示すること:
CRTBNDRPG PGM(ライブラリ/メンバー名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
- サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
── ファイル定義(DCL-F)関連 ──
DISK/PRINTER ファイル変換前に「実ファイルのレコード様式名」を必ず確認すること
フリーフォーマットのDCL-Fでは、ファイル名と同名のレコード様式が実ファイルに存在すると
RNF2121(様式名重複)→ RNF2109(ファイル全体が無視)が発生する。
この問題は DISK / PRINTER / プログラム記述ファイルすべてに適用される。変換前に必ずやること:
get_table_metadataまたはread_ibmi_sourceで対象ファイルのレコード様式名を確認する- ファイル名とレコード様式名が同一の場合 → 必ず以下のいずれかで対処すること
- DISK 外部記述ファイル:
EXTDESC('ライブラリ/別名ファイル')で衝突を回避する- DISK プログラム記述ファイル(F区分=F):バッファ変数方式(後述ルール3)に変換する
- PRINTER ファイル:後述ルール2に従う
- 対処方法が不明な場合は処理を中断してユーザーに確認を求めること
RNF2109 が発生するとどうなるか:
ファイルが無視されると後続のすべての定義(DCL-S / DCL-DS / DCL-PI)や
演算命令(IF / ENDIF 等)が演算仕様として誤認され、RNF5347 / RNF0724 が大量発生する。
この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。PRINTER ファイルの変換方針
固定長 RPG IV の PRINTER ファイルは以下の2パターンがあり、変換前に判定すること。【パターンA】外部記述 PRINTER ファイル(F仕様に E キーワードあり)
- 対応する独自 DDS が存在する →
EXTDESCでそのファイルを指定するOFLIND(*INOF)はOFLIND(*IN0F)に変換する(英字「O」ではなく数字「0」)QPRINTのようなシステム標準ファイルは QGPL/QPRINT に同名様式が存在するため必ずEXTDESCで独自 DDS を指定する
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F); ← 同名様式 → RNF2109
正) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');【パターンB】プログラム記述 PRINTER ファイル(F仕様に F 区分あり、E キーワードなし)
- 例:
FQPRINT O F 132 PRINTER OFLIND(*INOF)- フリーフォーマットには
PGMDESCキーワードが存在しないため、外部記述として扱われ RNF2109 が発生する- 対応する独自プリンター DDS がない場合は変換を中断してユーザーに確認を求めること
- 独自 DDS が用意できる場合のみ
EXTDESCで指定して変換する
例:
変換前) FQPRINT O F 132 PRINTER OFLIND(*INOF)
正) // 独自プリンターDDS(例: MYLIB/MYPRT)を事前に用意する
DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');
DCL-S QPREC CHAR(132);
// ...
WRITE QPRINT QPREC;DCL-F に RECLN キーワードは指定できない(DISK プログラム記述ファイルはバッファ変数方式を使う)
フリーフォーマットのDCL-FではRECLNキーワードは認識されず(RNF2023/RNF2109)。
固定長プログラム記述 DISK ファイル(F仕様のF区分)は、以下のバッファ変数方式に変換すること。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
注意: 実ファイルに同名レコード様式が存在する場合、DCL-F ABAWP42 DISK ...だけでは
RNF2121 → RNF2109 が発生してファイルごと無視される。バッファ変数方式だけでは解決しない。
この場合はEXTDESCで別名ファイルを指定するか、DDS 側のレコード様式名変更をユーザーに確認すること。WORKSTN ファイルは
DCL-F ファイル名 WORKSTN;のみで定義すること(RNF2023/RNF2401)
固定長 F 仕様の WORKSTN ファイルはCF(Combined)とE(外部記述)を組み合わせて記述するが、
フリーフォーマットのDCL-FではCFとEは認識されないキーワードのため RNF2023 で無視される。
その結果ファイルが DISK として扱われ、EXFMT命令が RNF5199(オペランドが正しくない)エラーになる。
フリーフォーマットではWORKSTNキーワードだけで「外部記述・双方向入出力」の意味を持つため、
CF/Eは不要。INFDSやSFILEキーワードが必要な場合はそれぞれ追記すること。
例:
変換前) FBD003D0 CF E WORKSTN
誤) DCL-F BD003D0 CF E WORKSTN; ← CF・E が RNF2023 → DISK 扱い → EXFMT が RNF5199
正) DCL-F BD003D0 WORKSTN;INFDS(情報 DS)が必要な場合:
正) DCL-F BD003D0 WORKSTN INFDS(WS_INFDS);ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
固定長 F 仕様の入出力区分(I/O/U/A)を DCL-F の USAGE キーワードに正しく対応させること。
固定長の組み合わせ フリーフォーマット 備考 I のみ USAGE(*INPUT) READ/CHAIN のみ O のみ USAGE(*OUTPUT) WRITE のみ U のみ USAGE(*UPDATE) READ/CHAIN/WRITE/UPDATE/DELETE I+A USAGE(*UPDATE:*OUTPUT) CHAIN+WRITE が必要なため *UPDATE を使う(RNF5197 防止) O+A USAGE(*OUTPUT) WRITE のみ U+A USAGE(*UPDATE:*OUTPUT) WRITE も可(USAGE(*UPDATE:*ADD) は RNF2370 エラー) **【重要①】I+A(入力+追加)は USAGE(UPDATE:OUTPUT) を使うこと
固定長でI(入力)とA(追加)の両方が指定されている場合(例:FAA001L0 IF A E K DISK)、
CHAIN と WRITE の両方を使うためUSAGE(*INPUT)では WRITE 時に RNF5197 エラーになる。
必ずUSAGE(*UPDATE:*OUTPUT)を指定すること。
例:
変換前) FAA001L0 IF A E K DISK ← I(入力)+A(追加)
誤) DCL-F AA001L0 DISK KEYED USAGE(*INPUT); ← WRITE が RNF5197
正) DCL-F AA001L0 DISK KEYED USAGE(**UPDATE:*OUTPUT);**【重要②】USAGE(UPDATE:ADD) は無効(RNF2370 エラー)
U(更新)と A(追加)の両方が指定されている場合でもUSAGE(*UPDATE:*ADD)は使えない。
USAGE(*UPDATE:*OUTPUT)を指定すること。更新ファイルに WRITE 命令を使えば追加も可能。
例:
変換前) FXXXFILE UF A E K DISK ← U(更新)+A(追加)
誤) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*ADD); ← RNF2370
正) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*OUTPUT);
── 定義仕様(DCL-S / DCL-DS / DCL-PI)関連 ──
プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;フリーフォーマット
DCL-DSには必ず DS 名または*Nを指定すること
固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットのDCL-DSでは
DS 名または*N(匿名)を必ず指定しなければならない(RNF3368)。
例:
誤) DCL-DS;
正) DCL-DS *N;フリーフォーマット
DCL-DSのサブフィールドにPOSキーワードは使用できない
固定長 I 仕様のバイト位置指定(POS(n))はフリーフォーマットでは認識されない(RNF5347 の原因)。
位置共有が必要な場合はOVERLAY(親フィールド:開始位置)キーワードを使うこと。
例:
誤) DCL-DS *N;
UYM1 ZONED(4:0) POS(1);
UYY1 ZONED(2:0) POS(1);
UMM1 ZONED(2:0) POS(3);
END-DS;
正) DCL-DS *N;
UYM1 ZONED(4:0);
UYY1 ZONED(2:0) OVERLAY(UYM1:1);
UMM1 ZONED(2:0) OVERLAY(UYM1:3);
END-DS;【重要】外部ファイルフィールドと OVERLAY を組み合わせた DS は変換漏れに注意
固定長 RPG IV では、外部記述ファイルのフィールドをバイト位置で参照する無名 DS を定義し、
複数フィールドを1つの集約変数(例:年月日を YYYYMMDD の8桁に合算)として扱うパターンがある。
このような DS は変換時に丸ごと抜け落ちやすいため、元ソースの D 仕様を全件確認し必ず変換すること。
例(元ソース固定長):
D DS
D A0SKHZ 1 8 0 ← 削除予定日8桁(集約)
D A0SKYY 1 4 0 ← 年(A0SKHZ と同位置でオーバーレイ)
D A0SKMM 5 6 0
D A0SKDD 7 8 0
変換後(フリーフォーマット):
DCL-DS *N;
A0SKHZ ZONED(8:0);
A0SKYY ZONED(4:0) OVERLAY(A0SKHZ:1);
A0SKMM ZONED(2:0) OVERLAY(A0SKHZ:5);
A0SKDD ZONED(2:0) OVERLAY(A0SKHZ:7);
END-DS;
※ この DS が抜けると「A0SKHZ が未定義」(RNF7030)となり、演算命令でコンパイルエラーになる。ZONED / PACKED 数値型の桁数は最大 63 桁まで
ZONED(nnn:0)やPACKED(nnn:0)の桁数に 64 以上を指定すると RNF0503 エラーになる。
63 桁を超えるデータ領域はCHAR型に変換すること。
DATE型変数の日付フォーマットにゼロサフィックスは使用できない
DATE(*ISO0)のようにゼロを付けると RNF0619 エラーになる。
変数定義では*ISO・*YMD・*MDY・*DMY・*JULなどゼロなしのフォーマットを使うこと。
例:
誤) DCL-S WB5DATE DATE(*ISO0);
正) DCL-S WB5DATE DATE(*ISO);プロシージャー名・変数名・フィールド名に使用できる文字の制限
英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字は使用できない。
¥SB100 → SB100 のように変換すること。フリーフォーマット RPG の予約語を変数名・フィールド名に使用しないこと(RNF3314 → RNF5347/RNF7030 連鎖の原因)
RPG の特殊語(予約語)と同一の名前を変数名・フィールド名に使用すると RNF3314(名前の指定が予約語である)
エラーになり、その変数を参照する演算命令が正しく解釈されなくなる。
さらに RNF3314 が発生すると、コンパイラの内部状態が崩れ、後続のENDIF/ENDDOのENDが
未定義名として RNF7030 → RNF5347 / RNF5177 / RNF5248 が大量に連鎖する。使用禁止の主な予約語(変数名・フィールド名として使えない):
予約語 説明 PAGEプリンター出力の現行ページ番号(特殊語) PAGE1~PAGE7プリンター出力用ページ番号(特殊語) *DATEプログラム実行日付(固定長では変数名としても使われるが FF では不可) *TIMEプログラム実行時刻 *IN標識配列 *INLR*IN01等標識名 *ON*OFF*HIVAL*LOVAL*BLANK*ZERO*NULL等特殊値 変換方針: 固定長 RPG IV のフィールド名が予約語と一致する場合、先頭に
WやXを付けて別名にする。
例:
変換前) D PAGE 2S 0 ← ZONED 2桁のフィールド名が PAGE
誤) DCL-S PAGE ZONED(2:0); ← RNF3314 → ENDIF/ENDDO が大量 RNF5347 になる連鎖
正) DCL-S WPAGE ZONED(2:0); ← 先頭に W を付けて回避【精査チェック】変換後に予約語が変数名・フィールド名として使われていないか全定義をスキャンすること。
特にPAGE/PAGE1~PAGE7は印刷プログラムに頻出するため注意すること。PSDS のサブフィールド定義はフリーフォーマットの記法に正しく変換すること
固定長のSDS(プログラム状況 DS)はフリーフォーマットでDCL-DS *N PSDSに変換する。
各サブフィールドの変換ルールは以下の通り。*【PROC フィールド】
固定長で*PROC特殊語を使ったサブフィールド定義(現行プロシージャー名)は、
フリーフォーマットでは*PROCキーワード自体が RNF3308 エラーになる。
PSDS の先頭 10 バイトが自動的に現行プロシージャー名に設定されるため、
*PROCキーワードを付けずに先頭のCHAR(10)フィールドとして定義すること。
例:
変換前) D W¥PGM *PROC
誤) WPGM CHAR(10) *PROC; ← RNF3308
正) WPGM CHAR(10); ← 先頭10バイトが自動的に現行PGM名になる【バイト位置指定フィールド(POS)】
PSDS のサブフィールドではPOS(n)キーワードは使用可能(通常 DS のルール7とは異なる)。
固定長の位置指定はそのままPOS(n)で変換してよい。
例:
変換前) D W¥WSID 244 253
正) WWSID CHAR(10) POS(244);【フィールド名の制限】
英大文字・数字・#・@・$ のみ使用可能。¥ を含む名前は変換する。
例:W¥PGM → WPGM、W¥WSID → WWSID、@@USER → XUSER(@ は2個連続不可のため変更)
── 演算命令関連 ──
DFTACTGRP(YES) ではフリーフォーマット RPG は正しくコンパイルできない
フリーフォーマット RPG ではCTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);を必ず先頭に記述する*こと。
さらに重要:CTL-OPT にいくらDFTACTGRP(*NO)と書いても、コンパイルコマンド(CRTBNDRPG)側が
DFTACTGRP(*YES)だと CTL-OPT が無視される。 その場合、ENDIF/ENDDOがすべて演算命令として
誤認され RNF5347(割り当て演算子が必要)が大量連鎖する。コンパイル時は必ず
DFTACTGRP(*NO)を指定すること(ルール30参照)。
例:
正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER); ← ソース先頭
正) CRTBNDRPG PGM(LIB/PGM) SRCFILE(LIB/SRC) DFTACTGRP(*NO) ← コンパイルコマンドフリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;CHAIN の結果は
%FOUNDで判定すること
フリーフォーマットのCHAINに固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
CHAIN の後は%FOUNDまたは%FOUND(ファイル名)で判定すること。【重要】
%FOUND()の引数はファイル名(DCL-F で定義した名前)を渡すこと(RNF0394)
レコード様式名(ファイル名 + 数字サフィックス等)ではなく、RPG がファイルを参照する名前を使うこと。
例えばファイル名がDH301L1、レコード様式名がDH301L11の場合、引数はDH301L1になる。
例:
誤) CHAIN KFLDS GADPL11 *IN03;
正) CHAIN KFLDS GADPL11;
IF NOT %FOUND(GADPL11);誤) CHAIN (K#SHN1:K#SHN2:K#SHN3) DH301L1;
IF NOT %FOUND(DH301L11); ← レコード様式名を渡している → RNF0394
正) CHAIN (K#SHN1:K#SHN2:K#SHN3) DH301L1;
IF NOT %FOUND(DH301L1); ← ファイル名を渡すREAD / READE / READP 命令の結果(EOF)判定
【READ の EOF 判定】
フリーフォーマットのREAD命令では、結果標識をオペランドとして直接渡す
READ ファイル名 *INxx;の形式は RNF0637(オペランドが必要)エラーになる。
EOF 判定はREADの後で%EOF(ファイル名)を使うこと。
例:
誤) READ BD001L0 *IN60; ← RNF0637 + RNF7030(IN60 未定義)
正) READ BD001L0;
*IN60 = %EOF(BD001L0); ← 必要なら標識に保存
IF %EOF(BD001L0); ← 直接判定する場合【READE の EOF 判定(単一キー)】
単一キーのREADEは同様に結果標識を直接渡す形式が不可。%EOFで判定すること。
例:
誤) READE KFLD FILNAME *IN70;
正) READE KFLD FILNAME;
IF %EOF(FILNAME);【READE の EOF 判定(複合キー)】
READE (キー1:キー2) ファイル名;の後に%EOF(ファイル名)を使うと RNF0391 エラーになる場合がある。
この場合はREADEに結果標識パラメーターとして渡さず、%EOFをファイル名なしで使うか、
READE後に別途標識を参照する方法を採ること。
例:
誤) READE (WTOKU:FSIKU) GADPL141;
*IN03 = %EOF(GADPL141); ← RNF0391
正) READE (WTOKU:FSIKU) GADPL141;
IF %EOF; ← ファイル名なしなら可
または)
// READ/READE に先立ち *IN70 = *OFF; でリセット、
// %EOF 判定で代入
READE (WTOKU:FSIKU) GADPL141;
*IN70 = %EOF;
IF *IN70;
*INLR = *ONとRETURNはサブルーチン定義の前に記述すること
BEGSR~ENDSRブロックの直後に演算命令を記述すると RNF5005 エラーになる。
プログラム終了処理は必ずサブルーチン定義の前に記述すること。
例:
誤) BEGSR @END;
ENDSR;
*INLR = *ON; ← RNF5005
RETURN;
正) *INLR = *ON; ← サブルーチン定義の前
RETURN;
BEGSR @END;
ENDSR;1行に複数ステートメントをセミコロンで区切って記述しない(RNF5508)
フリーフォーマットでは1つの物理行に1つのステートメントのみ記述すること。
IF 条件; 処理; ENDIF;のような「1行 IF」も RNF5508 エラーになるため禁止。
元ソースで固定長 CASxx / IFxx などの1行条件処理を変換する場合も必ず複数行に展開すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
誤) IF S01 = 9999999; S01 = 0; ENDIF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;
正) IF S01 = 9999999;
S01 = 0;
ENDIF;KLIST / KFLD は複合キー形式
(key1:key2:...)に変換すること
固定長 RPG IV のKLIST/KFLDはフリーフォーマットに変換できない命令である。
CHAIN / SETLL / SETGT / READE / READPE での複合キー指定は、カッコで囲んだコロン区切り形式
(key1:key2:...)に変換すること。【禁止】DS 全体をキーとして渡す方法(RNF7078 エラー)
KLIST の代替として全キーフィールドを DS にまとめCHAIN KEYDS FILNAME;と記述すると、
RPG は DS 先頭のフィールドの長さとファイルの最初のキーフィールドの長さを比較するため
RNF7078(長さ不一致)が発生する。DS 名を CHAIN の Factor1 に渡してはいけない。
例:
変換前) C KEYA01 CHAIN AA001L01
← KLIST KEYA01 は #KKASI(7):#KTOKU(4):#KNONY(4):... の12フィールド
誤) CHAIN KEYA01DS AA001L01; ← DS全体(53バイト)→ RNF7078
正) CHAIN (#KKASI:#KTOKU:#KNONY:#KNKOJ:#KNUKE
:#KMEHZ:#KMEBB:#KHINB:#KBUHI:#KSHUY
:#KKNRI:#KOIBN) AA001L01;SETLL / SETGT / READE でも同様にコロン区切り複合キー形式を使うこと。
例:
変換前) C KEYA01 SETLL AA001L01
正) SETLL (#KKASI:#KTOKU:...) AA001L01;固定長形式のコメント行(
*で始まる行)はフリーフォーマットでは乗算演算子として誤認される(RNF5347 連鎖の根本原因)
固定長 RPG IV では桁1に*を記述することでコメント行として扱われるが、
フリーフォーマットでは*が乗算演算子として解釈される。
その結果 RNF0955(EVAL左辺として無効)→ RNF5347(割り当て演算子が必要)が発生し、
さらにコンパイラの内部状態が崩壊して後続のENDIF/ENDDO/ENDSRが
すべて演算命令として誤認され、RNF5177 / RNF5248 / RNF7030 が大量に連鎖する。
この1行の変換漏れがプログラム全体のコンパイルエラーを引き起こす。変換方針:
*で始まるすべてのコメント行を//コメント行に変換するか、不要であれば削除すること- 特に
BEGSR~ENDSRの後ろや、サブルーチン区切り線として使われる
* * * * * *や*----...のような行が残りやすいため重点的にチェックすること
例:
変換前) * サブルーチン SB210
*---------------------------------------
誤) * サブルーチン SB210 ← フリーフォーマットでは乗算演算子として誤認
正) // サブルーチン SB210
// ---------------------------------------【精査チェック】変換後ソース全行を対象に
*で始まる行(ただし**FREEを除く)が
残っていないかスキャンすること。
**FREEはフリーフォーマット宣言なので除外する。
- フリーフォーマットでは
GOTO/TAG命令は使用できない(RNF7030/RNF5347 連鎖の原因)
固定長 RPG IV のGOTO ラベル名と対応するTAG ラベル名は、フリーフォーマットでは
コンパイラに演算命令として誤認され、RNF7030(名前未定義)→ RNF5347(割り当て演算子が必要)
が大量に連鎖する。フリーフォーマットにはTAG命令に相当する構文が存在しない。変換方針:
GOTOを使ったループはDOW *ONループに置き換え、終了条件はLEAVEで抜けるGOTOを使ったループ先頭へのITER相当はITERに置き換える- それ以外の
GOTO(前方ジャンプ等)は構造化された IF/SELECT に書き直す例(メインループを GOTO + TAG で実装していた場合):
変換前) C TAG @STR
C EXFMT BD003D01
...
C GOTO @STR
正) DOW *ON;
EXFMT BD003D01;
...
IF 終了条件;
LEAVE;
ENDIF;
ENDDO;注意:
ラベル名:の行(フリーフォーマットでの TAG 相当)がソース中に残ったままだと
コンパイラが演算命令として解釈し、RNF5347 が大量発生する。
必ずすべてのGOTO文と対応するラベル行を除去・変換すること。
── 組み込み関数・型変換関連 ──
固定長の
TIME命令は%INT(%DEC(%TIMESTAMP()))で変換すること
固定長 RPG IV のTIME命令は、14桁の ZONED 型 DS(WTIME等)に現在の日時を
YYYYMMDDHHMMSS形式の数値として格納する。
フリーフォーマットではTIME命令が使えないため、以下のように変換すること。
例:
変換前) C TIME WTIME ← WTIME は ZONED(14:0) DS
正) WTIME = %INT(%DEC(%TIMESTAMP()));これにより WTIME(14桁 ZONED DS)に日時数値が入り、OVERLAY 定義されたサブフィールド
(WTIYY/WTIMM/WTIDD 等)も自動的に更新される。
%YEAR/%MONTH/%DAYを使った個別代入は不要であり、使用を避けること。
%YEAR(%DATE())等は RNF0604/RNF0325 が連鎖して発生する環境があるため信頼しないこと。年月日の8桁数値(例:WTODAY)が個別に必要な場合は、
%TIMESTAMP()の数値変換から
%INT(%DEC(%TIMESTAMP()))の上位8桁を取得する方法を使うこと。
例:
// %TIMESTAMP() → "YYYY-MM-DD-HH.MM.SS.NNNNNN" 形式
// %DEC(%TIMESTAMP()) → 14桁数値(YYYYMMDDHHMMSS に近い形)
// WTIME DS の OVERLAY を活用して年月日を得る方法が最も安全:
WTIME = %INT(%DEC(%TIMESTAMP()));
WTODAY = (WTIYY * 10000) + (WTIMM * 100) + WTIDD;【参考】単独で日付数値(YYYYMMDD)が必要な場合
%INT(%DEC(%DATE()))は DATE 型なので精度指定なしで使用可能(ルール22参照)。
ただし戻り値のフォーマットはジョブの日付書式に依存するため、%TIMESTAMP 経由の方が確実。%DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
%DEC(%TIME():6:0)のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
例:
誤) %TRIM(W1MBMN) ← ZONED 型
正) %TRIM(%CHAR(W1MBMN))ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO;
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うこと。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式%EDITW の編集語はフィールド桁数分の置換文字が必要
対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールド → %EDITW(NO: ' ')
── 外部プログラム呼び出し関連 ──
固定長の
CALL命令は必ずCALLP+ プロトタイプ宣言に変換すること(RNF7030/RNF5502)
固定長 RPG IV のCALL '外部プログラム名'はフリーフォーマットでは使用できない。
フリーフォーマットで外部プログラムを呼び出す場合は、以下の両方を守ること。
- 必ず
DCL-PR ~ END-PRでプロトタイプを事前宣言すること(RNF7030 防止)- 呼び出し時は
CALLP プログラム名();と 括弧を付けること(RNF5502 防止)
パラメーターがなくても括弧は必須。
例:
変換前) CALL 'BD001R' ← 固定長の CALL 命令
誤) CALLP BD001R; ← RNF5502(括弧が必要)
正) DCL-PR BD001R; ← プロトタイプ宣言
END-PR;
// ...
CALLP BD001R(); ← パラメーターなしでも括弧は必須
正) CALLP BD001R(ARG1:ARG2); ← パラメーターあり外部記述ファイルのフィールドと同名の変数を定義する場合は桁数を一致させること(RNF6033)
DCL-F で外部記述ファイルを定義している場合、ファイルのフィールドと同名の変数を
RPG 内で異なる桁数・型で再定義すると RNF6033(外部記述フィールドの長さが前の定義と同じでない)
エラーになり、その仕様が無視される。この確認は DISK ファイルだけでなく PRINTER ファイルにも適用される。
PRINTER ファイルの DDS に定義されたフィールド(@DATE・@TIME・@@USER等)は、
RPG 内で同名の作業変数を定義すると桁数・型の一致が必要になる。
変換前に必ず DDS ソースを読み込んで各フィールドの桁数・型を把握すること。外部記述フィールドと同名の変数が必要な場合は、
get_column_metadata(DISK)または
read_ibmi_source(PRINTER の DDS ソース)でフィールドの桁数・型を確認し、RPG 変数と一致させること。
例(DISK ファイルの場合):
外部フィールド @DATE が ZONE(8,0) の場合:
誤) DCL-S @DATE ZONED(6:0); ← 桁数が異なる → RNF6033
正) DCL-S @DATE ZONED(8:0); ← 外部定義と一致させる
例(PRINTER ファイルの DDS の場合):
DDS:@DATE 8S 0(ZONED 8桁)
誤) DCL-S @DATE ZONED(6:0); ← 桁数が異なる → RNF6033
正) DCL-S @DATE ZONED(8:0); ← DDS 定義と一致させる
※ 外部定義と異なる桁数で作業変数が必要な場合は別名(例:W@DATE)を使うこと。コンパイルコマンド(CRTBNDRPG)は必ず
DFTACTGRP(*NO)を指定すること
フリーフォーマット RPG はコンパイル時にDFTACTGRP(*NO)を指定しないと、
CTL-OPT の記述に関わらずDFTACTGRP(*YES)として扱われる場合がある。
DFTACTGRP(*YES)のままコンパイルするとENDIF/ENDDOが演算命令として誤認され、
RNF5347(EVAL に割り当て演算子が必要)が全ブロック終端行で大量発生する。変換後のソースを書き込んだら、必ず以下のコマンドでコンパイルするようユーザーに伝えること:
CRTBNDRPG PGM(ライブラリ/プログラム名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)また、CTL-OPT に
DFTACTGRP(*NO)を記述することと、コンパイルコマンドで指定することは
両方必要であり、どちらか片方だけでは不十分な場合がある(ルール14参照)。
3-14. ソース⑦(3回目)
ついにコンパイル成功!
コンパイル結果 → 成功!
警告 |
エラー |
重大エラー |
|---|---|---|
| 0 | 0 | 0 |
うまく変換できたロジック
- WORKSTN / DISK ファイルを
DCL-F ... WORKSTN/DCL-F ... DISK KEYED USAGE(*INPUT)に正しく変換 - プログラム引数(
*ENTRY PLIST/PARM)をDCL-PI *N ~ END-PIブロックに変換 - 固定長 DS(バイト位置指定)を
DCL-DS *N+OVERLAY形式に変換(WTIME DS 全体) - 外部プログラム呼び出し(
CALL 'DATR11')をDCL-PR EXTPGM+CALLP形式に変換 - 2つの KLIST を個別の
DCL-Sキー変数に展開し、CHAIN / SETLL / READE のコロン区切り複合キーに変換 -
DOWEQ / ENDDOをDOW ~ ENDDOに、DO *HIVAL ~ ENDDOをDOW *ON ~ ENDDOに変換 -
GOTO ECHKによるエラー脱出をLEAVESRに置き換えて構造化 -
TIME命令を%INT(%DEC(%TIMESTAMP()))に変換(WTIME DS の OVERLAY も活用) - CTDATA 配列(
ER(99))の定義と**CTDATAセクションをそのまま引き継ぎ -
CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER)が先頭に正しく配置されエラーゼロでコンパイル成功
変換には成功したが、エラー原因となる可能性があるロジック
-
CHAIN K#SHN DH301L11をファイル名DH301L1ではなくレコード様式名DH301L11で CHAIN していたが、コンパイルは通過(今回は問題なし) -
READE (K#SHN1:K#SHN2:K#SHN3) DH301L3後に%EOFをファイル名なしで使用→ RNF0391 を踏まずに済んだが、やや綱渡り -
P@DATE = %EDITC(WYMD:'Z')で 8 桁数値を文字列に変換しているが、WYMDが ZONED のため%CHARでも可(ただし今回はエラーなし) -
@STHZ = %DEC(PODATE:8:0)で文字列を数値に変換→ 意図どおり動くが、PODATE が CHAR(8) のため実行時に非数値が入ると例外の可能性 - RNF8042(CTDATA レコード不足)が 1 件発生→
ER配列は 99 要素定義だがデータは 5 行しかなく、残り 94 要素が空のまま(重大度 00 で作成は成功) - 未参照フィールド(RNF7031)が 52 件→ DS サブフィールド(WBB・WFF 等)や D4xxx 系フィールドが軒並み定義のみで参照なし(このプログラム単体では不使用)
- 外部記述ファイルのレコード様式(DH301L11・DH301L31)が未使用扱い(RNF7066)→ FFでは様式名を直接コードに書かないため発生(動作上は問題なし)
まとめ
今回の変換はエラーゼロ(最高重大度 00)でプログラム作成に成功した。
ファイル定義・パラメータ定義・DS の OVERLAY 変換・KLIST の複合キー展開・GOTO の LEAVESR 置き換えなど、
変換が難しいとされる箇所を軒並みクリアしており、変換精度はかなり高い。
手直しなしで即コンパイル成功という、かなり理想的な結果になった。
・使用したプロンプト
(本文を表示)
RPGⅣ を FF-RPG に変換したい
対象メンバー
- 変換元
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_07
- 変換後
- ライブラリー:MYLIB
- ソースファイル:QPGMSRC
- ソースメンバー:MBR_07_FF
タスク
【事前確認①】変換元ソース全体を読み込んで構成を把握する
- F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
- KLIST / KFLD 定義が存在する場合は使用箇所(CHAIN/SETLL/SETGT/READE)とキーフィールドを全件メモする
- READ / READE / READP の使用箇所を全件メモし、固定長の結果標識(*INxx)を使っているか確認する
- GOTO / TAG の使用箇所を全件メモする(フリーフォーマットでは使用不可 → ルール29)
GOTO が存在する場合、対応する TAG(ラベル)とジャンプ先の文脈を把握し、変換方針(DOW/LEAVE/ITER/IF)を決定する*で始まるコメント行の使用箇所を全件確認する(フリーフォーマットでは乗算演算子として誤認 → ルール32)
区切り線(*----...)やサブルーチン直後の*行が残存するだけでプログラム全体のコンパイルエラーになる- CALLP / CALL で外部プログラムを呼び出している箇所を全件メモする
呼び出し先プログラム名をメモし、それが*PGMか*SRVPGMかをget_object_metadataで必ず確認する
*PGMの場合はDCL-PR プログラム名 EXTPGM('プログラム名');が必要(ルール27 / バインドエラー防止)**CTDATAセクションが存在する場合、その全角文字(DBCS)の有無と配列の PERRCD 値を確認する(ルール33)
全角文字を含む CTDATA はソース書き込み後に文字化けが発生するリスクがある- 外部記述ファイルのフィールドと同名の DCL-S / DCL-DS サブフィールドを定義している箇所を確認する
- D仕様の全フィールド名を RPG 予約語リストと照合する(ルール31)
PAGE/PAGE1~PAGE7は印刷プログラムに頻出するため特に注意すること
予約語と一致するフィールド名があれば、先頭にWを付けた別名(例:WPAGE)に置き換える計画を立てる【事前確認②】F仕様の全ファイルを対象に以下を確認する
2-1. WORKSTN ファイルの確認
- WORKSTN ファイルは
DCL-F ファイル名 WORKSTN;のみで定義する(ルール4)- 固定長の
CF/Eキーワードはフリーフォーマットでは 認識されず RNF2023 になるため、必ず除去することCF Eが残ったままだとファイルが DISK として扱われ、EXFMTが RNF5199 になる2-2. DISK ファイルの確認
get_table_metadataで各 DISK ファイルの実レコード様式名を確認する- 外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述で同名様式あり →
EXTDESCで別名ファイルを指定(ユーザーに確認)- プログラム記述(F区分=F) → バッファ変数方式を採用(ルール3)
ただし実ファイルに同名様式が存在する場合はEXTDESCの要否もユーザーに確認すること- 入出力区分(I/O/U/A の組み合わせ)を確認し、ルール6の変換表に従って USAGE を決定する
特に I+A(入力+追加)はUSAGE(*UPDATE:*OUTPUT)を使うこと(USAGE(*INPUT) では WRITE が RNF5197)
U+A(更新+追加)もUSAGE(*UPDATE:*OUTPUT)のみ(USAGE(*UPDATE:*ADD) は RNF2370)get_column_metadataで外部記述フィールドの桁数・型を確認し、同名変数を定義する場合は一致させる(ルール28 / RNF6033)2-3. PRINTER ファイルの確認
- 各 PRINTER ファイルが外部記述(E キーワードあり)かプログラム記述(F区分=F)かを判定する
- 外部記述 →
get_table_metadataでレコード様式名を確認し、同名様式があればEXTDESCで独自 DDS を指定- 外部記述 PRINTER ファイルの DDS ソースを
read_ibmi_sourceで読み込み、各様式のフィールド名と桁数・型を把握すること(RNF6033 防止 / ルール28)
- DDS で定義されているフィールド(
@DATE・@TIME・@@USER等)は、同名の作業変数を RPG 内で定義する際に桁数・型を一致させること- 例)DDS に
@DATE 8S 0(ZONED 8桁)があれば、RPG 変数も@DATE ZONED(8:0)にする- プログラム記述(F区分=F) → 対応する独自プリンター DDS ファイルをユーザーに確認する
DDS が特定できない場合はそのファイルの変換を保留し、ユーザーに判断を仰ぐことOFLIND(*INOF)は必ずOFLIND(*IN0F)に変換する(英字 O → 数字 0)2-4. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む
【変換】事前確認の結果を反映しながら、RPG IV 固定長形式を完全フリーフォーマットに変換する
- ソースコード先頭に
**FREEを記述する- "Rule_Convert_FF.md" の全ルールに従うこと
- 元ソースの D 仕様(DCL-S / DCL-DS)を1件も漏らさず変換すること(ルール9の重要注記参照)
- 特に以下を重点確認すること
- ファイル定義(ルール1〜6):事前確認の対処方針を確実に反映する
- WORKSTN ファイル(ルール4):
DCL-F ファイル名 WORKSTN;のみ。CF/Eを残さないこと(RNF2023 → RNF5199)- 予約語の変数名(ルール31):事前確認で判明した予約語フィールド(
PAGE等)を別名に変換し、演算命令内の全参照箇所も置き換えること- DCL-DS の POS → OVERLAY への変換(ルール9)
- PSDS(SDS)の変換(ルール13):
*PROCキーワードを除去し先頭 CHAR(10) として定義する- TIME 命令の変換(ルール21):DS の OVERLAY 構造を活かして
WTIME = %INT(%DEC(%TIMESTAMP()))に変換する- GOTO / TAG の変換(ルール29):
GOTOと対応するラベル行をすべて除去しDOW *ON/LEAVE/ITER/IFに置き換える
ラベル行(@STR:等)が1行でも残るとコンパイラが演算命令として誤認し RNF5347 が大量連鎖する- 固定長コメント行の変換(ルール32):
*で始まるすべての行を//コメントに変換するか削除すること
ENDSRの後ろや区切り線(*----...、* * * * * *)が残りやすいため全行スキャンすること
**FREEのみ例外として除外する- KLIST / KFLD の変換(ルール20):
CHAIN/SETLL/SETGT/READEでは(key1:key2:...)の複合キー形式を使う。DS 名を Factor1 に渡さないこと(RNF7078)- READ / READE / READP の EOF 判定(ルール17):
READ ファイル名 *INxx;形式はフリーフォーマットでは RNF0637 になる。必ずREAD ファイル名; *INxx = %EOF(ファイル名);またはIF %EOF(ファイル名);形式に変換すること- CALL 命令の変換(ルール27):
CALL 'PGM'は必ず CALLP + プロトタイプ宣言に変換すること
- 呼び出し先が
*PGMの場合はDCL-PR PGM EXTPGM('PGM');とEXTPGMキーワードを必ず付けること
EXTPGMを省略するとバインドステップでCPD5D02(記号の定義が見つからない)が発生する- 呼び出し先が
*SRVPGMのプロシージャーの場合はEXTPGM不要- CALLP の括弧(ルール27):
CALLP プログラム名();と括弧を付けること。パラメーターなしでも括弧は必須(RNF5502)- 演算命令のオペランド順序(ルール15)
- 1行に複数ステートメントを書かない(ルール19):
IF X; Y=0; ENDIF;も禁止【精査】出力前にソースコードを精査し、重大度20以上のエラー要因を除去する
- 予約語チェック(ルール31 / RNF3314 → RNF5347/RNF7030 大量連鎖の防止):全 DCL-S / DCL-DS サブフィールドの名前を予約語リストと照合する
PAGE/PAGE1~PAGE7が変数名・フィールド名として残っていないか全定義をスキャンする- 予約語が残っていた場合は
WPAGEなどの別名に変更し、演算命令内の参照箇所もすべて置き換える*で始まる行(**FREEを除く)が1行も残っていないか全行スキャンする(ルール32 / RNF5347 大量連鎖の根本原因)
区切り線・サブルーチン後の*行1行でプログラム全体のコンパイルエラーになる- GOTO 文およびラベル行(
ラベル名:の行)が1行も残っていないか全行スキャンする(ルール29 / RNF5347 連鎖)- CALLP 関連の確認(ルール27):
- 括弧があるか全件確認する(
CALLP PGM;→CALLP PGM();/ RNF5502)*PGMを呼び出す全DCL-PRにEXTPGM('プログラム名')キーワードがあるか確認する(バインドエラー / CPD5D02)- 外部記述フィールドと同名の変数定義で桁数・型が一致しているか確認する(ルール28 / RNF6033)
- PRINTER ファイルの DDS で定義されたフィールド(
@DATE・@TIME・@@USER等)についても同様に確認すること- WORKSTN ファイルの
DCL-FにCF/Eが残っていないか確認する(RNF2023 → RNF5199)- ファイル定義の問題(RNF2109 / RNF2121)が残っていないか確認する
- 1行に複数ステートメントが残っていないか全行スキャンする(RNF5508)
- PSDS の *PROC キーワードが残っていないか確認する(RNF3308)
- USAGE(*UPDATE:*ADD) / USAGE(*INPUT) でWRITEしている箇所がないか確認する(RNF2370/RNF5197)
- CHAIN / SETLL / SETGT / READE の Factor1 に DS 名が使われていないか確認する(RNF7078)
- READ / READE / READP の命令の直後に
*INxxが直接記述されていないか全行スキャンする(RNF0637)*INLR = *ON/RETURNが BEGSR ブロックより後ろに記述されていないか確認する(RNF5005)- ファイル定義エラーを起点とした連鎖エラー(RNF5347 / RNF0724 の大量発生)がないか確認する
- CTDATA に全角文字が含まれている場合(ルール33):
write_ibmi_source書き込み後、コンパイルリストの「コンパイル時データ」セクションで文字化けがないか確認するRNF8267(DBCS指定が正しくない)やRNF8042(レコードが不足)が出ている場合は全角文字の文字化けを疑うこと- 重大度 00 のため作成自体は成功するが、実行時に配列の初期値が誤る可能性があることをユーザーに伝えること
- エラー要因を修正したらソースコード全体の整合性を再確認する
- 新たなエラー原因が見つかった場合は本ステップを繰り返す
【出力】変換後メンバーとして新規出力する
write_ibmi_sourceで書き込んだ後、コンパイルする場合は必ずDFTACTGRP(*NO)を指定すること(ルール30)- CTL-OPT に
DFTACTGRP(*NO) ACTGRP(*CALLER)を記述していても、コンパイルコマンド側がDFTACTGRP(*YES)だと CTL-OPT が無視されENDIF/ENDDOが演算命令として誤認される(RNF5347 大量発生)- ユーザーに対して、以下のコンパイルコマンドを提示すること:
CRTBNDRPG PGM(ライブラリ/メンバー名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
- サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する
- "C:\Users\ユーザー名\Desktop\作業フォルダ名"
・使用したルールファイル
(本文を表示)
【コンパイルエラー防止ルール】
── ファイル定義(DCL-F)関連 ──
DISK/PRINTER ファイル変換前に「実ファイルのレコード様式名」を必ず確認すること
フリーフォーマットのDCL-Fでは、ファイル名と同名のレコード様式が実ファイルに存在すると
RNF2121(様式名重複)→ RNF2109(ファイル全体が無視)が発生する。
この問題は DISK / PRINTER / プログラム記述ファイルすべてに適用される。変換前に必ずやること:
get_table_metadataまたはread_ibmi_sourceで対象ファイルのレコード様式名を確認する- ファイル名とレコード様式名が同一の場合 → 必ず以下のいずれかで対処すること
- DISK 外部記述ファイル:
EXTDESC('ライブラリ/別名ファイル')で衝突を回避する- DISK プログラム記述ファイル(F区分=F):バッファ変数方式(後述ルール3)に変換する
- PRINTER ファイル:後述ルール2に従う
- 対処方法が不明な場合は処理を中断してユーザーに確認を求めること
RNF2109 が発生するとどうなるか:
ファイルが無視されると後続のすべての定義(DCL-S / DCL-DS / DCL-PI)や
演算命令(IF / ENDIF 等)が演算仕様として誤認され、RNF5347 / RNF0724 が大量発生する。
この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。PRINTER ファイルの変換方針
固定長 RPG IV の PRINTER ファイルは以下の2パターンがあり、変換前に判定すること。【パターンA】外部記述 PRINTER ファイル(F仕様に E キーワードあり)
- 対応する独自 DDS が存在する →
EXTDESCでそのファイルを指定するOFLIND(*INOF)はOFLIND(*IN0F)に変換する(英字「O」ではなく数字「0」)QPRINTのようなシステム標準ファイルは QGPL/QPRINT に同名様式が存在するため必ずEXTDESCで独自 DDS を指定する
例:
誤) DCL-F QPRINT PRINTER OFLIND(*INOF);
誤) DCL-F QPRINT PRINTER OFLIND(*IN0F); ← 同名様式 → RNF2109
正) DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');【パターンB】プログラム記述 PRINTER ファイル(F仕様に F 区分あり、E キーワードなし)
- 例:
FQPRINT O F 132 PRINTER OFLIND(*INOF)- フリーフォーマットには
PGMDESCキーワードが存在しないため、外部記述として扱われ RNF2109 が発生する- 対応する独自プリンター DDS がない場合は変換を中断してユーザーに確認を求めること
- 独自 DDS が用意できる場合のみ
EXTDESCで指定して変換する
例:
変換前) FQPRINT O F 132 PRINTER OFLIND(*INOF)
正) // 独自プリンターDDS(例: MYLIB/MYPRT)を事前に用意する
DCL-F QPRINT PRINTER OFLIND(*IN0F) EXTDESC('MYLIB/MYPRT');
DCL-S QPREC CHAR(132);
// ...
WRITE QPRINT QPREC;DCL-F に RECLN キーワードは指定できない(DISK プログラム記述ファイルはバッファ変数方式を使う)
フリーフォーマットのDCL-FではRECLNキーワードは認識されず(RNF2023/RNF2109)。
固定長プログラム記述 DISK ファイル(F仕様のF区分)は、以下のバッファ変数方式に変換すること。
例(出力用固定長ファイル):
変換前) FABAWP42 O F 308 DISK
正) DCL-F ABAWP42 DISK USAGE(*OUTPUT);
DCL-S ABAWREC CHAR(308);
// ...
WRITE ABAWP42 ABAWREC;
注意: 実ファイルに同名レコード様式が存在する場合、DCL-F ABAWP42 DISK ...だけでは
RNF2121 → RNF2109 が発生してファイルごと無視される。バッファ変数方式だけでは解決しない。
この場合はEXTDESCで別名ファイルを指定するか、DDS 側のレコード様式名変更をユーザーに確認すること。WORKSTN ファイルは
DCL-F ファイル名 WORKSTN;のみで定義すること(RNF2023/RNF2401)
固定長 F 仕様の WORKSTN ファイルはCF(Combined)とE(外部記述)を組み合わせて記述するが、
フリーフォーマットのDCL-FではCFとEは認識されないキーワードのため RNF2023 で無視される。
その結果ファイルが DISK として扱われ、EXFMT命令が RNF5199(オペランドが正しくない)エラーになる。
フリーフォーマットではWORKSTNキーワードだけで「外部記述・双方向入出力」の意味を持つため、
CF/Eは不要。INFDSやSFILEキーワードが必要な場合はそれぞれ追記すること。
例:
変換前) FBD003D0 CF E WORKSTN
誤) DCL-F BD003D0 CF E WORKSTN; ← CF・E が RNF2023 → DISK 扱い → EXFMT が RNF5199
正) DCL-F BD003D0 WORKSTN;INFDS(情報 DS)が必要な場合:
正) DCL-F BD003D0 WORKSTN INFDS(WS_INFDS);ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
固定長 F 仕様の入出力区分(I/O/U/A)を DCL-F の USAGE キーワードに正しく対応させること。
固定長の組み合わせ フリーフォーマット 備考 I のみ USAGE(*INPUT) READ/CHAIN のみ O のみ USAGE(*OUTPUT) WRITE のみ U のみ USAGE(*UPDATE) READ/CHAIN/WRITE/UPDATE/DELETE I+A USAGE(*UPDATE:*OUTPUT) CHAIN+WRITE が必要なため *UPDATE を使う(RNF5197 防止) O+A USAGE(*OUTPUT) WRITE のみ U+A USAGE(*UPDATE:*OUTPUT) WRITE も可(USAGE(*UPDATE:*ADD) は RNF2370 エラー) **【重要①】I+A(入力+追加)は USAGE(UPDATE:OUTPUT) を使うこと
固定長でI(入力)とA(追加)の両方が指定されている場合(例:FAA001L0 IF A E K DISK)、
CHAIN と WRITE の両方を使うためUSAGE(*INPUT)では WRITE 時に RNF5197 エラーになる。
必ずUSAGE(*UPDATE:*OUTPUT)を指定すること。
例:
変換前) FAA001L0 IF A E K DISK ← I(入力)+A(追加)
誤) DCL-F AA001L0 DISK KEYED USAGE(*INPUT); ← WRITE が RNF5197
正) DCL-F AA001L0 DISK KEYED USAGE(**UPDATE:*OUTPUT);**【重要②】USAGE(UPDATE:ADD) は無効(RNF2370 エラー)
U(更新)と A(追加)の両方が指定されている場合でもUSAGE(*UPDATE:*ADD)は使えない。
USAGE(*UPDATE:*OUTPUT)を指定すること。更新ファイルに WRITE 命令を使えば追加も可能。
例:
変換前) FXXXFILE UF A E K DISK ← U(更新)+A(追加)
誤) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*ADD); ← RNF2370
正) DCL-F XXXFILE DISK KEYED USAGE(*UPDATE:*OUTPUT);
── 定義仕様(DCL-S / DCL-DS / DCL-PI)関連 ──
プログラムパラメータは DCL-PI ~ END-PI で定義すること
フリーフォーマットでDCL-PARMを単独で記述すると RNF3703 エラーになる。
プログラムのエントリーパラメータは必ずDCL-PI *N~END-PIブロック内に記述すること。
例:
誤) DCL-PARM PHIZK CHAR(4);
DCL-PARM PKBN CHAR(1);
正) DCL-PI *N;
PHIZK CHAR(4);
PKBN CHAR(1);
END-PI;フリーフォーマット
DCL-DSには必ず DS 名または*Nを指定すること
固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットのDCL-DSでは
DS 名または*N(匿名)を必ず指定しなければならない(RNF3368)。
例:
誤) DCL-DS;
正) DCL-DS *N;フリーフォーマット
DCL-DSのサブフィールドにPOSキーワードは使用できない
固定長 I 仕様のバイト位置指定(POS(n))はフリーフォーマットでは認識されない(RNF5347 の原因)。
位置共有が必要な場合はOVERLAY(親フィールド:開始位置)キーワードを使うこと。
例:
誤) DCL-DS *N;
UYM1 ZONED(4:0) POS(1);
UYY1 ZONED(2:0) POS(1);
UMM1 ZONED(2:0) POS(3);
END-DS;
正) DCL-DS *N;
UYM1 ZONED(4:0);
UYY1 ZONED(2:0) OVERLAY(UYM1:1);
UMM1 ZONED(2:0) OVERLAY(UYM1:3);
END-DS;【重要】外部ファイルフィールドと OVERLAY を組み合わせた DS は変換漏れに注意
固定長 RPG IV では、外部記述ファイルのフィールドをバイト位置で参照する無名 DS を定義し、
複数フィールドを1つの集約変数(例:年月日を YYYYMMDD の8桁に合算)として扱うパターンがある。
このような DS は変換時に丸ごと抜け落ちやすいため、元ソースの D 仕様を全件確認し必ず変換すること。
例(元ソース固定長):
D DS
D A0SKHZ 1 8 0 ← 削除予定日8桁(集約)
D A0SKYY 1 4 0 ← 年(A0SKHZ と同位置でオーバーレイ)
D A0SKMM 5 6 0
D A0SKDD 7 8 0
変換後(フリーフォーマット):
DCL-DS *N;
A0SKHZ ZONED(8:0);
A0SKYY ZONED(4:0) OVERLAY(A0SKHZ:1);
A0SKMM ZONED(2:0) OVERLAY(A0SKHZ:5);
A0SKDD ZONED(2:0) OVERLAY(A0SKHZ:7);
END-DS;
※ この DS が抜けると「A0SKHZ が未定義」(RNF7030)となり、演算命令でコンパイルエラーになる。ZONED / PACKED 数値型の桁数は最大 63 桁まで
ZONED(nnn:0)やPACKED(nnn:0)の桁数に 64 以上を指定すると RNF0503 エラーになる。
63 桁を超えるデータ領域はCHAR型に変換すること。
DATE型変数の日付フォーマットにゼロサフィックスは使用できない
DATE(*ISO0)のようにゼロを付けると RNF0619 エラーになる。
変数定義では*ISO・*YMD・*MDY・*DMY・*JULなどゼロなしのフォーマットを使うこと。
例:
誤) DCL-S WB5DATE DATE(*ISO0);
正) DCL-S WB5DATE DATE(*ISO);プロシージャー名・変数名・フィールド名に使用できる文字の制限
英大文字・数字・#・@・$ のみ使用すること。
円マーク(¥ / \)やマルチバイト文字は使用できない。
¥SB100 → SB100 のように変換すること。フリーフォーマット RPG の予約語を変数名・フィールド名に使用しないこと(RNF3314 → RNF5347/RNF7030 連鎖の原因)
RPG の特殊語(予約語)と同一の名前を変数名・フィールド名に使用すると RNF3314(名前の指定が予約語である)
エラーになり、その変数を参照する演算命令が正しく解釈されなくなる。
さらに RNF3314 が発生すると、コンパイラの内部状態が崩れ、後続のENDIF/ENDDOのENDが
未定義名として RNF7030 → RNF5347 / RNF5177 / RNF5248 が大量に連鎖する。使用禁止の主な予約語(変数名・フィールド名として使えない):
予約語 説明 PAGEプリンター出力の現行ページ番号(特殊語) PAGE1~PAGE7プリンター出力用ページ番号(特殊語) *DATEプログラム実行日付(固定長では変数名としても使われるが FF では不可) *TIMEプログラム実行時刻 *IN標識配列 *INLR*IN01等標識名 *ON*OFF*HIVAL*LOVAL*BLANK*ZERO*NULL等特殊値 変換方針: 固定長 RPG IV のフィールド名が予約語と一致する場合、先頭に
WやXを付けて別名にする。
例:
変換前) D PAGE 2S 0 ← ZONED 2桁のフィールド名が PAGE
誤) DCL-S PAGE ZONED(2:0); ← RNF3314 → ENDIF/ENDDO が大量 RNF5347 になる連鎖
正) DCL-S WPAGE ZONED(2:0); ← 先頭に W を付けて回避【精査チェック】変換後に予約語が変数名・フィールド名として使われていないか全定義をスキャンすること。
特にPAGE/PAGE1~PAGE7は印刷プログラムに頻出するため注意すること。PSDS のサブフィールド定義はフリーフォーマットの記法に正しく変換すること
固定長のSDS(プログラム状況 DS)はフリーフォーマットでDCL-DS *N PSDSに変換する。
各サブフィールドの変換ルールは以下の通り。*【PROC フィールド】
固定長で*PROC特殊語を使ったサブフィールド定義(現行プロシージャー名)は、
フリーフォーマットでは*PROCキーワード自体が RNF3308 エラーになる。
PSDS の先頭 10 バイトが自動的に現行プロシージャー名に設定されるため、
*PROCキーワードを付けずに先頭のCHAR(10)フィールドとして定義すること。
例:
変換前) D W¥PGM *PROC
誤) WPGM CHAR(10) *PROC; ← RNF3308
正) WPGM CHAR(10); ← 先頭10バイトが自動的に現行PGM名になる【バイト位置指定フィールド(POS)】
PSDS のサブフィールドではPOS(n)キーワードは使用可能(通常 DS のルール7とは異なる)。
固定長の位置指定はそのままPOS(n)で変換してよい。
例:
変換前) D W¥WSID 244 253
正) WWSID CHAR(10) POS(244);【フィールド名の制限】
英大文字・数字・#・@・$ のみ使用可能。¥ を含む名前は変換する。
例:W¥PGM → WPGM、W¥WSID → WWSID、@@USER → XUSER(@ は2個連続不可のため変更)
── 演算命令関連 ──
DFTACTGRP(YES) ではフリーフォーマット RPG は正しくコンパイルできない
フリーフォーマット RPG ではCTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);を必ず先頭に記述する*こと。
さらに重要:CTL-OPT にいくらDFTACTGRP(*NO)と書いても、コンパイルコマンド(CRTBNDRPG)側が
DFTACTGRP(*YES)だと CTL-OPT が無視される。 その場合、ENDIF/ENDDOがすべて演算命令として
誤認され RNF5347(割り当て演算子が必要)が大量連鎖する。コンパイル時は必ず
DFTACTGRP(*NO)を指定すること(ルール30参照)。
例:
正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER); ← ソース先頭
正) CRTBNDRPG PGM(LIB/PGM) SRCFILE(LIB/SRC) DFTACTGRP(*NO) ← コンパイルコマンドフリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
例:
誤) SETGT EK003W11 *HIVAL;
正) SETGT *HIVAL EK003W11;
誤) READE EK003W11 #KNO;
正) READE #KNO EK003W11;CHAIN の結果は
%FOUNDで判定すること
フリーフォーマットのCHAINに固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
CHAIN の後は%FOUNDまたは%FOUND(ファイル名)で判定すること。【重要】
%FOUND()の引数はファイル名(DCL-F で定義した名前)を渡すこと(RNF0394)
レコード様式名(ファイル名 + 数字サフィックス等)ではなく、RPG がファイルを参照する名前を使うこと。
例えばファイル名がDH301L1、レコード様式名がDH301L11の場合、引数はDH301L1になる。
例:
誤) CHAIN KFLDS GADPL11 *IN03;
正) CHAIN KFLDS GADPL11;
IF NOT %FOUND(GADPL11);誤) CHAIN (K#SHN1:K#SHN2:K#SHN3) DH301L1;
IF NOT %FOUND(DH301L11); ← レコード様式名を渡している → RNF0394
正) CHAIN (K#SHN1:K#SHN2:K#SHN3) DH301L1;
IF NOT %FOUND(DH301L1); ← ファイル名を渡すREAD / READE / READP 命令の結果(EOF)判定
【READ の EOF 判定】
フリーフォーマットのREAD命令では、結果標識をオペランドとして直接渡す
READ ファイル名 *INxx;の形式は RNF0637(オペランドが必要)エラーになる。
EOF 判定はREADの後で%EOF(ファイル名)を使うこと。
例:
誤) READ BD001L0 *IN60; ← RNF0637 + RNF7030(IN60 未定義)
正) READ BD001L0;
*IN60 = %EOF(BD001L0); ← 必要なら標識に保存
IF %EOF(BD001L0); ← 直接判定する場合【READE の EOF 判定(単一キー)】
単一キーのREADEは同様に結果標識を直接渡す形式が不可。%EOFで判定すること。
例:
誤) READE KFLD FILNAME *IN70;
正) READE KFLD FILNAME;
IF %EOF(FILNAME);【READE の EOF 判定(複合キー)】
READE (キー1:キー2) ファイル名;の後に%EOF(ファイル名)を使うと RNF0391 エラーになる場合がある。
この場合はREADEに結果標識パラメーターとして渡さず、%EOFをファイル名なしで使うか、
READE後に別途標識を参照する方法を採ること。
例:
誤) READE (WTOKU:FSIKU) GADPL141;
*IN03 = %EOF(GADPL141); ← RNF0391
正) READE (WTOKU:FSIKU) GADPL141;
IF %EOF; ← ファイル名なしなら可
または)
// READ/READE に先立ち *IN70 = *OFF; でリセット、
// %EOF 判定で代入
READE (WTOKU:FSIKU) GADPL141;
*IN70 = %EOF;
IF *IN70;
*INLR = *ONとRETURNはサブルーチン定義の前に記述すること
BEGSR~ENDSRブロックの直後に演算命令を記述すると RNF5005 エラーになる。
プログラム終了処理は必ずサブルーチン定義の前に記述すること。
例:
誤) BEGSR @END;
ENDSR;
*INLR = *ON; ← RNF5005
RETURN;
正) *INLR = *ON; ← サブルーチン定義の前
RETURN;
BEGSR @END;
ENDSR;1行に複数ステートメントをセミコロンで区切って記述しない(RNF5508)
フリーフォーマットでは1つの物理行に1つのステートメントのみ記述すること。
IF 条件; 処理; ENDIF;のような「1行 IF」も RNF5508 エラーになるため禁止。
元ソースで固定長 CASxx / IFxx などの1行条件処理を変換する場合も必ず複数行に展開すること。
例:
誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
誤) IF S01 = 9999999; S01 = 0; ENDIF;
正) *IN31 = *OFF;
*IN32 = *OFF;
*IN33 = *OFF;
正) IF S01 = 9999999;
S01 = 0;
ENDIF;KLIST / KFLD は複合キー形式
(key1:key2:...)に変換すること
固定長 RPG IV のKLIST/KFLDはフリーフォーマットに変換できない命令である。
CHAIN / SETLL / SETGT / READE / READPE での複合キー指定は、カッコで囲んだコロン区切り形式
(key1:key2:...)に変換すること。【禁止】DS 全体をキーとして渡す方法(RNF7078 エラー)
KLIST の代替として全キーフィールドを DS にまとめCHAIN KEYDS FILNAME;と記述すると、
RPG は DS 先頭のフィールドの長さとファイルの最初のキーフィールドの長さを比較するため
RNF7078(長さ不一致)が発生する。DS 名を CHAIN の Factor1 に渡してはいけない。
例:
変換前) C KEYA01 CHAIN AA001L01
← KLIST KEYA01 は #KKASI(7):#KTOKU(4):#KNONY(4):... の12フィールド
誤) CHAIN KEYA01DS AA001L01; ← DS全体(53バイト)→ RNF7078
正) CHAIN (#KKASI:#KTOKU:#KNONY:#KNKOJ:#KNUKE
:#KMEHZ:#KMEBB:#KHINB:#KBUHI:#KSHUY
:#KKNRI:#KOIBN) AA001L01;SETLL / SETGT / READE でも同様にコロン区切り複合キー形式を使うこと。
例:
変換前) C KEYA01 SETLL AA001L01
正) SETLL (#KKASI:#KTOKU:...) AA001L01;固定長形式のコメント行(
*で始まる行)はフリーフォーマットでは乗算演算子として誤認される(RNF5347 連鎖の根本原因)
固定長 RPG IV では桁1に*を記述することでコメント行として扱われるが、
フリーフォーマットでは*が乗算演算子として解釈される。
その結果 RNF0955(EVAL左辺として無効)→ RNF5347(割り当て演算子が必要)が発生し、
さらにコンパイラの内部状態が崩壊して後続のENDIF/ENDDO/ENDSRが
すべて演算命令として誤認され、RNF5177 / RNF5248 / RNF7030 が大量に連鎖する。
この1行の変換漏れがプログラム全体のコンパイルエラーを引き起こす。変換方針:
*で始まるすべてのコメント行を//コメント行に変換するか、不要であれば削除すること- 特に
BEGSR~ENDSRの後ろや、サブルーチン区切り線として使われる
* * * * * *や*----...のような行が残りやすいため重点的にチェックすること
例:
変換前) * サブルーチン SB210
*---------------------------------------
誤) * サブルーチン SB210 ← フリーフォーマットでは乗算演算子として誤認
正) // サブルーチン SB210
// ---------------------------------------【精査チェック】変換後ソース全行を対象に
*で始まる行(ただし**FREEを除く)が
残っていないかスキャンすること。
**FREEはフリーフォーマット宣言なので除外する。
- フリーフォーマットでは
GOTO/TAG命令は使用できない(RNF7030/RNF5347 連鎖の原因)
固定長 RPG IV のGOTO ラベル名と対応するTAG ラベル名は、フリーフォーマットでは
コンパイラに演算命令として誤認され、RNF7030(名前未定義)→ RNF5347(割り当て演算子が必要)
が大量に連鎖する。フリーフォーマットにはTAG命令に相当する構文が存在しない。変換方針:
GOTOを使ったループはDOW *ONループに置き換え、終了条件はLEAVEで抜けるGOTOを使ったループ先頭へのITER相当はITERに置き換える- それ以外の
GOTO(前方ジャンプ等)は構造化された IF/SELECT に書き直す例(メインループを GOTO + TAG で実装していた場合):
変換前) C TAG @STR
C EXFMT BD003D01
...
C GOTO @STR
正) DOW *ON;
EXFMT BD003D01;
...
IF 終了条件;
LEAVE;
ENDIF;
ENDDO;注意:
ラベル名:の行(フリーフォーマットでの TAG 相当)がソース中に残ったままだと
コンパイラが演算命令として解釈し、RNF5347 が大量発生する。
必ずすべてのGOTO文と対応するラベル行を除去・変換すること。
── 組み込み関数・型変換関連 ──
固定長の
TIME命令は%INT(%DEC(%TIMESTAMP()))で変換すること
固定長 RPG IV のTIME命令は、14桁の ZONED 型 DS(WTIME等)に現在の日時を
YYYYMMDDHHMMSS形式の数値として格納する。
フリーフォーマットではTIME命令が使えないため、以下のように変換すること。
例:
変換前) C TIME WTIME ← WTIME は ZONED(14:0) DS
正) WTIME = %INT(%DEC(%TIMESTAMP()));これにより WTIME(14桁 ZONED DS)に日時数値が入り、OVERLAY 定義されたサブフィールド
(WTIYY/WTIMM/WTIDD 等)も自動的に更新される。
%YEAR/%MONTH/%DAYを使った個別代入は不要であり、使用を避けること。
%YEAR(%DATE())等は RNF0604/RNF0325 が連鎖して発生する環境があるため信頼しないこと。年月日の8桁数値(例:WTODAY)が個別に必要な場合は、
%TIMESTAMP()の数値変換から
%INT(%DEC(%TIMESTAMP()))の上位8桁を取得する方法を使うこと。
例:
// %TIMESTAMP() → "YYYY-MM-DD-HH.MM.SS.NNNNNN" 形式
// %DEC(%TIMESTAMP()) → 14桁数値(YYYYMMDDHHMMSS に近い形)
// WTIME DS の OVERLAY を活用して年月日を得る方法が最も安全:
WTIME = %INT(%DEC(%TIMESTAMP()));
WTODAY = (WTIYY * 10000) + (WTIMM * 100) + WTIDD;【参考】単独で日付数値(YYYYMMDD)が必要な場合
%INT(%DEC(%DATE()))は DATE 型なので精度指定なしで使用可能(ルール22参照)。
ただし戻り値のフォーマットはジョブの日付書式に依存するため、%TIMESTAMP 経由の方が確実。%DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
%DEC(%TIME():6:0)のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
例:
誤) WTIME = %INT(%DEC(%TIME():6:0));
正) WTIME = %INT(%DEC(%TIME()));%TRIM は文字型(CHAR / VARCHAR)にしか使用できない
数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
例:
誤) %TRIM(W1MBMN) ← ZONED 型
正) %TRIM(%CHAR(W1MBMN))ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
%SUBST(文字変数:開始:長さ) = 数値変数は型不一致(RNF7416)になる。
%EDITC(数値:'Z')や%CHAR(数値)で文字列に変換してから代入すること。
例:
誤) %SUBST(ABAWREC:43:5) = N1USYO;
正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');%CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
日付を特定フォーマットの文字列にする場合は%EDITCの編集コード'Y'を使うこと。
例:
誤) %CHAR(*DATE:'*YMD0')
正) %EDITC(*DATE:'Y') ← YYMMDD 形式%EDITW の編集語はフィールド桁数分の置換文字が必要
対象フィールドの整数桁数と同数の空白(置換文字)が必要。
例:4桁フィールド → %EDITW(NO: ' ')
── 外部プログラム呼び出し関連 ──
固定長の
CALL命令は必ずCALLP+ プロトタイプ宣言に変換すること(RNF7030/RNF5502/バインドエラー)
固定長 RPG IV のCALL '外部プログラム名'はフリーフォーマットでは使用できない。
フリーフォーマットで外部プログラムを呼び出す場合は、以下のすべてを守ること。【重要①】呼び出し先が
*PGMの場合はEXTPGMキーワードが必須(バインドエラー防止)
EXTPGMを省略したDCL-PRはサービスプログラム(*SRVPGM)のプロシージャーとして解決しようとするため、
*PGMを呼び出す場合にバインドステップでCPD5D02(記号の定義が見つからない)が発生する。
呼び出し先が*PGMか*SRVPGMかを必ず確認し、*PGMの場合はEXTPGM('プログラム名')を付けること。
例:
誤) DCL-PR DATR11; ← EXTPGM なし → バインド時に CPD5D02
END-PR;
正) DCL-PR DATR11 EXTPGM('DATR11'); ← *PGM 呼び出し
END-PR;【重要②】プロトタイプ宣言は必須(RNF7030 防止)
必ずDCL-PR ~ END-PRでプロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。【重要③】呼び出し時は括弧を付けること(RNF5502 防止)
CALLP プログラム名();と 括弧を付けること。パラメーターがなくても括弧は必須。例(総合):
変換前) CALL 'BD001R' ← 固定長の CALL 命令
誤) CALLP BD001R; ← RNF5502(括弧が必要)
誤) DCL-PR BD001R; END-PR; ← EXTPGM なし → バインドエラー
正) DCL-PR BD001R EXTPGM('BD001R'); ← *PGM 呼び出しには EXTPGM 必須
END-PR;
// ...
CALLP BD001R(); ← パラメーターなしでも括弧は必須
正) CALLP BD001R(ARG1:ARG2); ← パラメーターあり外部記述ファイルのフィールドと同名の変数を定義する場合は桁数を一致させること(RNF6033)
DCL-F で外部記述ファイルを定義している場合、ファイルのフィールドと同名の変数を
RPG 内で異なる桁数・型で再定義すると RNF6033(外部記述フィールドの長さが前の定義と同じでない)
エラーになり、その仕様が無視される。この確認は DISK ファイルだけでなく PRINTER ファイルにも適用される。
PRINTER ファイルの DDS に定義されたフィールド(@DATE・@TIME・@@USER等)は、
RPG 内で同名の作業変数を定義すると桁数・型の一致が必要になる。
変換前に必ず DDS ソースを読み込んで各フィールドの桁数・型を把握すること。外部記述フィールドと同名の変数が必要な場合は、
get_column_metadata(DISK)または
read_ibmi_source(PRINTER の DDS ソース)でフィールドの桁数・型を確認し、RPG 変数と一致させること。
例(DISK ファイルの場合):
外部フィールド @DATE が ZONE(8,0) の場合:
誤) DCL-S @DATE ZONED(6:0); ← 桁数が異なる → RNF6033
正) DCL-S @DATE ZONED(8:0); ← 外部定義と一致させる
例(PRINTER ファイルの DDS の場合):
DDS:@DATE 8S 0(ZONED 8桁)
誤) DCL-S @DATE ZONED(6:0); ← 桁数が異なる → RNF6033
正) DCL-S @DATE ZONED(8:0); ← DDS 定義と一致させる
※ 外部定義と異なる桁数で作業変数が必要な場合は別名(例:W@DATE)を使うこと。コンパイルコマンド(CRTBNDRPG)は必ず
DFTACTGRP(*NO)を指定すること
フリーフォーマット RPG はコンパイル時にDFTACTGRP(*NO)を指定しないと、
CTL-OPT の記述に関わらずDFTACTGRP(*YES)として扱われる場合がある。
DFTACTGRP(*YES)のままコンパイルするとENDIF/ENDDOが演算命令として誤認され、
RNF5347(EVAL に割り当て演算子が必要)が全ブロック終端行で大量発生する。変換後のソースを書き込んだら、必ず以下のコマンドでコンパイルするようユーザーに伝えること:
CRTBNDRPG PGM(ライブラリ/プログラム名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)また、CTL-OPT に
DFTACTGRP(*NO)を記述することと、コンパイルコマンドで指定することは
両方必要であり、どちらか片方だけでは不十分な場合がある(ルール14参照)。
── CTDATA / コンパイル時データ関連 ──
CTDATA 配列に全角文字(DBCS)を含む場合はソース CCSID と DBCS 指定に注意すること(RNF8267)
固定長 RPG IV の**CTDATAセクションやALTSEQテーブルに全角文字(漢字・ひらがな・カタカナ等)が
含まれている場合、ソースメンバーの CCSID と TGTCCSID の組み合わせによって
RNF8267(配列/テーブルのDBCS指定が正しくない)が発生する。
さらに CTDATA レコード数が不足しているとRNF8042(ソース・レコードが十分でない)も連鎖する。発生パターン:
- ソース CCSID が 5026(DBCS 対応シングルバイト)の場合、全角文字には SO/SI バイトが付加される
- TGTCCSID が 5035(EBCDIC DBCS)の場合、CCSID 変換後に CTDATA のバイト配置がずれることがある
- 変換後のソースを別メンバーに書き込んだ際に文字化けが発生すると CTDATA レコードの長さも変わる
対処方針:
- CTDATA の全角文字メッセージは、配列要素ごとに正確な桁数(
PERRCDで指定した長さ)になっているか確認する- 文字化けが疑われる場合は、CTDATA のメッセージ文字列をすべて半角英数字で書き直すか、
外部メッセージファイル(QMSGF)に移行することを検討するRNF8267/RNF8042は重大度 00(通知)のため、プログラムの作成自体は妨げないが
実行時に配列の初期値が正しく設定されないリスクがあるwrite_ibmi_sourceでソースを書き込む際、元の CTDATA 全角文字が正しく転送されているか
コンパイルリストの「コンパイル時データ」セクションで必ず確認すること例:
元の CTDATA(正常):
E-01社内品番の入力は必須です
コンパイルリストで文字化けしている場合:
→ RNF8267 が発生 → 実行時にメッセージが正しく表示されない可能性がある
→ CTDATA 行の全角文字を外部メッセージに切り出すことを推奨
4.まとめ
今回の検証では、試行回数を重ねてプロンプトとルールファイルを作り込み、どんなソースコードにも対応できるようなエージェントの作成を目指しました。
全体として、重大度20以上のエラー発生数には減少傾向が見られましたが、前回うまくいっていた変換が次のタスクで失敗するなど、AI 特有の出力の振れも散見されました。
また、今回はプロンプトとルールファイルでガチガチに縛った状態で検証を進めたため、
「RPGLE Free などの拡張機能にルールを補完して変換させるのと同じでは?」≒「AI を使う意義とは?」
といった疑問も湧く結果となりました。
最後まで読んでいただきありがとうございます、本記事が何かのお役に立てば幸いです。