Parser SLR, LALR dan LR semuanya dapat diimplementasikan menggunakan mesin berbasis tabel yang sama persis.
Pada dasarnya, algoritme parsing mengumpulkan token input T berikutnya, dan berkonsultasi dengan status S saat ini (dan tabel lookahead, GOTO, dan reduksi terkait) untuk memutuskan apa yang harus dilakukan:
- SHIFT: Jika tabel saat ini mengatakan untuk SHIFT pada token T, pasangan (S, T) didorong ke tumpukan parse, status diubah sesuai dengan apa yang tabel GOTO katakan untuk token saat ini (misalnya, GOTO (T) ), token masukan lain T 'diambil, dan prosesnya berulang
- MENGURANGI: Setiap negara bagian memiliki 0, 1, atau banyak kemungkinan pengurangan yang mungkin terjadi di negara bagian tersebut. Jika parser adalah LR atau LALR, token akan diperiksa terhadap kumpulan lookahead untuk semua pengurangan yang valid untuk status tersebut. Jika token cocok dengan lookahead yang ditetapkan untuk pengurangan aturan tata bahasa G = R1 R2 .. Rn, pengurangan tumpukan dan pergeseran terjadi: tindakan semantik untuk G dipanggil, tumpukan muncul n (dari Rn) kali, pasangan ( S, G) didorong ke tumpukan, status baru S 'diatur ke GOTO (G), dan siklus berulang dengan token yang sama T.Jika pengurai adalah pengurai SLR, paling banyak ada satu aturan pengurangan untuk keadaan dan tindakan reduksi dapat dilakukan secara membabi buta tanpa mencari untuk melihat pengurangan mana yang berlaku. Hal ini berguna untuk parser SLR tahu apakah ada yangpengurangan atau tidak; ini mudah untuk mengetahui apakah setiap negara bagian secara eksplisit mencatat jumlah pengurangan yang terkait dengannya, dan penghitungan itu diperlukan untuk versi L (AL) R dalam praktiknya.
- EROR: Jika SHIFT atau REDUCE tidak dimungkinkan, kesalahan sintaksis dideklarasikan.
Jadi, jika mereka semua menggunakan mesin yang sama, apa gunanya?
Nilai yang diklaim dalam SLR adalah kesederhanaannya dalam implementasi; Anda tidak perlu memindai melalui kemungkinan pengurangan memeriksa kumpulan lookahead karena paling banyak ada satu, dan ini adalah satu-satunya tindakan yang dapat dilakukan jika tidak ada SHIFT keluar dari status. Pengurangan mana yang berlaku dapat dilampirkan secara khusus ke status, sehingga mesin pengurai SLR tidak perlu memburunya. Dalam praktiknya, parser L (AL) R menangani sekumpulan bahasa yang lebih besar dan berguna, dan sangat sedikit pekerjaan tambahan untuk diterapkan sehingga tidak ada yang mengimplementasikan SLR kecuali sebagai latihan akademis.
Perbedaan antara LALR dan LR berkaitan dengan generator tabel. Generator parser LR melacak semua kemungkinan pengurangan dari status tertentu dan set lookahead yang tepat; Anda berakhir dengan status di mana setiap pengurangan dikaitkan dengan lookahead persisnya yang ditetapkan dari konteks kirinya. Ini cenderung membangun kumpulan negara bagian yang agak besar. Generator parser LALR bersedia menggabungkan status jika tabel GOTO dan set lookhead untuk pengurangan kompatibel dan tidak bertentangan; ini menghasilkan jumlah status yang jauh lebih kecil, dengan harga tidak dapat membedakan rangkaian simbol tertentu yang dapat dibedakan oleh LR. Jadi, pengurai LR dapat mengurai sekumpulan bahasa yang lebih besar daripada pengurai LALR, tetapi memiliki tabel parser yang jauh lebih besar. Dalam praktiknya, seseorang dapat menemukan tata bahasa LALR yang cukup dekat dengan bahasa target sehingga ukuran mesin status layak untuk dioptimalkan;
Jadi: Ketiganya menggunakan mesin yang sama. SLR adalah "mudah" dalam arti bahwa Anda dapat mengabaikan sedikit mesin tetapi itu tidak sebanding dengan masalahnya. LR mem-parsing serangkaian bahasa yang lebih luas tetapi tabel status cenderung cukup besar. Itu membuat LALR sebagai pilihan praktis.
Setelah mengatakan semua ini, perlu diketahui bahwa pengurai GLR dapat mengurai bahasa bebas konteks apa pun, menggunakan mesin yang lebih rumit tetapi tabel yang persis sama (termasuk versi yang lebih kecil yang digunakan oleh LALR). Ini berarti GLR benar-benar lebih bertenaga daripada LR, LALR dan SLR; cukup banyak jika Anda dapat menulis tata bahasa BNF standar, GLR akan mengurai sesuai dengan itu. Perbedaan dalam permesinan adalah GLR bersedia untuk mencoba beberapa parse ketika ada konflik antara tabel GOTO dan atau set lookahead. (Bagaimana GLR melakukan ini secara efisien adalah jenius belaka [bukan milik saya] tetapi tidak akan muat dalam posting SO ini).
Bagi saya itu adalah fakta yang sangat berguna. Saya membangun penganalisis program dan transformator kode dan parser diperlukan tetapi "tidak menarik"; pekerjaan yang menarik adalah apa yang Anda lakukan dengan hasil parsing sehingga fokusnya adalah melakukan pekerjaan pasca parsing. Menggunakan GLR berarti saya dapat dengan mudah membangun tata bahasa yang berfungsi, dibandingkan dengan meretas tata bahasa untuk masuk ke bentuk yang dapat digunakan LALR. Ini sangat penting ketika mencoba berurusan dengan bahasa non-akademis seperti C ++ atau Fortran, di mana Anda benar-benar membutuhkan ribuan aturan untuk menangani seluruh bahasa dengan baik, dan Anda tidak ingin menghabiskan hidup Anda mencoba meretas aturan tata bahasa ke memenuhi batasan LALR (atau bahkan LR).
Sebagai contoh terkenal, C ++ dianggap sangat sulit untuk diurai ... oleh orang yang melakukan penguraian LALR. C ++ mudah diurai menggunakan mesin GLR menggunakan hampir semua aturan yang disediakan di bagian belakang manual referensi C ++. (Saya memiliki parser seperti itu, dan tidak hanya menangani vanilla C ++, tetapi juga berbagai dialek vendor. Ini hanya mungkin dalam praktiknya karena kami menggunakan pengurai GLR, IMHO).
[EDIT November 2011: Kami telah memperluas parser kami untuk menangani semua C ++ 11. GLR membuatnya jauh lebih mudah untuk dilakukan. EDIT Agustus 2014: Sekarang menangani semua C ++ 17. Tidak ada yang rusak atau bertambah buruk, GLR tetaplah mengeong kucing.]