Aturan umum untuk menulis kompiler X ke Z di Y


9

Misalkan X adalah bahasa input, Z adalah bahasa output, maka f adalah kompiler, yang ditulis dalam bahasa Y.

f = X -> Z

Karena f hanya sebuah program, saya pikir Y dapat bahasa apa pun, bukan? Jadi kita dapat memiliki kompiler f1, f2, masing-masing ditulis dalam Y1, Y2.

f1 = f Y1    
f2 = f Y2

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

Ambil cpython compiler misalnya, X adalah Python, Z adalah kode VM Python, Y adalah C.

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

Sumber-sumber Python dikompilasi ke kode VM Python, file .pyc, kemudian ditafsirkan oleh penerjemah. Sepertinya mungkin ada kompiler yang dapat langsung melakukan Python -> MachineCode, meskipun jauh lebih sulit untuk diimplementasikan:

   hardpython = interpreter2 . cpython 

Kita juga dapat menulis kompiler lain melakukan pekerjaan Python -> PythonVMCode, dalam bahasa lain, katakan Python itu sendiri.

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

Sekarang, inilah contoh rumit PyPy. Saya hanya pemula di PyPy, koreksi saya jika saya salah:

PyPy doc http://doc.pypy.org/en/latest/architecture.html#pypy-the-translation-framework

Tujuan kami adalah untuk memberikan solusi yang mungkin untuk masalah pelaksana bahasa: harus menulis penerjemah l * o * p untuk bahasa yang dinamis dan platform p dengan o keputusan desain yang penting.

Kita dapat berpikir l adalah X, p adalah Y. Ada sebuah program yang menerjemahkan semua program RPython ke 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

Program RPython sama seperti instruksi VM, rpython_compiler adalah VM.

q1. pypy adalah interpreter, program RPython yang dapat menginterpretasikan kode Python, tidak ada bahasa output, jadi kita tidak bisa menganggapnya sebagai kompiler, kan?

Ditambahkan:

  • Saya baru menemukan bahwa walaupun setelah menerjemahkan, pypy masih menjadi penerjemah, hanya saja kali ini ditulis dalam C.
  • Jika kita melihat jauh ke dalam pypy interpreter, saya percaya pasti ada semacam kompiler, yang mengkompilasi sumber Python ke beberapa AST, kemudian jalankan

seperti ini:

compiler_inside_pypy = Python -> AST_or_so

q2. Bisakah kompiler py2rpy ada, mengubah semua program Python menjadi RPython? Dalam bahasa mana itu ditulis tidak relevan. Jika ya, kami mendapatkan py2c kompiler lain. Apa perbedaan antara pypy dan py2rpy di alam? Apakah py2rpy jauh lebih sulit untuk ditulis daripada pypy?

q3. Apakah ada aturan umum atau teori yang tersedia tentang ini?

Lebih banyak kompiler:

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. Diberikan f = X -> Z, sebuah program P ditulis dalam X. Ketika kita ingin mempercepat P, apa yang bisa kita lakukan? Cara berbisa:

  • tulis ulang P dalam algoritma yang lebih efisien

  • tulis ulang f untuk menghasilkan Z yang lebih baik

  • jika Z ditafsirkan, tulislah juru bahasa Z yang lebih baik (PyPy ada di sini?)

  • mempercepat program yang ditulis dalam Z secara rekursif

  • dapatkan mesin yang lebih baik

ps. Pertanyaan ini bukan tentang hal-hal teknologi tentang cara menulis kompiler, tetapi kelayakan dan kompleksitas penulisan kompiler jenis tertentu.


Tidak terkait langsung, tetapi konsep yang agak mirip: en.wikipedia.org/wiki/Supercompilation
SK-logic

1
Saya tidak yakin pertanyaan ini benar-benar cocok dengan Stack Overflow, terutama karena ada begitu banyak pertanyaan di dalamnya, tapi saya masih mengagumi pemikiran yang masuk ke masalah ini.

4
Terlepas dari apa yang telah diajarkan kepada Anda, AST tidak diperlukan - ini hanyalah strategi yang digunakan beberapa penyusun.

1
Mungkin ini milik cstheory.stackexchange.com
9000

3
Implementasi Python Python, seperti kebanyakan "interpreter", sebenarnya adalah kompiler bytecode dan penerjemah untuk format bytecode dalam satu.

Jawaban:


4

