XコンパイラをYのZに書き込むための一般的なルール


9

Xが入力言語、Zが出力言語、fが言語Yで記述されたコンパイラであるとします。

f = X -> Z

fは単なるプログラムなので、Yはどの言語でもかまいません。したがって、それぞれがY1、Y2で記述されたコンパイラf1、f2を持つことができます。

f1 = f Y1    
f2 = f Y2

g = Z -> M
h = g . f    # We get a compiler X -> M

たとえば、cpythonコンパイラを例にとると、XはPython、ZはPython VMコード、YはCです。

cpython = Python -> PythonVMCode C
interpreter = PythonVMCode -> Nothing
interpreter2 = PythonVMCode -> MachineCode

Pythonソースは、Python VMコード、.pycファイルにコンパイルされ、インタープリターによって解釈されます。Python-> MachineCodeを直接実行できるコンパイラが存在する可能性があるように見えますが、実装は非常に困難です。

   hardpython = interpreter2 . cpython 

また、Python-> PythonVMCodeを実行する別のコンパイラを別の言語で記述して、Python自体を記述することもできます。

mypython = Python -> PythonVMCode Python
mypython2 = Python -> PythonVMCode Ruby

さて、ここにPyPyの複雑な例があります。私はPyPyの初心者です。間違っている場合は修正してください。

PyPyドキュメントhttp://doc.pypy.org/en/latest/architecture.html#pypy-the-translation-framework

私たちの目標は、言語実装者の問題に対する可能な解決策を提供することです。l動的言語用のl * o * pインタープリターと、重要な設計上の決定を伴うpプラットフォームを作成する必要があります。

lはX、pはYと考えることができます。すべてのRPythonプログラムをCに変換するプログラムが存在します。

 rpython_compiler = RPython -> C  Python

 pypy = Python -> Nothing RPython

 translate = compile the program pypy written in RPython using rpython_compiler

 py2rpy = Python -> RPython  Python
 py2c = Python -> C Python 
 py2c = rpython_compiler . py2rpy

RPythonプログラムはVMの命令と同じで、rpython_compilerがVMです。

q1。pypyはインタープリターであり、Pythonコードを解釈できるRPythonプログラムです。出力言語がないため、コンパイラーと見なすことはできません。

追加:

  • 翻訳した後でも、pypyはまだインタプリタであり、今回はCでのみ記述されていることがわかりました。
  • インタプリタpypyを詳しく調べると、PythonソースをASTにコンパイルして実行するなんらかの種類のコンパイラが存在している必要があると思います。

このような:

compiler_inside_pypy = Python -> AST_or_so

q2。コンパイラpy2rpyが存在して、すべてのPythonプログラムをRPythonに変換できますか?どの言語で書かれているかは関係ありません。はいの場合、別のコンパイラーpy2cを取得します。pypyとpy2rpyの違いは何ですか?py2rpyはpypyよりも書くのがはるかに難しいですか?

q3。これに関して利用可能ないくつかの一般的なルールまたは理論はありますか?

その他のコンパイラ:

gcc_c = C -> asm? C  # not sure, gimple or rtl?
g++ =   C++ -> asm? C
clang = C -> LLVM_IR  C++
jython = Python -> JVMCode java
ironpython = Python -> CLI C#

q4。f = X-> Zの場合、プログラムPはXで書かれています。Pを高速化したい場合、どうすればよいでしょうか。可能な方法:

  • より効率的なアルゴリズムでPを書き換えます

  • より良いZを生成するためにfを書き直します

  • Zが解釈される場合は、より優れたZインタープリターを作成します(PyPyはここにありますか?)

  • Zで書かれたプログラムを再帰的に高速化する

  • より良い機械を手に入れる

ps。この質問は、コンパイラーの作成方法に関する技術的な問題ではなく、特定の種類のコンパイラーを作成することの実現可能性と複雑さについてです。


直接関係はありませんが、やや類似した概念:en.wikipedia.org/wiki/Supercompilation
SK-logic

1
この質問が本当にスタックオーバーフローに当てはまるかどうかはわかりませんが、特にサブ質問が非常に多いためですが、これについての考えにはまだ感心しています。

