web-dev-qa-db-ja.com

インタープリターはマシンコードを生成しますか?

コンパイラとインタプリタのトピックを集中的に研究しています。基本的な理解が正しいかどうかを確認したいので、次のことを前提とします。

「Foobish」という言語があり、そのキーワードは

<OUTPUT> 'TEXT', <Number_of_Repeats>;

したがって、コンソールに10回印刷する場合は、

OUTPUT 'Hello World', 10;

こんにちは、World.foobish-file。

次に、選択した言語でインタープリターを作成します。この場合はC#です。

using System;

namespace FoobishInterpreter
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            analyseAndTokenize(Hello World.foobish-file)//Pseudocode
            int repeats = Token[1];
            string outputString = Token[0];
            for (var i = 0; i < repeats; i++)
            {
                Console.WriteLine(outputString);
            }
        }
    }
}

非常に簡単なインタプリタレベルでは、インタプリタはスクリプトファイルなどを分析し、インタプリタの実装の方法でfoobish-languageを実行します。

コンパイラーは、物理ハードウェアで直接実行される機械語を作成しますか?

インタプリタは機械語を生成しませんが、コンパイラはその入力のためにそれを行いますか?

コンパイラーとインタープリターがどのように機能するかについて、基本的な誤解がありますか?

43
GrayFox

「インタプリタ」と「コンパイラ」という用語は、以前よりもあいまいです。何年も前、コンパイラが後で実行されるマシンコードを生成するのがより一般的でしたが、インタプリタは多かれ少なかれソースコードを直接「実行」しました。したがって、これら2つの用語は当時よく理解されていました。

しかし今日、「コンパイラ」と「インタプリタ」の使用には多くのバリエーションがあります。たとえば、VB6はバイトコード( Intermediate Language の形式)に「コンパイル」され、次にVBランタイムによって解釈されます。同様のプロセスが行われます。 C#では [〜#〜] cil [〜#〜] を生成し、次に Just-In-Time Compiler(JIT) によって実行されます。日間は、インタプリタと見なされていました。 NGen.exe を使用して、JITの出力を実際のバイナリ実行可能ファイルに「フリーズドライ」できます。 コンパイラの昔の.

したがって、あなたの質問に対する答えは、かつてほど簡単ではありません。

さらに読む
ウィキペディアのコンパイラと通訳

78
Robert Harvey

以下に示す要約は、「コンパイラ、原理、技法、およびツール」、Aho、Lam、Sethi、Ullman(Pearson International Edition、2007)、1、2ページに基づいており、独自のアイデアがいくつか追加されています。

プログラムを処理するための2つの基本的なメカニズムは、compilationおよびinterpretationです。

コンパイルは、特定の言語のソースプログラムを入力として受け取り、ターゲット言語のターゲットプログラムを出力します。

source program --> | compiler | --> target program

ターゲット言語がマシンコードの場合、一部のプロセッサで直接実行できます。

input --> | target program | --> output

コンパイルには、入力プログラム(またはモジュール)全体のスキャンと変換が含まれ、実行は含まれません。

解釈は、入力としてソースプログラムとその入力を受け取り、ソースプログラムの出力を生成します。

source program, input --> | interpreter | --> output

解釈には、通常、プログラムを一度に1文ずつ処理(分析および実行)することが含まれます。

実際には、多くの言語プロセッサは2つのアプローチを組み合わせて使用​​します。たとえば、Javaプログラムは最初に中間プログラム(バイトコード)に変換(コンパイル)されます。

source program --> | translator | --> intermediate program

次に、このステップの出力が仮想マシンによって実行(解釈)されます。

intermediate program + input --> | virtual machine | --> output

さらに複雑なことに、JVMは実行時にジャストインタイムのコンパイルを実行して、バイトコードを別の形式に変換し、それを実行します。

また、マシン言語にコンパイルする場合でも、基盤となるプロセッサによって実装されるバイナリファイルを実行するインタープリターが存在します。したがって、この場合でも、コンパイルと解釈のハイブリッドを使用しています。

したがって、実際のシステムでは2つを組み合わせて使用​​しているため、特定の言語プロセッサがコンパイラとインタープリタのどちらであるかを判断するのは困難です。この場合、おそらくより中立的な別の用語を使用するほうが適切でしょう。

それにもかかわらず、上の図で説明したように、コンパイルと解釈は2つの異なる種類の処理です。

最初の質問に答える。

