1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IBM Bob(プロンプト作りこみ版)

1
Last updated at Posted at 2026-09-14

0.目次

1. はじめに

この記事は、2026年度の IBM RiSING、f-モダナイゼーションチームへ参加した際の記録です。
IBM Bob (PP4i無し、自社環境接続用のMCPサーバー構築) を利用して、固定長 RPG IV から FFRPG への変換タスクを実行しています。

2. 活動内容

2-1. 検証方針

最優先目標は「コンパイルが通るソースコードを安定して出力すること」としました。

  • サブプロシージャによる責務分離や深いネストの改善などのリファクタリングは行わない

本検証では、変換タスクの都度プロンプトの修正やルールの追加を Bob 自身に行わせ、コンパイルが通る FFRPG のコードを安定的に出力させるエージェントになってもらうことを目指しました。

  • Bob coin の消費は度外視し、プロンプトとルールファイルを作り込んでいく作戦

※同活動内では、プロンプトによる補正効果ではなく、Bob が標準状態でどの程度ソースコードを理解し FFRPG へ変換できるのかを検証した記事もありますので是非読んでみてください

2-2. 進め方

基本的に下記の流れを繰り返します。

  1. 変換元の 固定長 RPG IV ソースを Bob に伝え、MCP サーバー経由でコードや関連ファイルを解析してもらい、FFRPG の新規ソースメンバーとして出力してもらう
  2. 変換後のソースをコンパイルし、エラーとなった場合はコンパイルリストを Bob に読み込ませ、エラー原因を分析させる
  3. 同じエラーが発生しないようにプロンプトおよびルールファイルを Bob に修正させる
  4. 手順 1 に戻る

3. 変換結果

ここからは実際に変換タスクを実行した結果が続いていきます(長いです)。

⇑ PAGE TOP

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\作業フォルダ名"

・使用したルールファイル
 なし


⇑ PAGE TOP

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\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

  1. プロシージャー名・変数名に使用できる文字の制限
    プロシージャー名・変数名・フィールド名には、英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字はフリーフォーマット RPG の識別子として使用できないため、
    ¥SB100 → SB100 のように変換すること。

  2. *DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
    サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
    CRTBNDRPG のデフォルトは DFTACTGRP(*YES) であるため、プロシージャーが存在すると RNF1520 エラーになる。

  3. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  4. %DATE() / %TIME() の戻り値は DATE / TIME 型であり、数値型変数へ直接代入できない
    ZONED や PACKED の変数に年月日を格納する場合は、%YEARS / %MONTHS / %DAYS / %HOURS 等を使用した上で
    %INT() 等で数値型に変換してから代入すること。
    例:
    誤) WTIYY = %YEARS(%DATE());
    正) WTIYY = %INT(%YEARS(%DATE()));

  5. 1行に複数ステートメントをセミコロンで連結しない
    フリーフォーマットの1行は最大100桁だが、固定長ソース(SRCTYPE=RPGLE)では80桁制限が適用される場合がある。
    複数の独立したステートメントは必ず別々の行に記述すること。
    例:
    誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
    正) *IN31 = *OFF;
    *IN32 = *OFF;
    *IN33 = *OFF;

  6. ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
    DCL-F で外部記述ファイルを定義している場合、同名フィールドを RPG 内で異なる長さで再定義・使用すると
    RNF6033 エラーになる。フィールド長は外部 DDS の定義と必ず一致させること。

  7. %EDITW の編集語はフィールド桁数分の置換文字が必要
    %EDITW(フィールド: '編集語') の編集語には、対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールドには 4文字の編集語が必要 → %EDITW(NO: ' ')

  8. 外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要
    CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で
    プロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。

  9. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型(ZONED / PACKED / INT 等)のフィールドに %TRIM を適用しないこと。
    数値を文字として扱いたい場合は %CHAR() で変換してから %TRIM を適用すること。
    例:
    誤) %TRIM(W1MBMN) ← W1MBMNがZONED型
    正) %TRIM(%CHAR(W1MBMN))

  10. PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
    *PROC キーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる正当な RPG 名を使用すること。
    ¥ を含む名前(W¥PGM 等)や @@ で始まる名前は使用不可。

  11. ファイル仕様書のフラグ(入力、更新、追加など)を正確に変換すること
     


⇑ PAGE TOP

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\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

  1. プロシージャー名・変数名に使用できる文字の制限
    プロシージャー名・変数名・フィールド名には、英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字はフリーフォーマット RPG の識別子として使用できないため、
    ¥SB100 → SB100 のように変換すること。

  2. *DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
    サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
    CRTBNDRPG のデフォルトは DFTACTGRP(*YES) であるため、プロシージャーが存在すると RNF1520 エラーになる。

  3. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  4. %DATE() / %TIME() の戻り値は DATE / TIME 型であり、数値型変数へ直接代入できない
    ZONED や PACKED の変数に年月日を格納する場合は、%YEARS / %MONTHS / %DAYS / %HOURS 等を使用した上で
    %INT() 等で数値型に変換してから代入すること。
    例:
    誤) WTIYY = %YEARS(%DATE());
    正) WTIYY = %INT(%YEARS(%DATE()));

  5. 1行に複数ステートメントをセミコロンで連結しない
    フリーフォーマットの1行は最大100桁だが、固定長ソース(SRCTYPE=RPGLE)では80桁制限が適用される場合がある。
    複数の独立したステートメントは必ず別々の行に記述すること。
    例:
    誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
    正) *IN31 = *OFF;
    *IN32 = *OFF;
    *IN33 = *OFF;

  6. ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
    DCL-F で外部記述ファイルを定義している場合、同名フィールドを RPG 内で異なる長さで再定義・使用すると
    RNF6033 エラーになる。フィールド長は外部 DDS の定義と必ず一致させること。

  7. %EDITW の編集語はフィールド桁数分の置換文字が必要
    %EDITW(フィールド: '編集語') の編集語には、対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールドには 4文字の編集語が必要 → %EDITW(NO: ' ')

  8. 外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要
    CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で
    プロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。

  9. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型(ZONED / PACKED / INT 等)のフィールドに %TRIM を適用しないこと。
    数値を文字として扱いたい場合は %CHAR() で変換してから %TRIM を適用すること。
    例:
    誤) %TRIM(W1MBMN) ← W1MBMNがZONED型
    正) %TRIM(%CHAR(W1MBMN))

  10. PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
    *PROC キーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる正当な RPG 名を使用すること。
    ¥ を含む名前(W¥PGM 等)や @@ で始まる名前は使用不可。

  11. ファイル仕様書のフラグ(入力、更新、追加など)を正確に変換すること

  12. 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;

  13. プログラムパラメータは 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;

  14. 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;

  15. %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()));

  16. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    数値は %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO; ← N1USYO が ZONED 型
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  17. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない
    %CHAR(*DATE:'*YMD0') のように日付フォーマットを第2パラメーターに渡すと RNF0621 エラーになる。
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うか、
    DATE 型変数を %CHAR() でそのまま変換(デフォルト書式)すること。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式(編集コードY)
     