4
何を教えられたとしても、ASTは必須ではありません。これは、一部のコンパイラが使用する戦略にすぎません。

1
おそらくこれはcstheory.stackexchange.comに属している
9000

3
ほとんどの「インタプリタ」と同様に、PyPyのPython実装は、実際にはバイトコードコンパイラであり、そのバイトコード形式のインタプリタです。

回答:


4

q1。pypyはインタープリターであり、Pythonコードを解釈できるRPythonプログラムです。出力言語がないため、コンパイラーと見なすことはできません。

PyPyはCPythonに似ており、どちらにもコンパイラ+インタープリタがあります。CPythonには、PythonをPython VMバイトコードにコンパイルするCで記述されたコンパイラーがあり、Cで記述されたインタープリターでバイトコードを実行します。PyPyは、PythonをPython VMバイトコードにコンパイルし、RPythonで記述されたPyPyインタープリターで実行するRPythonで記述されたコンパイラーを備えています。

q2。コンパイラpy2rpyが存在して、すべてのPythonプログラムをRPythonに変換できますか?どの言語で書かれているかは関係ありません。はいの場合、別のコンパイラーpy2cを取得します。pypyとpy2rpyの違いは何ですか?py2rpyはpypyよりも書くのがはるかに難しいですか?

コンパイラーpy2rpyは存在しますか?理論的にはそうです。チューリング完全性はそう保証します。

構築する1つの方法py2rpyは、生成されたソースコードにRPythonで記述されたPythonインタープリターのソースコードを単に含めることです。Bashで書かれたpy2rpyコンパイラの例:

// suppose that /pypy/source/ contains the source code for pypy (i.e. Python -> Nothing RPython)
cp /pypy/source/ /tmp/py2rpy/pypy/

// suppose $inputfile contains an arbitrary Python source code
cp $inputfile /tmp/py2rpy/prog.py

// generate the main.rpy
echo "import pypy; pypy.execfile('prog.py')" > /tmp/py2rpy/main.rpy

cp /tmp/py2rpy/ $outputdir

ここで、PythonコードをRPythonコードに変換する必要があるときはいつでも、このスクリプトを呼び出します。これにより、$ outputdirにRPython main.rpy、RPythonのPythonインタープリターソースコード、およびバイナリblob prog.pyが生成されます。そして、を呼び出すことで、生成されたRPythonスクリプトを実行できますrpython main.rpy

(注:私はrpythonプロジェクトに精通していないため、rpythonインタープリターを呼び出すための構文、pypyをインポートしてpypy.execfileを実行する機能、および.rpy拡張子は完全に構成されていますが、要点は理解できると思います)

q3。これに関して利用可能ないくつかの一般的なルールまたは理論はありますか?

はい、チューリングコンプリート言語は理論的にはチューリングコンプリート言語に翻訳できます。一部の言語は他の言語よりもはるかに翻訳が難しい場合がありますが、質問が「可能ですか?」の場合、答えは「はい」です。

q4。...

ここに質問はありません。


あなたのpy2rpyコンパイラは本当に賢いです。それは私を別のアイデアに導きます。1. pypyは、コンパイラーのRPythonで作成する必要がありますか?必要なのは、Pythonファイルを解釈できるものだけですよね?2. RPythonでサポートされている場合、os.system( 'python $ inputfile')も機能する可能性があります。それがコンパイラと呼ばれることができるかどうかは、少なくとも文字通りではありません。

pypyはまだPython VMを使用していますか?今では明らかです。pypy_the_compiler = Python-> PythonVMCode RPython、pypy_the_interpreter = PythonVMCode-> Nothing RPython、cpython_the_compiler = Python-> PythonVMCode C、cpython_the_interpreter = PythonVMCode-> Nothing C

