Apakah ada kompiler yang mencoba untuk memperbaiki kesalahan sintaks sendiri? [Tutup]

15

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.

Nathan Osman
sumber
3
Apakah IntelliSense termasuk dalam kategori ini? Banyak kompiler memiliki kesalahan yang mirip dengan [titik koma] yang diharapkan.
Robert Harvey
1
@ Robert: Tidak, tapi itu bagus.
Nathan Osman
1
Seorang teman saya melakukan sedikit peretasan pada preprocessor C, misalnya 'inlcude -> include', dan beberapa upaya untuk mencari tahu di mana kondisi terbuka seharusnya ditutup. Itu adalah tesis tuannya, yang dengan cepat dia tinggalkan untuk sesuatu yang lebih mudah. Tetap saja, pertanyaan yang cukup menarik!
Tim Post
3
Kompiler AC # gagal dengan pesan kesalahan SANGAT berguna. Itu dikombinasikan dengan dokumentasi yang baik tersedia online untuk setiap kode kesalahan berfungsi dengan baik. Adalah ide yang buruk untuk mengoreksi sintaksis secara otomatis, walaupun penerjemah HTML (mis. Browser) tetap melakukannya.
Ayub
1
Kompiler yang Anda maksud adalah PL / I asli. Diasumsikan bahwa apa pun yang ditulis oleh programmer pasti ada artinya, dan mencoba menebak apa itu. Dalam pengalaman saya, itu memang sangat buruk!
david.pfx

Jawaban:

28

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.

Lennart Regebro
sumber
4
Ini adalah jawaban yang benar. Setelah kompiler dapat pulih dari kesalahan, itu tidak lagi benar-benar kesalahan. Perl (dalam?) Terkenal dengan perilaku "Do What I Mean" ini, memilih apa yang paling mungkin dimaksudkan oleh programmer yang diberikan sumber yang ambigu.
Jon Purdy
Perl mengorbankan verbositas untuk ukuran kode sumber.
Nathan Osman
@ George Edison: Itu tautologi atau kontradiksi.
Jon Purdy
Atau wawasan yang mendalam. :)
Lennart Regebro
23

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.

nganju
sumber
5
Saya tahu itu. Kompiler seperti itu tidak akan berguna untuk kompilasi, tetapi konsepnya cukup menarik dan memiliki potensi belajar.
Nathan Osman
2
hampir semua IDE terbaru memberikan saran untuk sintaks dan itu sangat membantu. dan untuk bagian selanjutnya setuju dengan nganju
Jigar Joshi
Saya tidak akan menggunakan kompiler seperti itu. Itu datang di bawah judul 'ilmu hitam'.
Michael K
Hmmm di mana Anda menilai inferensi tipe Scala pada skala ini? Setelah mencobanya, itu akan mengatakan itu adalah kontribusi besar untuk kode ringkas. Di sisi lain, kadang-kadang menembak saya di kaki (misalnya karena saya pikir saya berurusan dengan daftar tetapi sebenarnya masih berurusan dengan set).
timday
Kami memiliki hal-hal seperti autoscope di OMP, jadi sedikit bisa dilakukan. Tentu saja kode yang saya gunakan telah mematikan autoscoping karena kami tidak mempercayainya. Saya bisa melihat memiliki kompiler interaktif yang bertanya "apakah maksud Anda XXX?". Sejauh yang saya mau. Dan bahkan itu mungkin terlalu berbahaya.
Omega Centauri
12

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.