⇑ PAGE TOP

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\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

  1. プロシージャー名・変数名に使用できる文字の制限
    プロシージャー名・変数名・フィールド名には、英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字はフリーフォーマット RPG の識別子として使用できないため、
    ¥SB100 → SB100 のように変換すること。

  2. *DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
    サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
    CRTBNDRPG のデフォルトは DFTACTGRP(*YES) であるため、プロシージャーが存在すると RNF1520 エラーになる。

  3. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  4. %DATE() / %TIME() の戻り値は DATE / TIME 型であり、数値型変数へ直接代入できない
    ZONED や PACKED の変数に年月日を格納する場合は、%YEARS / %MONTHS / %DAYS / %HOURS 等を使用した上で
    %INT() 等で数値型に変換してから代入すること。
    例:
    誤) WTIYY = %YEARS(%DATE());
    正) WTIYY = %INT(%YEARS(%DATE()));

  5. 1行に複数ステートメントをセミコロンで連結しない
    フリーフォーマットの1行は最大100桁だが、固定長ソース(SRCTYPE=RPGLE)では80桁制限が適用される場合がある。
    複数の独立したステートメントは必ず別々の行に記述すること。
    例:
    誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
    正) *IN31 = *OFF;
    *IN32 = *OFF;
    *IN33 = *OFF;

  6. ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
    DCL-F で外部記述ファイルを定義している場合、同名フィールドを RPG 内で異なる長さで再定義・使用すると
    RNF6033 エラーになる。フィールド長は外部 DDS の定義と必ず一致させること。

  7. %EDITW の編集語はフィールド桁数分の置換文字が必要
    %EDITW(フィールド: '編集語') の編集語には、対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールドには 4文字の編集語が必要 → %EDITW(NO: ' ')

  8. 外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要
    CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で
    プロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。

  9. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型(ZONED / PACKED / INT 等)のフィールドに %TRIM を適用しないこと。
    数値を文字として扱いたい場合は %CHAR() で変換してから %TRIM を適用すること。
    例:
    誤) %TRIM(W1MBMN) ← W1MBMNがZONED型
    正) %TRIM(%CHAR(W1MBMN))

  10. PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
    *PROC キーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる正当な RPG 名を使用すること。
    ¥ を含む名前(W¥PGM 等)や @@ で始まる名前は使用不可。

  11. ファイル仕様書のフラグ(入力、更新、追加など)を正確に変換すること

  12. 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;

  13. プログラムパラメータは 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;

  14. 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;

  15. %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()));

  16. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    数値は %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO; ← N1USYO が ZONED 型
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  17. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない
    %CHAR(*DATE:'*YMD0') のように日付フォーマットを第2パラメーターに渡すと RNF0621 エラーになる。
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うか、
    DATE 型変数を %CHAR() でそのまま変換(デフォルト書式)すること。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式(編集コードY)

  18. プリンターファイルの 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);

  19. 固定長プログラム記述ファイル(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 を付けること。
     


⇑ PAGE TOP

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\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

  1. プロシージャー名・変数名に使用できる文字の制限
    プロシージャー名・変数名・フィールド名には、英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字はフリーフォーマット RPG の識別子として使用できないため、
    ¥SB100 → SB100 のように変換すること。

  2. *DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
    サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
    CRTBNDRPG のデフォルトは DFTACTGRP(*YES) であるため、プロシージャーが存在すると RNF1520 エラーになる。

  3. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  4. %DATE() / %TIME() の戻り値は DATE / TIME 型であり、数値型変数へ直接代入できない
    ZONED や PACKED の変数に年月日を格納する場合は、%YEARS / %MONTHS / %DAYS / %HOURS 等を使用した上で
    %INT() 等で数値型に変換してから代入すること。
    例:
    誤) WTIYY = %YEARS(%DATE());
    正) WTIYY = %INT(%YEARS(%DATE()));

  5. 1行に複数ステートメントをセミコロンで連結しない
    フリーフォーマットの1行は最大100桁だが、固定長ソース(SRCTYPE=RPGLE)では80桁制限が適用される場合がある。
    複数の独立したステートメントは必ず別々の行に記述すること。
    例:
    誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
    正) *IN31 = *OFF;
    *IN32 = *OFF;
    *IN33 = *OFF;

  6. ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
    DCL-F で外部記述ファイルを定義している場合、同名フィールドを RPG 内で異なる長さで再定義・使用すると
    RNF6033 エラーになる。フィールド長は外部 DDS の定義と必ず一致させること。

  7. %EDITW の編集語はフィールド桁数分の置換文字が必要
    %EDITW(フィールド: '編集語') の編集語には、対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールドには 4文字の編集語が必要 → %EDITW(NO: ' ')

  8. 外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要
    CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で
    プロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。

  9. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型(ZONED / PACKED / INT 等)のフィールドに %TRIM を適用しないこと。
    数値を文字として扱いたい場合は %CHAR() で変換してから %TRIM を適用すること。
    例:
    誤) %TRIM(W1MBMN) ← W1MBMNがZONED型
    正) %TRIM(%CHAR(W1MBMN))

  10. PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
    *PROC キーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる正当な RPG 名を使用すること。
    ¥ を含む名前(W¥PGM 等)や @@ で始まる名前は使用不可。

  11. ファイル仕様書のフラグ(入力、更新、追加など)を正確に変換すること

  12. 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;

  13. プログラムパラメータは 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;

  14. 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;

  15. %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()));

  16. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    数値は %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO; ← N1USYO が ZONED 型
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  17. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない
    %CHAR(*DATE:'*YMD0') のように日付フォーマットを第2パラメーターに渡すと RNF0621 エラーになる。
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うか、
    DATE 型変数を %CHAR() でそのまま変換(デフォルト書式)すること。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式(編集コードY)

  18. プリンターファイルの 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);

  19. ファイル名と同名のレコード様式が実在すると 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'); ← 別名ファイルで様式衝突を回避

  20. 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); ← 直接判定する場合

  21. 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); ← 必要な単位で個別定義

  22. 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);

  23. フリーフォーマット 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;

  24. フリーフォーマット 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;
     


⇑ PAGE TOP

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

タスク

  1. RPGⅣ の固定長形式から、ソースコード先頭に "**FREE" を記述した完全フリーフォーマットの RPG に変換する
  • "C:\Users\ユーザー名.bob\rules\Rule_Convert_FF.md" のルールに従うこと
  1. 出力前にソースコードを精査し、重大度30以上のエラーの発生要因を特定する
  2. エラー要因箇所を修正し、修正が終わったらソースコード全体を読んで、修正個所とそれ以外の部分の整合性が取れているか確認する
  • 新たなエラー原因となる箇所が見つかった場合は 2 に戻り修正を行うこと
  1. 変換後メンバーとして新規出力する
  2. 変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
  • "C:\Users\A126552\Desktop\作業用フォルダ\AI\IBM Bob\CVTRPGSRCテスト"
     

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

  1. プロシージャー名・変数名に使用できる文字の制限
    プロシージャー名・変数名・フィールド名には、英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字はフリーフォーマット RPG の識別子として使用できないため、
    ¥SB100 → SB100 のように変換すること。

  2. *DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
    サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
    CRTBNDRPG のデフォルトは DFTACTGRP(*YES) であるため、プロシージャーが存在すると RNF1520 エラーになる。

  3. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  4. %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()));

  5. 1行に複数ステートメントをセミコロンで連結しない
    フリーフォーマットの1行は最大100桁だが、固定長ソース(SRCTYPE=RPGLE)では80桁制限が適用される場合がある。
    複数の独立したステートメントは必ず別々の行に記述すること。
    例:
    誤) *IN31 = *OFF; *IN32 = *OFF; *IN33 = *OFF;
    正) *IN31 = *OFF;
    *IN32 = *OFF;
    *IN33 = *OFF;

  6. ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
    DCL-F で外部記述ファイルを定義している場合、同名フィールドを RPG 内で異なる長さで再定義・使用すると
    RNF6033 エラーになる。フィールド長は外部 DDS の定義と必ず一致させること。

  7. %EDITW の編集語はフィールド桁数分の置換文字が必要
    %EDITW(フィールド: '編集語') の編集語には、対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールドには 4文字の編集語が必要 → %EDITW(NO: ' ')

  8. 外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要
    CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で
    プロトタイプを事前宣言すること。宣言がないと RNF7030 エラーになる。

  9. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型(ZONED / PACKED / INT 等)のフィールドに %TRIM を適用しないこと。
    数値を文字として扱いたい場合は %CHAR() で変換してから %TRIM を適用すること。
    例:
    誤) %TRIM(W1MBMN) ← W1MBMNがZONED型
    正) %TRIM(%CHAR(W1MBMN))

  10. PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
    *PROC キーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる正当な RPG 名を使用すること。
    ¥ を含む名前(W¥PGM 等)や @@ で始まる名前は使用不可。

  11. ファイル仕様書のフラグ(入力、更新、追加など)を正確に変換すること

  12. 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;

  13. プログラムパラメータは 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;

  14. 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;

  15. %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()));

  16. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    数値は %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO; ← N1USYO が ZONED 型
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  17. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない
    %CHAR(*DATE:'*YMD0') のように日付フォーマットを第2パラメーターに渡すと RNF0621 エラーになる。
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うか、
    DATE 型変数を %CHAR() でそのまま変換(デフォルト書式)すること。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式(編集コードY)

  18. プリンターファイルの 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);

  19. ファイル名と同名のレコード様式が実在すると 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名を指定

  20. 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); ← 直接判定する場合

  21. 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); ← 必要な単位で個別定義

  22. 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);

  23. フリーフォーマット 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;

  24. フリーフォーマット 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;

  25. *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;
     


