こんにちは!メインフレームの世界へようこそ。
JavaやCOBOLといった他のモダンな言語の経験がある方にとって、IBMの汎用機(メインフレーム)やPL/Iという言語は、どこか要塞の壁のように分厚く、近づきがたい雰囲気に感じられるかもしれませんよね。
「なんだか古い暗号みたい……」
「コンパイルエラーが出たらどうしよう……」
そんな風に身構えてしまうお気持ち、とてもよく分かります。でも、安心してください。一つひとつの仕様を紐解いていけば、PL/Iは非常にロジカルで、作り手の意図に素直に従う可愛い奴なんです。
今回は、そんなPL/Iの基本構文の裏側を覗き見しつつ、「LISTコンパイラオプション」を使ってソースコードが最終的にどんなアセンブラ(機械語)に生まれ変わるのかを、一緒に優しく紐解いていきたいと思います。レガシーシステムの深淵を覗く旅の始まりです!
—
1. 他の言語とはちょっと違う?PL/Iの命名規則と「予約語がない」世界
JavaやCOBOLを触ってきた方なら、「この単語はシステム専用だから変数名に使っちゃいけないんだよな(予約語)」という制約に、何度も悩まされた経験があるのではないでしょうか。
例えば、COBOLでは `IF` や `MOVE`、`DISPLAY` などの動詞はすべて予約語としてガチガチに固められています。しかし、PL/Iの非常にユニーク(そして最初はちょっと戸惑う)な点として、「PL/Iには厳密な意味での予約語が存在しない」という特徴があります。
「えっ、じゃあ `IF` という名前の変数を作れちゃうの?」
その通りなんです。PL/Iのコンパイラは、その単語が書かれている「文脈(コンテキスト)」を見て、それが命令なのか変数名なのかを賢く判断しています。
1
/ 怖がらなくて大丈夫!文脈で判断してくれる優しい世界 /
DECLARE IF FIXED BINARY(31); / 「IF」という名前の整数型変数を定義 /
IF = 10; / 変数IFに10を代入 /
IF IF = 10 THEN / 最初のIFは命令、2つ目のIFは変数! /
PUT SKIP LIST(‘十です’);
なんだかちょっと魔法みたいですよね。「予約語がない」なんて聞くとコンパイラが混乱しそうに思えますが、長年金融や流通の基幹システムを支えてきたIBMのコンパイラは優秀です。ただ、現場の保守性を考えると、わざわざ `IF` なんていう紛らわしい変数名をつける人はいませんのでご安心を(笑)。
—
2. LISTコンパイラオプションとは?〜ソースとアセンブラの架け橋〜
さて、本題に入りましょう。
私たちが普段書いたPL/Iのソースコードは、コンパイラによってIBMメインフレームが直接理解できる「機械語(マシン語)」へと翻訳されます。
ここで登場するのが、`LIST` コンパイラオプションです。
コンパイル時に `LIST` を指定すると、コンパイルリスト(SYSPRINT)の中に、「自分が書いたPL/Iのソースコード」と「それに対応するアセンブラ(マシン語のニーモニック表現)」が対になって出力されます。
「なぜアセンブラなんて見る必要があるの?」と思われるかもしれませんが、バッチ処理の性能チューニングや、どうしても原因が分からないメモリ破壊のデバッグ、あるいは「この書き方をするとコンパイルが余計なコードを吐いていないか?」を確認する際、このアセンブラ対照図が最強の武器になるのです。
コンパイルリストのイメージを覗いてみよう
実際に `LIST` オプションを有効にしてコンパイルした際に出力されるリストのイメージを、少しだけ覗いてみましょう。
Loc Object Code Source Statement
000000 4110C000 DCL 1 W_KKAZEI FIXED BIN(31) INIT(0);
5810C000 W_KKAZEI = W_KKAZEI + 100;
000004 5A10C000
左側にある `4110C000` や `5810C000` といった呪文のような数字と英字の組み合わせが、マシン語(オブジェクトコード)です。そしてその右側に、私たちが書いた見慣れたPL/Iの文(ソースステートメント)が並んでいます。
「自分が書いたたった1行の足し算が、アセンブラの世界ではどう翻訳されているのか?」を突き合わせることで、コンパイラの挙動を生々しく実感できるというわけです。
—
3. 実践!PL/Iコードと生成アセンブラの対照検証
では、もう少し具体的な実務を想定したコードで、その挙動を検証してみましょう。
以下のサンプルコードは、売上金額に税率を掛け合わせて、結果を整えるだけのシンプルな処理です。
1
/ ======================================================== /
/ プログラム名: CALCTAX /
/ 概要 : 簡易的な税額計算を行うサンプル /
/ ======================================================== /
CALCTAX: PROC OPTIONS(MAIN);
/ データストレージ属性の宣言 /
DCL W_URISAGE FIXED DEC(9,2) INIT(12345.67); / 売上(固定小数点) /
DCL W_ZEIRITSU FIXED DEC(3,2) INIT(0.10); / 税率(10%) /
DCL W_ZEIGAKU FIXED DEC(9,2); / 税額格納用 /
/ 演算処理の実行 /
W_ZEIGAKU = W_URISAGE W_ZEIRITSU;
/ 結果の出力 /
PUT SKIP LIST(‘計算された税額は:’, W_ZEIGAKU);
END CALCTAX;
ここで注目したいポイント
JavaやCOBOLから来た方は、`FIXED DEC(9,2)` という見慣れないデータ宣言に少し戸惑うかもしれません。これは「パック十進数(Packed Decimal)」と呼ばれる、メインフレーム特有のデータ形式です。
金融計算で大敵となる「浮動小数点誤差」を絶対に発生させないために、ビジネス計算ではこのパック十進数が好んで使われます。
このコードを `LIST` オプション付きでコンパイルし、出力されたアセンブラコードを眺めてみると、コンパイラが裏側で何をしているのかが見えてきます。
1. パック乗算命令の生成:
Javaであれば単純な “ 演算子ですが、アセンブラレベルでは `MP(Multiply Packed)` といった、メインフレームのハードウェア(CPU)が持つ専用の十進演算命令に翻訳されます。
2. レジスタとストレージの往復:
ワーキングストレージ(メモリ上の領域)からデータを汎用レジスタや浮動小数点(あるいは十進演算用)のワークエリアにロードし、計算してストアする一連の流れが、アドレス(Loc)の進み具合とともに手に取るように分かります。
「あ、この一行の裏で、ハードウェアはこれだけのステップ数を動いているんだな」という感覚を掴むことが、アーキテクトとしての第一歩になります。
—
4. おわりに:レガシーの裏側を恐れず楽しもう
いかがでしたでしょうか?
「LISTコンパイラオプションによるソースとアセンブラの対照」と聞くと、なんだか冷徹で難解な技術に思えたかもしれませんが、要するに「自分が書いたプログラムが、機械の中でどう翻訳されているかのお手紙を読むこと」です。
PL/Iという言語は、一見すると歴史の重みを感じさせる独特な構文をしていますが、その背後にあるコンパイラの賢さや、メインフレームのハードウェア構造を知れば知るほど、実に合理的に、そして堅牢に設計されていることに気づかされます。
「レガシーだから怖い」なんて思わず、ぜひご自身の開発環境でも `LIST` オプションをフリックして、コードとアセンブラの対話を楽しんでみてくださいね。基幹システムの世界が、少しだけ身近で面白いものに変わるはずです。
それでは、次回のメインフレーム・アーキテクチャ解説でお会いしましょう!
