星にゃーんのブログ

ほとんど無害。

世の中間言語を集める

個人的なプロジェクトとして、コンパイラ中間言語の設計に取り組んでいる。 今できてるのはラムダ計算に毛が生えてコード生成に向いてるセマンティクスを持つみたいなやつで、『星を継ぐもの』に登場するコリエルというキャラクターから名前をもらってkorielと呼んでいる。

まだまだ未完成で、Haskellで扱うためのライブラリはできたが、ドキュメントもなければバイナリ表現やテキスト表現もない。

github.com

今後korielの開発を進めるに当たって、他の「中間言語」について調べてみようと思った。 プログラミング言語については良く知っているが、言語処理系の中間表現についてはあまり詳しくないからだ。

中間表現と中間言語

中間言語っぽいものを表す言葉は二つある。 「中間表現」"Intermediate representation"と「中間言語」"Intermediate language"だ。 これは混乱を招くので、ちょっと整理しておきたい。

まず、中間表現とは、コンパイラVM*1ソースコードを表現するためのデータ構造だ。単純な文字列ではなく、木構造(ASTとか)やグラフ構造(モジュールの依存関係グラフとか)のように、コンパイラVMにとって都合のいいデータ構造が使われている。

中間表現の中でも、プログラムによって読み書きできるコードの形になっているものを中間言語と呼ぶ。

An IR may take one of several forms: an in-memory data structure, or a special tuple- or stack-based code readable by the program.[3] In the latter case it is also called an intermediate language. Intermediate representation - Wikipedia

C

Cは割と良く使われる中間言語だ。もちろん、Cは汎用プログラミング言語として設計された。しかし、他の言語に比べてアセンブリに近いこと、多くのOS、CPUの上で動作する性能の良い処理系が存在していることから、中間言語として採用されることが多い。

言語Aのコンパイラを作るときに、いきなりA to assemblyなコンパイラを書くのは骨が折れる。そこで、A to Cなコンパイラを書き、あとのことはCコンパイラに任せる、というスタイルがある。

他にも、部分的にコードをCにコンパイルすることで高速化をはかることもある。 Cythonはその好例だ。

LLVM IR

LLVM*2コンパイラのさまざまな機能を提供するツールチェーンだ。 もちろん中間言語もあって、LLVM IRという。 Clang, Rustなど多くのコンパイラで使われている。

Kotlin/Native*3というプロジェクトでは、KotlinをJVMを介さずネイティブなバイナリにコンパイルするが、ここでもLLVMが使われている。

他にも非常に多くのプロジェクトで使われている、デファクトスタンダード的存在である。

SSAをベースとしており、Cのより中間言語向きなバージョンといった雰囲気。

共通中間言語 (CIL)

LLVMデファクトスタンダードである一方で、CILはもっとも「名前は聞いたことがある」中間言語だろう。

C#で使われている中間言語で、.NET対応言語はこの中間言語コンパイルされ、アプリケーションやライブラリはこの中間言語の状態で配布される。 ユーザーの環境にインストールされた.NETのVMがこれを解釈したりJITコンパイルしながら実行される。

パッと調べたところ、例えば以下の記事が詳しい。

ufcpp.net

スタックベースで、オブジェクト指向をサポートするための言語機能が充実している。

JVM byte code

JVMはおそらく(Oracleを信じるなら)30億のデバイスにインストールされている。 JVMが実行するJVM byte codeもそれなりに良く使われる中間言語で、Scala、Kotlin、Groovyなど、JVMで動く言語も多い。RubyにはJVMで走るように実装されたJRubyという実装がある。

これもCILと同様に、スタックベースの言語であり、オブジェクト指向をサポートするための言語機能が充実している。

TODO(追記予定)