⇑ PAGE TOP

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

タスク

  1. 【事前確認】変換を開始する前に、変換元ソース全体を読みこんで構成を把握する
  2. 【事前確認】変換を開始する前に、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. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む

  3. 【変換】事前確認の結果を反映しながら、RPG IV 固定長形式を完全フリーフォーマットに変換する
    • ソースコード先頭に **FREE を記述する
    • "Rule_Convert_FF.md" の全ルールに従うこと
    • 特に以下を重点確認すること
      • ファイル定義(ルール1〜4):事前確認の対処方針を確実に反映する
      • DCL-DS の POS → OVERLAY への変換(ルール7)
      • 演算命令のオペランド順序(ルール13)
      • 1行に複数ステートメントを書かない(ルール17):IF X; Y=0; END-IF; も禁止
  4. 【精査】出力前にソースコードを精査し、重大度20以上のエラー要因を除去する
    • ファイル定義の問題(RNF2109 / RNF2121)が残っていないか確認する
    • 1行に複数ステートメントが残っていないか全行スキャンする(RNF5508)
    • ファイル定義エラーを起点とした連鎖エラー(RNF5347 / RNF0724 の大量発生)がないか確認する
    • エラー要因を修正したらソースコード全体の整合性を再確認する
    • 新たなエラー原因が見つかった場合は本ステップを繰り返す
  5. 【出力】変換後メンバーとして新規出力する
  6. 【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する
    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
    • サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
  7. 【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する
    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

── ファイル定義(DCL-F)関連 ──

  1. 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 が大量発生する。
    この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。

  2. 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;
  3. 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 側のレコード様式名変更をユーザーに確認すること。

  4. ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
    固定長 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)関連 ──

  1. プログラムパラメータは 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;

  2. フリーフォーマット DCL-DS には必ず DS 名または *N を指定すること
    固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットの DCL-DS では
    DS 名または *N(匿名)を必ず指定しなければならない(RNF3368)。
    例:
    誤) DCL-DS;
    正) DCL-DS *N;

  3. フリーフォーマット 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;

  4. ZONED / PACKED 数値型の桁数は最大 63 桁まで
    ZONED(nnn:0) や PACKED(nnn:0) の桁数に 64 以上を指定すると RNF0503 エラーになる。
    63 桁を超えるデータ領域は CHAR 型に変換すること。

  5. DATE 型変数の日付フォーマットにゼロサフィックスは使用できない
    DATE(*ISO0) のようにゼロを付けると RNF0619 エラーになる。
    変数定義では *ISO・*YMD・*MDY・*DMY・*JUL などゼロなしのフォーマットを使うこと。
    例:
    誤) DCL-S WB5DATE DATE(*ISO0);
    正) DCL-S WB5DATE DATE(*ISO);

  6. プロシージャー名・変数名・フィールド名に使用できる文字の制限
    英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字は使用できない。
    ¥SB100 → SB100 のように変換すること。

  7. PSDS の特殊フィールド定義には RPG の命名規則に従った名前を使用すること
    *PROC キーワードを持つ PSDS サブフィールドには、英数字・#・@・$ のみからなる名前を使うこと。
    ¥ を含む名前(W¥PGM 等)は使用不可。


── 演算命令関連 ──

  1. *DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
    サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
    例:
    正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);

  2. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  3. CHAIN の結果は %FOUND で判定すること
    フリーフォーマットの CHAIN に固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
    CHAIN の後は %FOUND または %FOUND(ファイル名) で判定すること。
    例:
    誤) CHAIN KFLDS GADPL11 *IN03;
    正) CHAIN KFLDS GADPL11;
    IF NOT %FOUND(GADPL11);

  4. READE 後の %EOF は複合キー形式では結果標識を使うこと
    READE (キー1:キー2) ファイル名; の後に %EOF(ファイル名) を使うと RNF0391 エラーになる場合がある。
    この場合は結果標識を直接使うこと。
    例:
    誤) READE (WTOKU:FSIKU) GADPL141;
    *IN03 = %EOF(GADPL141);
    正) READE (WTOKU:FSIKU) GADPL141 *IN03;
    IF *IN03;

  5. *INLR = *ON と RETURN はサブルーチン定義の前に記述すること
    BEGSR ~ ENDSR ブロックの直後に演算命令を記述すると RNF5005 エラーになる。
    プログラム終了処理は必ずサブルーチン定義の前に記述すること。
    例:
    誤) BEGSR @END;
    ENDSR;
    *INLR = *ON; ← RNF5005
    RETURN;
    正) *INLR = *ON; ← サブルーチン定義の前
    RETURN;
    BEGSR @END;
    ENDSR;

  6. 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;


── 組み込み関数・型変換関連 ──

  1. %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()));

  2. %DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
    %DEC(%TIME():6:0) のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
    例:
    誤) WTIME = %INT(%DEC(%TIME():6:0));
    正) WTIME = %INT(%DEC(%TIME()));

  3. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
    例:
    誤) %TRIM(W1MBMN) ← ZONED 型
    正) %TRIM(%CHAR(W1MBMN))

  4. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO;
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  5. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うこと。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式

  6. %EDITW の編集語はフィールド桁数分の置換文字が必要
    対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールド → %EDITW(NO: ' ')


── 外部プログラム呼び出し関連 ──

  1. 外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要(RNF7030)
    CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で宣言すること。

  2. ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
    DCL-F で外部記述ファイルを定義している場合、同名フィールドを異なる長さで定義すると RNF6033 エラーになる。
     


⇑ PAGE TOP

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; のコロン区切り複合キー形式にする必要がある
  • 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

タスク

  1. 【事前確認①】変換元ソース全体を読み込んで構成を把握する

    • F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
  2. 【事前確認②】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. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む

  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; も禁止
  4. 【精査】出力前にソースコードを精査し、重大度20以上のエラー要因を除去する

    • ファイル定義の問題(RNF2109 / RNF2121)が残っていないか確認する
    • 1行に複数ステートメントが残っていないか全行スキャンする(RNF5508)
    • PSDS の *PROC キーワードが残っていないか確認する(RNF3308)
    • USAGE(*UPDATE:*ADD) が使われていないか確認する(RNF2370)
    • ファイル定義エラーを起点とした連鎖エラー(RNF5347 / RNF0724 の大量発生)がないか確認する
    • エラー要因を修正したらソースコード全体の整合性を再確認する
    • 新たなエラー原因が見つかった場合は本ステップを繰り返す
  5. 【出力】変換後メンバーとして新規出力する

  6. 【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
    • サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
  7. 【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