q1. pypy adalah interpreter, program RPython yang dapat menginterpretasikan kode Python, tidak ada bahasa output, jadi kita tidak bisa menganggapnya sebagai kompiler, kan?

PyPy mirip dengan CPython, keduanya memiliki kompiler + juru bahasa. CPython memiliki kompiler yang ditulis dalam C yang mengkompilasi bytecode Python ke Python VM kemudian mengeksekusi bytecode dalam sebuah interpreter yang ditulis dalam C. PyPy memiliki kompiler yang ditulis dalam RPython yang mengkompilasi bytecode Python ke Python VM, kemudian mengeksekusinya dalam PyPy Interpreter yang ditulis dalam RPython.

q2. Bisakah kompiler py2rpy ada, mengubah semua program Python menjadi RPython? Dalam bahasa mana itu ditulis tidak relevan. Jika ya, kami mendapatkan py2c kompiler lain. Apa perbedaan antara pypy dan py2rpy di alam? Apakah py2rpy jauh lebih sulit untuk ditulis daripada pypy?

Bisakah sebuah compiler py2rpy ada? Secara teoritis ya. Turing menjamin kelengkapan begitu.

Salah satu metode untuk membangun py2rpyadalah dengan hanya memasukkan kode sumber dari juru bahasa Python yang ditulis dalam RPython dalam kode sumber yang dihasilkan. Contoh kompiler py2rpy, ditulis dalam Bash:

// 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

sekarang setiap kali Anda perlu menerjemahkan kode Python ke kode RPython, Anda memanggil skrip ini, yang menghasilkan - dalam $ outputdir - RPython main.rpy, kode sumber Penerjemah Python RPython, dan prog.py. biner gumpalan biner Dan kemudian Anda dapat menjalankan skrip RPython yang dihasilkan dengan memanggil rpython main.rpy.

(catatan: karena saya tidak terbiasa dengan proyek rpython, sintaks untuk memanggil interpreter rpython, kemampuan untuk mengimpor pypy dan melakukan pypy.execfile, dan ekstensi .rpy murni dibuat, tetapi saya pikir Anda mengerti maksudnya)

q3. Apakah ada aturan umum atau teori yang tersedia tentang ini?

Ya, bahasa Turing Lengkap apa pun secara teoritis dapat diterjemahkan ke bahasa Turing Lengkap apa pun. Beberapa bahasa mungkin jauh lebih sulit diterjemahkan daripada bahasa lain, tetapi jika pertanyaannya adalah "apakah mungkin?", Jawabannya adalah "ya"

q4. ...

Tidak ada pertanyaan di sini.


Kompiler py2rpy Anda sangat pintar. Ini menuntun saya ke ide lain. 1. Apakah pypy harus ditulis dalam RPython di kompiler Anda? Yang Anda butuhkan adalah sesuatu dapat menafsirkan file Python, bukan? 2. os.system ('python $ inputfile') juga dapat berfungsi jika didukung dalam RPython. Tidak yakin apakah masih bisa disebut kompiler, setidaknya tidak secara harfiah.

Apakah pypy masih menggunakan Python VM? Sekarang sudah jelas. pypy_the_compiler = Python -> PythonVMCode RPython, pypy_the_interpreter = PythonVMCode -> Tidak ada yang RPython, cpython_the_compiler = Python -> PythonVMCode C, cpython_the_interpreter = PythonVMCode -> Tidak ada yang C

@jaimechen: Does pypy have to be written in RPython in your compiler?Tidak, tidak perlu ditulis dalam RPython, tetapi RPython harus dapat memberi tahu "penerjemah tambahan" / "runtime" untuk menjalankan kode Python. Ya memang benar ini bukan "kompiler" dalam arti praktis, tetapi ini adalah bukti konstruktif bahwa mungkin untuk menulis Python -> RPython. Is pypy still using the Python VM?Saya percaya pypy tidak menggunakan CPython sama sekali (saya bisa saja salah), malahan PyPy memiliki implementasi sendiri dari "Python VM" yang ditulis dalam RPython.
Lie Ryan

@jaimechen: kompiler yang lebih praktis mungkin dapat menganalisis file input untuk urutan kode yang ia tahu bagaimana mengkompilasi dan mengkompilasi ini secara terpisah dan juga cara untuk bolak-balik antara Python "recompiled-to-RPython" dan "interpreter- dibantu "Python. Mungkin juga menggunakan teknik yang biasa digunakan dalam kompilasi JIT untuk mendeteksi jika input tertentu dapat menghasilkan output yang berbeda karena perbedaan dalam semantik RPython dan Python dan fallback ke interpretasi dalam kasus-kasus tersebut. Semua itu adalah kecanggihan yang dapat dilihat dalam Python -> RPythonkompiler yang lebih praktis .
Lie Ryan

