インタプリタ

インタプリタのしくみ

プログラミング言語処理系には、コンパイラ、 アセンブラ以外にインタプリタと呼ばれるものもある。

コンパイラを用いた場合、 ソースプログラムは CPU が直接理解可能な機械語に変換されるので、 コンパイル後にできたプログラムはそれ単独で動く。 つまり、実行時には処理系(コンパイラ)の介在を必要としない。


            ┌─────────┐ コンパイル ┌─────────┐
            │ ソースプログラム │─────→│ 機械語プログラム │
            └─────────┘            └─────────┘
                                                        ↑
                                                    CPU が直接
                                                    実行

これに対して、インタプリタはソースプログラムをコンパイルしない。 ソースプログラムを読んでその内容を解釈しながら実行する。 従って、実行時にインタプリタ処理系がなければプログラムを動かすことができない。


            ┌─────────┐ 
            │ ソースプログラム │
            └─────────┘
                      ↑
                      │解釈しながら実行
                      │ 
            ┌─────────┐ 
            │   インタプリタ   │
            └─────────┘

例えば、z = x + y; という文を、コンパイラは

    addu $t2, $t0, $t1          # レジスタだけを使う場合

とか、あるいは

    addu $v0, $t0, $t1          # z をスタックフレームに置く場合
    sw $v0, -8($fp)

といったアセンブリ言語で表される機械語に変換する。変換後のプログラム は直接CPUによって実行される。

これに対し、同じ z = x + y; という文をインタプリタが実行する場合、 概略次のようなことが起こる(詳細は個々のインタプリタによって多少異なる):

  前の文の解釈実行終了
          ↓
  z = x + y; が読まれる
          ↓
  代入文処理ルーチン呼出し ──→[代入文処理ルーチン]
                                         ↓
                                 左辺計算ルーチン呼出──→[左辺計算ルーチン]
                                                                ↓
                                                            z の場所を求めて
                                                            リターン
                                          ←──────────┘
                                         ↓
                                 右辺計算のため、
                                 式計算ルーチン呼出し──→[式計算ルーチン]
                                                                ↓
                                                            x + y を求める
                                          ←──────────┘
                                         ↓
                                 z の場所に x + y の
                                 値をしまって
                                 リターンする
           ←──────────────┘
          ↓
       次の文へ
          ↓
          :
          :

コンパイラとインタプリタの比較

プログラムの実行形態

対話性(interactiveness)

例えて言えば、コンパイル後のプログラムを走らせるのは、 翻訳された本を読むのに似ている。 翻訳が必要なのは最初だけであり、その際は時間がかかるが、 その後は何度読もうが翻訳のコストはかからない。 一方、インタプリタは(同時)通訳に似ている。 通訳は毎回その場にいなければ役に立たない。

コンパイラのことを日本語で「翻訳系」ということがある。インタプリタを 「通訳系」とか「解釈系」ということがある。(でもカタカナで呼ぶことのほ うがはるかに多い。)

実行効率

開発効率(プログラムの開発のしやすさ)

効率について一言:

プログラムの効率については、実行時のことだけを考えていてはいけない。 できたプログラムが高速でも、 プログラミングにひどく時間がかかったので は、現実の問題解決には間に合わないことがある。 特に、一度だけしか実行しないプログラムの場合は、実行速度が遅くても 「開発時間+実行時間」 が短かければそれでよいと考えられる。 世の中には一度だけ実行すれば済む「使い捨てプログラム」 が思った以上に多いものである。

筆者は日常の仕事をこなすのにそういうプログラムをしょっちゅう書いている。 くり返し使うプログラムよりずっと多い。

逆に、何度もくり返し使うプログラムの場合、実行速度が速いことのメリッ トが大きくなるので、多少開発に時間をかけても高速なプログラムを作る価 値があるケースが多くなる。

開発中、完成が近くなるまでインタプリタで開発し、 ほとんどバグが取れたらコンパイラにかける、というアプローチもある。

こうしたことを考えに入れて、コンパイラ・インタプリタの使い分け、 あるいはプログラミング言語そのものの使い分けをすべきである。 (開発時間を短くしやすいが、実行効率が少し悪い処理系、 といったものもある。)

処理系の作りやすさ

簡単なインタプリタの一つくらいは作っておくと非常に勉強になります。 色々なアルゴリズムやプログラミングテクニックを学べます。 Lisp 言語のインタプリタあたりが一番楽。

注意

インタプリタかコンパイラか、という違いは、処理系の違いであって、言語 の違いではない。 よく、「C はコンパイラだから速い」という言い方がされることがあるが、 本当は正しくない言い方。 C 言語自体の規格には、処理系をコンパイラにしなければいけない、 ということはない。 実際、C のインタプリタも存在する。 ただ、C の処理系のほとんどがコンパイラなのは確かであり、 また、大抵のコンピュータ上には速いコードを吐く C コンパイラが用意されているのも事実だろう。 (C や Fortran のコンパイラ作成技術は歴史が長いためよく研究されているし、 速いコンパイラを作りやすい言語なのは確か。)

また、一つの処理系がインタプリタとコンパイラを兼ねていることもある。 例えば、Lisp 言語の処理系の場合、インタプリタの機能を持つと同時に、 インタプリタの中からコンパイル機能も呼び出すことができるものが多い。 大抵、一つ一つの関数ごとにコンパイルできるから、 コンパイルされた関数とされていない関数を混ぜこぜに使うことができる。 (デバッグに便利。)

コンパイラ・インタプリタ以外の方式

ある意味でインタプリタとコンパイラの中間にあたるような実行方式もある。 そのような実行方式については、 それを採用している言語処理系を習う授業で教わると思うので、 ここでは細かい話は省略する。

例

  1. Java 言語の処理系(「マルチメディアプログラミング」で解説)。
  2. Standard ML 言語の New Jersey コンパイラと呼ばれる処理系 (「プログラミング言語学」で解説)。

Java の処理系は、ソースプログラムを仮想機械の機械語に変換(翻訳)する。 実行時にこの翻訳系は要らないので、そのような意味ではコンパイラ。 また、仮想機械の機械語は、ソースプログラムの言語よりも低級言語と考えられるので、 その意味でもコンパイラである。 しかし、実行の際には、 このコンパイラとは別のプログラムとして用意されているインタプリタが必要。 (あるいは、仮想機械と同じ動作をするハードウェアがあれば、 それを使ってもよい。) つまり、変換後のプログラムは、仮想的な機械の機械語であるが、 インタプリタによって解釈実行される。

Standard ML 言語の New Jersey コンパイラ はインクリメンタルコンパイラ(←今覚えなくてよい)である。 一見インタプリタだが、ユーザが入力した式は、 入力されるそばから逐一コンパイルされ、即座に実行される。 コンパイラの実行時効率とインタプリタの対話性を両立させようとしたもの。