── ファイル定義(DCL-F)関連 ──

  1. 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 が大量発生する。
    この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。

  2. 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;
  3. 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 側のレコード様式名変更をユーザーに確認すること。

  4. ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
    固定長 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)関連 ──

  1. プログラムパラメータは 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;

  2. フリーフォーマット DCL-DS には必ず DS 名または *N を指定すること
    固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットの DCL-DS では
    DS 名または *N(匿名)を必ず指定しなければならない(RNF3368)。
    例:
    誤) DCL-DS;
    正) DCL-DS *N;

  3. フリーフォーマット 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)となり、演算命令でコンパイルエラーになる。

  4. ZONED / PACKED 数値型の桁数は最大 63 桁まで
    ZONED(nnn:0) や PACKED(nnn:0) の桁数に 64 以上を指定すると RNF0503 エラーになる。
    63 桁を超えるデータ領域は CHAR 型に変換すること。

  5. DATE 型変数の日付フォーマットにゼロサフィックスは使用できない
    DATE(*ISO0) のようにゼロを付けると RNF0619 エラーになる。
    変数定義では *ISO・*YMD・*MDY・*DMY・*JUL などゼロなしのフォーマットを使うこと。
    例:
    誤) DCL-S WB5DATE DATE(*ISO0);
    正) DCL-S WB5DATE DATE(*ISO);

  6. プロシージャー名・変数名・フィールド名に使用できる文字の制限
    英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字は使用できない。
    ¥SB100 → SB100 のように変換すること。

  7. 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個連続不可のため変更)


── 演算命令関連 ──

  1. *DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
    サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
    例:
    正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);

  2. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  3. CHAIN の結果は %FOUND で判定すること
    フリーフォーマットの CHAIN に固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
    CHAIN の後は %FOUND または %FOUND(ファイル名) で判定すること。
    例:
    誤) CHAIN KFLDS GADPL11 *IN03;
    正) CHAIN KFLDS GADPL11;
    IF NOT %FOUND(GADPL11);

  4. READE 後の %EOF は複合キー形式では結果標識を使うこと
    READE (キー1:キー2) ファイル名; の後に %EOF(ファイル名) を使うと RNF0391 エラーになる場合がある。
    この場合は結果標識を直接使うこと。
    例:
    誤) READE (WTOKU:FSIKU) GADPL141;
    *IN03 = %EOF(GADPL141);
    正) READE (WTOKU:FSIKU) GADPL141 *IN03;
    IF *IN03;

  5. *INLR = *ON と RETURN はサブルーチン定義の前に記述すること
    BEGSR ~ ENDSR ブロックの直後に演算命令を記述すると RNF5005 エラーになる。
    プログラム終了処理は必ずサブルーチン定義の前に記述すること。
    例:
    誤) BEGSR @END;
    ENDSR;
    *INLR = *ON; ← RNF5005
    RETURN;
    正) *INLR = *ON; ← サブルーチン定義の前
    RETURN;
    BEGSR @END;
    ENDSR;

  6. 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;


── 組み込み関数・型変換関連 ──

  1. 固定長の 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 経由の方が確実。

  2. %DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
    %DEC(%TIME():6:0) のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
    例:
    誤) WTIME = %INT(%DEC(%TIME():6:0));
    正) WTIME = %INT(%DEC(%TIME()));

  3. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
    例:
    誤) %TRIM(W1MBMN) ← ZONED 型
    正) %TRIM(%CHAR(W1MBMN))

  4. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO;
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  5. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うこと。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式

  6. %EDITW の編集語はフィールド桁数分の置換文字が必要
    対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールド → %EDITW(NO: ' ')


── 外部プログラム呼び出し関連 ──

  1. 外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要(RNF7030)
    CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で宣言すること。

  2. ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
    DCL-F で外部記述ファイルを定義している場合、同名フィールドを異なる長さで定義すると RNF6033 エラーになる。
     


⇑ PAGE TOP

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

タスク

  1. 【事前確認①】変換元ソース全体を読み込んで構成を把握する

    • F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
    • KLIST / KFLD 定義が存在する場合は使用箇所(CHAIN/SETLL/SETGT/READE)とキーフィールドを全件メモする
  2. 【事前確認②】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. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む

  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; も禁止
  4. 【精査】出力前にソースコードを精査し、重大度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 の大量発生)がないか確認する
    • エラー要因を修正したらソースコード全体の整合性を再確認する
    • 新たなエラー原因が見つかった場合は本ステップを繰り返す
  5. 【出力】変換後メンバーとして新規出力する

  6. 【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
    • サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
  7. 【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

── ファイル定義(DCL-F)関連 ──

  1. 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 が大量発生する。
    この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。

  2. 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;
  3. 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 側のレコード様式名変更をユーザーに確認すること。

  4. ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
    固定長 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)関連 ──

  1. プログラムパラメータは 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;

  2. フリーフォーマット DCL-DS には必ず DS 名または *N を指定すること
    固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットの DCL-DS では
    DS 名または *N(匿名)を必ず指定しなければならない(RNF3368)。
    例:
    誤) DCL-DS;
    正) DCL-DS *N;

  3. フリーフォーマット 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)となり、演算命令でコンパイルエラーになる。

  4. ZONED / PACKED 数値型の桁数は最大 63 桁まで
    ZONED(nnn:0) や PACKED(nnn:0) の桁数に 64 以上を指定すると RNF0503 エラーになる。
    63 桁を超えるデータ領域は CHAR 型に変換すること。

  5. DATE 型変数の日付フォーマットにゼロサフィックスは使用できない
    DATE(*ISO0) のようにゼロを付けると RNF0619 エラーになる。
    変数定義では *ISO・*YMD・*MDY・*DMY・*JUL などゼロなしのフォーマットを使うこと。
    例:
    誤) DCL-S WB5DATE DATE(*ISO0);
    正) DCL-S WB5DATE DATE(*ISO);

  6. プロシージャー名・変数名・フィールド名に使用できる文字の制限
    英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字は使用できない。
    ¥SB100 → SB100 のように変換すること。

  7. 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個連続不可のため変更)


── 演算命令関連 ──

  1. *DFTACTGRP(YES) ではサブプロシージャーを持つプログラムを作成できない
    サブプロシージャー(DCL-PROC)を含む場合は、CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を必ず指定すること。
    例:
    正) CTL-OPT DFTACTGRP(*NO) ACTGRP(*CALLER);

  2. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  3. CHAIN の結果は %FOUND で判定すること
    フリーフォーマットの CHAIN に固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
    CHAIN の後は %FOUND または %FOUND(ファイル名) で判定すること。
    例:
    誤) CHAIN KFLDS GADPL11 *IN03;
    正) CHAIN KFLDS GADPL11;
    IF NOT %FOUND(GADPL11);

  4. READE 後の %EOF は複合キー形式では結果標識を使うこと
    READE (キー1:キー2) ファイル名; の後に %EOF(ファイル名) を使うと RNF0391 エラーになる場合がある。
    この場合は結果標識を直接使うこと。
    例:
    誤) READE (WTOKU:FSIKU) GADPL141;
    *IN03 = %EOF(GADPL141);
    正) READE (WTOKU:FSIKU) GADPL141 *IN03;
    IF *IN03;

  5. *INLR = *ON と RETURN はサブルーチン定義の前に記述すること
    BEGSR ~ ENDSR ブロックの直後に演算命令を記述すると RNF5005 エラーになる。
    プログラム終了処理は必ずサブルーチン定義の前に記述すること。
    例:
    誤) BEGSR @END;
    ENDSR;
    *INLR = *ON; ← RNF5005
    RETURN;
    正) *INLR = *ON; ← サブルーチン定義の前
    RETURN;
    BEGSR @END;
    ENDSR;

  6. 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;

  7. 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;


── 組み込み関数・型変換関連 ──

  1. 固定長の 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 経由の方が確実。

  2. %DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
    %DEC(%TIME():6:0) のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
    例:
    誤) WTIME = %INT(%DEC(%TIME():6:0));
    正) WTIME = %INT(%DEC(%TIME()));

  3. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
    例:
    誤) %TRIM(W1MBMN) ← ZONED 型
    正) %TRIM(%CHAR(W1MBMN))

  4. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO;
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  5. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うこと。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式

  6. %EDITW の編集語はフィールド桁数分の置換文字が必要
    対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールド → %EDITW(NO: ' ')


