web-dev-qa-db-ja.com

解釈済みvsコンパイル済み:有用な区別?

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

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

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

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

31
Winston Ewert

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

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

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

25
Zach Smith

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

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

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

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

インタープリターカーネルがなければ、SBCLのように、既存のLISPでbootstrapを実行する必要があります。

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

解釈:コンパイルに至る道の重要な足掛かり!

12
Kaz

実際、多くの言語の実装はまだ厳密に解釈されており、あなたはそれらに気付かないかもしれません。いくつか例を挙げると、UNIXシェル言語、Windows cmdおよびPowerScriptシェル、Perl、awk、sed、MATLAB、Mathematicaなどです。

1

私は思います:絶対にそうです

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

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

1
CapelliC

「コンパイル済み」はプログラムのカテゴリの名前だけでなく、動詞(具体的には、「コンパイルする」の過去分詞)でもあることを覚えておくと役立ちます。言い換えると、「コンパイル済み」カテゴリに分類されるプログラムはすべて、コンパイルeventまたはprocessを介して渡される必要がありました。これは、コンパイルされていないプログラムとの質的な違いです。まったく灰色ではありません。

コンパイルプロセスには、ソースコードをオブジェクトコードに変換するだけではありません。また、コンパイルに固有のいくつかの機能も含まれています。

  1. コンパイル時(「前処理」)のディレクティブ、条件、および変数
  2. コンパイル時の検証(例:構文と型チェック
  3. コンパイル時エラー
  4. 事前バインディング
  5. 静的リンク
  6. 文字列インターンや末尾呼び出しなどの特定の最適化

これにより、特定の重要な違いが生じます。たとえば、コンパイルされるプログラムには、有効な(必ずしも正しいとは限りません)ソースコードが含まれている必要があります。対照的に、インタプリタされたプログラムには、無効なソースが含まれている可能性があります。 Javascriptプログラムは、無効なコード行に遭遇するまで問題なく実行でき、その時点で単に停止またはエラーになります。

JITコンパイルされたコードに関しては、灰色の領域があると思います。これは、解釈されたコードと同様に処理されます。たとえば、無効なソースコードは、JITコンパイルが発生するまで問題を引き起こさない場合があります。ただし、JITコンパイルが完了すると、コードが有効になったことが保証されます。

この区別は「有用ですか」。それは意見の問題だと思います。ただし、違いを理解していないソフトウェアエンジニアは採用しないでしょう。

1
John Wu

便利な違い:インタプリタされたプログラムは、実行時に関数を追加または変更することにより、プログラム自体を変更できます。

0
Diego Pacheco

区別が非常に灰色になっていると思います。私はJava Matlabを呼び出す方法、Javaがコンパイルされている一方で、Matlabが最近、より低いレベルにコンパイルされている間に、デジタル回路設計の背景から来て、レジスタレベルの操作でさえ、ステートマシンの状態遷移の制御フローロジックに対応する一連のコードで表すことができることを知っています。実際、これらの「イベント」がハードウェアレベルは、3GLソースコード(Verilog、VHDL、SystemCで説明されている場合)のように著しく見える可能性があります。このような高レベルの低レベルの操作のビューを「ソースコード」と呼びますか?操作が詳細に指定されている場合はどうなりますか?コンパイラが最終的なブールロジックを決定する自由がないということですか?それから、ハードウェア、状態、およびI/Oにデザイナーにわかりやすい名前を付けるだけです-それでもコンパイルされるソースコードはありますか?ゼロと1をエディターで表示することは、実際のビンと同様に抽象的ですary状態は、特定のノードで特定の電荷レベルと電圧を持つトランジスタゲートレイアウトの結果です。これらの線に沿って、論理セルの選択、レイアウト、および相互接続ルーティングを、コード化された記述のハードウェアへのマッピングとその操作を「コンパイル」として認定する自由度と見なす必要がありますか?

ただし、ぼやけているにもかかわらず、インタラクティブなコマンドラインがあるため、Matlabは解釈されたように思われます。コマンドラインステートメント間でデータオブジェクトをナビゲートおよび操作できます。 VBAはコンパイルされていますが、同じことができる「イミディエイトウィンドウ」があります。 C++デバッガーも同様の環境を提供しますが、何十年も3GLを使用していなかったため、その機能は当時はかなり厄介でした。次に、再びJavaが「コンパイルされ」、Web検索で、インタラクティブなコマンドラインが学習できることがわかりますJava(わかりません) )。

技術的な詳細から引き返して、それがどのように感じ、コンソールで何ができるかというブラックボックスの観点からのみ質問を見ても、それはまだかなりぼやけています。

0
user2153235