Saya sedang meneliti CoffeeScript di situs webnya http://coffeescript.org/ , dan memiliki teks
Kompiler CoffeeScript itu sendiri ditulis dalam CoffeeScript
Bagaimana kompiler dapat mengkompilasi sendiri, atau apa arti pernyataan ini?
Saya sedang meneliti CoffeeScript di situs webnya http://coffeescript.org/ , dan memiliki teks
Kompiler CoffeeScript itu sendiri ditulis dalam CoffeeScript
Bagaimana kompiler dapat mengkompilasi sendiri, atau apa arti pernyataan ini?
Jawaban:
Edisi pertama sebuah kompiler tidak dapat dihasilkan mesin dari bahasa pemrograman khusus untuk itu; kebingunganmu bisa dimengerti. Versi kompiler yang lebih baru dengan lebih banyak fitur bahasa (dengan sumber ditulis ulang dalam versi pertama bahasa baru) dapat dibangun oleh kompiler pertama. Versi itu kemudian dapat mengkompilasi kompiler berikutnya, dan seterusnya. Ini sebuah contoh:
Catatan: Saya tidak yakin persis bagaimana versi CoffeeScript diberi nomor, itu hanya contoh.
Proses ini biasanya disebut bootstrap . Contoh lain dari kompiler bootstrap adalah rustc
, kompiler untuk bahasa Rust .
Dalam makalah Reflection on Trusting Trust , Ken Thompson, salah satu penggagas Unix, menulis ikhtisar yang menarik (dan mudah dibaca) tentang bagaimana kompiler C mengkompilasi dirinya sendiri. Konsep serupa dapat diterapkan ke CoffeeScript atau bahasa lainnya.
Gagasan kompiler yang mengkompilasi kode sendiri samar-samar mirip dengan quine : kode sumber yang, ketika dijalankan, menghasilkan sebagai output kode sumber asli. Ini adalah salah satu contoh quine CoffeeScript. Thompson memberikan contoh ini tentang kuota C:
char s[] = {
'\t',
'0',
'\n',
'}',
';',
'\n',
'\n',
'/',
'*',
'\n',
… 213 lines omitted …
0
};
/*
* The string s is a representation of the body
* of this program from '0'
* to the end.
*/
main()
{
int i;
printf("char\ts[] = {\n");
for(i = 0; s[i]; i++)
printf("\t%d,\n", s[i]);
printf("%s", s);
}
Selanjutnya, Anda mungkin bertanya-tanya bagaimana kompiler diajarkan bahwa urutan melarikan diri seperti '\n'
mewakili kode ASCII 10. Jawabannya adalah bahwa di suatu tempat dalam kompiler C, ada rutin yang mengartikan literal karakter, berisi beberapa kondisi seperti ini untuk mengenali urutan backslash:
…
c = next();
if (c != '\\') return c; /* A normal character */
c = next();
if (c == '\\') return '\\'; /* Two backslashes in the code means one backslash */
if (c == 'r') return '\r'; /* '\r' is a carriage return */
…
Jadi, kita dapat menambahkan satu syarat ke kode di atas ...
if (c == 'n') return 10; /* '\n' is a newline */
... untuk menghasilkan kompiler yang tahu yang '\n'
mewakili ASCII 10. Menariknya, kompiler itu, dan semua kompiler berikutnya yang dikompilasi olehnya , "tahu" pemetaan itu, jadi pada generasi berikutnya dari kode sumber, Anda dapat mengubah baris terakhir menjadi
if (c == 'n') return '\n';
... dan itu akan melakukan hal yang benar! Itu 10
berasal dari kompiler, dan tidak perlu lagi didefinisikan secara eksplisit dalam kode sumber kompilator. 1
Itu adalah salah satu contoh fitur bahasa C yang diimplementasikan dalam kode C. Sekarang, ulangi proses itu untuk setiap fitur bahasa tunggal, dan Anda memiliki kompiler "hosting sendiri": kompiler C yang ditulis dalam C.
1 Pelintiran plot yang dijelaskan dalam makalah ini adalah bahwa karena kompiler dapat "diajarkan" fakta-fakta seperti ini, itu juga dapat diajarkan secara salah untuk menghasilkan executable trojan dengan cara yang sulit untuk dideteksi, dan tindakan sabotase semacam itu dapat bertahan di semua kompiler yang diproduksi oleh kompiler tercemar.
Anda sudah mendapatkan jawaban yang sangat bagus, namun saya ingin menawarkan Anda perspektif yang berbeda, yang diharapkan akan mencerahkan Anda. Pertama-tama mari kita buat dua fakta yang bisa kita sepakati bersama:
Saya yakin Anda bisa setuju bahwa # 1 dan # 2 benar. Sekarang, lihat dua pernyataan. Apakah Anda melihat sekarang bahwa itu sepenuhnya normal untuk kompiler CoffeeScript untuk dapat mengkompilasi kompiler CoffeeScript?
Kompiler tidak peduli apa yang dikompilasi. Selama ini adalah program yang ditulis dalam CoffeeScript, ia dapat mengompilasinya. Dan kompiler CoffeeScript sendiri kebetulan merupakan program semacam itu. Kompiler CoffeeScript tidak peduli bahwa itu adalah kompiler CoffeeScript itu sendiri yang dikompilasi. Yang terlihat hanyalah beberapa kode CoffeeScript. Titik.
Bagaimana kompiler dapat mengkompilasi sendiri, atau apa arti pernyataan ini?
Ya, itulah yang dimaksud pernyataan itu, dan saya harap Anda dapat melihat sekarang bagaimana pernyataan itu benar.
Bagaimana kompiler dapat mengkompilasi sendiri, atau apa arti pernyataan ini?
Artinya persis seperti itu. Pertama-tama, beberapa hal yang perlu dipertimbangkan. Ada empat objek yang perlu kita perhatikan:
Sekarang, harus jelas bahwa Anda dapat menggunakan rakitan yang dihasilkan - yang dapat dieksekusi - dari kompiler CoffeScript untuk mengkompilasi sembarang program CoffeScript, dan menghasilkan rakitan untuk program tersebut.
Sekarang, kompiler CoffeScript itu sendiri hanyalah sebuah program CoffeScript sewenang-wenang, dan karenanya, dapat dikompilasi oleh kompiler CoffeScript.
Tampaknya kebingungan Anda berasal dari kenyataan bahwa ketika Anda membuat bahasa baru Anda sendiri, Anda belum memiliki kompiler namun dapat Anda gunakan untuk mengkompilasi kompiler Anda. Ini pasti terlihat seperti masalah telur ayam , kan?
Perkenalkan proses yang disebut bootstrap .
Sekarang Anda perlu menambahkan fitur baru. Katakanlah Anda hanya menerapkan while
-loops, tetapi juga ingin for
-loops. Ini bukan masalah, karena Anda dapat menulis ulang setiap for
-loop sedemikian rupa sehingga while
-loop. Ini berarti Anda hanya dapat menggunakan while
-lompatan dalam kode sumber kompiler Anda, karena rakitan yang Anda miliki hanya dapat mengkompilasi itu. Tetapi Anda dapat membuat fungsi di dalam kompiler Anda yang dapat membuat dan mengkompilasi for
-loops dengannya. Kemudian Anda menggunakan perakitan yang sudah Anda miliki, dan kompilasi versi kompiler baru. Dan sekarang Anda memiliki perakitan kompiler yang juga dapat menguraikan dan mengkompilasi for
-loops! Anda sekarang dapat kembali ke file sumber kompiler Anda, dan menulis ulang while
-loops yang tidak Anda inginkan ke for
-loops.
Bilas dan ulangi sampai semua fitur bahasa yang diinginkan dapat dikompilasi dengan kompiler.
while
dan for
jelas hanya contoh, tetapi ini berfungsi untuk fitur bahasa baru yang Anda inginkan. Dan kemudian Anda berada dalam situasi CoffeScript sekarang: Kompiler mengkompilasi dirinya sendiri.
Ada banyak literatur di luar sana. Refleksi Kepercayaan Kepercayaan adalah klasik yang setiap orang tertarik pada topik itu harus membaca setidaknya sekali.
Di sini istilah compiler mengungkap fakta bahwa ada dua file yang terlibat. Satu adalah file yang dapat dieksekusi yang mengambil file input yang ditulis dalam CoffeScript dan menghasilkan sebagai file output file yang dapat dieksekusi, file objek yang dapat ditautkan, atau pustaka bersama. Yang lainnya adalah file sumber CoffeeScript yang kebetulan menggambarkan prosedur untuk mengkompilasi CoffeeScript.
Anda menerapkan file pertama ke yang kedua, menghasilkan yang ketiga yang mampu melakukan tindakan kompilasi yang sama seperti yang pertama (mungkin lebih, jika file kedua mendefinisikan fitur yang tidak diterapkan oleh yang pertama), dan dengan demikian dapat mengganti yang pertama jika Anda jadi keinginan.
Karena versi Ruby dari kompiler CoffeeScript sudah ada, itu digunakan untuk membuat versi CoffeeScript dari kompiler CoffeeScript.
Ini dikenal sebagai kompiler hosting mandiri .
Ini sangat umum, dan biasanya hasil dari keinginan penulis untuk menggunakan bahasa mereka sendiri untuk mempertahankan pertumbuhan bahasa itu.
Ini bukan masalah kompiler di sini, tetapi masalah ekspresi bahasa, karena kompiler hanyalah sebuah program yang ditulis dalam beberapa bahasa.
Ketika kita mengatakan bahwa "suatu bahasa ditulis / diimplementasikan" kita sebenarnya berarti bahwa kompiler atau penerjemah untuk bahasa tersebut diimplementasikan. Ada bahasa pemrograman di mana Anda dapat menulis program yang mengimplementasikan bahasa (adalah kompiler / juru bahasa untuk bahasa yang sama). Bahasa-bahasa ini disebut bahasa universal .
Agar dapat memahami hal ini, pikirkan tentang bubut logam. Ini adalah alat yang digunakan untuk membentuk logam. Mungkin saja, hanya menggunakan alat itu, untuk membuat alat lain yang identik, dengan membuat bagian-bagiannya. Dengan demikian, alat itu adalah mesin universal. Tentu saja, yang pertama dibuat menggunakan cara lain (alat lain), dan mungkin kualitasnya lebih rendah. Tetapi yang pertama digunakan untuk membangun yang baru dengan presisi lebih tinggi.
Printer 3D hampir merupakan mesin universal. Anda dapat mencetak seluruh printer 3D menggunakan printer 3D (Anda tidak dapat membuat ujung yang melelehkan plastik).
Versi n + 1 dari kompiler ditulis dalam X.
Dengan demikian dapat dikompilasi oleh versi ke-9 dari kompiler (juga ditulis dalam X).
Tetapi versi pertama dari kompiler yang ditulis dalam X harus dikompilasi oleh kompiler untuk X yang ditulis dalam bahasa selain X. Langkah ini disebut bootstrap the compiler.
Compiler mengambil spesifikasi tingkat tinggi dan mengubahnya menjadi implementasi tingkat rendah, seperti dapat dieksekusi pada perangkat keras. Oleh karena itu tidak ada hubungan antara format spesifikasi dan eksekusi yang sebenarnya selain semantik bahasa yang ditargetkan.
Kompiler lintas pindah dari satu sistem ke sistem lain, kompiler lintas bahasa mengkompilasi satu spesifikasi bahasa ke spesifikasi bahasa lain.
Kompilasi pada dasarnya adalah terjemahan yang adil, dan levelnya biasanya tingkat bahasa yang lebih tinggi ke tingkat bahasa yang lebih rendah, tetapi ada banyak varian.
Kompiler bootstrap adalah yang paling membingungkan, tentu saja, karena mereka mengkompilasi bahasa mereka. Jangan lupa langkah awal dalam bootstrap yang memerlukan setidaknya versi minimal yang ada yang dapat dieksekusi. Banyak kompiler bootstrap bekerja pada fitur minimal bahasa pemrograman terlebih dahulu dan menambahkan fitur bahasa tambahan yang kompleks ke depan asalkan fitur baru dapat diekspresikan menggunakan fitur sebelumnya. Jika bukan itu masalahnya maka bagian "kompiler" harus dikembangkan dalam bahasa lain terlebih dahulu.
self-hosting
kompiler. Lihat programmers.stackexchange.com/q/263651/6221