Intro
Kompiler tipikal melakukan langkah-langkah berikut:
- Parsing: teks sumber dikonversi ke pohon sintaksis abstrak (AST).
- Resolusi referensi ke modul lain (C menunda langkah ini sampai menghubungkan).
- Validasi semantik: menghilangkan pernyataan yang benar secara sintaksis yang tidak masuk akal, misalnya kode yang tidak dapat dijangkau atau deklarasi rangkap.
- Transformasi yang setara dan optimisasi tingkat tinggi: AST ditransformasikan untuk mewakili komputasi yang lebih efisien dengan semantik yang sama. Ini termasuk misalnya perhitungan awal dari subekspresi umum dan ekspresi konstan, menghilangkan penugasan lokal yang berlebihan (lihat juga SSA ), dll.
- Pembuatan kode: AST diubah menjadi kode linier tingkat rendah, dengan lompatan, alokasi register, dan sejenisnya. Beberapa panggilan fungsi dapat diuraikan pada tahap ini, beberapa loop terbuka, dll.
- Optimalisasi lubang telepon: kode tingkat rendah dipindai untuk inefisiensi lokal sederhana yang dihilangkan.
Kebanyakan kompiler modern (misalnya, gcc dan dentang) ulangi dua langkah terakhir sekali lagi. Mereka menggunakan bahasa tingkat rendah menengah-platform tapi independen untuk pembuatan kode awal. Kemudian bahasa itu dikonversi menjadi kode platform-spesifik (x86, ARM, dll) melakukan hal yang kira-kira sama dengan cara yang dioptimalkan platform. Ini termasuk misalnya penggunaan instruksi vektor bila memungkinkan, penataan ulang instruksi untuk meningkatkan efisiensi prediksi cabang, dan sebagainya.
Setelah itu, kode objek siap untuk dihubungkan. Sebagian besar kompiler kode asli tahu cara memanggil tautan untuk menghasilkan yang dapat dieksekusi, tetapi itu bukan langkah kompilasi per se. Dalam bahasa seperti Java dan tautan C # mungkin benar-benar dinamis, dilakukan oleh VM pada waktu pengambilan.
Ingat dasar-dasarnya
- Buat itu bekerja
- Jadikan itu indah
- Jadikan efisien
Urutan klasik ini berlaku untuk semua pengembangan perangkat lunak, tetapi menanggung pengulangan.
Berkonsentrasilah pada langkah pertama dari urutan. Buat hal paling sederhana yang mungkin bisa berhasil.
Baca buku!
Baca Buku Naga oleh Aho dan Ullman. Ini klasik dan masih cukup berlaku hingga saat ini.
Desain Kompiler Modern juga dipuji.
Jika hal ini terlalu sulit bagi Anda sekarang, bacalah beberapa pengantar tentang penguraian terlebih dahulu; biasanya parsing pustaka termasuk intro dan contoh.
Pastikan Anda merasa nyaman bekerja dengan grafik, terutama pohon. Hal-hal ini adalah program-program yang dibuat dari pada tingkat logis.
Definisikan bahasa Anda dengan baik
Gunakan notasi apa pun yang Anda inginkan, tetapi pastikan Anda memiliki deskripsi yang lengkap dan konsisten dari bahasa Anda. Ini termasuk sintaks dan semantik.
Saatnya untuk menulis cuplikan kode dalam bahasa baru Anda sebagai kasus uji untuk kompiler masa depan.
Gunakan bahasa favorit Anda
Tidak apa-apa menulis kompiler dengan Python atau Ruby atau bahasa apa pun yang mudah bagi Anda. Gunakan algoritma sederhana yang Anda pahami dengan baik. Versi pertama tidak harus cepat, efisien, atau lengkap fitur. Hanya perlu cukup benar dan mudah dimodifikasi.
Tidak apa-apa untuk menulis tahapan kompiler yang berbeda dalam bahasa yang berbeda, jika diperlukan.
Bersiaplah untuk menulis banyak tes
Seluruh bahasa Anda harus dicakup oleh uji kasus; secara efektif itu akan ditentukan oleh mereka. Kenal baik-baik dengan kerangka pengujian pilihan Anda. Tulis tes dari hari pertama. Berkonsentrasi pada tes 'positif' yang menerima kode yang benar, yang bertentangan dengan deteksi kode yang salah.
Jalankan semua tes secara teratur. Perbaiki tes yang rusak sebelum melanjutkan. Memalukan untuk berakhir dengan bahasa yang tidak jelas yang tidak dapat menerima kode yang valid.
Buat parser yang bagus
Generator Parser banyak . Pilih apa pun yang Anda inginkan. Anda juga dapat menulis parser Anda sendiri dari awal, tetapi itu hanya layak jika sintaks bahasa Anda sudah mati sederhana.
Parser harus mendeteksi dan melaporkan kesalahan sintaksis. Tulis banyak kasus uji, baik positif maupun negatif; gunakan kembali kode yang Anda tulis saat mendefinisikan bahasa.
Output parser Anda adalah pohon sintaksis abstrak.
Jika bahasa Anda memiliki modul, output parser mungkin merupakan representasi paling sederhana dari 'kode objek' yang Anda hasilkan. Ada banyak cara sederhana untuk membuang pohon ke file dan dengan cepat memuatnya kembali.
Buat validator semantik
Kemungkinan besar bahasa Anda memungkinkan konstruksi yang benar secara sintaksis yang mungkin tidak masuk akal dalam konteks tertentu. Contohnya adalah deklarasi duplikat dari variabel yang sama atau melewati parameter dari tipe yang salah. Validator akan mendeteksi kesalahan seperti itu melihat pohon.
Validator juga akan menyelesaikan referensi ke modul lain yang ditulis dalam bahasa Anda, memuat modul lain ini dan digunakan dalam proses validasi. Misalnya, langkah ini akan memastikan bahwa jumlah parameter yang diteruskan ke fungsi dari modul lain sudah benar.
Sekali lagi, tulis dan jalankan banyak test case. Kasus-kasus sepele sangat diperlukan dalam pemecahan masalah seperti pintar dan kompleks.
Buat kode
Gunakan teknik paling sederhana yang Anda tahu. Seringkali tidak apa-apa untuk langsung menerjemahkan konstruksi bahasa (seperti if
pernyataan) ke templat kode yang parametrik ringan, tidak seperti templat HTML.
Sekali lagi, abaikan efisiensi dan konsentrasi pada kebenaran.
Menargetkan VM level rendah independen-platform
Saya kira Anda mengabaikan hal-hal tingkat rendah kecuali jika Anda tertarik pada detail perangkat keras tertentu. Detail-detail ini berdarah dan kompleks.
Pilihan Anda:
- LLVM: memungkinkan pembuatan kode mesin yang efisien, biasanya untuk x86 dan ARM.
- CLR: target .NET, sebagian besar berbasis x86 / Windows; memiliki JIT yang bagus.
- JVM: menargetkan dunia Java, cukup multiplatform, memiliki JIT yang baik.
Abaikan optimasi
Optimalisasi sulit. Hampir selalu optimisasi prematur. Hasilkan kode yang tidak efisien tetapi benar. Terapkan seluruh bahasa sebelum Anda mencoba mengoptimalkan kode yang dihasilkan.
Tentu saja, optimasi sepele boleh saja diperkenalkan. Tetapi hindari hal-hal yang licik dan berbulu sebelum kompiler Anda stabil.
Terus?
Jika semua ini tidak terlalu menakutkan bagi Anda, silakan lanjutkan! Untuk bahasa yang sederhana, setiap langkah mungkin lebih sederhana dari yang Anda kira.
Melihat 'Hello world' dari program yang dibuat oleh kompiler Anda mungkin sepadan dengan usaha.