@jaimechen:Does pypy have to be written in RPython in your compiler?いいえ、RPythonで作成する必要はありませんが、RPythonは「補助インタプリタ」/「ランタイム」にPythonコードを実行するように指示できる必要があります。はい、これは実際の意味での「コンパイラ」ではないことは事実ですが、を書くことが可能であることの建設的な証明ですPython -> RPythonIs pypy still using the Python VM?私はpypyがCPythonをまったく使用していないと考えています(私は間違っている可能性があります)。代わりに、PyPyはRPythonで記述された「Python VM」の独自の実装を持っています。
リーライアン

@jaimechen:より実用的なコンパイラーは、これらを個別にコンパイルおよびコンパイルする方法を知っているコードシーケンスの入力ファイルを分析し、「Rへの再コンパイル」Pythonと「インタープリター-支援」Python。また、JITコンパイルで一般的に使用される手法を使用して、RPythonとPythonのセマンティクスの違いと、それらの場合の解釈へのフォールバックにより、特定の入力が異なる出力を生成するかどうかを検出します。これらはすべて、より実用的なPython -> RPythonコンパイラで見られる洗練されたものです。
リーライアン

おそらくここに制約を追加する必要があります。既存の3番目のマシンを使用せずに、状態マシンXを状態マシンZに変換します。これは、Xが完全に新しい場合であり、コンパイラーやインタープリターは今のところ存在しません。
jaimechen '29年

2

q2だけに答えるために、William McKeemanによるコンパイラブックがあり、言語Yで記述され、出力言語Zを生成する言語Xのコンパイラの理論が、Tダイアグラムのシステムを介して探索されています。1970年代に発行されたタイトルです。


はい、ありがとうございます。en.wikipedia.org/wiki/Tombstone_diagram
jaimechen

1

q1。一般に、インタープリターはコンパイラーではありません。コンパイラーとインタープリターの主な違いは、インタープリターが毎回ソース言語のソースコードで新しく開始することです。pypyがpyASTまたはpyP-codeであり、ASTまたはP-codeインタープリターがあった場合、pyASTをコンパイラーと呼ぶことができます。これが、古いUCSD PASCALコンパイラの動作方法(および他のかなりの数)です。プログラムが実行されたときに解釈されたPコードにコンパイルされました。(生成されたオブジェクトコードのコンパクトさが速度よりもはるかに重要である場合、.NETでもこのようなものが提供されます。)

q2。はい、もちろん。UCSD PASCAL(およびその他多数)を参照してください。

q3。コンピュータサイエンスの古典的なテキストを掘り下げます。Per Brinch-HansenによるConcurrent PASCALについて読んでください(メモリが私に役立つ場合)。コンパイラとコード生成についてはたくさん書かれています。通常、マシンに依存しない疑似コードを生成する方が、マシンコードを生成するよりもはるかに簡単です。疑似コードには、通常、実際のマシンに常に含まれている癖がありません。

q4。生成されたオブジェクトをより高速に実行したい場合は、コンパイラーをよりスマートにして、最適化を向上させます。オブジェクトが解釈される場合は、より複雑な操作をプリミティブな疑似命令にプッシュダウンすることを検討し(CISCとRISCの類似性です)、インタープリターからフラックを最適化するために最善を尽くします。