コンパイラは、物理ハードウェアで直接実行される機械語を作成しますか?

必ずしもではないが、コンパイラは、マシンM1用に作成されたプログラムを、マシンM2用に作成された同等のプログラムに変換します。ターゲットマシンは、ハードウェアに実装することも、仮想マシンにすることもできます。概念的には違いはありません。重要な点は、コンパイラーがコードを見て、それを実行せずに別の言語に変換することです。

では、インタプリタは機械語を生成しませんが、コンパイラはその入力のためにそれを行いますか?

producingによって出力を参照している場合、コンパイラーは機械語のターゲットプログラムを生成しますが、インタープリターは生成しません。

34
Giorgio

コンパイラは機械語を作成します

いいえ。コンパイラは単に、言語で記述されたプログラムを入力として受け取るプログラム[〜#〜] a [〜#〜]であり、言語として意味的に同等のプログラムを出力として生成します[〜#〜] b [〜#〜]。言語[〜#〜] b [〜#〜]は何でもかまいませんが、機械語である必要はありません。

コンパイラーは、高水準言語から別の高水準言語(JavaをECMAScriptにコンパイルするGWTなど)、高水準言語から低水準言語(たとえば、スキームをCにコンパイルするGambit、高水準言語からマシンコード(たとえば、JavaネイティブコードにコンパイルするGCJ)、低水準言語から高レベル言語にコンパイルするGCJ)言語(CをJava、Lua、Perl、ECMAScript、Common LISPにコンパイルするClueなど)を低レベル言語から別の低レベル言語(たとえば、Android SDK、 JVMLバイトコードからDalvikバイトコード)、低レベル言語からマシンコード(JVMLバイトコードをマシンコードにコンパイルするHotSpotの一部であるC1Xコンパイラなど)、マシンコードから高水準言語(いわゆる「すべて」) decompiler」、またEmscripten、LLVMマシンコードをECMAScriptにコンパイル)、マシンコードを低レベル言語(x86ネイティブコードをJVMLバイトコードにコンパイルするJPCのJITコンパイラなど)、およびネイティブコードネイティブコード(例: PowerPCネイティブコードをx86ネイティブコードにコンパイルするPearPCのJITコンパイラ)。

「マシンコード」はいくつかの理由で本当にあいまいな用語であることにも注意してください。たとえば、JVMバイトコードをネイティブに実行するCPUや、x86マシンコード用のソフトウェアインタープリターがあります。では、何が「ネイティブマシンコード」になるのか、他のコードではないのでしょうか。また、every言語は、その言語の抽象マシンのコードです。