Eric Lippert
sumber
Saya berharap majikan saya memiliki sumber daya untuk bereksperimen seperti itu; kami bahkan tidak menjalankan tes unit pada malam hari karena ada begitu banyak fitur untuk ditambahkan dan bug untuk diperbaiki :(
Pekerjaan
1
Ini adalah jenis jawaban yang saya harapkan ... seperti yang saya sebutkan sebelumnya - jelas fitur seperti itu memiliki sedikit penggunaan praktis, tetapi akan memberikan cara yang bagus untuk mempelajari beberapa teknik yang dapat diterapkan pada hal-hal lain. (Penguraian bahasa, dll.)
Nathan Osman
1
@ Pekerjaan: Kebijaksanaan umum adalah bahwa jika Anda tidak secara teratur menjalankan tes unit, Anda akan memiliki lebih banyak bug untuk diperbaiki .
Eric Lippert
Saya sudah tahu apa yang harus saya lakukan tentang pekerjaan saya daripada mengeluh di sini. Pada beberapa perusahaan perangkat lunak, orang-orang di atas tidak benar-benar memahami perbedaan antara prototipe dan produk jadi. Lagipula, dari segi pixel seringkali tidak ada banyak perbedaan. Tidak bijaksana untuk tidak memulai dengan prototipe, sehingga waktu tidak terbuang sia-sia. Tetapi tanggapan yang mengerikan "terlihat bagus, berapa hari untuk memindahkan ini ke produksi?". Mereka adalah orang yang sama yang akan curiga jika insinyur mengatakan kepada mereka bahwa mereka perlu menghabiskan waktu di infrastruktur atau refactoring. Saya mendengar bahkan Spolsky tidak menyukainya.
Pekerjaan
10

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.

Dean Harding
sumber
1
Dengan sepenuh hati saya setuju dengan fitur penyisipan semi-kolon JavaScript - sama sekali tidak berguna.
Nathan Osman
7

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:

int x = 5 6;

Seharusnya:

int x = 5 + 6;

Ini bisa saja menjadi salah satu dari berikut: 56, 5 - 6, 5 & 6. Tidak ada cara bagi kompiler untuk mengetahuinya.

Teknologi itu belum ada.

jjnguy
sumber
1
Teknologi seperti itu tidak ada. Membaca pikiran tidak diperbolehkan; semua instruksi harus jelas berasal dari kode.
Ayub
Benar, tetapi yang saya maksud adalah "Apakah ada kompiler yang mencoba memperbaiki sintaks yang tidak valid dengan membuat tebakan berdasarkan konteks." Fakta bahwa kompiler mengoreksi sintaks tidak valid tidak membuat sintaks valid. Juga, saya menyadari bahwa alat seperti itu tidak akan berguna untuk pengembangan kode.
Nathan Osman
6

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:

 if (true == x)
 {
    dothis();
 }
 else
 {
    dothat();
 }

Dapat direduksi menjadi:

if (true == x)
    dothis();
else
    dothat();

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":

if (true == x)
    if (true == y)
       dothis();
else
    dothat();
MIA
sumber
Perlu dicatat bahwa XHTML memberikan solusi untuk kekacauan yang dibuat oleh spesifikasi buruk HTML.
Nathan Osman
2
if (x && y) dothis(); else dothat();akan terlihat sedikit lebih baik.
Pekerjaan
1
Seekor kucing mati setiap kali seseorang membandingkan trueatau false.
JensG
2

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),

timday
sumber
2
Kompiler-kompiler itu akan berlanjut, tetapi mereka HANYA akan berlanjut dengan tujuan mencoba menemukan kesalahan lebih lanjut, sehingga Anda dapat (berpotensi) memperbaiki beberapa hal sebelum mengirimkan kembali. PC modern cukup cepat sehingga sepenuhnya layak untuk kompiler "interaktif" untuk berhenti pada kesalahan sintaksis pertama dan menjatuhkan Anda ke editor. (Dan, pada kenyataannya, Turbo Pascal asli, pada awal 1980-an, bekerja persis seperti itu. Itu bagus.)
John R. Strohm
1
Ya, saya ingat IBM PL / I mengoptimalkan kompiler akan memasok pernyataan BEGIN dan END yang hilang sesekali, ISTR juga menyediakan titik koma yang hilang.
TMN
1

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 #]

const double oneTenth = 0.1;
const float  oneTenthF = 0.1f;
...
float f1 = oneTenth;
double d1 = oneTenthF;

Memiliki kompiler menambah typecast implisit untuk penugasan f1akan sangat membantu, karena hanya ada satu hal logis yang ingin f1dikandung oleh programmer ( floatnilai 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, penugasan d1mungkin 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.

supercat
sumber
0

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.

Ingo
sumber
-1

Kompiler seperti itu hanya akan menjadi implementasi santai dan tidak standar dari bahasa apa pun yang dikompilasi.

Rei Miyasaka
sumber
-2

Ini telah dicoba beberapa kali, tetapi seringkali tidak mencapai efek yang diinginkan: pikirkan HAL 9000 atau GlaDOS.

cbrandolino
sumber
-3

Di C, Anda tidak bisa melewatkan array dengan nilai, namun kompiler memungkinkan Anda untuk menulis:

void foo(int array[10]);

yang kemudian ditulis ulang sebagai:

void foo(int* array);

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.

fredoverflow
sumber