── 外部プログラム呼び出し関連 ──

  1. 外部プログラムを CALLP で呼び出す場合はプロトタイプ宣言が必要(RNF7030)
    CALLP で別プログラム・別プロシージャーを呼び出す場合は、必ず DCL-PR ~ END-PR で宣言すること。

  2. ワークステーションファイルへの OUTPUT 仕様では、フィールド長を外部定義と一致させること
    DCL-F で外部記述ファイルを定義している場合、同名フィールドを異なる長さで定義すると RNF6033 エラーになる。
     


⇑ PAGE TOP

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

タスク

  1. 【事前確認①】変換元ソース全体を読み込んで構成を把握する

    • F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
    • KLIST / KFLD 定義が存在する場合は使用箇所(CHAIN/SETLL/SETGT/READE)とキーフィールドを全件メモする
    • READ / READE / READP の使用箇所を全件メモし、固定長の結果標識(*INxx)を使っているか確認する
  2. 【事前確認②】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. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む

  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; も禁止
  4. 【精査】出力前にソースコードを精査し、重大度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 の大量発生)がないか確認する
    • エラー要因を修正したらソースコード全体の整合性を再確認する
    • 新たなエラー原因が見つかった場合は本ステップを繰り返す
  5. 【出力】変換後メンバーとして新規出力する

  6. 【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
    • サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
  7. 【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

── ファイル定義(DCL-F)関連 ──

  1. 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 が大量発生する。
    この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。

  2. 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;
  3. 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 側のレコード様式名変更をユーザーに確認すること。

  4. 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);

  5. ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
    固定長 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)関連 ──

  1. プログラムパラメータは 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;

  2. フリーフォーマット DCL-DS には必ず DS 名または *N を指定すること
    固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットの DCL-DS では
    DS 名または *N(匿名)を必ず指定しなければならない(RNF3368)。
    例:
    誤) DCL-DS;
    正) DCL-DS *N;

  3. フリーフォーマット 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)となり、演算命令でコンパイルエラーになる。

  4. ZONED / PACKED 数値型の桁数は最大 63 桁まで
    ZONED(nnn:0) や PACKED(nnn:0) の桁数に 64 以上を指定すると RNF0503 エラーになる。
    63 桁を超えるデータ領域は CHAR 型に変換すること。

  5. DATE 型変数の日付フォーマットにゼロサフィックスは使用できない
    DATE(*ISO0) のようにゼロを付けると RNF0619 エラーになる。
    変数定義では *ISO・*YMD・*MDY・*DMY・*JUL などゼロなしのフォーマットを使うこと。
    例:
    誤) DCL-S WB5DATE DATE(*ISO0);
    正) DCL-S WB5DATE DATE(*ISO);

  6. プロシージャー名・変数名・フィールド名に使用できる文字の制限
    英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字は使用できない。
    ¥SB100 → SB100 のように変換すること。

  7. 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個連続不可のため変更)


── 演算命令関連 ──

  1. 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) ← コンパイルコマンド

  2. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  3. CHAIN の結果は %FOUND で判定すること
    フリーフォーマットの CHAIN に固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
    CHAIN の後は %FOUND または %FOUND(ファイル名) で判定すること。
    例:
    誤) CHAIN KFLDS GADPL11 *IN03;
    正) CHAIN KFLDS GADPL11;
    IF NOT %FOUND(GADPL11);

  4. 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;

  5. *INLR = *ON と RETURN はサブルーチン定義の前に記述すること
    BEGSR ~ ENDSR ブロックの直後に演算命令を記述すると RNF5005 エラーになる。
    プログラム終了処理は必ずサブルーチン定義の前に記述すること。
    例:
    誤) BEGSR @END;
    ENDSR;
    *INLR = *ON; ← RNF5005
    RETURN;
    正) *INLR = *ON; ← サブルーチン定義の前
    RETURN;
    BEGSR @END;
    ENDSR;

  6. 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;

  7. 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;


── 組み込み関数・型変換関連 ──

  1. 固定長の 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;

  2. %DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
    %DEC(%TIME():6:0) のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
    例:
    誤) WTIME = %INT(%DEC(%TIME():6:0));
    正) WTIME = %INT(%DEC(%TIME()));

  3. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
    例:
    誤) %TRIM(W1MBMN) ← ZONED 型
    正) %TRIM(%CHAR(W1MBMN))

  4. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO;
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  5. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うこと。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式

  6. %EDITW の編集語はフィールド桁数分の置換文字が必要
    対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールド → %EDITW(NO: ' ')


── 外部プログラム呼び出し関連 ──

  1. 固定長の 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); ← パラメーターあり

  2. 外部記述ファイルのフィールドと同名の変数を定義する場合は桁数を一致させること(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)を使うこと。


── コンパイルコマンド関連 ──

  1. コンパイルコマンド(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参照)。
     


⇑ PAGE TOP

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

タスク

  1. 【事前確認①】変換元ソース全体を読み込んで構成を把握する

    • F仕様・D仕様・C仕様(特殊命令)の全体像を把握してから変換に進む
    • KLIST / KFLD 定義が存在する場合は使用箇所(CHAIN/SETLL/SETGT/READE)とキーフィールドを全件メモする
    • READ / READE / READP の使用箇所を全件メモし、固定長の結果標識(*INxx)を使っているか確認する
  2. 【事前確認②】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. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む

  3. 【変換】事前確認の結果を反映しながら、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; も禁止
  4. 【精査】出力前にソースコードを精査し、重大度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 の大量発生)がないか確認する
    • エラー要因を修正したらソースコード全体の整合性を再確認する
    • 新たなエラー原因が見つかった場合は本ステップを繰り返す
  5. 【出力】変換後メンバーとして新規出力する

  6. 【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
    • サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
  7. 【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

── ファイル定義(DCL-F)関連 ──

  1. 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 が大量発生する。
    この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。

  2. 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;
  3. 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 側のレコード様式名変更をユーザーに確認すること。

  4. 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 で失敗する。

  5. ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
    固定長 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)関連 ──

  1. プログラムパラメータは 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;

  2. フリーフォーマット DCL-DS には必ず DS 名または *N を指定すること
    固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットの DCL-DS では
    DS 名または *N(匿名)を必ず指定しなければならない(RNF3368)。
    例:
    誤) DCL-DS;
    正) DCL-DS *N;

  3. フリーフォーマット 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)となり、演算命令でコンパイルエラーになる。

  4. ZONED / PACKED 数値型の桁数は最大 63 桁まで
    ZONED(nnn:0) や PACKED(nnn:0) の桁数に 64 以上を指定すると RNF0503 エラーになる。
    63 桁を超えるデータ領域は CHAR 型に変換すること。

  5. DATE 型変数の日付フォーマットにゼロサフィックスは使用できない
    DATE(*ISO0) のようにゼロを付けると RNF0619 エラーになる。
    変数定義では *ISO・*YMD・*MDY・*DMY・*JUL などゼロなしのフォーマットを使うこと。
    例:
    誤) DCL-S WB5DATE DATE(*ISO0);
    正) DCL-S WB5DATE DATE(*ISO);

  6. プロシージャー名・変数名・フィールド名に使用できる文字の制限
    英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字は使用できない。
    ¥SB100 → SB100 のように変換すること。

  7. 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個連続不可のため変更)


── 演算命令関連 ──

  1. 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) ← コンパイルコマンド

  2. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  3. CHAIN の結果は %FOUND で判定すること
    フリーフォーマットの CHAIN に固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
    CHAIN の後は %FOUND または %FOUND(ファイル名) で判定すること。
    例:
    誤) CHAIN KFLDS GADPL11 *IN03;
    正) CHAIN KFLDS GADPL11;
    IF NOT %FOUND(GADPL11);

  4. 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;

  5. *INLR = *ON と RETURN はサブルーチン定義の前に記述すること
    BEGSR ~ ENDSR ブロックの直後に演算命令を記述すると RNF5005 エラーになる。
    プログラム終了処理は必ずサブルーチン定義の前に記述すること。
    例:
    誤) BEGSR @END;
    ENDSR;
    *INLR = *ON; ← RNF5005
    RETURN;
    正) *INLR = *ON; ← サブルーチン定義の前
    RETURN;
    BEGSR @END;
    ENDSR;

  6. 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;

  7. 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;


