解釈とコンパイル:有用な区別?


29

ここでは、インタプリタ言語とコンパイル言語の実装について多くの質問があります。区別が実際に意味をなすかどうか疑問に思っています。(実際には、質問は通常言語に関するものですが、それらの言語の最も一般的な実装について本当に考えています)。

現在、厳密に解釈される実装はほとんどありません。つまり、コードを一度に1行ずつ解析して実行する人はほとんどいません。さらに、マシンコードにコンパイルする実装も一般的ではなくなりました。ますます、コンパイラはある種の仮想マシンをターゲットにしています。

実際、ほとんどの実装は同じ基本戦略に集中しています。コンパイラーは、JITを介してネイティブコードに解釈またはコンパイルされるバイトコードを生成します。コンパイルと解釈の伝統的なアイデアのミックスです。

したがって、私は尋ねます:最近、解釈された実装とコンパイルされた実装の間に便利な区別はありますか?


7
@DeadMGは、あなたが思うかもしれ新品同様未:ジャストインタイムの簡単な履歴を ...
ヤニス

4
@DeadMG過去10年程度で導入された新しい言語の大部分は、主に何らかのVMで実行されることを考えると、彼にはポイントがあると思います。もちろん、ネイティブコードにコンパイルされた言語はまだあり(今後数十年になるでしょう)、JITは贅沢なままです(または、PyPyの人たちが自分のやり方を持っている場合はそうではありません)。そう、誇張の可能性がありますが、主流(現在および近い将来)はバイトコードコンパイラ+おそらくJITであることに同意します。

4
@ DeadMG、VMモデルが「新しい」場合は、長い白ひげが必要です。P-code1966年に最初に導入されました。IBM Aixは1986
SKロジック

6
UNIXシェル、Tclなどのようなものは常に純粋に解釈されるため、少なくとも学術的なCSでは区別が理にかなっています。しかし、コーダーがインタープリターとコンパイラーについて口をつぐんでいるとき、ほとんどの場合意味をなさないことは事実です。
SKロジック

3
SK-ロジック@、私はあなたのコメントは、その後、任意の実際の掲載答えの良い答えだと思う
ウィンストンエバート

回答:


23

解釈とコンパイルは、単なる相互の代替手段ではないことを覚えておくことが重要です。最終的に、作成したプログラム(マシンコードにコンパイルされたものを含む)は解釈されます。コードの解釈とは、単に一連の指示を取得して回答を返すことを意味します。

一方、コンパイルとは、ある言語のプログラムを別の言語に変換することを意味します。通常、コンパイルが行われると、コードは「下位レベル」言語(たとえば、マシンコード、何らかのVMバイトコードなど)にコンパイルされると想定されます。このコンパイルされたコードは、後で解釈されます。

インタープリター言語とコンパイル済み言語の間に有用な区別があるかどうかについてのあなたの質問に関して、私の個人的な意見は、誰もがインタープリテーション中に書くコードに何が起こっているのかを基本的に理解する必要があるということです。そのため、コードがJITコンパイルまたはバイトコードキャッシュなどされている場合、プログラマーは少なくともその意味を基本的に理解している必要があります。


3
はい、プログラマは基本的な理解が必要です。しかし、コンパイルされた/解釈された用語がそれを邪魔しないのではないかと思います。
ウィンストンイーバート

2
ありがとうございました!!Interpretedは「実行済み」の同義語であり、それがすべてのプログラムの実行方法です。
ガーデンヘッド

9

コンパイルされた言語は、解釈された言語が必ずしも必要としない方法でセマンティクスを制限するため、区別は深く意味があります。一部の解釈手法は、コンパイルが非常に困難です(実際には不可能です)。

解釈されたコードは、実行時にコードを生成するなどのことを実行でき、既存のスコープの字句バインディングに対するコードの可視性を提供します。それが一例です。もう1つは、インタープリターを、コードの評価方法を制御できるインタープリターコードで拡張できることです。これは、古代のLisp "fexprs"の基礎です。未評価の引数で呼び出され、それらをどう処理するかを決定する関数(コードのウォークや変数の評価などに必要な環境へのフルアクセスがあります)。コンパイルされた言語では、その手法を実際に使用することはできません。代わりにマクロを使用します。未評価の引数でコンパイル時に呼び出され、解釈ではなくコードを変換する関数。

一部の言語実装は、これらの手法を中心に構築されています。著者は、コンパイルを重要な目標として拒否し、むしろこの種の柔軟性を受け入れます。

解釈は、コンパイラをブートストラップするための手法として常に役立ちます。具体的な例については、CLISP(Common Lispの一般的な実装)をご覧ください。CLISPには、それ自体で記述されたコンパイラがあります。CLISPをビルドすると、そのコンパイラはビルドの初期段階で解釈されます。それはそれ自身をコンパイルするために使用され、それがコンパイルされると、コンパイルされたコンパイラを使用してコンパイルが行われます。

インタープリターカーネルがなければ、SBCLのように、既存のLispでブートストラップする必要があります。

解釈を使用すると、アセンブリ言語から始めて、絶対にゼロから言語を開発できます。基本的なI / Oおよびコアルーチンを開発してから、まだ評価されているマシン言語を記述します。evalを取得したら、高級言語で記述します。マシンコードカーネルが評価を行います。この機能を使用して、より多くのルーチンでライブラリを拡張し、コンパイラも作成します。コンパイラを使用して、これらのルーチンとコンパイラ自体をコンパイルします。

解釈:編集に至る道の重要な足がかり!