特別な機能を実行するコンパイラには、多くの特殊な名前があります。これらは特殊な名前であるという事実にもかかわらず、これらはすべてコンパイラーであり、特別な種類のコンパイラーです。

  • 言語[〜#〜] a [〜#〜]が言語とほぼ同じ抽象化レベルであると認識された場合[〜#〜] b [〜#〜] =、コンパイラはtranspilerと呼ばれる場合があります(例:Ruby-to-ECMAScript-transpilerまたはECMAScript2015-to-ECMAScript5-transpiler)
  • 言語[〜#〜] a [〜#〜]が言語よりも低い抽象化レベルにあると認識される場合[〜#〜] b [〜#〜] =、コンパイラはdecompilerと呼ばれる場合があります(例:x86-machine-code-to-C-decompiler)
  • 言語[〜#〜] a [〜#〜] ==言語[〜#〜] b [〜#〜]の場合、コンパイラはoptimizerobfuscator、またはminifier(コンパイラの特定の関数に依存)

物理ハードウェアで直接実行されるのはどれですか?

必ずしも。インタープリターまたはVMで実行できます。さらに別の言語にコンパイルできます。

では、インタプリタは機械語を生成しませんが、コンパイラはその入力のためにそれを行いますか?

通訳は何も作成しません。プログラムを実行するだけです。

コンパイラは何かを生成しますが、必ずしもマシン言語である必要はなく、どの言語でもかまいません。入力言語と同じ言語でもかまいません。たとえば、Supercompilers、LLCには、Javaを入力として受け取り、最適化されたJavaを出力として生成するコンパイラがあります。ECMAScriptをそれらの入力は、最適化され、縮小され、難読化されたECMAScriptを出力として生成します。


また興味があるかもしれません:

23
Jörg W Mittag

「コンパイラーインタープリター」という概念は完全に削除するべきだと思います。これは誤った二分法なのでです。

  • コンパイラトランスフォーマーです:これは、 ソース言語と同等のものをターゲット言語で出力します。通常、ソース言語はターゲット言語よりも高レベルです。逆の場合、そのようなトランスフォーマーはdecompilerと呼ばれます。
  • インタプリタ実行エンジンです。その言語の仕様に従って、1つの言語で記述されたコンピュータープログラムを実行します。私たちは主にソフトウェアという用語を使用します(ただし、ある意味で、従来のCPUは、そのマシンコードのハードウェアベースの「インタプリタ」と見なすことができます)。

抽象プログラミング言語を現実の世界で有用にするための集合的なWordは、implementationです。

以前は、プログラミング言語の実装は、コンパイラー(およびそれがコードを生成したCPU)またはインタープリターのみで構成されることが多かったため、のように見える場合がありますこれらの2種類のツールは相互に排他的です。今日、これが事実ではないことをはっきりと見ることができます(そして、それが最初からあったわけではありませんでした)。洗練されたプログラミング言語の実装を採用し、それに「コンパイラ」または「インタープリタ」という名前を押し付けようとすると、多くの場合、結論が出ない、または一貫しない結果になります。

単一のプログラミング言語の実装には、任意の数のコンパイラーとインタープリターが含まれることがあり、多くの場合、複数の形式(スタンドアロン、オンザフライ)、その他の任意の数の静的アナライザーおよびオプティマイザーなどのツール、および任意の数のステップ。また、任意の数の中間言語の実装全体を含めることもできます(実装される言語とは関係がない場合があります)。

実装スキームの例は次のとおりです。

  • Cをx86マシンコードに変換するCコンパイラと、そのコードを実行するx86 CPU。
  • CをLLVM IRに変換するCコンパイラ、LLVM IRをx86マシンコードに変換するLLVMバックエンドコンパイラ、およびそのコードを実行するx86 CPU。
  • CをLLVM IRに変換するCコンパイラ、およびLLVM IRを実行するLLVMインタープリター。
  • JavaコンパイラをJavaからJVMバイトコードに変換し、そのコードを実行するインタプリタを備えたJRE。
  • JavaコンパイラをJavaからJVMバイトコードに変換し、そのコードの一部を実行するインタプリタとそのコードの他の部分をx86マシンコードに変換するコンパイラの両方を備えたJRE 、およびそのコードを実行するx86 CPU。
  • JavaコンパイラをJavaからJVMバイトコードに変換し、ARM CPUでそのコードを実行します。
  • C#をCILに変換するC#コンパイラ、CILをx86マシンコードに変換するコンパイラを備えたCLR、およびそのコードを実行するx86 CPU。
  • Rubyを実行するRubyインタープリター。
  • Rubyを実行するインタープリターとRubyをx86マシンコードに変換するコンパイラー、およびそのコードを実行するx86 CPUの両方を備えたRuby環境。

...等々。

コンパイラとインタプリタの間の線は時間の経過とともに曖昧になっていますが、プログラムが何をすべきか、コンパイラ/インタプリタが何をするかの意味論を見ることによって、それらの間で線を引くことができます。

コンパイラーは、別のプログラム(通常はマシンコードなどの低レベル言語)を生成します。そのプログラムが実行されると、プログラムは本来実行すべきことを実行します。

インタープリターは、プログラムがすべきことを行います。

これらの定義を使用すると、曖昧になる場所は、コンパイラー/インタープリターが、見方に応じて異なることを行うと考えることができる場合です。たとえば、PythonはあなたのPythonコードを受け取り、コンパイルコンパイルしてPythonバイトコード。これがPythonバイトコードがPythonバイトコードインタプリタを介して実行される場合)、ただし、ほとんどの場合、Python開発者はこれらのステップの両方が1つの大きなステップで実行されると考えているため、 CPython インタープリターとしてinterpretingそれらのソースコード、そして途中でcompiledされたという事実は、実装の詳細と見なされます。このように、それはすべて視点の問題です。

7
Cort Ammon

コンパイラーとインタープリターの間の単純な概念的な曖昧さを以下に示します。

3つの言語について考えてみましょう。programming言語、P(プログラムの記述内容)。 ドメイン言語、D(実行中のプログラムで何が行われているのか);およびtarget言語、T(いくつかの第3言語)。

概念的には、

  • acompilerはPをTに変換して、T(D)を評価できるようにします。一方

  • インタプリタは、P(D)を直接評価します。

5
Lawrence