Jawaban singkatnya adalah: Anda benar dalam kecurigaan Anda, Anda selalu membutuhkan penerjemah lain yang ditulis dalam X atau kompiler dari Y ke beberapa bahasa lain yang sudah Anda miliki juru bahasanya. Interpreter mengeksekusi, compiler hanya menerjemahkan dari satu bahasa ke bahasa lain, di beberapa titik dalam sistem Anda, ada harus menjadi juru ... bahkan itu hanya CPU.
Tidak peduli berapa banyak penerjemah baru yang Anda tulis dalam bahasa Y , Anda selalu harus menggunakan penerjemah pertama yang ditulis dalam X untuk menafsirkan penerjemah berikutnya. Ini tampaknya menjadi masalah hanya karena sifat penafsir.
Benar. Apa yang Anda bisa lakukan adalah menulis compiler dari Y ke X (atau bahasa lain yang Anda memiliki seorang penerjemah), dan Anda bahkan dapat melakukan itu di Y . Kemudian Anda dapat menjalankan kompiler Y Anda yang ditulis dalam Y pada juru bahasa Y yang ditulis dalam X (atau pada juru bahasa Y yang ditulis dalam Y yang berjalan pada juru bahasa Y yang ditulis dalam X , atau pada juru bahasa Y yang ditulis dalam Y yang menjalankan juru bahasa Y yang ditulis dalam Y berlari di atas Ypenerjemah ditulis dalam X , atau ... ad infinitum) untuk mengkompilasi penerjemah Y Anda ditulis dalam Y ke X , sehingga Anda kemudian dapat menjalankannya pada penerjemah X. Dengan begitu, Anda telah menyingkirkan penerjemah Y Anda yang ditulis dalam X , tetapi sekarang Anda membutuhkan penerjemah X (kami tahu bahwa kami sudah memilikinya, karena, jika tidak, kami tidak dapat menjalankan penerjemah X yang ditulis dalam Y ), dan Anda harus menulis Y -to- X -compiler pertama.
Namun , di sisi lain, artikel Wikipedia tentang penerjemah sebenarnya berbicara tentang penerjemah mandiri. Berikut adalah kutipan kecil yang relevan:
Interpreter mandiri adalah interpreter bahasa pemrograman yang ditulis dalam bahasa pemrograman yang dapat menafsirkan dirinya sendiri; contohnya adalah juru bahasa BASIC yang ditulis dalam bahasa BASIC. Interpreter mandiri terkait dengan kompiler hosting mandiri.
Jika tidak ada kompiler untuk bahasa yang akan ditafsirkan, membuat penerjemah sendiri membutuhkan implementasi bahasa dalam bahasa host (yang mungkin merupakan bahasa pemrograman lain atau assembler). Dengan memiliki juru bahasa pertama seperti ini, sistem di-bootstrap dan versi-versi baru dari juru bahasa tersebut dapat dikembangkan dalam bahasa itu sendiri
Namun masih belum jelas bagi saya, bagaimana tepatnya hal ini dilakukan. Tampaknya apa pun yang terjadi, Anda selalu akan dipaksa untuk menggunakan versi pertama penerjemah Anda yang ditulis dalam bahasa host.
Benar. Perhatikan bahwa artikel Wikipedia secara eksplisit mengatakan bahwa Anda memerlukan implementasi kedua bahasa Anda, dan itu tidak mengatakan bahwa Anda dapat menyingkirkan yang pertama.
Sekarang artikel yang disebutkan di atas menghubungkan ke artikel lain di mana Wikipedia memberikan beberapa contoh penerjemah self-hosting yang seharusnya. Namun, setelah diperiksa lebih dekat, tampaknya bagian "penafsiran" utama dari banyak penafsir hosting sendiri (terutama beberapa yang lebih umum seperti PyPy atau Rubinius) sebenarnya ditulis dalam bahasa lain seperti C ++ atau C.
Sekali lagi, benar. Itu adalah contoh yang sangat buruk. Ambil Rubinius, misalnya. Ya, memang benar bahwa bagian Ruby dari Rubinius di-host-sendiri, tetapi itu adalah kompiler, bukan penerjemah: ia mengkompilasi kode sumber Ruby ke bytecode Rubinius. Bagian penerjemah OTOH tidak di-host-sendiri: ini mengartikan bytecode Rubinius, tetapi ditulis dalam C ++. Jadi, menyebut Rubinius sebagai "penerjemah yang di-hosting-sendiri" adalah salah: bagian yang di -hosting-sendiri bukan seorang juru bahasa , dan bagian juru bahasa tidak di -hosting-sendiri .
PyPy mirip, tetapi bahkan lebih salah: ia bahkan tidak ditulis dengan Python, ia ditulis dalam RPython, yang merupakan bahasa yang berbeda. Secara sintaksis mirip dengan Python, secara semantik merupakan "subset diperluas", tetapi sebenarnya adalah bahasa yang diketik secara statis kira-kira pada tingkat abstraksi yang sama dengan Java, dan implementasinya adalah kompiler dengan beberapa backend yang mengkompilasi kode sumber RPython ke C, ECMAScript kode sumber, kode byte CIL, bytecode JVM, atau kode sumber Python.
Jadi apa yang saya jelaskan di atas mungkin? Bisakah penerjemah tuan rumah mandiri dari tuan rumah aslinya? Jika demikian, bagaimana tepatnya hal ini dilakukan?
Tidak, tidak dengan sendirinya. Anda perlu menyimpan penerjemah asli atau menulis kompiler dan mengkompilasi penerjemah mandiri Anda.
Ada yang beberapa meta-melingkar VMS, seperti Klein (ditulis dalam Diri ) dan Maxine (ditulis di Jawa). Perhatikan, bagaimanapun, bahwa di sini definisi "meta-sirkular" belum berbeda: VM ini tidak ditulis dalam bahasa yang mereka jalankan: Klein mengeksekusi bytecode diri tetapi ditulis dalam Self, Maxine mengeksekusi bytecode JVM tetapi ditulis dalam Java. Namun, Diri / Java kode sumber VM benar-benar akan dikompilasi untuk Diri / JVM bytecode dan kemudian dieksekusi oleh VM, sehingga pada saat VM dijalankan, itu adalah dalam bahasa dijalankan. Fiuh.
Perhatikan juga bahwa ini berbeda dari VM seperti SqueakVM dan Jikes RVM . Jikes ditulis dalam Java, dan SqueakVM ditulis dalam bahasa Slang (suatu sintaksis yang diketik secara statik dan subtek dari Smalltalk kira-kira pada tingkat abstraksi yang sama dengan assembler tingkat tinggi), dan keduanya dikompilasi secara statis dengan kode asli sebelum dijalankan. Mereka tidak lari ke dalam diri mereka sendiri. Namun, Anda dapat menjalankannya di atas diri mereka sendiri (atau di atas Smalltalk VM / JVM lainnya). Tapi itu bukan "meta-melingkar" dalam pengertian ini.
Maxine dan Klein, OTOH lakukanlari di dalam diri mereka sendiri; mereka mengeksekusi bytecode mereka sendiri menggunakan implementasi mereka sendiri. Ini benar-benar melegakan hati! Ini memungkinkan beberapa peluang optimisasi yang keren, misalnya karena VM mengeksekusi dirinya sendiri bersama dengan program pengguna, ia dapat menyatukan panggilan dari program pengguna ke VM dan sebaliknya, misalnya panggilan ke pengumpul sampah atau pengalokasi memori dapat digabungkan ke dalam pengguna kode, dan panggilan balik reflektif dalam kode pengguna dapat dimasukkan ke dalam VM. Juga, semua trik optimisasi pintar yang dilakukan oleh VM modern, di mana mereka menonton program yang mengeksekusi dan mengoptimalkannya tergantung pada beban kerja dan data yang sebenarnya, VM dapat menerapkan trik-trik yang sama untuk dirinya sendiri ketika menjalankan program pengguna sementara program pengguna sedang mengeksekusi beban kerja spesifik. Dengan kata lain, VM sangat mengkhususkan diri untuk ituprogram tertentu berjalan yang beban kerja tertentu.
Namun, perhatikan saya mengitari penggunaan kata "interpreter" di atas, dan selalu menggunakan "mengeksekusi"? Nah, VMs itu tidak dibangun di sekitar interpreter, mereka dibangun di sekitar (JIT) kompiler. Ada penerjemah yang ditambahkan ke Maxine nanti, tetapi Anda selalu membutuhkan kompiler: Anda harus menjalankan VM sekali di atas VM lain (mis. Oracle HotSpot dalam kasus Maxine), sehingga VM dapat (JIT) mengkompilasi sendiri. Dalam kasus Maxine, JIT akan mengkompilasi fase boot-nya sendiri, kemudian membuat serial yang mengkompilasi kode asli ke image VM bootstrap dan menempelkan bootloader yang sangat sederhana di depan (satu-satunya komponen VM yang ditulis dalam C, meskipun itu hanya untuk kenyamanan , bisa juga di Jawa). Sekarang Anda dapat menggunakan Maxine untuk mengeksekusi sendiri.
Anda benar dalam mencatat bahwa juru bahasa hosting sendiri masih membutuhkan juru bahasa untuk menjalankannya sendiri, dan tidak dapat di-bootstrap dalam arti yang sama dengan kompiler.
Namun, diri-host bahasa bukanlah hal yang sama sebagai juru diri-host. Biasanya lebih mudah membangun interpreter daripada membangun kompiler. Oleh karena itu, untuk mengimplementasikan bahasa baru, kami mungkin pertama-tama mengimplementasikan seorang juru bahasa dalam bahasa yang tidak terkait. Kemudian kita bisa menggunakan juru bahasa itu untuk mengembangkan kompiler untuk bahasa kita. Bahasa tersebut kemudian di-host-sendiri, karena kompiler ditafsirkan. Compiler kemudian dapat mengkompilasi sendiri, dan kemudian dapat dianggap sepenuhnya bootstrap.
Kasus khusus dari ini adalah runtime kompilasi JIT self-hosting. Itu bisa dimulai dengan juru bahasa dalam bahasa host, yang kemudian menggunakan bahasa baru untuk mengimplementasikan kompilasi JIT, setelah itu kompiler JIT dapat mengkompilasi dirinya sendiri. Ini terasa seperti interpreter hosting sendiri, tetapi menghindari masalah penerjemah tak terbatas. Pendekatan ini digunakan, tetapi belum terlalu umum.
Teknik terkait lainnya adalah interpreter yang dapat diperluas, di mana kita dapat membuat ekstensi dalam bahasa yang ditafsirkan. Misalnya, kami mungkin menerapkan opcode baru dalam bahasa. Ini dapat mengubah juru bahasa telanjang menjadi juru bahasa kaya fitur, selama kita menghindari ketergantungan sirkular.
Sebuah kasus yang benar-benar terjadi cukup umum adalah kemampuan bahasa untuk mempengaruhi penguraiannya sendiri, misalnya sebagai makro yang dievaluasi waktu-parsing. Karena bahasa makro sama dengan bahasa yang sedang diproses, bahasa ini cenderung jauh lebih kaya fitur daripada bahasa makro khusus atau terbatas. Namun, benar untuk dicatat bahwa bahasa yang melakukan ekstensi adalah bahasa yang sedikit berbeda dari bahasa setelah ekstensi.
Ketika interpreter yang di-host secara nyata digunakan, ini biasanya dilakukan untuk alasan pendidikan atau penelitian. Misalnya, menerapkan juru bahasa untuk Skema di dalam Skema adalah cara yang keren untuk mengajarkan bahasa pemrograman (lihat SICP).
sumber