Mungkin kendala harus ditambahkan di sini: mengubah mesin negara X ke mesin negara Z, tanpa bantuan mesin ke-3 yang ada. Ini adalah kasus ketika X benar-benar baru, tidak ada compiler atau interpreter yang pernah ada sejauh ini.
jaimechen

2

Untuk menjawab q2 saja, ada buku kompiler oleh William McKeeman di mana teori kompiler untuk bahasa X ditulis dalam bahasa Y yang menghasilkan bahasa keluaran Z dieksplorasi melalui sistem diagram-T. Diterbitkan pada tahun 1970-an, judul tidak diserahkan, maaf



1

q1. Secara umum, juru bahasa bukan kompiler. Perbedaan utama antara kompiler dan interpreter adalah bahwa interpreter mulai baru, dengan kode sumber dalam bahasa sumber, setiap saat. Jika pypy Anda bukan pyAST, atau pyP-code, dan kemudian Anda memiliki juru bahasa AST atau P-code, maka Anda bisa memanggil pyAST kompiler. Ini adalah cara kerja kompiler UCC PASCAL lama bekerja (juga beberapa yang lain): mereka dikompilasi ke beberapa kode-P, yang ditafsirkan ketika program dijalankan. (Bahkan. NET menyediakan sesuatu seperti ini, ketika kekompakan kode objek yang dihasilkan jauh lebih penting daripada kecepatan.)

q2. Ya tentu saja. Lihat UCSD PASCAL (dan banyak lainnya).

q3. Gali teks-teks klasik dalam ilmu komputer. Baca di Concurrent PASCAL, oleh Per Brinch-Hansen (jika ingatanku). Banyak yang telah ditulis tentang kompiler dan pembuatan kode. Membuat pseudocode yang tidak tergantung pada mesin biasanya jauh lebih mudah daripada menghasilkan kode mesin: pseudocode biasanya bebas dari keanehan yang dikandung oleh mesin nyata.

q4. Jika Anda ingin objek yang Anda buat berjalan lebih cepat, Anda membuat kompiler lebih pintar, untuk melakukan optimasi yang lebih baik. Jika objek Anda ditafsirkan, Anda mempertimbangkan untuk mendorong operasi yang lebih kompleks ke dalam konstruksi pseudoin primitif (CISC vs RISC adalah analoginya), maka Anda melakukan yang terbaik untuk mengoptimalkan frack out dari juru bahasa Anda.

