Bagaimana kompiler C ++ pertama bisa ditulis dalam C ++?

48

Stroustrup mengklaim bahwa Cfront, kompiler C ++ pertama, ditulis dalam C ++ ( Stroustrup FAQ ).

Namun, bagaimana mungkin kompiler C ++ pertama ditulis dalam C ++?

Kode yang membentuk kompiler perlu dikompilasi juga, dan dengan demikian kompiler C ++ pertama tidak dapat ditulis dalam C ++, bukan?

Pacerier
sumber

Jawaban:

57

Kuncinya ada di sini:

Kompiler C ++ pertama (Cfront) ditulis dalam C ++. Untuk membangun itu, saya pertama kali menggunakan C untuk menulis preprocessor "C with Classes" -to-C. "C with Classes" adalah dialek C yang menjadi leluhur langsung ke C ++. Preprosesor itu menerjemahkan konstruksi "C dengan Kelas" (seperti kelas dan konstruktor) ke dalam C. Itu adalah preprosesor tradisional yang tidak mengerti semua bahasa, membuat sebagian besar jenis memeriksa untuk kompiler C yang harus dilakukan, dan menerjemahkan masing-masing membangun tanpa pengetahuan lengkap. Saya kemudian menulis versi pertama Cfront di "C with Classes".

Jadi versi pertama Cfront tidak ditulis dalam C ++, melainkan dalam bahasa perantara. Kemampuan untuk membuat kompiler C dan preprosesor langsung di C menyebabkan banyak inovasi (dan lubang keamanan besar - besaran ) di C. Jadi Anda menulis preprosessor baru Anda yang mengubah kode "C dengan Kelas" menjadi kode C lurus (karena C langsung dapat melakukan apa pun) dan kemudian Anda menggunakan "C dengan Kelas" untuk menulis kompiler C ++ (bukan bahwa Anda tidak bisa melakukannya di C, hanya saja akan butuh waktu) dan kemudian Anda menggunakan kompiler C ++ untuk menulis kompiler yang lebih efisien / lengkap di C ++. Mengerti?

Christopher Bibbs
sumber
5
Beri +1 untuk menyertakan tautan ke salah satu kisah favorit saya tentang hal-hal yang dapat dilakukan (dan tidak boleh).
jwernerny
3
Kompiler ditulis dalam kode C ++ yang valid, tetapi hanya menggunakan beberapa fitur C ++ lengkap, yang didukung oleh preprocessor "C with Classes". Itu menggunakan subset dari bahasa lengkap, jadi itu juga dikompilasi pada hasil (versi kerja pertama Cfront). Setelah melakukan langkah "bootstrap" ini, ia mungkin tidak perlu menggunakan preprocessor lagi.
joeytwiddle
2
@ jwernerny - Saya selalu menemukan artikel yang tidak memuaskan. Dia membahas bagian yang paling sulit dan non-sepele: "Bug akan cocok dengan kode dalam perintah 'login' UNIX. Kode pengganti akan salah mengkompilasi perintah login sehingga akan menerima baik kata sandi terenkripsi yang dimaksud atau kata sandi yang dikenal tertentu. " Tetapi bagaimana ini akan dilakukan? Pernahkah itu benar-benar ditunjukkan?
detly
3
"menyebabkan banyak inovasi (dan lubang keamanan besar) di C": Sejauh yang saya tahu trik ini dapat digunakan dalam bahasa apa pun, bukan hanya dalam C. Jadi bahasa lain dapat memiliki lubang keamanan yang sama.
Giorgio
2
@detly: Kedengarannya sepele sekarang, tetapi pada tahun 1983 ini adalah serangan baru yang dibuat layak karena kurangnya keragaman implementasi. Kami lebih mempercayai binari saat itu, sebagian karena mengkompilasi segala sesuatu dari sumber adalah cobaan yang jauh lebih besar daripada sekarang.
Blrfl
17

Itu bootstrap. Segera setelah fitur C ++ ditambahkan ke cfront, maka cfront juga dapat menggunakan fitur itu sejak saat itu (tetapi tidak untuk mengimplementasikan fitur tersebut). Ini bekerja karena cfront memiliki kemampuan untuk mengkonversi kode C ++ ke kode C. Jadi jika beberapa platform baru keluar, Anda bisa menggunakan cfront pada platform lain untuk mengonversi cfront dari C ++ ke C, dan kemudian menggunakan kompiler C platform baru untuk menyelesaikan kompilasi dari C ke kode objek.

