6. RPG固定形式と取り違え防止

IBM i / AS400 解析・リバース — 最良の手順と手法(匿名化公開用)

版 2026-07-22 · 対外公開用 · プロンプト+実践知見+用語集

対外公開版(匿名化済み) — 顧客名・案件名・固有ライブラリ/パス/プログラム名は一般化しています。用語は青点線にマウスオーバーで定義を表示。巻末「用語集」も参照。
現場で一番効いた気づき: 表示上 CHAINRECFMT01 / WRITESCR02 のように命令と対象がくっついて見えるのは、 「予約語が優先されて動く」のではなく、固定形式の列位置で別欄に置かれているだけ。 現行資産は RPG III 列(Opcode 28–32)が多い。RPG IV 列だけ見ると 0件になる。 実装の主経路は tools/rpg_io_parse.py

列位置早見(実装と一致)

RPG III(1始まり)RPG IV
Form Type66
Factor118–2712–25
Opcode28–3226–35
Factor233–4236–49

ファイル名 vs レコード様式

命令Factor2に来やすいものCRUD寄せ先
CHAIN/READ/SETLL…ファイル名 or 様式ファイル(DDS突合)
WRITE/UPDAT/DELETレコード様式所属ファイルへ正規化
EXFMTDSPF様式画面(CRUD図では除外)
やってはいけないこと: ソースの空白圧縮・タブ化・一般フォーマッタ整形 / F仕様の IF/UF だけで CONFIRMED / HTMLやOCRだけを正本 / EXCEPT を無条件に DB CREATE 扱い。

実践キュレーション全文(2026-07-22)

正本: documents/IBM_i_解析_取り間違いやすい記法_キュレーション_20260722.md

IBM i / RPGCL 解析で取り間違いやすい記法(実践キュレーション)

- 社内キュレーション IBM_i_AS400_詳細解析_情報収集手順書_v1.1.md(§6.1.1 ほか)

- IBM Documentation: DSPPGMREF / QWHDRPPR(WHFUSG

- IBM ILE RPG Reference(C-spec 列位置)

- Midware RPG IV C-specs / MC Press(WRITE/UPDATE はレコード様式

- midrange.com RPG400-L(FILE vs FORMAT)

- 現行 SRC 実例(SRC\**\*.RPG


1. 最重要: 「CHAIN○○」は予約語優先ではない

現象(現行 SRC 実例)

表示上は空白が無く見える。

C           SSCODE    CHAINRECFMT01               11
C                     EXFMTSCR01
C                     WRITESCR02
C                     SETLLFILE01                99

正しい解釈

固定形式(RPG IV)では 列位置 が構文である。

RPG IV 列(1始まり)0始まり index
Form Type65
Factor 112–2511:25
Opcode(+ext)26–3525:35
Factor 236–4935:49
Result50–6349:63
Resulting indicators71–7670:76

CHAINRECFMT01 は「CHAIN という予約語が隣接識別子を食った」のではなく、

が隣接して 表示上つながって見える ことが多い。

解析器への実践ルール

  1. 第一優先: Form Type=C の行は列スライスで Opcode / Factor2 を取る(空白正規表現に依存しない)。
  2. 第二: OP_GLUEDCHAIN+識別子)はフォールバック。誤爆しやすい(CHAIN を含む長い名前等)。
  3. 空白圧縮・タブ化・行頭 trim したコピーは解析対象にしない。
  4. HTML/証跡に載せる引用は white-space: pre / コードフェンスで原文保持。

自由形式との違い

chain CustomerNo CustomerF;   // OK
chainCustomerNo CustomerF;    // 通常は1トークン扱いかエラー
chain(e)CustomerNo CustomerF; // 括弧で区切れる場合あり(可読性は悪い)

/FREE 行では列パーサを使わず、字句解析する。


2. ファイル名 vs レコード様式CRUD 誤りの本丸)

事実(外部記述ファイル)

命令Factor2 / オペランドに来やすいもの
CHAIN / READ / READE / SETLL / SETGTファイル名 または レコード様式
WRITE / UPDATE(UPDAT) / DELETE(DELET)原則 レコード様式(ファイル名ではない)
EXFMTレコード様式DSPF
EXCEPTO-spec の例外名(帳票・部分出力)。DB 直書きと誤認しやすい

現行資産での典型

→ 証跡の「対象」が FA011L01IFF仕様のファイル名)なのに、命令側は FA011R だけ、という 名前不一致PARTIAL の主因。

