Hanya untuk menyatakan masalahnya, Masalah Dangling Else adalah ambiguitas dalam spesifikasi sintaksis kode di mana mungkin tidak jelas, dalam kasus ifs dan elses berikutnya, yang lain milik yang jika.
Contoh paling sederhana dan klasik:
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
Tidak jelas, bagi mereka yang tidak tahu spesifikasi spesifik bahasa dengan hati, yang if
mendapatkan else
(dan potongan kode khusus ini berlaku dalam setengah lusin bahasa, tetapi dapat melakukan berbeda di masing-masing).
Konstruksi Dangling Else menimbulkan masalah potensial untuk implementasi parser tanpa pemindai, karena strateginya adalah untuk menyeruput aliran file satu karakter pada satu waktu, hingga parser melihat bahwa ia memiliki cukup untuk tokenize (dicerna ke dalam perakitan atau bahasa perantara yang dikompilasi) . Ini memungkinkan parser untuk mempertahankan kondisi minimal; segera setelah ia berpikir ia memiliki informasi yang cukup untuk menulis token yang diuraikan ke file, ia akan melakukannya. Itulah tujuan akhir dari pengurai tanpa pemindai; kompilasi cepat, sederhana, ringan.
Dengan asumsi baris baru dan spasi putih sebelum atau setelah tanda baca tidak ada artinya (karena mereka dalam sebagian besar bahasa C-style), pernyataan ini akan muncul ke kompiler sebagai:
if(conditionA)if(conditionB)doFoo();else doBar;
Dapat mengurai dengan sempurna ke komputer, jadi mari kita lihat. Saya mendapatkan satu karakter pada satu waktu sampai saya memiliki:
if(conditionA)
Oh, saya tahu apa artinya itu (dalam C #), itu berarti " push
conditionA ke tumpukan eval dan kemudian panggil brfalse
untuk melompat ke pernyataan setelah titik koma berikutnya jika itu tidak benar". Saat ini saya tidak melihat tanda titik koma, jadi untuk saat ini saya akan mengatur lompatan offset saya ke ruang berikutnya setelah instruksi ini, dan saya akan menambah offset itu ketika saya memasukkan lebih banyak instruksi sampai saya melihat tanda titik koma. Terus mengurai ...
if(conditionB)
OK, ini di-parsing ke pasangan serupa dari operasi IL, dan langsung berjalan setelah instruksi saya baru saja diuraikan. Saya tidak melihat tanda titik koma, jadi saya akan menambah lompatan offset dari pernyataan saya sebelumnya dengan panjang dua perintah saya (satu untuk push dan satu untuk break) dan terus mencari.
doFoo();
Oke, itu mudah. Itu " call
doFoo". Dan apakah itu titik koma yang saya lihat? Nah, itu hebat, itulah akhir dari dialog. Saya akan menambah offset lompatan kedua blok saya dengan panjang kedua perintah ini dan lupa bahwa saya pernah peduli. Oke, pindah ...
else
... Uh oh. Ini tidak sesederhana kelihatannya. OK, saya lupa apa yang baru saja saya lakukan, tetapi else
sarana ada pernyataan istirahat bersyarat di suatu tempat yang sudah saya lihat, jadi biarkan saya melihat ke belakang ... ya, itu dia brfalse
,, tepat setelah saya mendorong beberapa "conditionB" pada tumpukan, apa pun itu. OK, sekarang saya perlu tanpa syarat break
sebagai pernyataan selanjutnya. Pernyataan yang akan datang setelah itu sekarang pasti target istirahat bersyarat saya, jadi saya akan memastikan saya sudah benar, dan saya akan menambah istirahat tanpa syarat yang saya masukkan. Pindah ...
doBar();
Itu mudah. " call
doBar". Dan ada titik koma, dan saya tidak pernah melihat kawat gigi. Jadi, tanpa syarat break
harus melompat ke pernyataan berikutnya, apa pun itu, dan aku bisa lupa aku pernah peduli.
Jadi, apa yang kita miliki ... (catatan: ini jam 22:00 dan saya tidak merasa ingin mengubah bit offset ke heksadesimal atau mengisi shell IL lengkap dari suatu fungsi dengan perintah ini, jadi ini hanya pseudo-IL menggunakan nomor baris di mana biasanya ada byte byte):
ldarg.1 //conditionA
brfalse <line 6> //jumps to "break"
ldarg.2 //conditionB
brfalse <line 7> //jumps to "call doBar"
call doFoo
break <line 8> //jumps beyond statement in scope
call doBar
<line 8 is here>
Nah, yang sebenarnya dieksekusi dengan benar, JIKA aturannya (seperti dalam kebanyakan bahasa gaya-C) adalah yang else
paling dekat if
. Bertekad untuk mengikuti eksekusi nesting, ia akan mengeksekusi seperti ini, di mana jika conditionA salah, seluruh sisa potongan dilewati:
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
... tetapi ia melakukannya dengan kebetulan, karena jeda yang terkait dengan if
pernyataan luar melompat ke break
pernyataan di bagian dalam if
, yang mengambil pointer eksekusi melampaui seluruh pernyataan. Ini lompatan ekstra yang tidak dibutuhkan, dan jika contoh ini lebih kompleks, itu mungkin tidak lagi berfungsi jika diuraikan dan tokenized dengan cara ini.
Juga, bagaimana jika spesifikasi bahasa mengatakan bahwa menjuntai else
milik yang pertama if
, dan jika conditionA salah maka doBar dieksekusi, sedangkan jika conditionA benar tetapi bukan conditionB maka tidak ada yang terjadi, seperti itu?
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
Parser telah melupakan yang pertama yang if
pernah ada, dan algoritma parser sederhana ini tidak akan menghasilkan kode yang benar, untuk mengatakan tidak ada kode yang efisien.
Sekarang, parser bisa menjadi cukup pintar untuk mengingat huruf if
s dan else
s untuk waktu yang lebih lama, tetapi jika spek bahasa mengatakan satu else
setelah dua if
s cocok dengan yang pertama if
, itu menyebabkan masalah dengan dua if
s dengan padanan else
s:
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
else
doBaz();
Parser akan melihat yang pertama else
, cocok dengan yang pertama if
, kemudian melihat yang kedua dan panik "apa yang saya lakukan lagi" mode. Pada titik ini parser mendapatkan kode yang agak banyak dalam keadaan bisa berubah yang lebih baik telah didorong ke output filestream.
Ada solusi untuk semua masalah ini dan bagaimana-jika. Tetapi, baik kode yang diperlukan agar pintar meningkatkan kompleksitas algoritma parser, atau spesifikasi bahasa yang memungkinkan parser menjadi bodoh ini meningkatkan verbositas kode sumber bahasa, seperti dengan meminta terminasi pernyataan seperti end if
, atau tanda kurung yang mengindikasikan bersarang blok jika if
pernyataan memiliki else
(keduanya biasanya terlihat dalam gaya bahasa lain).
Ini hanya satu, contoh sederhana dari beberapa if
pernyataan, dan lihat semua keputusan yang harus dibuat oleh kompiler, dan di mana itu bisa dengan mudah mengacaukannya. Ini adalah detail di balik pernyataan berbahaya dari Wikipedia dalam pertanyaan Anda.