IBM i / AS400 解析・リバース — 最良の手順と手法(匿名化公開用)
rpg_io_parse.py 側に反映済みの部分と、
今後の厚み付け候補(SQL・インジケーター・エラー処理)が混在する。
解析前に次を判定する。
| 種類 | 特徴 |
|---|---|
| RPG II/III | 非常に古い仕様、位置依存、サイクル依存 |
| RPG/400 | H/F/E/I/C/O仕様、インジケーター多用 |
| RPG IV固定形式 | H/F/D/I/C/P仕様、列位置依存 |
| RPG IV混在形式 | 固定形式+/FREE |
| 完全フリーフォームRPG | **FREE、ctl-opt、dcl-f、dcl-s等 |
| SQLRPGLE | /EXEC SQLまたはexec sqlを含む |
| ILE RPG | モジュール、プロシージャ、サービスプログラム、活動化グループ |
固定形式RPGでは、単純に空白を削除したり整形したりしない。列位置そのものが構文の一部である。
固定形式RPGでは、CHAIN、READ、WRITE、UPDATE、EXSR等が「予約語として周囲の文字より優先的に認識される」ため動作するわけではない。
コンパイラーは、行内の列位置を基準として、各部分を別の欄として読み取る。
概念的には次のように分かれている。
仕様タイプ | 条件標識 | 演算項目1 | 命令コード | 演算項目2 | 結果フィールド | 結果標識
例えば、等幅フォント上では次のように見えるコードがある。
C CUSTOMERNO CHAIN CUSTOMERF
これは空白文字を単なる区切りとして解釈しているのではなく、CUSTOMERNO、CHAIN、CUSTOMERFが、それぞれ所定の列範囲に置かれているため認識される。
したがって、画面表示、HTML変換、PDF変換、OCR、CSV化等によって空白が詰まり、次のように見えたとしても、
CUSTOMERNOCHAINCUSTOMERF
元のソース上で各文字が正しい列に存在していれば、コンパイル時には別々の欄として解釈される。
この場合の正しい理解は次のとおりである。
> 「書き方として不適切だが、予約語が優先されて動く」のではない。
> 「固定形式の列定義に従った正常な記述であり、表示上は空白が少なく見えることがある」。
自由形式RPGでは、列位置ではなく、空白、括弧、演算子、セミコロン等による字句の区切りが重要になる。
chain CustomerNo CustomerF;
次のように命令コードと識別子を連結すると、通常はCHAIN命令とCustomerNoには分解されない。
chainCustomerNo CustomerF;
これはchainCustomerNoという一つの識別子として扱われるか、構文エラーになる可能性がある。
括弧が字句の境界になる次の記述は解析できる場合がある。
chain(e)CustomerNo CustomerF;
ただし、可読性と保守性のため、次のように空白を入れる。
chain(e) CustomerNo CustomerF;
| 判定項目 | 固定形式 | 自由形式 |
|---|---|---|
| 仕様タイプ | 行頭付近のH、F、D、I、C、O、P | ctl-opt、dcl-f、dcl-s等 |
| 列位置 | 構文上の意味を持つ | 原則として意味を持たない |
| 文末 | セミコロンを使用しない旧形式が中心 | セミコロンが必要 |
| 命令位置 | 命令コード欄に配置 | 行内の任意位置 |
| 空白圧縮 | ソース破壊につながる | トークン境界を保てば影響が小さい |
| 自動整形 | 原則禁止、専用パーサーが必要 | RPG対応フォーマッターなら可能 |
固定形式RPGを解析、変換、検索、AI投入する場合は、次を守る。
white-space: preまたはpre-wrapを使用する。{
"sourceLineNumber": 245,
"rawLine": "C CUSTOMERNO CHAIN CUSTOMERF",
"specificationType": "C",
"factor1": "CUSTOMERNO",
"operationCode": "CHAIN",
"factor2": "CUSTOMERF",
"resultField": "",
"resultIndicators": [],
"parserMode": "FIXED_FORMAT",
"columnLayoutVersion": "RPG_IV"
}
rawLineは整形せず、抽出した原文をそのまま保存する。
次の場合は、ソースの破損または変換ミスを疑う。
0とO、1とI、標識欄が誤認されている。列ずれが疑われる場合は、ソース物理ファイルの元メンバー、コンパイルリスト、SEUまたはRDi上の列ルーラーを基準に再確認する。
各プログラムについて、次を作成する。
プログラム概要
入力
出力
更新ファイル
参照ファイル
呼出元
呼出先
外部API
画面
帳票
メッセージ
データエリア
データキュー
IFS
コミット単位
例外処理
業務ルール
日付処理
文字コード処理
並行実行・ロック
性能上の注意
未確定事項
確認対象:
DFTACTGRP
ACTGRP
OPTION
BNDDIR
THREAD
CCSID
DATFMT
TIMFMT
DECEDIT
SRTSEQ
LANGID
ALWNULL
DEBUG
COPYNEST
EXPROPTS
MAIN
NOMAIN
確認観点:
ファイルごとに次を抽出する。
RPG上のファイル名
外部記述/プログラム記述
入力/出力/更新/組合せ
キー付き/キーなし
DISK/WORKSTN/PRINTER/SPECIAL
USROPN
EXTFILE
EXTMBR
RENAME
PREFIX
IGNORE
INCLUDE
COMMIT
INFDS
INDDS
RECNO
SFILE
MAXDEV
HANDLER
| 項目 | 例 |
|---|---|
| RPG名 | CUSTL1 |
| 宣言名 | CUSTL1 |
| コンパイル時ライブラリー | DBLIB |
| オブジェクトタイプ | LF |
| レコード様式 | CUSTR |
| 利用方法 | READ、UPDATE |
| キー | CUSTOMER_NO |
| 実行時オーバーライド | 有/無/不明 |
| 実行時実体 | TESTLIB/CUSTL1 |
| 根拠 | DSPPGMREF+OVRDBF+ジョブログ |
| 信頼度 | 確定 |
抽出対象:
DCL-S
DCL-C
DCL-DS
DCL-PR
DCL-PI
DCL-PARM
DCL-SUBF
LIKEDS
LIKEREC
LIKE
QUALIFIED
TEMPLATE
DIM
OCCURS
BASED
POINTER
OBJECT
VARYING
CONST
VALUE
OPTIONS(*NOPASS:*OMIT:*VARSIZE)
INZ
STATIC
EXPORT
IMPORT
CTDATA
FROMFILE
確認観点:
LIKERECの入力・出力・全フィールドの違い。抽出対象:
IF / ELSEIF / ELSE
SELECT / WHEN / OTHER
DOU / DOW / FOR
ITER / LEAVE
MONITOR / ON-ERROR
RETURN
GOTO / TAG
EXSR / BEGSR / ENDSR
CALL / CALLP
プロシージャ呼出
作成するもの:
抽出対象:
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;
このコードを解析するときは、次が必要になる。
CustL1の実体。抽出対象:
SELECT
INSERT
UPDATE
DELETE
MERGE
CALL
VALUES
SET
DECLARE CURSOR
OPEN
FETCH
CLOSE
PREPARE
EXECUTE
EXECUTE IMMEDIATE
COMMIT
ROLLBACK
SAVEPOINT
CONNECT
SET OPTION
GET DIAGNOSTICS
WHENEVER
各SQLについて記録する。
静的SQL/動的SQL
対象スキーマ
対象表・ビュー
列
JOIN
WHERE
GROUP BY
HAVING
ORDER BY
分離レベル
コミット
カーソル
ロック
ホスト変数
NULL処理
SQLCODE
SQLSTATE
GET DIAGNOSTICS
動的に生成される部分
実行計画取得可否
SET OPTION NAMING=*SYSと*SQL。CURRENT SCHEMA、CURRENT PATH。DFTRDBCOL。CLOSQLCSR。COMMIT指定。区別して記録する。
| 呼出方式 | 例 | 名前解決 |
|---|---|---|
| 外部プログラム静的名称 | CALLP SomePgm(...)、EXTPGM('ABC') | 実行時ライブラリー検索 |
| 動的プログラム名 | 変数、API、コマンド文字列 | 実行時のみ確定 |
| バインド済みプロシージャ | EXTPROC | バインド情報 |
| サービスプログラム | BNDDIR、BNDSRVPGM | バインド時 |
| コマンド実行 | QCMDEXC、system() | 文字列解析が必要 |
| SQLプロシージャ | CALL schema.proc | SQLパス・命名規則 |
| API | QSYS API等 | パラメーター形式も解析 |
QCMDEXCへ渡す文字列。CALL PGM(を組み立てる処理。CEERAN0等の動的解決API。CALL文を動的生成する箇所。古いRPGでは、次を一覧化する。
*IN01~*IN99
*INLR
*INRT
*INH1~*INH9
*INKA~*INKY
ファイル状態インジケーター
結果インジケーター
制御レベル
表示ファイル応答インジケーター
| 番号 | 設定箇所 | 解除箇所 | 参照箇所 | DDS用途 | 意味 | 信頼度 |
|---|---|---|---|---|---|---|
| 03 | 検索エラー時 | 初期化時 | 画面出力前 | ERRMSG表示 | 顧客未登録 | 確定 |
| 12 | 不明 | 不明 | EXSR条件 | なし | 未確認 | 未確定 |
確認対象:
UDATE
*DATE
%DATE
%TIME
%TIMESTAMP
%DIFF
%SUBDT
%YEARS等
MOVE / MOVEL
TEST(D/E/T)
TIME
日付8桁・6桁
和暦
年度
締日
ゼロ日付
数値化日付
CCSID変換
EBCDICゾーン
外字
全角・半角
末尾空白
特に古いRPGでは、日付が数値・文字列・ゾーン10進数で管理されることがある。項目名だけで日付と断定せず、利用箇所と値例を確認する。
抽出対象:
MONITOR / ON-ERROR
(E)拡張
%ERROR
INFDS
PSDS
INFSR
*PSSR
SQLCODE
SQLSTATE
GET DIAGNOSTICS
SNDMSG
SNDPGMMSG
QMHSNDPM
RETURN
SETON LR
ROLLBACK
確認する情報:
*PSSRで一律正常終了していないか。SQLCODE < 0だけで扱い、警告を無視していないか。