解析器への実践ルール

  1. DDS / DSPFFD から (ファイル名, レコード様式, PFILE) の対応表を必ず持つ(現行 load_lf_dds を強化)。
  2. WRITE/UPDAT/DELET は Factor2 がレコード様式でも、所属ファイルへ CRUD を寄せる
  3. EXCEPT は PRTF/O-spec か DB かを分け、DB の C と決め打ちしない。
  4. DSPPGMREFWHRFNMレコード様式)と WHFNAM/WHSNAM を突合する。

3. F仕様の罠(宣言だけ ≠ CRUD

よくある誤判定

F仕様の見え方やりがち正しい扱い
... IP ... DISKCONFIRMED READ宣言のみ → PARTIAL(操作命令待ち)
... UF ... DISKCONFIRMED UPDATE同上。更新可能宣言であり UPDATE 行が必要
... O ... DISKCONFIRMED CREATEWRITE/EXCEPT 行が必要
WORKSTN / DSPFDISK と同じ CRUD画面。EXFMT/WRITE 様式単位
RENAME(rec:alias)様式名不一致で見逃し別名表を作る
PREFIX / EXTFILE / EXTMBR静的名で確定実行時名は UNRESOLVED/推定

現行方針「F仕様だけでは CONFIRMED にしない」は正しい。維持する。


4. 命令の略称・別名(検索漏れ)

ソースに出やすい正規化先CRUD めやす
UPDATUPDATEU
DELETDELETED
BITOF / LOKUP(RPG III 残滓・変換途中)BITOFF / LOOKUPI/O ではないことが多い
READE / READP / READPEREADR
WRITE + EXFMT画面系R/C(DSPF

\bUPDATE\b だけだと UPDAT を落とす。現行 OP_PAT は両方あるが、列パーサ側の Opcode 正規化表も同じ集合にする。


5. 結果標識・条件付き I/O(行を捨てない)

C  N60                WRITESCR02                  61
C           SSCODE    CHAINRECFMT01               11

解析時に「標識付き行を雑に除外」すると CRUD が薄くなる。


6. CL・オーバーライド(ソース名 ≠ 実行時実体)

OVRDBF FILE(ORDERPF) TOFILE(LIB/REALPF) MBR(MBR01)
CALL PGM(ORD001)
DLTOVR FILE(ORDERPF)
静的に見える名実行時
ORDERPFREALPF / 別メンバの可能性

7. DSPPGMREFWHFUSG)の使い方 — 精度を上げる最短ルート

現行 OBJ情報/プログラム参照情報(DSPPGMREF).csv に既にある。

WHFUSG(ビット合成)

意味CRUD への寄せ方(めやす)
1InputR
2OutputC
3I/OR+C
4UpdateU
5I+UR+U
6O+UC+U
7I/O/UR+C+U
8Unspecified確定に使わない(CREATE/DROP 等も)
0N/A使わない
9–15上記+Unspecified下位ビットだけ採用し 8 は無視

主要列: WHPNAM(PGM), WHFNAM/WHSNAM(参照名), WHLNAM, WHRFNM(様式), WHFUSG, WHOBJT

推奨突合(成果物フォーマットは変えず)

  1. 証跡の PARTIALF仕様のみ)に対し、同一 PGM×同一ファイル系で WHFUSG∈{1..7} があれば

- 昇格はしないBob ルール: SRC 行番号必須のまま)

- ただしメモ/含意に「DSPPGMREF: WHFUSG=5 → コンパイル時は I+U」を追記し、確認先を明示。

  1. SRC で WRITE 様式 を検出したら、DSPPGMREFWHRFNM でファイルへ正規化して CONFIRMED
  2. ⑤の CRUD マトリクスは「SRC確定 ∪(明示ラベル付きで)PGMREF推定」を内部集計してもよいが、表の判定列は現行どおり SRC 優先。

8. COBOL・SQL・その他の取り違え

