C を育てた土台の B。その B は、何から来たのか
第5回で C は B から育ったと見て、最後に「では B は何から?」と残しました。答えは BCPL。1967年に Martin Richards が作った言語です。じつは Ken Thompson は最初 PDP-7 用に Fortran のコンパイラを書こうとし、メモリに収まらず、BCPL をぐっと簡略化して型なし(1語だけ)の B を作りました。そして BCPL には、今回の主役 ── O-code という中間コードがあった。第4回の EM で見た「真ん中を挟む」発想の、ずっと古い先祖です。この逃げ道こそ、鶏と卵をさかのぼる旅でくり返し現れる“移植の魔法”でした。
第5回の系図を、もう一段さかのぼります。C の祖先は一本道です。
B は「BCPL の意味を絞り込み、別の書き方に詰め込んだ」言語でした。最初期の PDP-7 版はスレッデッドコードにコンパイルされ、のちに Ritchie が TMG という道具(コンパイラを作るためのコンパイラ)を使って機械語を吐く B コンパイラを書いています。── 道具にもまた道具がある。輪は本当にどこまでも続きます。
BCPL がコンパイラ史に残る理由は、言語そのものよりコンパイラの作りにあります。Richards は BCPL のコンパイラを、はっきり二つ(実際は三段)に割りました ── 前半が原文を読んで O-code(機種非依存の中間コード)を吐き、後半がその O-code をその機種の機械語へ翻訳する。第4回の ACK/EM と、まったく同じ骨格です。
新しい機種に BCPL を移すとき、書き直すのはコンパイラの約 1/5(バックエンドだけ)。当時の見積もりで2〜5人月。残り 4/5(フロントエンド)は機種を知らないので、そのまま使い回せる。
結果、BCPL コンパイラはそれ自身が BCPL で書かれ、しかも移植が容易。だから当時「新しいシステムをブートストラップする定番の言語」になりました。Richards は2003年、この功績(「BCPL によるシステムソフトの移植性の先駆」)で表彰されています。まさに本シリーズのテーマそのものです。
中間コードの正体は、ソース言語と機械語のあいだに、“機種を知らない島”を一つ置くことです。フロントエンドは島まで運べばよく、機械のことを知らなくていい。機械の知識はバックエンドに隔離される。だから機種が変わっても、島から向こう(バックエンド)だけ架け替えればいい。
この「機種非依存の島」は、名前を変えて何度も現れます ── O-code(BCPL, 1967) → Pascal の P-code → 第4回の EM(ACK) → JVM バイトコード → LLVM IR(clang) → WebAssembly。半世紀を貫く同じ一つの発明です。ブートストラップの文脈では効き方が特に鮮やか ── 島まで作っておけば、新機種で架けるのは最後の短い橋(小さなバックエンド/インタプリタ)だけ。
O-code が本当に威力を出すのは、コンパイラ自身を新しい機械へ運ぶときです。O-code は機種非依存なので、コンパイラを O-code の姿にしておけば、そのまま新しい機械へ運べる。あとは新機械で小さな受け皿(O-code を動かす後半)を用意するだけ。下の図で、その渡り方を順に見てください。
O-code は移植を身軽にしますが、鶏と卵を消しはしません(第4回と同じ但し書き)。新機械には、結局「O-code を動かす最初の受け皿」を、機械語で用意しないといけない。その受け皿は誰が作る? ── ここからは中間コードの魔法が効かない領域です。B も BCPL も、いちばん下ではアセンブリ言語、そして初代 Unix そのものへ。次回からは、いよいよ言語の下・機械のすぐ上へ降ります。
(1) 「約1/5」「2〜5人月」は当時の代表的な見積もりで、機種や時代で幅があります。骨格(フロントエンドは共通、バックエンドだけ差し替え)が本体です。(2) BCPL のコンパイラは「二つに割る」と言いましたが、実際は三段構成で、O-code はその中間段の名前です。さらに移植をうんと軽くするための、より単純な中間形(インタプリタで受ける方式)も用意されました。ここでは骨格を優先しています。
(3) B が「BCPL の簡略化」なのは事実ですが、Thompson 自身の好みや以前の言語(bon)の影響も混じります。系図は一本の細い糸ではなく、束です。(4) 中間コードは移植を楽にするだけで、最初の受け皿(機械語)と最初の機械は、やはり別に用意が要る ── 鶏と卵は下段へ送られるだけ、という点は第3・4回と同じです。
C を育てた B は、Martin Richards の BCPL(1967)の子。Thompson が PDP-7 で Fortran コンパイラに挫折し、BCPL を型なしに簡略化したのが B だった(CPL→BCPL→B→C)。BCPL の真価はコンパイラの作りにあり、前半がO-code(機種非依存の中間コード)を吐き、後半がそれを機械語へ訳す。新機種にはバックエンド(約1/5・2〜5人月)だけ書き直せばよく、だから BCPL はブートストラップの定番言語になった。
中間コードの正体は「機種を知らない島」を真ん中に置き、機械の知識をバックエンドに隔離すること。O-code → P-code → EM → JVM → LLVM IR → WASM と、半世紀を貫く同じ発明だ。しかも O-code はコンパイラを別の機械へ運ぶ逃げ道になる ── これは第8回「紙テープで運ぶ」初代 Unix の原理版。ただし逃げ道の下では、新機械に最初の受け皿(機械語)を別に用意せねばならず、鶏と卵は下段へ送られる。── 次回、いよいよ言語の下、アセンブリで書かれた初代 Unix へ。
印刷 / PDF 化:⌘+P(Windows は Ctrl+P)。画面では図1のボタンで対象機種を変え(差し替わるのはバックエンドだけ)、図2のスライダーで O-code による機械間の移植を追えます。「答えを見る」で解答が開きます。