── 組み込み関数・型変換関連 ──

  1. 固定長の 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;

  2. %DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
    %DEC(%TIME():6:0) のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
    例:
    誤) WTIME = %INT(%DEC(%TIME():6:0));
    正) WTIME = %INT(%DEC(%TIME()));

  3. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
    例:
    誤) %TRIM(W1MBMN) ← ZONED 型
    正) %TRIM(%CHAR(W1MBMN))

  4. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO;
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  5. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うこと。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式

  6. %EDITW の編集語はフィールド桁数分の置換文字が必要
    対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールド → %EDITW(NO: ' ')


── 外部プログラム呼び出し関連 ──

  1. 固定長の 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); ← パラメーターあり

  2. 外部記述ファイルのフィールドと同名の変数を定義する場合は桁数を一致させること(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)を使うこと。


── コンパイルコマンド関連 ──

  1. コンパイルコマンド(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参照)。


── 出力前の精査チェックリスト ──

  1. 変換後ソースを出力する前に以下の全項目をスキャンして重大度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)
       

⇑ PAGE TOP

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

タスク

  1. 【事前確認①】変換元ソース全体を読み込んで構成を把握する

    • 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)に置き換える計画を立てる
  2. 【事前確認②】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. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む

  3. 【変換】事前確認の結果を反映しながら、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; も禁止
  4. 【精査】出力前にソースコードを精査し、重大度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 の大量発生)がないか確認する
    • エラー要因を修正したらソースコード全体の整合性を再確認する
    • 新たなエラー原因が見つかった場合は本ステップを繰り返す
  5. 【出力】変換後メンバーとして新規出力する

    • write_ibmi_source で書き込んだ後、コンパイルする場合は必ず DFTACTGRP(*NO) を指定すること(ルール30)
    • CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を記述していても、コンパイルコマンド側が DFTACTGRP(*YES) だと CTL-OPT が無視され ENDIF/ENDDO が演算命令として誤認される(RNF5347 大量発生)
    • ユーザーに対して、以下のコンパイルコマンドを提示すること:
      CRTBNDRPG PGM(ライブラリ/メンバー名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)
      
  6. 【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
    • サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
  7. 【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

── ファイル定義(DCL-F)関連 ──

  1. 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 が大量発生する。
    この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。

  2. 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;
  3. 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 側のレコード様式名変更をユーザーに確認すること。

  4. 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);

  5. ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
    固定長 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)関連 ──

  1. プログラムパラメータは 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;

  2. フリーフォーマット DCL-DS には必ず DS 名または *N を指定すること
    固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットの DCL-DS では
    DS 名または *N(匿名)を必ず指定しなければならない(RNF3368)。
    例:
    誤) DCL-DS;
    正) DCL-DS *N;

  3. フリーフォーマット 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)となり、演算命令でコンパイルエラーになる。

  4. ZONED / PACKED 数値型の桁数は最大 63 桁まで
    ZONED(nnn:0) や PACKED(nnn:0) の桁数に 64 以上を指定すると RNF0503 エラーになる。
    63 桁を超えるデータ領域は CHAR 型に変換すること。

  5. DATE 型変数の日付フォーマットにゼロサフィックスは使用できない
    DATE(*ISO0) のようにゼロを付けると RNF0619 エラーになる。
    変数定義では *ISO・*YMD・*MDY・*DMY・*JUL などゼロなしのフォーマットを使うこと。
    例:
    誤) DCL-S WB5DATE DATE(*ISO0);
    正) DCL-S WB5DATE DATE(*ISO);

  6. プロシージャー名・変数名・フィールド名に使用できる文字の制限
    英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字は使用できない。
    ¥SB100 → SB100 のように変換すること。

  7. フリーフォーマット 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 は印刷プログラムに頻出するため注意すること。

  8. 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個連続不可のため変更)


── 演算命令関連 ──

  1. 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) ← コンパイルコマンド

  2. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  3. CHAIN の結果は %FOUND で判定すること
    フリーフォーマットの CHAIN に固定長の結果標識(NR標識)は付加できない(RNF0637/RNF7030)。
    CHAIN の後は %FOUND または %FOUND(ファイル名) で判定すること。
    例:
    誤) CHAIN KFLDS GADPL11 *IN03;
    正) CHAIN KFLDS GADPL11;
    IF NOT %FOUND(GADPL11);

  4. 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;

  5. *INLR = *ON と RETURN はサブルーチン定義の前に記述すること
    BEGSR ~ ENDSR ブロックの直後に演算命令を記述すると RNF5005 エラーになる。
    プログラム終了処理は必ずサブルーチン定義の前に記述すること。
    例:
    誤) BEGSR @END;
    ENDSR;
    *INLR = *ON; ← RNF5005
    RETURN;
    正) *INLR = *ON; ← サブルーチン定義の前
    RETURN;
    BEGSR @END;
    ENDSR;

  6. 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;

  7. 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;

  8. 固定長形式のコメント行(* で始まる行)はフリーフォーマットでは乗算演算子として誤認される(RNF5347 連鎖の根本原因)
    固定長 RPG IV では桁1に * を記述することでコメント行として扱われるが、
    フリーフォーマットでは * が乗算演算子として解釈される。
    その結果 RNF0955(EVAL左辺として無効)→ RNF5347(割り当て演算子が必要)が発生し、
    さらにコンパイラの内部状態が崩壊して後続の ENDIF / ENDDO / ENDSR が
    すべて演算命令として誤認され、RNF5177 / RNF5248 / RNF7030 が大量に連鎖する。
    この1行の変換漏れがプログラム全体のコンパイルエラーを引き起こす。

変換方針:

  • * で始まるすべてのコメント行を // コメント行に変換するか、不要であれば削除すること
  • 特に BEGSR ~ ENDSR の後ろや、サブルーチン区切り線として使われる
    * * * * * * や *----... のような行が残りやすいため重点的にチェックすること
    例:
    変換前) * サブルーチン SB210
    *---------------------------------------
    誤) * サブルーチン SB210 ← フリーフォーマットでは乗算演算子として誤認
    正) // サブルーチン SB210
    // ---------------------------------------

【精査チェック】変換後ソース全行を対象に * で始まる行(ただし **FREE を除く)が
残っていないかスキャンすること。

**FREE はフリーフォーマット宣言なので除外する。

  1. フリーフォーマットでは 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 文と対応するラベル行を除去・変換すること。


── 組み込み関数・型変換関連 ──

  1. 固定長の 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 経由の方が確実。

  2. %DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
    %DEC(%TIME():6:0) のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
    例:
    誤) WTIME = %INT(%DEC(%TIME():6:0));
    正) WTIME = %INT(%DEC(%TIME()));

  3. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
    例:
    誤) %TRIM(W1MBMN) ← ZONED 型
    正) %TRIM(%CHAR(W1MBMN))

  4. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO;
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  5. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うこと。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式

  6. %EDITW の編集語はフィールド桁数分の置換文字が必要
    対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールド → %EDITW(NO: ' ')


── 外部プログラム呼び出し関連 ──

  1. 固定長の 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); ← パラメーターあり
  2. 外部記述ファイルのフィールドと同名の変数を定義する場合は桁数を一致させること(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)を使うこと。

  3. コンパイルコマンド(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参照)。
     


⇑ PAGE TOP

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