Jika Anda ingin kompiler Anda berjalan lebih cepat, Anda harus melihat SEMUANYA, termasuk memikirkan kembali kode sumber Anda. Setelah memuat kompiler itu sendiri, bagian kompilasi yang paling memakan waktu adalah SELALU membaca kode sumber ke dalam kompiler. (Sebagai contoh, pertimbangkan C ++. Semua hal lainnya relatif sama, sebuah kompiler yang harus menghitung 9.000 (atau mungkin 50.000) baris #include file untuk mengkompilasi program "Hello, World" yang sederhana tidak akan pernah secepat satu yang hanya perlu membaca empat atau lima baris.)

Saya tidak ingat di mana saya membacanya, tetapi kompiler Oberon asli di ETH-Zurich memiliki mekanisme tabel simbol yang sangat canggih, cukup elegan. Benchmark Wirth untuk kinerja kompiler adalah waktu yang dibutuhkan bagi kompiler untuk mengkompilasi dirinya sendiri. Suatu pagi, dia masuk, menarik keluar tabel simbol ultra-pohon simbol multiply-linked yang cantik, dan menggantinya dengan array linier sederhana dan pencarian linear lurus. Mahasiswa pascasarjana dalam kelompoknya TERSAMPIR. Setelah perubahan, kompiler menjadi lebih cepat, karena modul-modul yang dikompilasi selalu cukup kecil sehingga monster elegan mengenakan overhead total lebih banyak daripada array linier dan pencarian linear.


1
Terima kasih. 'Kompilasi' kompiler, sementara penerjemah 'mengeksekusi', dapatkah ada lebih banyak wawasan tentang dua jenis program, seperti tipenya yang berbeda?
jaimechen

1

Pertanyaan Anda sebagaimana dinyatakan membuat saya percaya bahwa apa yang benar-benar Anda inginkan / butuhkan adalah penjelasan tentang apa itu kompiler, apa penerjemah itu dan perbedaan di antara keduanya.

Kompiler memetakan program yang ditulis dalam bahasa X ke program yang secara fungsional setara ditulis dalam bahasa Y. Sebagai contoh, kompiler dari Pascal ke C mungkin mengkompilasi

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

untuk

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

Kebanyakan kompiler mengkompilasi 'ke bawah', sehingga mereka mengkompilasi bahasa pemrograman tingkat tinggi ke dalam bahasa tingkat lebih rendah, bahasa tingkat bawah yang paling tinggi adalah kode mesin.

Sebagian besar kompiler mengkompilasi langsung ke kode mesin, tetapi beberapa (terutama bahasa Java dan .NET) mengkompilasi ke 'bytecode' ( Java bytecode dan CIL ). Pikirkan bytecode sebagai kode mesin untuk komputer hipotetis. Bytecode ini kemudian diartikan atau JITted ketika dijalankan (lebih lanjut tentang itu nanti).

Seorang penerjemah mengeksekusi suatu program yang ditulis dalam beberapa bahasa Z. Seorang penerjemah membaca suatu program sedikit demi sedikit, mengeksekusinya seiring berjalannya waktu. Contohnya:

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

Bayangkan penerjemah melihat baris program itu untuk baris, memeriksa baris, mengeksekusi apa yang dilakukannya, melihat baris berikutnya dan seterusnya.

Contoh terbaik juru bahasa adalah CPU komputer Anda. Ini mengartikan kode mesin dan menjalankannya. Cara kerja CPU ditentukan oleh bagaimana ia dibangun secara fisik. Cara kerja program juru bahasa ditentukan oleh seperti apa kode tersebut. CPU karenanya menginterpretasikan dan mengeksekusi program interpreter, yang pada gilirannya menginterpretasikan dan mengeksekusi inputnya. Anda dapat menghubungkan penerjemah dengan cara ini.

JITter adalah kompiler Just-In-Time. JITter adalah kompiler. Satu-satunya perbedaan adalah waktu dieksekusi: sebagian besar program ditulis, dikompilasi, dikirim ke penggunanya dan kemudian dieksekusi, tetapi bytecode Java dan CIL dikirim ke penggunanya terlebih dahulu, dan sebelum mereka dieksekusi mereka dikompilasi ke mesin kode pengguna mereka.

C # -> (kompilasi) -> CIL -> dikirim ke pelanggan -> (kompilasi sesaat sebelum eksekusi) -> kode mesin -> (jalankan)

Hal terakhir yang ingin Anda ketahui adalah kelengkapan Turing ( tautan ). Bahasa pemrograman adalah Turing Lengkap jika dapat menghitung semua yang bisa ' mesin Turing ', yaitu setidaknya sama kuatnya dengan mesin Turing. The Gereja-Turing tesis menyatakan bahwa mesin Turing setidaknya sekuat setiap mesin yang kita dapat pernah membangun. Oleh karena itu, setiap bahasa lengkap Turing sama kuatnya dengan mesin Turing, dan karena itu semua bahasa lengkap Turing sama kuatnya.

Dengan kata lain, selama bahasa pemrograman Anda Turing lengkap (hampir semuanya), tidak masalah bahasa yang Anda pilih, karena mereka semua dapat menghitung hal yang sama. Ini juga berarti bahwa sangat tidak relevan bahasa pemrograman mana yang Anda pilih untuk menulis kompiler atau juru bahasa Anda. Last but not least, itu berarti Anda selalu dapat menulis kompiler dari bahasa X ke Y jika X dan Y keduanya Turing lengkap.

Perhatikan bahwa menjadi Turing selesai tidak mengatakan apa-apa tentang apakah bahasa Anda efisien, atau tentang semua detail implementasi CPU Anda dan perangkat keras lain, atau kualitas kompiler yang Anda gunakan untuk bahasa tersebut. Juga, sistem operasi Anda mungkin memutuskan program Anda tidak memiliki hak untuk membuka file, tetapi itu tidak menghalangi kemampuan Anda untuk menghitung apa pun - saya sengaja tidak mendefinisikan komputasi, karena itu akan membutuhkan dinding teks yang lain.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.