記法注意
READ ZS-STM INVALID ...ファイル名にハイフン。RPG 用正規表現だと落ちる
OPEN INPUT ZS / SELECT 名内部名と SELECT 名の対応が必要
embedded SQL INSERT INTODSPPGMREF に出ても WHFUSG=8 になりうる。SQL ソース精読が必要
QRYDFN / RUNQRYCALL ツリーに出ない。CL 逆引き必須(現行ツールあり)
CALL 変数 / CALLP静的閉包に出ない → UNRESOLVED

9. 列パーサ疑似コード(実装指針)

OPS = {
    "CHAIN": "R", "READ": "R", "READE": "R", "READP": "R", "READPE": "R",
    "SETLL": "R", "SETGT": "R", "EXFMT": "R",
    "WRITE": "C", "EXCEPT": "C",
    "UPDAT": "U", "UPDATE": "U",
    "DELET": "D", "DELETE": "D",
}

def parse_fixed_c_spec(line: str) -> dict | None:
    # 注意: タブ展開禁止。短行は右側を空白パディングしてからスライス
    if len(line) < 6 or line[5].upper() != "C":
        return None
    if len(line) > 6 and line[6] == "*":
        return None
    padded = line.ljust(80)
    op = padded[25:35].strip().upper()
    # opcode extender: CHAIN(E) 等 → 括弧除去
    op = re.sub(r"\(.*\)$", "", op)
    if op not in OPS:
        return None
    return {
        "factor1": padded[11:25].strip().upper(),
        "op": op,
        "factor2": padded[35:49].strip().upper(),
        "result": padded[49:63].strip().upper(),
        "crud": OPS[op],
    }

自由形式・CL・COBOL は別パーサ。固定形式に \bCHAIN\s+(\w+) だけ頼らない。


10. チェックリスト(解析バッチ投入前)


11. 出典(一次情報)

  1. IBM Docs — Displaying objects used by programs (DSPPGMREF usage codes)
  2. IBM Support — QADSPPGM / QWHDRPPR field list(WHFUSG 説明)
  3. IBM ILE RPG Reference — Calculation specification column layout
  4. Midware — RPG IV C-specs(Opcode 26–35, Factor2 36–49)
  5. MC Press — Using Keys and Output Opcodes in /Free(WRITE/UPDATE は record format)
  6. 社内手順書 v1.1 §6.1.1(空白連結の誤解の否定)

12. 現行実装との対応(要約)

項目現状推奨
OP_GLUEDあり(有効)列パーサを主、GLUED は副
F仕様のみ PARTIAL正しい維持
DDS 突合一部WRITE 様式→ファイル必須化
DSPPGMREF取得済・レポートに薄いWHFUSG/WHRFNM を昇格判定の補助+メモに常時
業務意味機能一覧・メニュー・画面ワイヤーデータ系(PFILE)単位の業務ラベルを用語集と接続

手順書 v1.1 から抜粋 — §6.1.1 固定形式の空白

正本: documents/IBM_i_AS400_詳細解析_情報収集手順書_v1.1.md

6.1.1 固定形式RPGにおける命令コードと空白の扱い

固定形式RPGでは、CHAINREADWRITEUPDATEEXSR等が「予約語として周囲の文字より優先的に認識される」ため動作するわけではない。

コンパイラーは、行内の列位置を基準として、各部分を別の欄として読み取る。

概念的には次のように分かれている。

仕様タイプ | 条件標識 | 演算項目1 | 命令コード | 演算項目2 | 結果フィールド | 結果標識

例えば、等幅フォント上では次のように見えるコードがある。

C     CUSTOMERNO    CHAIN     CUSTOMERF

これは空白文字を単なる区切りとして解釈しているのではなく、CUSTOMERNOCHAINCUSTOMERFが、それぞれ所定の列範囲に置かれているため認識される。

したがって、画面表示、HTML変換、PDF変換、OCR、CSV化等によって空白が詰まり、次のように見えたとしても、

CUSTOMERNOCHAINCUSTOMERF

元のソース上で各文字が正しい列に存在していれば、コンパイル時には別々の欄として解釈される。

この場合の正しい理解は次のとおりである。

> 「書き方として不適切だが、予約語が優先されて動く」のではない。

> 「固定形式の列定義に従った正常な記述であり、表示上は空白が少なく見えることがある」。

