web-dev-qa-db-ja.com

すべての言語をコンパイルできますか?そして、すべての言語を解釈できますか?

すべてのインタプリタ言語をコンパイルできるかどうか疑問に思っていましたか?そして、すべてのコンパイル済み言語を解釈できますか?

3
wannik

可能なすべての言語は、定義によってコンパイルと解釈の両方をサポートする必要があります

トリックは、「コンパイル」と「解釈」の概念の根底にある意味にあります。

解釈は、「言語Xで記述されたこのプログラムを取り上げ、言語Xの規則をプログラムに適用するプロセスを作成すること」です。それは「解釈がプログラムを実行していること」の空想的な言い方です。

コンパイルは、このプログラムを言語Xで記述し、言語Yで新しいプログラムを記述します。解釈すると、Xでプログラムを直接解釈した場合と同じ結果になります。これは、ある言語から別の言語へのマッピング操作です。それは、「後で、私が書いたものを実行するが、より高速なプログラムを作成するのに少し時間がかかる」という空想的な方法です。

すべての言語を別の言語にマッピングできます。そうでない場合、その言語は実際にはコンピュータで実行できません。したがって、すべての言語を技術的にコンパイルできます。また、コンパイルされたプログラムは、「プログラムをコンパイルする動作を解釈してから結果を解釈する」という形式で記述できるため、すべてのプログラムを解釈することもできます。

アセンブリのラインはあいまいです。 CPUの仕事は命令を解釈することなので、x86コードが解釈されることを前提としています。ただし、実際には、文字どおりに解釈するとx86は遅すぎます。代わりに、every最新のCPUはx86を独自の「ネイティブ」マイクロコードにコンパイルします。これは、文字通りすべての「解釈された」言語が、ある時点でコンパイルされることを意味します。

一部の言語はコンパイルまたは解釈が難しい

一部の言語は、コンパイルまたは解釈に適していません。 「良い」言語に期待されるのはスピードです。遅い言語は速い言語よりも望ましくない傾向があります。 C++には、解釈ではなく伝統的にコンパイルされるという事実を利用するルールがあります。これには非常に遅いルール(関数のオーバーロードの解決など)があり、コンパイラーはこれを非常に高速なアセンブリに(単純な高速ルールで)焼き付けることができます。ナイーブなC++インタープリターは、これらの遅いルールを繰り返し実行するのにかなりの時間を費やします。

同様に、一部の言語はコンパイルに向いていません。たとえば、Pythonはすべてにおいてダックタイピングに依存しています。これらのルールは、C++のコンパイルルールよりもはるかに高速ですが、アセンブリのルールよりも低速です。 Pythonをもっと単純なものにマッピングすることができなかったため、Pythonをコンパイルしてもそれほど多くは買えません。

...またはあなたはできますか?

PyPy、Psyco、またはIronPythonを見ると、Pythonをコンパイルする努力があります。ジャストインタイムコンパイル(JIT)と呼ばれる手法を使用して、報酬コンパイルを行うPythonのビットを見つけます。コンパイルが困難な部分を解釈しながら、それらの部分をコンパイルします。多くの一般的に発生するケースでは、IronPythonを使用してPythonコードをJITコンパイルする結果は、C++またはC#と同じかそれより高速です。

これは、コンパイルと解釈の境界が実際にどれほどぼやけているかを示しています。

5
Cort Ammon

はい。些細な例として、すべてのコンパイル済み言語を、インタープリターにAssemblyやその他のコンパイル結果を解釈させることで解釈させることができます。二重に、インタプリタ全体とプログラムを1つの実行可能ファイルにバンドルして、「コンパイルされた」結果を得ることができます。

あなたは「うまくコンパイルされた」とは言いませんでした:)

3
Daniel Gratzer

これは、インタープリターおよびコンパイルの定義に依存します。

たとえば、Perlには実行時にのみ解釈できる特定の構成要素があり、コンパイルが不可能であることを思い出します。

一方、解釈は通常、プログラムが開始される前にすべてのソースコードを解析できないことを意味します。頭の上から例を出すことはできませんが、これは、いくつかの言語をコンパイルする必要があることを意味しても驚かないでしょう。

最後に、ソースコードの生成(LISPメタプログラミング、Cマクロ、Eclipse EMFなど)やバイトコード操作(AspectJなど)などの機能がこの図にどのように適合するかが明確ではありません。

1
mkalkov

Cプログラムの場合、次の2行についてコンパイラーをラップできない理由はありません。

cc -g source.c
./a.out

これはかなり解釈されます。 -gを追加して、Cコードをソースに近づけることができることを強調しました。

また、効率を上げるためにインタープリター言語をコンパイルできます。 Javascriptは醜くなります。 Pythonこれらの素敵な.pycファイルをドロップします。

つまり、あなたが教えてきた二分法はナンセンスです。 JavaまたはScala toにコンパイルされたコードの解釈されたチェーンをフィードして、お互い、それはまさにUnixの哲学(そしてあらゆるBashスクリプト)です。

インタープリターとして記述された言語には、「コンパイル」時間エラーがない傾向があります。しかし、その後、コンパイラに組み込まれ、エラーが発生した場合に停止するlintコレクタがあります。これは、上記の私のおもちゃのコードのスタイルとほぼ同じです。

おそらく、解釈はより「動的」であることを意味します。つまり、コンパイルエラーまたはランタイムエラーの原因となるものが少なくなります。しかし、Javaのように厳密に呼ばれる言語でさえ、不正なクラスをロードしてランタイムエラーをスローする可能性があります。

そして、Cのような「コンパイルされた」言語は、アセンブリ/マシンコードにコンパイルされます。そして、CPUによって解釈されるコードでない場合、マシンコードとは何ですか?コンパイルされたコードはどこかに着陸する必要があります。

これは、JavaコンパイラがJavaソースからJavaバイトコードに変換するプロセスであり、ほぼ同じようにJVM PythonコードはPythonランタイムによって実行されます。したがって、仮想マシンで実行される解釈済みの言語にコンパイルされたコンパイル済み言語がありますそれは母国語(C++)でプログラムされています。

もちろん、brainfuckのようなおもちゃの言語は、JavaまたはCまたはRubyで実装できます。また、アセンブリを学習するための練習として、それらをアセンブリで簡単に書くことができます。ただし、再び= Rubyは、JRubyを介してJVMに置くことができます。これにより、Rubyは、コンパイルされた言語のようになります。

まだ入手しましたか?

0
djechlin