AS/400(IBM i)モダナイゼーション ― SlimeCL / SlimeRPG でできること・できないこと
正直な、実機 corpus に基づく解説です。以下の数字は実在する公開 IBM i ソース由来で、都合よく選んだ demo ではありません。できない所も公開します ― 透明性こそが moat だからです(競合は multi-target の合格率自体ほとんど公表しません)。
レガシー資産(古い言語のプログラム)を、意味を変えずに現代へ運ぶ製品です。ふつうの書き直しは気づかぬうちに中身がズレて事故になりますが、意味を解釈せず「骨組み(構造)」だけをそのまま写すので計算の中身が元と変わりません。動くことを"証明"してから渡すので移行の不安が消えます。写せる所だけ正直に写し、できない所は隠さず分けます。
手で書き直すと、数値計算や例外の細かな違い(境界条件)で挙動がズレ、その確認(新旧比較テスト)に膨大な人件費がかかります。言語特有のトラップまで忠実に写し、差分テストで「ズレゼロ」を実証、独立した参照実装で裏付け。成果物は人手の UAT でなく機械検証可能な「振る舞い不変の証明書」。誇張せず、対応できない部分は隠しません。
ソースを Slot IR(言語非依存の構造中間表現)へ射影し、構造を保存したままターゲットへ転写。静的に決まる核は bit-exact に、動的・状態依存は隔離帯へ正直に分離(isolate, don't confabulate)。差分ファジング + 適用可能箇所での形式手法で裏付け、第三者が手元で再現できる決定論的検証を提供します。
意味論でなく一意な構造として射影(π)。primitives はビットベクタ理論で厳密化し全入力で形式検証、合成・ループ等は Csmith 流差分ファジングで担保する二層保証。再現しない計算は意味同値+収束+残差の③層へ。「形のある所は bytes で、形のない所は意味で。どちらの面でも嘘をつかない」 ― SlimeNENC の机。
📋 「このレベルで AI に質問」= 選んだ解像度に合った指示つきで、このページの解説をコピーします。お手元の AI(Claude · GPT · Gemini · Grok 等)に貼れば、その目線でさらに深掘りできます。
実機ソースで計測(demo ではなく)
RPG(SlimeRPG → Java/runtime)
| 段階 | 結果 | 読み方 |
|---|---|---|
| 字句解析(lex) | 99.4%(1,701 / 1,711) | 固定形式 RPG/400 含め実機 RPG をほぼ全部読める |
| emit(出力生成) | 99.8% | crash せず構造化変換 |
| javac compile(標本) | 約82% | 正直な穴 ― 周辺 RPG(BIF・cursor 項目)が未完 |
| hang | 0 / 1,711 | emitter 無限ループ 10 件を発見・修正(DO-UNTIL / MONITOR / inline データ構造) |
CL(SlimeCL → bash / Rust)
| 段階 | 結果 | 読み方 |
|---|---|---|
| 字句解析(lex) | 100%(46 / 46) | 実機 CL を全部読める |
| emit | 100%(46 / 46)、hang 0 | 固まらない・落ちない |
| bash 構文OK | 100%(46 / 46) | CL のコマンド連携的な性質に bash が最も自然 |
| Rust compile | 100%(46 / 46) | この公開 corpus の全プログラムが 両 target に compile |
本イテレーション(2026-05-26)、同一 corpus で Rust compile は 69.6% → 100%、bash は 76.1% → 100% に上昇。shim 追加ではなく(未対応コマンドは元々コメントとして compile する)、古い CL の方言 ― 位置パラメータ形式(CHGVAR &X '1'・DCL (&X) (*CHAR)・位置形式 IF/THEN)、予約語の変数名(&Type)、部分文字列代入(CHGVAR %SST(&v s l))、記号比較演算子(= > <)、暗黙 DCLF *CHAR フィールド、%BIN、特殊値(*YES)、*CHAR↔*DEC 双方向変換、Rust の所有権(借用 vs move)、そして DDS 前段(DCLF の record フィールド型を .DSPF/.PF 定義から直接読む ― BMS / XMAP map parser と同じ positional 抽出の発想)― への emitter 対応による。各修正は無回帰を確認(29 unit tests + 4/4 bit-exact)。bitexact/measure_compile.sh で再現可能。
実機 IBM i で bit-exact 検証 ✓ 新
原 CL を実機 IBM i(7.5、PUB400.com)でコンパイル・実行し、その出力を SlimeCL が吐いた bash と Rust の出力とバイト単位で比較しました。これまで「未公開」としていたマイルストーンです。達成しました。
実機 IBM i == SlimeCL bash == SlimeCL Rust がバイト単位で一致。
| プログラム | 実機 IBM i | SlimeCL bash | SlimeCL Rust | |
|---|---|---|---|---|
countdown(1..5 の和、*DEC→*CHAR) | 00000000000000000015 | 00000000000000000015 | 00000000000000000015 | PASS |
exprdemo(括弧・*AND・*CAT) | OK | OK | OK | PASS |
sstdemo(%SST 部分文字列) | HELLO | HELLO | HELLO | PASS |
dtaara(データエリア + ALCOBJ/DLCOBJ) | HELLO | HELLO | HELLO | PASS |
ebcdic('A' *LT 'a' ― EBCDIC 照合) | GE | GE | GE | PASS |
binconv(%BIN('//') ― big-endian *INT2) | …24929 | …24929 | …24929 | PASS |
後の2本は compile は通るが実機で裏で揺れる Runtime Gap を封じたもの:*CHAR 比較は EBCDIC 照合(小文字 < 大文字 < 数字 ― ASCII の逆順)を使うので 'A' *LT 'a' は実機で 偽(→ GE)、ASCII 文字列比較の素朴な「真」ではない。%BIN はフィールドのバイトを big-endian 符号付き整数(*INT2/*INT4)として読む(ホストの little-endian ではない)。どちらも IBM i のセマンティクスに束縛し、上記でバイト単位検証済み。
価値があるのは実機が炙り出したもの ― 合成テストでは絶対に出ない fidelity gap を見つけ、修正した点です:
- 固定長
*CHAR:IBM i の文字フィールドは宣言長まで空白パディングされるため、20 バイトの&MSG *CAT '!'は!がフィールド末尾から溢れて消えOKになる。SlimeCL は*CHARを可変長文字列扱いしていた(OK!)。修正済 ― 両 target が固定長を再現。 *DEC→*CHAR変換:パック10進の合計を文字フィールドに代入すると、フィールド全幅へ右詰め・ゼロ詰めされる(00000000000000000015)。SlimeCL は素の15を出していた。修正済。SNDPGMMSG MSG()は*CHARを要求し、CALLの char↔packed パラメータ型整合は数値を静かに壊し得る。どちらも初回接続で露出し、文書化済。
正直な適用範囲。 これは代表3本であって全 corpus ではありません。要点は手法:各プログラムを実機 IBM i でコンパイル・実行し、出力を両 target と diff する再現可能な harness です。本数の拡大は継続作業。実機・バイト単位の transpiler 検証を公開している競合を我々は知りません。
5250 画面ハーネス ― 実機セッションを丸ごと再現 ✓ 新
バッチ出力の bit-exact に続き、対話画面(5250)も実機で再現できるようにしました。スクリプタブルな 5250 クライアントは既製品が無いため、std のみ・外部ライブラリゼロの Rust(JAVATEL の no-external-lib スタックに整合)でヘッドレス・クライアント s5250 を実装。実機 IBM i(PUB400.com)に対し認証セッションを丸ごと駆動し、各パネルを 24×80 グリッドへ再構成します。
SIGNOFF でクリーンに切断(セッションを放置しない)。
--- 実機 PUB400 から再構成したメインメニュー ---
MAIN IBM i Main Menu
System: PUB400
Select one of the following:
1.User tasks ... 9.Display a menu
90.Sign off
Selection or command
===>
F3=Exit F4=Prompt F9=Retrieve F12=Cancel ...
(C) COPYRIGHT IBM CORP. 1980, 2021.
プロトコルの実地知見(rigor の裏付け): インバウンドにも 10 バイトの GDS ヘッダが必要 ― 欠落するとホストが先頭バイトをレコード長と誤読して接続を切る。サインオン成功後、メニュー送出の前にホストがデバイス Query を投げるため、Query Reply を返さないと無応答(hang に見える)。サインオン画面の「Server name / Subsystem」等は入力フィールド(SF)ではなく SBA 書きのリテラルで、SF/FFW 解析が入力欄と見出しを切り分ける。QMAXSIGN を尊重 ― 正しい資格情報のみ送出し、形式の検証は資格情報無しの probe で行った。
SNDRCVF で全定数パネルを表示)を s5250 でメニューから CALL し、表示されたパネルを scrape。同じ DDS を SlimeGENBA-LUI が描いたグリッドと、正規化 24×80 テキストで diff → PASS(実機の画面 == レンダ、行単位一致)。バッチ出力の 6/6 bit-exact に対応する、画面レベルの bit-exact です。
== P1 L2 screen diff: live DCLF panel (real IBM i) vs DDS render ==
=> PASS (L2 bit-exact: live panel == DDS render)
SlimeCL P1 -- DCLF panel
Rendered from DDS constants.
Live via s5250 (5250/TELNET).
Same DDS via SlimeGENBA-LUI.
Diff = L2 screen bit-exact.
Press Enter to exit.
IF &IN03 RETURN が発火し、PAGE2 ではなくメニューへ早期復帰。キーが別々の意味を正しく運んでいます(空打ちではない)。
== P2 keystroke + multi-panel L2 diff (real IBM i) vs DDS render ==
panel 0 (MAIN): => PASS (L2 bit-exact)
panel 1 (PAGE2): => PASS (L2 bit-exact)
panel 2 (PAGE3): => PASS (L2 bit-exact)
== result: 3/3 panels L2 bit-exact ==
P3FIX を読んで計算・表示。候補側は SlimeCL が同じ CL を変換し、emit したプログラムが同じ fixture(環境変数で注入)を読んで計算 → フィールド値をダンプ → SlimeGENBA-LUI が DSPF にその値を配置。両者を L2 比較 → 一致。fixture を 42 と 100 で変えても両側が追従(…042/…126、…100/…300)。変換ロジック + DDS レンダ == 実機画面が、計算値込みで成立 ― P1/P2 で保留した部分を埋めました。
== P3 fixture + computed-field L2 diff (fixture P3FIX=42) == => PASS (L2 bit-exact: live computed panel == DDS render with candidate values) SlimeCL P3 -- record count Active (RECA): 0000000042 <- fixture 42 Total (RECT): 0000000126 <- 42 * 3, computed by the transpiled logic
type:VALUE)し、プログラムがそれを読んで計算(char→dec、×3、dec→char)、結果を表示。候補側は同じ打鍵値を入力 fixture(環境変数で注入)として受け取り、L2 で一致(7→…021、15→…045)。5250 の入力欄は再表示時に内部構造付きで再送され表示桁がずれるという実機特性を発見したので、入力フォーマットと出力専用フォーマット(入力値のエコー + 結果)を分け、整列する出力面で diff しています ― 誤魔化さず正面から。
RTVMBRD で実ファイルの件数を取得・表示。候補側は同じ N レコードの fixture ファイルを数えて表示。両者 L2 一致(5・12 レコードで検証)。正直な適用範囲: これはファイルのメタ(件数)読みです(CL の 1-DCLF 制約下で実機がファイルを読む現実的な形)。レコード単位のフィールド読み(RCVF over DB ファイル)は SlimeTree-VSAM バックエンドで次段。== P4 field-input == == P4F file-fixture ==
=> PASS (typed 7 -> Result …021) => PASS (5 records -> RTVMBRD …005)
これが解く問題。 オペレータが見る画面こそ、Legacy UI を捨てさせない製品が再現すべきもの。本ハーネスは画面側の半分(実機からの再構成)で、もう半分の SlimeGENBA-LUI(DDS → 2層UI レンダ)と突き合わせ「実機の画面 == 変換後の画面」を画面単位で diff します ― それが上の P1〜P4F です。正直な適用範囲: 画面再構成(P0/P0.5)、L2 bit-exact(P1)、キーストローク+複数パネル(P2)、計算フィールド値(P3)、フィールド入力(P4)、ファイル fixture の件数読み(P4F)まで達成。レコード単位の DB ファイル読みは SlimeTree-VSAM 連携で次段、数値フィールドの DDS 編集コード・属性/色(L3)も次段。DBCS パネルは日本語 CCSID の実機が要る(EBCDIC 照合と同じ blocker)。
Transport の一般化 ― RS-232C のオフコンにも届く ✓ 新
画面の再構成はトランスポート非依存です ― 「端末データストリームを舐めて 24×80 グリッドに直す」だけなので、TCP の外にも伸ばせます。国産オフコン(富士通 ASP、NEC A-VX、日立 …)には、SSH も TCP/IP も無く RS-232C 一本でブロックモード端末をぶら下げているものが現役で残っています。クラウド移行ツールは、工場の片隅でシリアル一本で生きているこうした機械に物理的に到達できません。
extern "C" 宣言で叩き、libc も serialport クレートも使いません(SHA-256 や EBCDIC 表を自前実装する no-external-lib スタックと同じ流儀)。非 tty パスは replay モードで、録ったデータストリームを実機なしで再構成できます。
本物データで transport 非依存を実証。 PUB400 のサインオン画面を TELNET で録った データストリームを、sserial のシリアル/ファイル経路で replay すると、s5250 が TCP で出したのと同一のグリッドに再構成されます ― 同じデータストリーム・別トランスポート・同じ画面。「トランスポートは差し替え可能、画面の意味は一つ」を体現しています。
正直な適用範囲。 実オフコンにはまだ一台も接続していません。 今の dialect は 5250 で、上の実証は TELNET キャプチャの replay までです。各社のブロックモード方言(KEIS/JEF/JIPS のコード系を含む)には RFC が無く、最初の実シリアル回線キャプチャが仕様を決めます。実シリアルでの検証は、DBCS と同じく現物(または回線キャプチャ)を貸してくれる協力先が要る宿題です。骨格(トランスポート + 再構成コア)は出来ており、方言パーサを一つ足すだけで伸ばせる作りにしてあります。
今できること ✓
- 制御フロー:
IF/ELSE、DOWHILE/DOUNTIL/DOFOR、GOTO+ラベル(bash にも安全な Rust にも goto が無いため、プログラムカウンタ状態機械で厳密に再現)。 - プログラム内サブルーチン(
SUBR/CALLSUBR)→ 実関数化。CL の変数はプログラム大域なので忠実にモデル化(Rust=モジュール static + 関数、bash=大域変数上の関数)。 - 式:優先順位・括弧を正しく解析。
(&A *GT 5) *AND (&B *LT 3)、文字列連結*CAT、BIF%SST/%SCAN/%LEN/%TRIM/%CHAR/%UPPER/%LOWER。 - 型推論:
*DEC→ i64/f64、*CHAR→ String、*LGL→ bool。 - 古い CL の方言:位置パラメータ形式(
CHGVAR &X '1'、DCL (&X) (*CHAR))、記号比較演算子(=><≥≤¬=)、部分文字列代入(CHGVAR %SST(&v s l))、予約語の変数名。 - OS サービスの runtime shim:データエリア(
RTV/CHG/CRT/DLT DTAARA)はプロセス内ストアで実行、オブジェクトロック(ALCOBJ/DLCOBJ)・ファイル上書きは認識済。 - 単一の静的バイナリ(Rust)― 汎用 x86/Linux で動作、IBM i ランタイム不要、外部ライブラリ不要。
まだできないこと ✗(正直に)
- 次の課題は compile ではなく挙動検証。 46本すべて compile し、bit-exact は代表6本で検証済(EBCDIC 照合・big-endian
%BIN含む)。OS サービス実行(SBMJOB/RCVMSGは compile するが完全実行は未対応、データエリア・ロックは runtime shim)が正直な残課題。 - DBCS(日本語2バイト)照合 ― 単バイト EBCDIC 順序は実装・検証済だが、2バイト(IBM 漢字、CCSID 5026/5035)の順序は 日本語 CCSID の IBM i でないと bit-exact 検証できない(検証機は CCSID 273)― 未検証では出さない。
- 実機 RPG の約18%は compile しない ― BIF 網羅と cursor host 変数の型付け(SQLRPGLE)が未完。
- 全 corpus の挙動検証 ― 実機 IBM i での bit-exact 検証は代表セットで達成済(6/6、上記参照)。全 corpus への拡大が継続作業。
- DDS(表示ファイル / 5250):L2 bit-exact(P1)・複数パネル遷移(P2)・計算フィールド値(P3)・フィールド入力(P4)・ファイル fixture の件数読み(P4F)まで達成(上記)。残るはレコード単位の DB ファイル読み(SlimeTree-VSAM 連携)・数値編集コード・属性/色(L3)。DB2 for i の埋込 SQL 意味論・QUERY/400 は捕捉済みだが完全実行は未対応。
パイプライン
CL1 lexer → CL2 Slot IR + 式パーサ → CL6 emitter { bash | Rust } (COBOL/RPG/PL/I/MUMPS… JAVATEL 変換ファミリ共通の段構成)
例 ― サブルーチンを呼ぶ CL DOFOR ループが idiomatic な Rust に:
i = 1;
while i <= 5 {
subr_addit(); /* CALLSUBR SUBR(ADDIT) */
i += 1;
}
fn subr_addit() { unsafe { sum = sum + i; } } // プログラム大域変数
なぜ「できない所」も公開するか
Micro Focus・Blu Age・AWS MMA 等は target 別の compile 合格率自体ほとんど公表しません。私たちは実機 corpus で lex/emit/compile/hang を数値公開し、穴を名指しし、改善の track record も示します(1 session で hang 10→0)。この透明性こそ差別化です ― 結果を信頼せねばならない金融・公共・SI の評価者にとって、「信じてください 100% です」より「正直で、速く改善している」が効きます。
国産オフコン modernization 共同検証 ― 協力会社募集
富士通 ASP・NEC A‑VX・日立 など 現役の国産オフコンを、止めず・現場の操作を変えずに現代の実行系へ。クラウド移行ツール(AWS MMA・Blu Age 等)は SSH/TCP 前提で、RS‑232C のみの現役機には物理的に届きません。私たちはその現場を対象に、画面・データ・処理を 1 バイト単位で扱う実行系を作っています。
残るは貴社の実機 1 台。国産オフコン固有の通信フォーマットと日本語コード(KEIS83 / JEF 等)の現物確認だけが最後のピースです。ご協力は立会い・現地でも可 ― 実機への接続、画面/シリアル通信のキャプチャ、または DBCS データのサンプルのいずれかで結構です。
- 無償(0円):協力会社向けの modernization 共同検証 PoC に費用はいただきません。
- データ持ち出し不要:現地検証が可能。サンプルも最小限・匿名化で構いません。
- 現場を変えない:3270 / XMAP / MELT / OLF の端末操作・ブラインドタッチを 100% 維持。必要なら現代 UI を 追加するだけ(「脱却」「移行」ではなく「現場の延命・modernization」)。
富士通 ASP・NEC A‑VX・日立 等の国産オフコンを今も運用・保守されている事業者・SIer 様で、「動いているが人もツールも先細りで将来が不安」「RS‑232C しかなく移行検討がそもそも入口で止まっている」基幹システムをお持ちの方へ。実機が 1 台、開いてくれる協力先が 1 社 ― それで現場は次の 20 年へ進めます。