タスク

  1. 【事前確認①】変換元ソース全体を読み込んで構成を把握する

    • 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)に置き換える計画を立てる
  2. 【事前確認②】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. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む

  3. 【変換】事前確認の結果を反映しながら、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; も禁止
  4. 【精査】出力前にソースコードを精査し、重大度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 の大量発生)がないか確認する
    • エラー要因を修正したらソースコード全体の整合性を再確認する
    • 新たなエラー原因が見つかった場合は本ステップを繰り返す
  5. 【出力】変換後メンバーとして新規出力する

    • write_ibmi_source で書き込んだ後、コンパイルする場合は必ず DFTACTGRP(*NO) を指定すること(ルール30)
    • CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を記述していても、コンパイルコマンド側が DFTACTGRP(*YES) だと CTL-OPT が無視され ENDIF/ENDDO が演算命令として誤認される(RNF5347 大量発生)
    • ユーザーに対して、以下のコンパイルコマンドを提示すること:
      CRTBNDRPG PGM(ライブラリ/メンバー名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)
      
  6. 【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
    • サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
  7. 【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

── ファイル定義(DCL-F)関連 ──

  1. 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 が大量発生する。
    この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。

  2. 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;
  3. 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 側のレコード様式名変更をユーザーに確認すること。

  4. 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);

  5. ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
    固定長 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)関連 ──

  1. プログラムパラメータは 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;

  2. フリーフォーマット DCL-DS には必ず DS 名または *N を指定すること
    固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットの DCL-DS では
    DS 名または *N(匿名)を必ず指定しなければならない(RNF3368)。
    例:
    誤) DCL-DS;
    正) DCL-DS *N;

  3. フリーフォーマット 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)となり、演算命令でコンパイルエラーになる。

  4. ZONED / PACKED 数値型の桁数は最大 63 桁まで
    ZONED(nnn:0) や PACKED(nnn:0) の桁数に 64 以上を指定すると RNF0503 エラーになる。
    63 桁を超えるデータ領域は CHAR 型に変換すること。

  5. DATE 型変数の日付フォーマットにゼロサフィックスは使用できない
    DATE(*ISO0) のようにゼロを付けると RNF0619 エラーになる。
    変数定義では *ISO・*YMD・*MDY・*DMY・*JUL などゼロなしのフォーマットを使うこと。
    例:
    誤) DCL-S WB5DATE DATE(*ISO0);
    正) DCL-S WB5DATE DATE(*ISO);

  6. プロシージャー名・変数名・フィールド名に使用できる文字の制限
    英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字は使用できない。
    ¥SB100 → SB100 のように変換すること。

  7. フリーフォーマット 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 は印刷プログラムに頻出するため注意すること。

  8. 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個連続不可のため変更)


── 演算命令関連 ──

  1. 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) ← コンパイルコマンド

  2. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  3. 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); ← ファイル名を渡す

  4. 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;

  5. *INLR = *ON と RETURN はサブルーチン定義の前に記述すること
    BEGSR ~ ENDSR ブロックの直後に演算命令を記述すると RNF5005 エラーになる。
    プログラム終了処理は必ずサブルーチン定義の前に記述すること。
    例:
    誤) BEGSR @END;
    ENDSR;
    *INLR = *ON; ← RNF5005
    RETURN;
    正) *INLR = *ON; ← サブルーチン定義の前
    RETURN;
    BEGSR @END;
    ENDSR;

  6. 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;

  7. 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;

  8. 固定長形式のコメント行(* で始まる行)はフリーフォーマットでは乗算演算子として誤認される(RNF5347 連鎖の根本原因)
    固定長 RPG IV では桁1に * を記述することでコメント行として扱われるが、
    フリーフォーマットでは * が乗算演算子として解釈される。
    その結果 RNF0955(EVAL左辺として無効)→ RNF5347(割り当て演算子が必要)が発生し、
    さらにコンパイラの内部状態が崩壊して後続の ENDIF / ENDDO / ENDSR が
    すべて演算命令として誤認され、RNF5177 / RNF5248 / RNF7030 が大量に連鎖する。
    この1行の変換漏れがプログラム全体のコンパイルエラーを引き起こす。

変換方針:

  • * で始まるすべてのコメント行を // コメント行に変換するか、不要であれば削除すること
  • 特に BEGSR ~ ENDSR の後ろや、サブルーチン区切り線として使われる
    * * * * * * や *----... のような行が残りやすいため重点的にチェックすること
    例:
    変換前) * サブルーチン SB210
    *---------------------------------------
    誤) * サブルーチン SB210 ← フリーフォーマットでは乗算演算子として誤認
    正) // サブルーチン SB210
    // ---------------------------------------

【精査チェック】変換後ソース全行を対象に * で始まる行(ただし **FREE を除く)が
残っていないかスキャンすること。

**FREE はフリーフォーマット宣言なので除外する。

  1. フリーフォーマットでは 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 文と対応するラベル行を除去・変換すること。


── 組み込み関数・型変換関連 ──

  1. 固定長の 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 経由の方が確実。

  2. %DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
    %DEC(%TIME():6:0) のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
    例:
    誤) WTIME = %INT(%DEC(%TIME():6:0));
    正) WTIME = %INT(%DEC(%TIME()));

  3. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
    例:
    誤) %TRIM(W1MBMN) ← ZONED 型
    正) %TRIM(%CHAR(W1MBMN))

  4. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO;
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  5. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うこと。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式

  6. %EDITW の編集語はフィールド桁数分の置換文字が必要
    対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールド → %EDITW(NO: ' ')


── 外部プログラム呼び出し関連 ──

  1. 固定長の 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); ← パラメーターあり
  2. 外部記述ファイルのフィールドと同名の変数を定義する場合は桁数を一致させること(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)を使うこと。

  3. コンパイルコマンド(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参照)。
     


⇑ PAGE TOP

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

タスク

  1. 【事前確認①】変換元ソース全体を読み込んで構成を把握する

    • 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)に置き換える計画を立てる
  2. 【事前確認②】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. 確認結果をリストアップして対処方針を提示し、問題なければ次へ進む

  3. 【変換】事前確認の結果を反映しながら、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; も禁止
  4. 【精査】出力前にソースコードを精査し、重大度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 のため作成自体は成功するが、実行時に配列の初期値が誤る可能性があることをユーザーに伝えること
    • エラー要因を修正したらソースコード全体の整合性を再確認する
    • 新たなエラー原因が見つかった場合は本ステップを繰り返す
  5. 【出力】変換後メンバーとして新規出力する

    • write_ibmi_source で書き込んだ後、コンパイルする場合は必ず DFTACTGRP(*NO) を指定すること(ルール30)
    • CTL-OPT に DFTACTGRP(*NO) ACTGRP(*CALLER) を記述していても、コンパイルコマンド側が DFTACTGRP(*YES) だと CTL-OPT が無視され ENDIF/ENDDO が演算命令として誤認される(RNF5347 大量発生)
    • ユーザーに対して、以下のコンパイルコマンドを提示すること:
      CRTBNDRPG PGM(ライブラリ/メンバー名) SRCFILE(ライブラリ/ソースファイル) DFTACTGRP(*NO)
      
  6. 【サマリー】変換タスクのサマリーを html ファイルにして、変換後メンバー名 + "_変換サマリー" の名前で下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
    • サマリーには事前確認で判明したファイル定義の問題点と対処方法も含めること
  7. 【ソースコードのエクスポート】変換後のソースコードのコピーを、変換後メンバー名の名前で、拡張子を RPGLE にして下記のローカルディレクトリに出力する

    • "C:\Users\ユーザー名\Desktop\作業フォルダ名"
       

・使用したルールファイル

(本文を表示)

 

【コンパイルエラー防止ルール】

