中間表現(ちゅうかんひょうげん)は、コンピュータデータクロスプラットフォームで扱うためやその他多数の目的のために使用されるデータ構造の表現である。クロスプラットフォームで扱うため以外にも、さまざまな目的のために使用される。

中間表現を用いたデータの抽象化はコンピューティング分野では一般的な手法である。異なるプラットフォームで同等の情報を保持するデータを異なるフォーマットで扱う場合に、データを中間表現で表現することで複数フォーマットへの変換処理を効率化することを手助けできる、というのは、この手法のあまたある利点(あるいは応用)のごく1つである。

表現形態編集

中間表現はテキストデータやバイナリデータなどのデータ構造をとる。すなわち任意のデータ構造をとる。Javaバイトコードなどの「バイトコード」はフィールドの区切りや構造の長さなどがバイト指向な中間表現を指す語である。内部的な場合にはアドレスを指すポインタ(ないしそれを抽象化したもの)によって要素を指し示すことで効率的な表現が可能だが、ファイルに書き出すなど外部的な場合には何らかの方法で永続化が必要である。内部的な表現としても、ポインタのような密結合で短命な表現ではなく、粗結合な表現を使うこともある。

プログラミング言語やその他の形式言語を扱うコンピュータ・プログラムでは、ソースコード等の入力にある文字列を字句解析器(レキシカルアナライザ)による字句解析によりトークン(字句)に切り分けた後、構文解析器(パーサ)による構文解析により、トークンを葉とする構文木と呼ばれる木構造を構築することが多い(構文解析の過程で直接にコード生成をしたりするものもある)。

構文木で表すことができるデータは抽象構文木の中間表現を用いる。抽象構文木は構文木の抽象化を目的として定義され、特定プラットフォームに依存した構文木から不特定多数プラットフォームに対応できる構文木で表現される。いずれの構文木も同等の情報を保持するデータを表す。命令セットを持つデータは中間表現で抽象化した上で、特定プラットフォームの命令セットと中間表現の命令セットをシンボルテーブルで紐付ける。中間表現とシンボルテーブルをセットで定義し、各プラットフォームの命令セットを中間表現を介して変換する。

中間言語編集

 
各種ソースコードと各種マシンコードを中間言語で中継するコンパイルのシーケンス

「中間言語」という語は、中間表現が言語(形式言語)の形態をしている場合にそう呼ばれるものである。ここでは主に、プログラミング言語に関係する場合について述べる。

コンパイラでは、ソースコードから直接ターゲットのコードを生成するのではなく、中間表現を経由するコンパイラがある。インタプリタでは、ソースコードを直接解釈実行するのではなく、中間表現を生成してそれを解釈実行するインタプリタがある。コンパイラにしてもインタプリタにしても、あるいはそういったコンピュータ・プログラミング言語の処理系に限らず、入力があって出力がある任意のコンピュータ・プログラムにおいて、そういった何らかの中間表現は1段階とは限らず、複数種類があって複数段階のこともある。

歴史的には、言語処理系では1970年代頃までは単一言語、単一ターゲットが普通であった。しかし発想自体は以前からあり、1958年のメルヴィン・コンウェイの文献Proposal for an UNCOL[1]で提案されているUNCOL(UNiversal Computer Oriented Language)がある。UNCOLは概念の提案のためのものであり、完備された仕様として示されたものではない。また、初期の日本のコンピュータにおいて森口繁一の提案による、素朴なものであるが命令名の共通化などをはかったSIP(Symbolic Input Program)というものがあった[2]

1980年代には一般的に見られるようになり、GNU Compiler Collectionでは、中間表現の内部形式は Register Transfer Language(RTL)などの非依存なものであり、Machine Descriptions(MD)と呼んでいるターゲットの記述によってコードを生成することにより、複数の言語やターゲットに対応している。ただし、中間表現を外部のファイルに書き出したり、外部のファイルから読み込んだり、ということが簡単にできるようにはなっておらず、これは意図的なものである。

その後2000年頃から日本において、GPLでなく利用できるそのようなインフラストラクチャが必要だという考えから整備された「COINSコンパイラ・インフラストラクチャ」(COINS: a COmpiler INfraStructure)[3]がある。COINSには高水準中間表現(HIR: High level intermediate representation)と低水準中間表現(LIR: Low level intermediate representation)があるなど、対応を広げるためと現代的な最適化のための充実した中間表現を持っている。またその少し後にあらわれたLLVMも同様に、ライセンスがGPLでなく[4]、中間言語を活用しており、フロントエンドが異なるプログラミング言語のソースコードを1つの中間言語に変換し、バックエンドが1つの中間言語を異なるターゲットのコードへ変換する[5]。LLVMはclangrustcEmscriptenなどの「コンパイラ基盤」として使われている。

初期のBASIC処理系の実装で用いられた中間言語は、バイトコードのようなものではなく、字句解析のみを行い、BASICの各ステートメント(ないしコマンド)を単にコードに直接変換するだけといったものもあった。実行時の字句解析が不要になるが、ソースコードに戻して表示、編集することもできる。GOTOの飛び先をキャッシュするなどの工夫がされたものもあった。高度な中間言語を利用する実装もあり、N88-日本語BASIC(86)(MS-DOS版)のコンパイラは、実行ファイルを出力するが、その内部は中間言語コードでありまたその実行には外部に、中間言語のインタプリタを含むランタイムライブラリが必要だった。 幾つかのバーチャルマシンインタプリタは中間言語を直接実行する。

その他の事例編集

C言語などの低水準言語を、高水準言語からのコンパイル先として利用することがある。そういった場合のC言語は「ある種の中間言語として使われている」ということができる。

Unix系の環境では、多くのコンパイラが、オブジェクトファイルを直接生成するのではなく、アセンブリ言語を中間言語として利用し、アセンブラがオブジェクトファイルを生成している。コンパイラドライバに実行ファイル名を指定しないとデフォルトの実行ファイル名が a.out になるという慣習は、大昔はそれがアセンブラからの出力だったからである。

関連記事編集

脚注編集

  1. ^ Melvin E. Conway. “Proposal for an UNCOL”. Communications of the ACM. 2018年4月22日閲覧。
  2. ^ 日本のコンピュータパイオニア > 森口繁一 などを参照
  3. ^ http://coins-compiler.osdn.jp/
  4. ^ バージョン9では「Apache License v2.0 with LLVM Exceptions」である。
  5. ^ David Chisnall (2017年6月12日). “Modern Intermediate Representations (IR) (pdf)”. University of Cambridge. 2018年4月22日閲覧。