Saya tidak mengerti kalimat ini dari artikel Wikipedia tentang masalah Dangling Else :
[Masalah Dangling Else] adalah masalah yang sering muncul dalam konstruksi compiler, terutama parsing tanpa pemindai.
Dapatkah seseorang menjelaskan kepada saya bagaimana teknik parsing tanpa pemindai dapat memperburuk masalah ini? Tampaknya bagi saya bahwa masalahnya adalah tata bahasa - karena ini ambigu - bukan dengan pilihan teknik penguraian. Apa yang saya lewatkan?
if a then if b then s1 else s2
, maka tata bahasa bersifat ambigu.Jawaban:
Tebakan terbaik saya adalah kalimat dalam artikel Wikipedia dihasilkan dari kesalahpahaman tentang karya E. Visser.
Tata bahasa untuk parser tanpa pemindai (yaitu tata bahasa yang mendeskripsikan suatu bahasa sebagai sekumpulan urutan karakter alih-alih sebagai sekuens urutan token dengan token yang dijelaskan secara terpisah sebagai rangkaian karakter) cenderung memiliki banyak ambiguitas. E. Kertas Visser Disambiguasi Filter untuk Pemindai LR Parser Generalized (*) mengusulkan beberapa mekanisme untuk memecahkan ambiguitas, salah satunya berguna untuk menyelesaikan masalah yang lain. Tetapi makalah ini tidak menyatakan bahwa ambiguitas yang tepat yang disebut "masalah menggantung lain" terkait dengan parser tanpa pemindai (atau bahkan bahwa mekanisme ini sangat berguna untuk parser tanpa pemindai).
Fakta bahwa ia mengusulkan suatu mekanisme untuk menyelesaikannya bukanlah pernyataan implisit sebagai mekanisme resolusi ambiguitas lain (prioritas dan prioritas operator) tampaknya juga sama sekali tidak terkait dengan sifat tanpa pemindai dari parser yang dianggap (pertimbangkan misalnya bahwa ambiguitas tersebut tidak dapat hadir dalam tata bahasa reguler karena mereka bersarang, sementara yang ditangani oleh aturan pertandingan terpanjang bisa).
(*) Yang mungkin merupakan makalah yang menjadi dasar artikel Wikipedia tentang parser tanpa pemindai bahkan jika mereka merujuk satu sama lain, juga oleh E. Visser, Parsless Generalized-LR Parsing .
sumber
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:
Tidak jelas, bagi mereka yang tidak tahu spesifikasi spesifik bahasa dengan hati, yang
if
mendapatkanelse
(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:
Dapat mengurai dengan sempurna ke komputer, jadi mari kita lihat. Saya mendapatkan satu karakter pada satu waktu sampai saya memiliki:
Oh, saya tahu apa artinya itu (dalam C #), itu berarti "
push
conditionA ke tumpukan eval dan kemudian panggilbrfalse
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 ...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.
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 ...... 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 diabrfalse
,, tepat setelah saya mendorong beberapa "conditionB" pada tumpukan, apa pun itu. OK, sekarang saya perlu tanpa syaratbreak
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 ...Itu mudah. "
call
doBar". Dan ada titik koma, dan saya tidak pernah melihat kawat gigi. Jadi, tanpa syaratbreak
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):
Nah, yang sebenarnya dieksekusi dengan benar, JIKA aturannya (seperti dalam kebanyakan bahasa gaya-C) adalah yang
else
paling dekatif
. Bertekad untuk mengikuti eksekusi nesting, ia akan mengeksekusi seperti ini, di mana jika conditionA salah, seluruh sisa potongan dilewati:... tetapi ia melakukannya dengan kebetulan, karena jeda yang terkait dengan
if
pernyataan luar melompat kebreak
pernyataan di bagian dalamif
, 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 pertamaif
, dan jika conditionA salah maka doBar dieksekusi, sedangkan jika conditionA benar tetapi bukan conditionB maka tidak ada yang terjadi, seperti itu?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 danelse
s untuk waktu yang lebih lama, tetapi jika spek bahasa mengatakan satuelse
setelah duaif
s cocok dengan yang pertamaif
, itu menyebabkan masalah dengan duaif
s dengan padananelse
s:Parser akan melihat yang pertama
else
, cocok dengan yang pertamaif
, 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 jikaif
pernyataan memilikielse
(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.sumber