コンパイラーをより高速に実行したい場合は、ソースコードの再考を含め、コンパイラーが実行するすべてのものを確認する必要があります。コンパイラ自体をロードした後、コンパイルの最も時間のかかる部分は、常にソースコードをコンパイラに読み込むことです。(たとえば、C ++を検討してください。他のすべては比較的同等です。単純な "Hello、World"プログラムをコンパイルするために#includeファイルの9,000(または多分50,000)行を削減しなければならないコンパイラは、1つほど速くなることは決してありません。 4行または5行を読むだけで十分です。)

どこで読んだか覚えていませんが、ETH-チューリッヒの元のOberonコンパイラには、非常に洗練された非常に洗練されたシンボルテーブルメカニズムがありました。コンパイラのパフォーマンスに関するWirthのベンチマークは、コンパイラがそれ自体をコンパイルするのにかかる時間でした。ある朝、彼は入り、ゴージャスな多重リンクされたウルトラツリーシンボルテーブルを引き出し、単純な線形配列と直線的な線形検索に置き換えました。彼のグループの大学院生はショックを受けました。変更後、コンパイラーはより高速になりました。コンパイルするモジュールは常に小さく、エレガントなモンスターが線形配列や線形検索よりも多くのオーバーヘッドを課すためでした。


1
ありがとう。コンパイラーは「コンパイル」し、インタープリターは「実行」しますが、2種類のプログラムについて、タイプが異なるなどの洞察が得られるでしょうか。
jaimechen '29年

1

述べられているようにあなたの質問は私があなたが本当に欲しい/必要とするものはコンパイラが何であるか、インタプリタは何であるか、そして2つの間の違いの説明であると信じるように導きます。

コンパイラーは、言語Xで書かれたプログラムを、言語Yで書かれた機能的に同等のプログラムにマップします。例として、PascalからCへのコンパイラーは、

function Square(i: Integer)
begin
    Square := i * i
end

int Square(int i)
{
    return i * i;
}

ほとんどのコンパイラは「下向き」にコンパイルするため、上位レベルのプログラミング言語を下位レベルの言語にコンパイルします。最終的な下位レベルの言語はマシンコードです。

ほとんどのコンパイラは直接マシンコードにコンパイルされますが、一部(特にJavaおよび.NET言語)は「バイトコード」(JavaバイトコードおよびCIL)にコンパイルされます。バイトコードを仮想コンピュータのマシンコードと考えてください。このバイトコードは、実行時に解釈またはJITされます(詳細は後で説明します)。

インタプリタは、ある言語Zで書かれたプログラムを実行します。インタプリタは、プログラムを少しずつ読み取り、それを実行しながら実行します。例えば:

int i = 0;
while (i < 1)
{
    i++
}
return i;

インタプリタがその行のプログラム行を見て、その行を調べ、それが実行することを実行し、次の行を見るなどを想像してみてください。

インタープリターの最も良い例は、コンピューターのCPUです。マシンコードを解釈して実行します。CPUがどのように動作するかは、物理的にどのように構築されているかによって指定されます。インタプリタプログラムがどのように機能するかは、コードがどのように見えるかによって指定されます。したがって、CPUはインタプリタプログラムを解釈して実行し、次にインタプリタプログラムが入力を解釈して実行します。この方法でインタプリタをチェーンできます。

JITterはJust-In-Timeコンパイラです。JITterはコンパイラーです。唯一の違いは、それが実行される時間です。ほとんどのプログラムは、作成、コンパイル、ユーザーに配布されてから実行されますが、JavaバイトコードとCILは最初にユーザーに配布され、次に実行される直前にマシンにコンパイルされます。ユーザーのコード。

C#->(コンパイル)-> CIL->顧客に出荷->(実行直前にコンパイル)->マシンコード->(実行)

最後に知っておきたいことは、チューリング完全性リンク)です。プログラミング言語は、「チューリングマシン」が実行できるすべてを計算できる場合、つまり、少なくともチューリングマシンと同じくらい「強力」である場合、チューリング完全です。チャーチ=チューリングのテーゼのチューリングマシンは、少なくとも私たちが今までに構築することができます任意のマシンとして強力なようであると述べています。したがって、すべてのチューリング完全言語はチューリングマシンとまったく同じくらい強力であり、したがってすべてのチューリング完全言語は同等に強力です。

つまり、プログラミング言語が完全なチューリングである限り(ほぼすべてがチューリング)、どの言語を選択しても問題ありません。それらはすべて同じものを計算できるためです。これは、コンパイラーまたはインタープリターを作成するためにどのプログラミング言語を選択するかはあまり重要ではないことも意味します。最後に重要なことですが、XとYの両方がチューリング完全であれば、常に言語XからYまでのコンパイラーを作成できることを意味します。

チューリング完全であっても、言語が効率的であるかどうか、CPUやその他のハードウェアの実装の詳細、言語で使用するコンパイラーの品質については何も言わないことに注意してください。また、オペレーティングシステムによっては、プログラムにファイルを開く権限がないと判断される場合がありますが、それによって何かを計算する能力が妨げられることはありません。テキストの別の壁が必要になるため、意図的に計算を定義しませんでした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.