Parser LR tidak dapat menangani aturan tata bahasa yang ambigu, berdasarkan desain. (Membuat teori lebih mudah di tahun 1970-an ketika ide sedang dikerjakan).
C dan C ++ keduanya memungkinkan pernyataan berikut:
x * y ;
Ini memiliki dua parse yang berbeda:
- Ini bisa berupa deklarasi y, sebagai pointer untuk mengetik x
- Ini bisa berupa kelipatan x dan y, membuang jawabannya.
Sekarang, Anda mungkin berpikir yang terakhir itu bodoh dan harus diabaikan. Sebagian besar akan setuju dengan Anda; Namun, ada kasus-kasus di mana ia mungkin memiliki efek samping (misalnya, jika multiply kelebihan beban). tapi bukan itu intinya. Intinya adalah ada yang dua mem-parsing yang berbeda, dan karena itu program dapat berarti hal yang berbeda tergantung pada bagaimana ini harus telah dipecah.
Kompiler harus menerima yang sesuai dalam keadaan yang sesuai, dan jika tidak ada informasi lain (misalnya, pengetahuan tentang tipe x) harus mengumpulkan keduanya untuk memutuskan nanti apa yang harus dilakukan. Jadi tata bahasa harus memungkinkan ini. Dan itu membuat tata bahasa ambigu.
Jadi parsing LR murni tidak bisa menangani ini. Juga tidak banyak generator parser lain yang tersedia secara luas, seperti Antlr, JavaCC, YACC, atau Bison tradisional, atau bahkan parser gaya PEG, yang digunakan dengan cara "murni".
Ada banyak kasus yang lebih rumit (sintaks templat parsing memerlukan tampilan acak, sedangkan LALR (k) dapat melihat ke depan di sebagian besar token k), tetapi hanya dibutuhkan satu sampel balik untuk menembak parsing LR murni (atau yang lain).
Kebanyakan parser C / C ++ nyata menangani contoh ini dengan menggunakan beberapa jenis parser deterministik dengan hack tambahan: mereka parsing terjalin dengan koleksi tabel simbol ... sehingga pada saat "x" ditemui, parser tahu jika x adalah tipe atau tidak, dan dengan demikian dapat memilih antara dua parse potensial. Tetapi parser yang melakukan ini tidak bebas konteks, dan parser LR (yang murni, dll.) Bebas konteks.
Satu dapat menipu, dan menambahkan pemeriksaan semantik waktu pengurangan aturan untuk parser LR untuk melakukan disambiguasi ini. (Kode ini seringkali tidak sederhana). Sebagian besar tipe parser lain memiliki beberapa cara untuk menambahkan pemeriksaan semantik di berbagai titik di parsing, yang dapat digunakan untuk melakukan ini.
Dan jika Anda cukup curang, Anda dapat membuat parser LR bekerja untuk C dan C ++. Orang-orang GCC melakukannya untuk sementara waktu, tetapi menyerahkannya untuk parsing kode tangan, saya pikir karena mereka menginginkan diagnostik kesalahan yang lebih baik.
Ada pendekatan lain, yang bagus dan bersih dan mem-parsing C dan C ++ dengan baik tanpa peretasan tabel simbol: parser GLR . Ini adalah parser bebas konteks penuh (memiliki lookahead efektif tak terbatas). Pengurai GLR hanya menerima kedua pengurai, menghasilkan "pohon" (sebenarnya grafik asiklik terarah yang sebagian besar seperti pohon) yang mewakili penguraian ambigu. Sebuah pascarsing pas dapat menyelesaikan ambiguitas.
Kami menggunakan teknik ini di ujung depan C dan C ++ untuk Perangkat Lunak DMS Reengineering Tookit kami (per Juni 2017 ini menangani C ++ 17 penuh dalam dialek MS dan GNU). Mereka telah digunakan untuk memproses jutaan baris sistem C dan C ++ besar, dengan parse lengkap, presisi yang menghasilkan AST dengan rincian lengkap dari kode sumber. (Lihat AST untuk parse yang paling menjengkelkan C ++. )