── ファイル定義(DCL-F)関連 ──

  1. 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 が大量発生する。
    この連鎖エラーは「ファイル定義の問題が根本原因」であり、演算命令を直しても解決しない。

  2. 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;
  3. 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 側のレコード様式名変更をユーザーに確認すること。

  4. 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);

  5. ファイル仕様書のフラグ(入力・更新・追加など)を正確に変換すること
    固定長 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)関連 ──

  1. プログラムパラメータは 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;

  2. フリーフォーマット DCL-DS には必ず DS 名または *N を指定すること
    固定長 RPG IV では無名 DS が許容されたが、フリーフォーマットの DCL-DS では
    DS 名または *N(匿名)を必ず指定しなければならない(RNF3368)。
    例:
    誤) DCL-DS;
    正) DCL-DS *N;

  3. フリーフォーマット 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)となり、演算命令でコンパイルエラーになる。

  4. ZONED / PACKED 数値型の桁数は最大 63 桁まで
    ZONED(nnn:0) や PACKED(nnn:0) の桁数に 64 以上を指定すると RNF0503 エラーになる。
    63 桁を超えるデータ領域は CHAR 型に変換すること。

  5. DATE 型変数の日付フォーマットにゼロサフィックスは使用できない
    DATE(*ISO0) のようにゼロを付けると RNF0619 エラーになる。
    変数定義では *ISO・*YMD・*MDY・*DMY・*JUL などゼロなしのフォーマットを使うこと。
    例:
    誤) DCL-S WB5DATE DATE(*ISO0);
    正) DCL-S WB5DATE DATE(*ISO);

  6. プロシージャー名・変数名・フィールド名に使用できる文字の制限
    英大文字・数字・#・@・$ のみ使用すること。
    円マーク(¥ / \)やマルチバイト文字は使用できない。
    ¥SB100 → SB100 のように変換すること。

  7. フリーフォーマット 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 は印刷プログラムに頻出するため注意すること。

  8. 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個連続不可のため変更)


── 演算命令関連 ──

  1. 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) ← コンパイルコマンド

  2. フリーフォーマット RPG の演算命令はオペランド順序が固定長と異なる
    SETGT / SETLL / READE / READP 等の命令は「キー/値 → ファイル名」の順序で記述すること。
    例:
    誤) SETGT EK003W11 *HIVAL;
    正) SETGT *HIVAL EK003W11;
    誤) READE EK003W11 #KNO;
    正) READE #KNO EK003W11;

  3. 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); ← ファイル名を渡す

  4. 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;

  5. *INLR = *ON と RETURN はサブルーチン定義の前に記述すること
    BEGSR ~ ENDSR ブロックの直後に演算命令を記述すると RNF5005 エラーになる。
    プログラム終了処理は必ずサブルーチン定義の前に記述すること。
    例:
    誤) BEGSR @END;
    ENDSR;
    *INLR = *ON; ← RNF5005
    RETURN;
    正) *INLR = *ON; ← サブルーチン定義の前
    RETURN;
    BEGSR @END;
    ENDSR;

  6. 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;

  7. 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;

  8. 固定長形式のコメント行(* で始まる行)はフリーフォーマットでは乗算演算子として誤認される(RNF5347 連鎖の根本原因)
    固定長 RPG IV では桁1に * を記述することでコメント行として扱われるが、
    フリーフォーマットでは * が乗算演算子として解釈される。
    その結果 RNF0955(EVAL左辺として無効)→ RNF5347(割り当て演算子が必要)が発生し、
    さらにコンパイラの内部状態が崩壊して後続の ENDIF / ENDDO / ENDSR が
    すべて演算命令として誤認され、RNF5177 / RNF5248 / RNF7030 が大量に連鎖する。
    この1行の変換漏れがプログラム全体のコンパイルエラーを引き起こす。

変換方針:

  • * で始まるすべてのコメント行を // コメント行に変換するか、不要であれば削除すること
  • 特に BEGSR ~ ENDSR の後ろや、サブルーチン区切り線として使われる
    * * * * * * や *----... のような行が残りやすいため重点的にチェックすること
    例:
    変換前) * サブルーチン SB210
    *---------------------------------------
    誤) * サブルーチン SB210 ← フリーフォーマットでは乗算演算子として誤認
    正) // サブルーチン SB210
    // ---------------------------------------

【精査チェック】変換後ソース全行を対象に * で始まる行(ただし **FREE を除く)が
残っていないかスキャンすること。

**FREE はフリーフォーマット宣言なので除外する。

  1. フリーフォーマットでは 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 文と対応するラベル行を除去・変換すること。


── 組み込み関数・型変換関連 ──

  1. 固定長の 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 経由の方が確実。

  2. %DEC に TIME 型を渡す場合は桁数・小数点パラメーターを指定しないこと
    %DEC(%TIME():6:0) のように桁数・小数位を指定すると RNF0328/RNF0339 エラーになる。
    例:
    誤) WTIME = %INT(%DEC(%TIME():6:0));
    正) WTIME = %INT(%DEC(%TIME()));

  3. %TRIM は文字型(CHAR / VARCHAR)にしか使用できない
    数値型フィールドに %TRIM を適用しないこと。数値は先に %CHAR() で変換すること。
    例:
    誤) %TRIM(W1MBMN) ← ZONED 型
    正) %TRIM(%CHAR(W1MBMN))

  4. ZONED/PACKED 数値を %SUBST の右辺に直接代入できない
    %SUBST(文字変数:開始:長さ) = 数値変数 は型不一致(RNF7416)になる。
    %EDITC(数値:'Z') や %CHAR(数値) で文字列に変換してから代入すること。
    例:
    誤) %SUBST(ABAWREC:43:5) = N1USYO;
    正) %SUBST(ABAWREC:43:5) = %EDITC(N1USYO:'Z');

  5. %CHAR() に日付フォーマット文字列を第2パラメーターとして指定できない(RNF0621)
    日付を特定フォーマットの文字列にする場合は %EDITC の編集コード 'Y' を使うこと。
    例:
    誤) %CHAR(*DATE:'*YMD0')
    正) %EDITC(*DATE:'Y') ← YYMMDD 形式

  6. %EDITW の編集語はフィールド桁数分の置換文字が必要
    対象フィールドの整数桁数と同数の空白(置換文字)が必要。
    例:4桁フィールド → %EDITW(NO: ' ')


── 外部プログラム呼び出し関連 ──

  1. 固定長の 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); ← パラメーターあり

  2. 外部記述ファイルのフィールドと同名の変数を定義する場合は桁数を一致させること(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)を使うこと。

  3. コンパイルコマンド(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 / コンパイル時データ関連 ──

  1. 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 レコードの長さも変わる

    対処方針:

    1. CTDATA の全角文字メッセージは、配列要素ごとに正確な桁数(PERRCD で指定した長さ)になっているか確認する
    2. 文字化けが疑われる場合は、CTDATA のメッセージ文字列をすべて半角英数字で書き直すか、
      外部メッセージファイル(QMSGF)に移行することを検討する
    3. RNF8267 / RNF8042 は重大度 00(通知)のため、プログラムの作成自体は妨げないが
      実行時に配列の初期値が正しく設定されないリスクがある
    4. write_ibmi_source でソースを書き込む際、元の CTDATA 全角文字が正しく転送されているか
      コンパイルリストの「コンパイル時データ」セクションで必ず確認すること

    例:
    元の CTDATA(正常):
    E-01社内品番の入力は必須です
    コンパイルリストで文字化けしている場合:
    → RNF8267 が発生 → 実行時にメッセージが正しく表示されない可能性がある
    → CTDATA 行の全角文字を外部メッセージに切り出すことを推奨
     


⇑ PAGE TOP

4.まとめ

今回の検証では、試行回数を重ねてプロンプトとルールファイルを作り込み、どんなソースコードにも対応できるようなエージェントの作成を目指しました。

全体として、重大度20以上のエラー発生数には減少傾向が見られましたが、前回うまくいっていた変換が次のタスクで失敗するなど、AI 特有の出力の振れも散見されました。

また、今回はプロンプトとルールファイルでガチガチに縛った状態で検証を進めたため、
「RPGLE Free などの拡張機能にルールを補完して変換させるのと同じでは?」≒「AI を使う意義とは?」
といった疑問も湧く結果となりました。

最後まで読んでいただきありがとうございます、本記事が何かのお役に立てば幸いです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?