自由形式RPGとの違い

自由形式RPGでは、列位置ではなく、空白、括弧、演算子、セミコロン等による字句の区切りが重要になる。

chain CustomerNo CustomerF;

次のように命令コードと識別子を連結すると、通常はCHAIN命令とCustomerNoには分解されない。

chainCustomerNo CustomerF;

これはchainCustomerNoという一つの識別子として扱われるか、構文エラーになる可能性がある。

括弧が字句の境界になる次の記述は解析できる場合がある。

chain(e)CustomerNo CustomerF;

ただし、可読性と保守性のため、次のように空白を入れる。

chain(e) CustomerNo CustomerF;

固定形式か自由形式かを判断する目安

判定項目固定形式自由形式
仕様タイプ行頭付近のHFDICOPctl-optdcl-fdcl-s
列位置構文上の意味を持つ原則として意味を持たない
文末セミコロンを使用しない旧形式が中心セミコロンが必要
命令位置命令コード欄に配置行内の任意位置
空白圧縮ソース破壊につながるトークン境界を保てば影響が小さい
自動整形原則禁止、専用パーサーが必要RPG対応フォーマッターなら可能

AI・変換ツールへ渡す際の必須ルール

固定形式RPGを解析、変換、検索、AI投入する場合は、次を守る。

  1. 元ソースの1行を固定長のまま保存する。
  2. 行頭からの列番号を保持する。
  3. タブ文字へ変換しない。
  4. 連続空白を1文字へ圧縮しない。
  5. 行頭・行末の空白を自動削除しない。
  6. 比例フォント表示だけを根拠に構文を判断しない。
  7. OCR結果だけで解析を確定しない。
  8. HTMLではwhite-space: preまたはpre-wrapを使用する。
  9. Markdownではコードフェンス内に原文を保持する。
  10. CSV化する場合も、元行、列開始位置、列終了位置を別途保持する。
  11. 自由形式へ変換する場合、変換前後をコンパイルし、外部記述、標識、命令拡張子を比較する。
  12. 元ソースと「人間向けに整形した表示用ソース」を別ファイルとして管理する。

推奨する固定形式の構造化データ

{
  "sourceLineNumber": 245,
  "rawLine": "C     CUSTOMERNO    CHAIN     CUSTOMERF",
  "specificationType": "C",
  "factor1": "CUSTOMERNO",
  "operationCode": "CHAIN",
  "factor2": "CUSTOMERF",
  "resultField": "",
  "resultIndicators": [],
  "parserMode": "FIXED_FORMAT",
  "columnLayoutVersion": "RPG_IV"
}

rawLineは整形せず、抽出した原文をそのまま保存する。

列ずれを疑う条件

次の場合は、ソースの破損または変換ミスを疑う。

列ずれが疑われる場合は、ソース物理ファイルの元メンバー、コンパイルリスト、SEUまたはRDi上の列ルーラーを基準に再確認する。

手順書 v1.1 から抜粋 — §6.7 ネイティブI/O

6.7 ネイティブI/O

抽出対象:

CHAIN
SETLL
SETGT
READE
READPE
READ
READP
WRITE
UPDATE
DELETE
EXCEPT
OPEN
CLOSE
UNLOCK
FEOD

各命令について記録する。

対象ファイル
対象レコード様式
キー値
キー項目順
部分キーか完全キーか
昇順/降順
検索開始位置
ループ条件
%FOUND
%EOF
%EQUAL
%ERROR
レコードロック
例外拡張子(E)
結果インジケーター
更新対象項目
コミットメント制御

setll (CustomerNo) CustL1;
reade (CustomerNo) CustL1;
dow not %eof(CustL1);
   // 処理
   reade (CustomerNo) CustL1;
enddo;

このコードを解析するときは、次が必要になる。

  1. CustL1の実体。
  2. LFのキー順。
  3. 複合キーのどこまで指定しているか。
  4. SELECT/OMIT条件。
  5. アクセスパスの昇降順。
  6. レコード様式名。
  7. オーバーライドの有無。
  8. ジョブのライブラリー・リスト。
  9. ロック待ち時間。
  10. 読取後の更新有無。
← 5. プロンプト全文 — Codex査読7. CRUD図・テーブル定義書・HTML →