Saya mendengar beberapa waktu lalu bahwa dulu ada kompiler yang berusaha untuk memperbaiki kesalahan sintaks dengan menganalisis konteks dan menyimpulkan apa yang dimaksudkan.
Apakah kompiler seperti itu benar-benar ada? Jelas itu memiliki nilai praktis yang kecil, tetapi akan sangat menarik untuk dimainkan dan dipelajari.
Jawaban:
Dalam beberapa hal, tindakan kompilasi adalah menyimpulkan apa sintaks tertentu dimaksudkan untuk melakukan, dan karenanya kesalahan sintaks adalah ketika compiler tidak dapat mengetahuinya. Anda dapat menambahkan lebih banyak "menebak" agar kompiler menyimpulkan hal-hal lebih lanjut dan menjadi lebih fleksibel dengan sintaks, tetapi ia harus melakukan ini dengan membuat seperangkat aturan tertentu. Dan aturan itu kemudian menjadi bagian dari bahasa, dan bukan lagi kesalahan.
Jadi, tidak, tidak ada kompiler seperti itu, sungguh, karena pertanyaannya tidak masuk akal. Menebak kesalahan sintaks yang dimaksudkan untuk dilakukan sesuai dengan beberapa aturan hanya menjadi bagian dari sintaks.
Dalam pengertian itu, ada contoh yang bagus dari kompiler yang melakukan ini: Kompiler C apa pun. Mereka akan sering hanya mencetak peringatan tentang sesuatu yang tidak seharusnya, dan kemudian menganggap Anda maksud X, dan teruskan. Ini sebenarnya adalah "menebak-nebak" kode yang tidak jelas (meskipun sebagian besar bukan sintaksis per se), sesuatu yang bisa menghentikan kompilasi dengan kesalahan, dan karenanya memenuhi syarat sebagai kesalahan.
sumber
Kedengarannya sangat berbahaya. Jika seorang kompiler mencoba menyimpulkan maksud Anda, menganggapnya salah, memperbaiki kode, dan kemudian tidak memberi tahu Anda (atau memberi tahu Anda dalam beberapa peringatan bahwa Anda, seperti semua orang, abaikan), maka Anda akan menjalankan kode yang mungkin serius melakukan beberapa kerusakan.
Kompiler seperti ini mungkin adalah sesuatu yang dengan sengaja TIDAK dibuat.
sumber
IDE untuk bahasa pemrograman biasanya akhir-akhir ini memiliki kompiler yang berjalan di latar belakang, sehingga ia dapat memberikan layanan analisis seperti pewarnaan sintaks, IntelliSense, kesalahan, dan sebagainya. Jelas kompiler seperti itu harus dapat memahami kode yang sangat rusak; sebagian besar waktu saat mengedit, kode tidak benar. Tapi kita masih harus memahaminya.
Namun, biasanya fitur pemulihan kesalahan hanya digunakan saat mengedit; tidak masuk akal untuk mengizinkannya untuk kompilasi aktual dalam skenario "arus utama".
Menariknya, kami memang membangun fitur itu ke dalam kompiler JScript.NET; pada dasarnya adalah mungkin untuk menempatkan kompiler ke dalam mode di mana kami mengizinkan kompiler untuk melanjutkan bahkan jika kesalahan terjadi, jika IDE akan pulih darinya. Anda dapat mengetik kode Visual Basic , menjalankan kompiler JScript.NET di atasnya, dan memiliki peluang yang masuk akal dari program yang bekerja keluar ujung yang lain!
Ini adalah demo yang lucu, tetapi ternyata itu bukan fitur yang sangat bagus untuk skenario "arus utama" karena banyak alasan. Penjelasan lengkap akan cukup panjang; penjelasan singkatnya adalah ia membuat untuk program yang bekerja secara tak terduga dan tidak sengaja , dan membuatnya sulit untuk menjalankan kode yang sama melalui beberapa kompiler, atau beberapa versi dari kompiler yang sama. Biaya besar yang ditambahkan fitur tidak dibenarkan oleh manfaatnya yang kecil.
Peter Torr, yang PM memiliki fitur kembali pada hari itu, membahasnya secara singkat di posting blog ini dari tahun 2003 .
Meskipun kami mengekspos fitur ini melalui API hosting skrip dari mesin JScript .NET, saya tidak tahu ada pelanggan nyata yang pernah menggunakannya.
sumber
Hal pertama yang muncul di benak saya adalah penyisipan semi-kolon otomatis Javascript . Fitur mengerikan, mengerikan yang seharusnya tidak masuk ke dalam bahasa.
Itu bukan untuk mengatakan bahwa itu tidak bisa melakukan pekerjaan yang lebih baik. Jika melihat ke depan pada baris berikut, maka mungkin bisa membuat tebakan yang lebih baik mengenai niat programmer, tetapi pada akhirnya, jika ada beberapa cara yang valid sintaks bisa pergi, maka benar-benar tidak ada pengganti untuk programmer yang eksplisit.
sumber
Kedengarannya bagi saya bahwa jika kompiler dapat memperbaiki sintaks yang salah, maka sintaks tersebut harus didokumentasikan dalam bahasa.
Alasan untuk kesalahan sintaks adalah karena parser tidak dapat membuat pohon sintaks abstrak dari program. Ini terjadi ketika token tidak pada tempatnya. Untuk menebak di mana token itu seharusnya, jika itu harus dihapus, atau jika beberapa token lainnya harus ditambahkan untuk memperbaiki kesalahan Anda akan memerlukan beberapa jenis komputer yang dapat menebak maksud seorang programmer. Bagaimana mesin dapat menebaknya:
Seharusnya:
Ini bisa saja menjadi salah satu dari berikut:
56
,5 - 6
,5 & 6
. Tidak ada cara bagi kompiler untuk mengetahuinya.Teknologi itu belum ada.
sumber
Meskipun bukan hal yang sama, inilah sebabnya HTML berubah menjadi bencana. Peramban mentolerir markup yang buruk dan hal berikutnya yang Anda tahu, peramban A tidak dapat merender dengan cara yang sama seperti Peramban B (ya ada alasan lain, tetapi ini adalah salah satu dari sedikit yang teratas, terutama sekitar 10 tahun yang lalu sebelum beberapa aturan kelonggaran menjadi konvensi) ).
Seperti Eric Lippert menyimpulkan, banyak dari hal-hal ini paling baik ditangani oleh IDE, bukan kompiler. Agar Anda dapat melihat apa yang bit otomatis coba lakukan untuk Anda.
Strategi yang saya pikir paling dominan sekarang adalah perbaikan bahasa terus-menerus alih-alih melonggarkan kompiler: Jika itu benar-benar sesuatu yang dapat dikompilasi oleh kompiler secara otomatis, maka perkenalkan konstruksi bahasa yang didefinisikan dengan baik di sekitarnya.
Contoh langsung yang muncul dalam pikiran adalah properti-otomatis dalam C # (bukan satu-satunya bahasa yang memiliki sesuatu yang serupa): Mengingat bahwa sebagian besar pengambil / setter dalam aplikasi apa pun benar-benar hanya pembungkus di sekitar bidang, cukup izinkan pengembang untuk menunjukkan mereka maksud dan biarkan kompiler menyuntikkan sisanya.
Yang kemudian membuat saya berpikir: Kebanyakan bahasa gaya C sudah melakukan ini sampai batas tertentu. Untuk hal-hal yang dapat dipecahkan secara otomatis, cukup perbaiki sintaksnya:
Dapat direduksi menjadi:
Pada akhirnya, saya pikir turun ke ini: Trennya adalah Anda tidak membuat kompiler "lebih pintar" atau "lebih longgar". Ini adalah bahasa yang dibuat lebih pintar atau lebih longgar.
Selain itu, terlalu banyak "bantuan" bisa berbahaya, seperti bug klasik "jika":
sumber
if (x && y) dothis(); else dothat();
akan terlihat sedikit lebih baik.true
ataufalse
.Ketika saya sedang mengkode FORTRAN dan PL / I kembali pada akhir 80-an dan awal 90-an pada DEC dan IBM minicomputer dan sistem mainframe, saya sepertinya ingat bahwa kompiler akan secara teratur log keluar pesan seperti "kesalahan bla bla; dengan asumsi bla bla dan teruskan .. . " Saat itu, ini adalah warisan dari (bahkan sebelumnya, sebelum waktu saya) hari saya pemrosesan batch dan kartu punch ketika ada kemungkinan besar menunggu antara mengirimkan kode Anda untuk menjalankan dan mendapatkan hasilnya kembali. Jadi masuk akal bagi kompiler untuk mencoba menebak programmer dan melanjutkan daripada membatalkan kesalahan pertama yang ditemui. Pikiran Anda, saya tidak ingat "koreksi" menjadi sangat canggih. Ketika saya akhirnya pindah ke workstation Unix interaktif (Sun, SGI dll),
sumber
Tujuan dari kompiler adalah untuk menghasilkan executable yang berperilaku seperti yang diinginkan. Jika seorang programmer menulis sesuatu yang tidak valid, bahkan jika kompiler dapat dengan probabilitas 90% menebak apa yang dimaksudkan, umumnya akan lebih baik untuk meminta programmer memperbaiki program untuk memperjelas maksud, daripada membuat kompiler maju dan menghasilkan yang dapat dieksekusi yang akan memiliki peluang besar untuk menyembunyikan bug.
Tentu saja, bahasa pada umumnya harus dirancang sehingga kode yang dengan jelas menyatakan niat akan sah, dan kode yang tidak secara jelas menyatakan niat harus dilarang, tetapi itu tidak berarti benar. Pertimbangkan kode berikut [Java atau C #]
Memiliki kompiler menambah typecast implisit untuk penugasan
f1
akan sangat membantu, karena hanya ada satu hal logis yang inginf1
dikandung oleh programmer (float
nilai yang paling dekat dengan 1/10). Alih-alih mendorong kompiler untuk menerima program yang tidak tepat, akan lebih baik bagi spec untuk mengizinkan konversi double-to-float implisit dalam beberapa konteks. Di sisi lain, penugasand1
mungkin atau tidak sesuai dengan yang diinginkan oleh programmer, tetapi tidak ada aturan bahasa yang melarangnya.Jenis aturan bahasa yang paling buruk adalah aturan di mana penyusun akan membuat kesimpulan dalam kasus-kasus di mana sesuatu tidak dapat dikompilasi secara sah sebaliknya, tetapi di mana suatu program mungkin "secara tidak sengaja" valid dalam kasus di mana inferensi dimaksudkan. Banyak situasi yang melibatkan pernyataan akhir implisit termasuk dalam kategori ini. Jika seorang programmer yang berniat untuk menulis dua pernyataan terpisah menghilangkan terminator pernyataan, kompilator biasanya dapat menyimpulkan batas pernyataan, tetapi kadang-kadang dapat dianggap sebagai satu pernyataan sesuatu yang seharusnya diproses sebagai dua.
sumber
Kesalahan sintaksis sangat sulit untuk diperbaiki. Ambil kasus hak yang hilang
)
: Kami tahu kami dapat memperbaiki kode dengan memasukkan satu, tetapi biasanya ada banyak tempat di mana kami dapat memasukkan satu dan mendapatkan program yang benar secara sintaksis.Titik yang jauh lebih mudah adalah pengidentifikasi salah eja (tetapi perhatikan ini bukan kesalahan sintaksis). Seseorang dapat menghitung jarak pengeditan antara pengidentifikasi yang tidak terselesaikan dan semua pengidentifikasi dalam cakupan, dan dengan mengganti kata yang tidak dapat dipecahkan dengan yang paling mungkin dimaksudkan pengguna, orang akan membuat program yang benar dalam banyak kasus. Namun, ternyata masih lebih baik untuk menandai kesalahan, dan biarkan IDE menyarankan penggantian yang valid.
sumber
Kompiler seperti itu hanya akan menjadi implementasi santai dan tidak standar dari bahasa apa pun yang dikompilasi.
sumber
Ini telah dicoba beberapa kali, tetapi seringkali tidak mencapai efek yang diinginkan: pikirkan HAL 9000 atau GlaDOS.
sumber
Di C, Anda tidak bisa melewatkan array dengan nilai, namun kompiler memungkinkan Anda untuk menulis:
yang kemudian ditulis ulang sebagai:
Betapa bodohnya itu? Saya lebih suka kesalahan keras di sini daripada menulis ulang diam-diam, karena aturan khusus ini telah membuat banyak programmer percaya bahwa array dan pointer pada dasarnya adalah hal yang sama. Mereka tidak.
sumber