1
IMO、これが最良の答えです。私は自分のおもちゃの言語に取り組んでおり、最後の段落では、私がそれを開発している方法を説明しています。本当に新しいアイデアに取り組むのがずっと簡単になります。また、CLISPブートストラッププロセスに言及するための+1。
-sinan

理論的には、インタープリターに加えてインタープリタープログラムのソースコードまたはバイトコードで構成されるEXEファイルを生成することにより、「解釈された」言語を「コンパイルされた」言語にすることができます。ただし、あまり効率的ではない場合があります。
dan04

WirthらがどのようにPASCALを新しいマシンアーキテクチャへの移植を簡素化するためにPコードを発明したかを読んでください。それは1970年代初期でした。
ジョンR.ストローム

1
冒頭の段落は、静的および動的な振る舞いとコンパイルと解釈を混同していると思われますが、疑いの恩恵を与え、コンパイルするのが「実際上不可能」なセマンティクスを持つ言語の例を求めます。コンパイラーのブートストラップに関しては、最初の実装は実装している言語以外で書く必要があるのは事実ですが、インタープリターである必要はなく、別の言語で書かれたコンパイラーでもかまいません。
ビットツリー

1

実際、言語の実装の多くはまだ厳密に解釈されていますが、それらを認識していない可能性があります。例を挙げると、UNIXシェル言語、Windows cmdおよびPowerScriptシェル、Perl、awk、sed、MATLAB、Mathematicaなどです。


3
Perlは内部的にバイトコードにコンパイルされており、少なくともMathematicaをコンパイルできると信じています。そしてawkとsedの実装を指示するものは何もありません(GNU coreutilsのいくつかは、実行前に正規表現を有限オートマトンにコンパイルします。

1
実際、Perl、MATLAB、Mathematicaはすべてバイトコードにコンパイルされると確信しています。PowerScriptに慣れていないのですが、Powershellですか?その場合、CLRを使用するため、バイトコードを使用します。
ウィンストンイーバート

@WinstonEwert、申し訳ありませんがPowerShellを意味していました。私の理解では、中間形式への翻訳は、何かが解釈されないという意味ではありません。元のDartmouth BASICインタープリターであるHeckは、ソースを解釈する前にトークンに変換しました。私が言及した各ツールには、1)ソースの行を読み取り、2)その行を実行可能な形式(おそらくネイティブコードではなく中間コード)に変換、3)その行のコードを実行、4)のモードがあります1)にループバックします。それは通訳の私の理解に対応しています。
チャールズE.グラント

2
バイトコードはコンパイルされていることを意味します。バイトコードコンパイラは、ソースを取得してバイトコードに変換するプログラムです。したがって、バイトコードの使用にはすべて、バイトコードコンパイラが必要です。ただし、バイトコードも解釈(またはJIT化)する必要があります。したがって、バイトコードを使用するものはすべて、インタープリター/コンパイラーのハイブリッドです。
ウィンストンイーバート

4
本当に、私のことは、人々が「pythonが解釈される」や「Javaがコンパイルされる」などのステートメントを、実装を理解せずに捨てることです。これらの用語で実装を説明するのに役立つかどうかを調べています。真実は通常、より複雑であり、それを解釈/コンパイルに要約しようとすることは役に立ちません。
ウィンストンイーバート

1

私は思う:絶対にはい

実際、ほとんどの実装は同じ基本戦略に収束しています

実際、C ++は、通常インタープリターに渡される高レベルの概念をコンパイラードメインに移植することを目指していますが、少数派のままです...


2
Clang + LLVMが最も一般的なコンパイラツールチェーンになるまで待ちます。
SKロジック

@ SK-logicは、名前にもかかわらず、Clang + LLVMがネイティブコードを生成すると考えています。
ウィンストンイーバート

1
@Winston Ewert、必要な場合のみ。LLVM IRレベルで停止し、必要な処理を実行できます-解釈、JITコンパイル、任意の方法でインストルメントします。あなたもJavaScriptにそれを翻訳して、通訳を通過することができますgithub.com/kripken/emscripten/wiki
SK-ロジック

@ SK-logic、きちんとしたもの!LLVMがそれを行えるとは知らなかった。
ウィンストンイーバート

1
llvmの美しさは、フロントエンドとバックエンドのこの意図的な分離です。そして、命令セットを対象とする前に中間を操作するためのツール。プロジェクト全体をバイトコードにマージし、全体を最適化できます。他のコンパイラーでは、単一のファイルソースまたは少なくとも1つのソースツリーが必要です。そのため、コンパイラーは1つの結合ソースで動作します また、llvmの下にあるツールのセットはすべてのターゲットに対して汎用的であり、ターゲットごとにビルドする必要はありません。1つのコンパイラがすべてに適合します(少なくともターゲットのasmに対して)。
old_timer

-1

便利な区別:解釈されたプログラムは、実行時に関数を追加または変更することで自分自身を変更できます。


8
ナンセンス。自己修正(マシン)コードは、本の中で最も古いトリックです。繰り返しになりますが、ネイティブコードでさえ、最終的にシリコン(CPU)にキャストされたインタープリターによって解釈されます。しかし、それを仮定すると、すべてのコードが解釈され、区別する必要はありません。

2
@delnanは正しい。新しいクラスを動的に作成し、ライブラリ(または.NETの「アセンブリ」など)をロード/アンロードすることで、現代の言語が自分自身を変更できることを追加します
Jalayn

5
Common Lispはコンパイルされますが、実行時に関数定義を簡単に置き換えることができます。
SKロジック

これは、解釈の非常に興味深く、必要な機能です(たとえば、Prologで)。
CapelliC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.