Menurut satu halaman di code.google.com, "rekursi kiri" didefinisikan sebagai berikut:
Rekursi kiri hanya mengacu pada sembarang rekursif nonterminal yang, ketika menghasilkan bentuk sentensial yang mengandung dirinya sendiri, salinan baru itu sendiri muncul di sebelah kiri aturan produksi.
Wikipedia menawarkan dua definisi berbeda:
Dalam hal tata bahasa bebas konteks, r non-terminal r kiri-rekursif jika simbol paling kiri di salah satu produksi r ('alternatif') baik langsung (langsung / langsung kiri-rekursif) atau melalui beberapa non-terminal lainnya definisi (tidak langsung / tersembunyi-rekursif kiri) ditulis ulang untuk r lagi.
"Tata bahasa adalah rekursif kiri jika kita dapat menemukan beberapa non-terminal A yang pada akhirnya akan mendapatkan bentuk sentensial dengan dirinya sendiri sebagai simbol kiri."
Saya baru saja memulai dengan penciptaan bahasa di sini, dan saya melakukannya di waktu luang saya. Namun ketika turun untuk memilih parser bahasa, apakah rekursi kiri didukung oleh parser ini atau parser itu adalah masalah yang langsung muncul di depan dan tengah. Mencari istilah seperti "bentuk sentensial" hanya mengarah pada daftar jargon lebih lanjut, tetapi perbedaan rekursi "kiri" hampir harus menjadi sesuatu yang sangat sederhana. Tolong terjemahkan?
sumber
::=
dariExpression
menjadiTerm
, dan jika Anda melakukan hal yang sama setelah yang pertama||
, itu tidak lagi akan menjadi rekursif kiri? Tetapi jika Anda hanya melakukannya setelah itu::=
, tetapi tidak||
, itu masih akan tetap rekursif?Expression
diganti denganTerm
, baik setelah::=
dan setelah yang pertama||
, semuanya akan baik-baik saja; karena cepat atau lambat, itu akan mengalami sesuatu yang bukanNumber
atau bukanVariable
, sehingga dapat menentukan bahwa ada sesuatu yang bukanExpression
tanpa eksekusi lebih lanjut ...Expression
, itu akan berpotensi menemukan sesuatu yang bukanTerm
, dan hanya akan terus memeriksa apakah semuanyaExpression
berulang. Apakah ini?Saya akan mencoba memasukkannya ke dalam istilah awam.
Jika Anda berpikir tentang pohon parse (bukan AST, tetapi kunjungan parser dan perluasan input), rekursi kiri menghasilkan pohon yang tumbuh ke kiri dan ke bawah. Rekursi yang tepat justru sebaliknya.
Sebagai contoh, tata bahasa umum dalam kompiler adalah daftar item. Mari kita ambil daftar string ("merah", "hijau", "biru") dan menguraikannya. Saya bisa menulis tata bahasa beberapa cara. Contoh-contoh berikut adalah rekursif langsung kiri atau kanan, masing-masing:
Pohon-pohon untuk parse ini:
Perhatikan bagaimana ia tumbuh ke arah rekursi.
Ini sebenarnya bukan masalah, tidak apa-apa jika ingin menulis tata bahasa rekursif kiri ... jika alat parser Anda dapat mengatasinya. Parser bottom up menanganinya dengan baik. Begitu juga parser LL yang lebih modern. Masalah dengan tata bahasa rekursif bukanlah rekursi, itu adalah rekursi tanpa memajukan pengurai, atau, berulang tanpa memakan token. Jika kita selalu mengonsumsi setidaknya 1 token saat kita kambuh, kita akhirnya mencapai akhir penguraian. Rekursi kiri didefinisikan sebagai berulang tanpa mengkonsumsi, yang merupakan loop tak terbatas.
Batasan ini adalah murni implementasi detail penerapan tata bahasa dengan parser LL top-down naif (parser keturunan rekursif). Jika Anda ingin tetap menggunakan tata bahasa rekursif kiri, Anda dapat mengatasinya dengan menulis ulang produksi untuk mengkonsumsi setidaknya 1 token sebelum berulang, jadi ini memastikan kami tidak pernah terjebak dalam lingkaran non-produktif. Untuk aturan tata bahasa yang kiri-rekursif, kita dapat menulis ulang dengan menambahkan aturan menengah yang meratakan tata bahasa hanya satu tingkat lookahead, menggunakan token di antara produksi rekursif. (CATATAN: Saya tidak mengatakan ini adalah satu-satunya cara atau cara yang disukai untuk menulis ulang tata bahasa, hanya menunjukkan aturan umum. Dalam contoh sederhana ini, opsi terbaik adalah menggunakan bentuk rekursif yang tepat). Karena pendekatan ini digeneralisasi, generator parser dapat mengimplementasikannya tanpa melibatkan programmer (secara teoritis). Dalam praktiknya, saya percaya ANTLR 4 sekarang melakukan hal itu.
Untuk tata bahasa di atas, implementasi LL menampilkan rekursi kiri akan terlihat seperti ini. Parser akan mulai dengan memprediksi daftar ...
Pada kenyataannya, apa yang sebenarnya kita hadapi adalah "implementasi naif", yaitu. kami awalnya memprediksikan kalimat yang diberikan, kemudian secara rekursif memanggil fungsi untuk prediksi itu, dan fungsi itu secara naif memanggil prediksi yang sama lagi.
Parser bottom-up tidak memiliki masalah aturan rekursif di kedua arah, karena mereka tidak mem-reparsing awal kalimat, mereka bekerja dengan menyatukan kalimat kembali.
Rekursi dalam tata bahasa hanya masalah jika kita menghasilkan dari atas ke bawah, yaitu. parser kami bekerja dengan "memperluas" prediksi kami saat kami mengkonsumsi token. Jika alih-alih berkembang, kami runtuh (produksi "berkurang"), seperti pada pengurai bottom-up LALR (Yacc / Bison), maka rekursi dari kedua sisi bukanlah masalah.
sumber