David Schwartz
sumber
9

Saya pikir BS menjawab pertanyaan itu:

Kompiler C ++ pertama (Cfront) ditulis dalam C ++. Untuk membangun itu, saya pertama kali menggunakan C untuk menulis preprocessor "C with Classes" -to-C. "C with Classes" adalah dialek C yang menjadi leluhur langsung ke C ++. Preprosesor itu menerjemahkan konstruksi "C dengan Kelas" (seperti kelas dan konstruktor) ke dalam C. Itu adalah preprosesor tradisional yang tidak mengerti semua bahasa, membuat sebagian besar jenis memeriksa untuk kompiler C yang harus dilakukan, dan menerjemahkan masing-masing membangun tanpa pengetahuan lengkap.

Saya kemudian menulis versi pertama Cfront di "C with Classes". Cfront adalah kompiler tradisional yang melakukan sintaksis lengkap dan pemeriksaan semantik sumber C ++. Untuk itu, ia memiliki parser lengkap, membangun tabel simbol, dan membangun representasi pohon internal lengkap dari setiap kelas, fungsi, dll. Ia juga melakukan beberapa optimasi tingkat sumber pada representasi pohon internal konstruksi C ++ sebelum menghasilkan C. Versi yang dihasilkan C, tidak bergantung pada C untuk pengecekan tipe apa pun. Itu hanya menggunakan C sebagai assembler. Kode yang dihasilkan cepat tanpa kompromi.

Pertama dia menciptakan sesuatu yang dia sebut "C with Classes" diimplementasikan oleh preprocessor sederhana ke dalam C. Itu pada dasarnya C ++, tetapi preprocessor melakukan sedikit atau tidak ada pengecekan. Dia kemudian menggunakannya untuk menulis Cfront, versi yang lebih kuat dari penerjemah C ++ ke C, lengkap dengan pengecekan tipe, tabel simbol, dll.

Mike Dunlavey
sumber
1
jadi pada dasarnya ketika kita mengkompilasi program C ++, itu akan dikonversi menjadi C, kemudian setelah itu dikonversi menjadi C, itu akan dikompilasi lagi ke kode mesin?
Pacerier
@ Peracerier: Awalnya, ya, tapi tidak sekarang saya pikir.
Mike Dunlavey
saya tidak mengerti komentar anda. maksud Anda sekarang ada kompiler yang melewatkan langkah kedua dan hanya mengambil sumber C ++ dan kompilasi ke kode mesin?
Pacerier
7
@ Peracerier: Ya, mereka tidak langsung ke bahasa assembly atau kode mesin. Biasanya mereka pertama kali pergi ke representasi perantara independen-mesin (tripel atau paha depan) dan menganalisis untuk optimasi. Dari itu mereka menghasilkan kode perakitan atau mesin. Jika Anda mengambil buku tentang desain kompiler (Aho & Ullman) saya yakin Anda akan menemukannya menarik.
Mike Dunlavey
1
Penting untuk dicatat bahwa C ++ yang sedang ia bangun juga merupakan sebagian kecil dari bahasa yang sekarang ada. Itu tidak memiliki template, tidak ada perpustakaan baru, hanya menggunakan casting C dan jika saya ingat dengan benar, tidak ada pengecualian.
Gort the Robot
2

Saya akan menambahkan jawaban ini karena tidak ada jawaban yang membahas aspek ini.

Anda secara teknis tidak memerlukan perangkat lunak untuk menyusun kode. Selama Anda memiliki spesifikasi kompiler yang diperlukan, Anda dapat melakukan kompilasi yang sebenarnya secara manual. Ini bukan bagaimana kompiler C ++ pertama dikompilasi. Saya hanya mengatakan itu mungkin.

Bandingkan dengan bahasa assembly. Ketika mereka digunakan di masa-masa awal, tidak ada perangkat lunak assembler untuk mengubah kode perakitan menjadi kode mesin. Itu dilakukan dengan tangan, tetapi bahasa assembly memberi programmer gambaran yang lebih baik.

klutt
sumber