گرامرهای بازگشتی سمت چپ. تجزیه حذف بازگشت چپ به صورت آنلاین

مشکل اصلی هنگام استفاده از تجزیه و تحلیل پیش بینی، یافتن یک دستور زبان برای زبان ورودی است که می تواند برای ساخت یک جدول تجزیه و تحلیل با ورودی های منحصر به فرد تعریف شده استفاده شود. گاهی اوقات، با برخی تبدیل‌های ساده، گرامر غیر LL(1) را می توان به گرامر LL(1) معادل تقلیل داد. در میان این تحولات، مؤثرترین آنها فاکتورسازی چپ و حذف است بازگشت چپ. در اینجا باید به دو نکته اشاره کرد. اولاً، هر گرامر پس از این تبدیل‌ها به LL(1) تبدیل نمی‌شود، و ثانیاً، پس از چنین تبدیل‌هایی گرامر حاصل ممکن است کمتر قابل درک شود.

بازگشت مستقیم سمت چپ، یعنی بازگشت فرم، به روش زیر قابل حذف است. ابتدا قوانین A را گروه بندی می کنیم:

که در آن هیچ یک از رشته ها با A شروع نمی شوند. سپس این مجموعه قوانین را جایگزین می کنیم

که در آن A" یک غیر پایانه جدید است. از غیر پایانه A می توانید همان زنجیره های قبلی را استخراج کنید، اما اکنون نمی توانید بازگشت چپ. این روش تمام مستقیم را حذف می کند بازگشت به سمت چپ، اما بازگشت سمت چپ شامل دو یا چند مرحله حذف نمی شود. در زیر آورده شده الگوریتم 4.8به شما اجازه می دهد همه چیز را حذف کنید بازگشت به سمت چپاز دستور زبان

الگوریتم 4.8. حذف بازگشت چپ.

ورود. KS-گرامر G بدون قوانین الکترونیکی (از شکل A -> e).

خارج شوید. KS-grammar G" بدون بازگشت چپ، معادل G.

روش. مراحل 1 و 2 را دنبال کنید.

(1) غیر پایانی های دستور G را به هر ترتیبی ترتیب دهید.

(2) روش زیر را انجام دهید:

پس از تکرار (i-1) حلقه بیرونی در مرحله 2 برای هر قانون فرم ، جایی که k< i, выполняется s >ک. در نتیجه، در تکرار بعدی (با i)، حلقه داخلی (با j) به طور متوالی کران پایین m را در هر قانون افزایش می‌دهد. ، تا m >= i. سپس، پس از حذف فوری بازگشت چپبرای A -قوانین، m بزرگتر از i می شود.

الگوریتم 4.8اگر گرامر قوانین الکترونیکی نداشته باشد (قوانین شکل A -> e) قابل اجرا است. قوانین الکترونیکی موجود در دستور زبان را می توان ابتدا حذف کرد. گرامر حاصل بدون بازگشت چپممکن است قوانین الکترونیکی داشته باشد.

فاکتورسازی چپ

ایده اصلی فاکتورسازی چپ این است که در مواردی که مشخص نیست کدام یک از دو گزینه باید برای گسترش یک A غیرترمینال استفاده شود، باید قوانین A را تغییر داد تا تصمیم گیری تا زمانی که اطلاعات کافی وجود داشته باشد به تعویق بیفتد. تصمیم درست بگیر

اگر - دو قانون A - و زنجیره ورودی با یک رشته غیر خالی شروع می شود، خروجی از ما نمی دانیم که طبق قانون اول گسترش دهیم یا دوم. شما می توانید تصمیم را با گسترش به تعویق بیندازید. سپس، پس از تجزیه و تحلیل آنچه که از آن قابل استنتاج است، می توانید با یا توسط . قوانین فاکتورسازی شده سمت چپ شکل می گیرند

الگوریتم 4.9. فاکتورسازی سمت چپ گرامر

ورود. KS-گرامر G.

خارج شوید. KS-grammar G" معادل G فاکتور شده سمت چپ.

روش. برای هر غیرترمینال A، طولانی ترین پیشوند مشترک دو یا چند گزینه دیگر را پیدا کنید. اگر، یعنی یک پیشوند مشترک غیر ضروری وجود دارد، همه قوانین A را جایگزین کنید

که در آن z نشان دهنده همه گزینه هایی است که با آن شروع نمی شوند

که در آن A" غیر پایانی جدید است. این تبدیل را تا زمانی اعمال کنید که هیچ دو گزینه ای پیشوند مشترک نداشته باشند.

مثال 4.9. اجازه دهید دوباره دستور زبان عبارات شرطی را در نظر بگیریم مثال 4.6:

S -> اگر E سپس S | اگر E سپس S دیگر S | a E -> b

پس از فاکتورسازی چپ، گرامر شکل می گیرد

S -> اگر E سپس SS" | a S" -> other S | e E -> b

متأسفانه، گرامر مبهم باقی می ماند و بنابراین گرامر LL(1) نیست.

LL(k)-گرامر اگر برای یک رشته معین و اولین k کاراکتر (در صورت وجود) مشتق شده از , حداکثر یک قانون وجود داشته باشد که می تواند برای A اعمال شود تا خروجی برخی از رشته های پایانی بدست آید.


برنج. 4.4.

با k پایانه های ذکر شده شروع می شود و با آنها ادامه می یابد.

اگر دستور زبان LL(k)-گرامر برای مقداری k باشد، گرامر LL(k) نامیده می شود.

مثال 4.7. گرامر را در نظر بگیرید G = ((S، A، B)، (0، 1، a، b)، P، S)، جایی که P از قوانین تشکیل شده است

S -> A | B، A -> aAb | 0، B -> aBbb | 1.

اینجا . G یک دستور زبان LL (k) برای هر k نیست. به طور شهودی، اگر با خواندن یک رشته به اندازه کافی طولانی از کاراکترهای a شروع کنیم، نمی دانیم کدام یک از قوانین S -> A و S -> B ابتدا اعمال شده است تا زمانی که با 0 یا 1 روبرو شویم.

با عطف به تعریف دقیق دستور زبان LL (k)، y = a k 1b 2k را تنظیم می کنیم. سپس نتیجه گیری

با نتایج (1) و (2) تعریف مطابقت دارد. اولین k کاراکتر رشته های x و y یکسان هستند. با این حال، نتیجه گیری غلط است. از آنجایی که k در اینجا خودسرانه انتخاب شده است، G یک دستور زبان LL نیست.

پیامدهای تعریف LL(k) -گرامر

قضیه 4.6. KS-گرامر یک دستور زبان LL(k) است اگر و فقط اگر برای دو قانون مختلفو از تقاطع P با این همه خالی ، چی .

اثبات. ضرورت. فرض کنیم که شرایط قضیه را برآورده کرده و حاوی x است. سپس، با تعریف FIRST، برای برخی از y و z نتایجی وجود دارد

(توجه داشته باشید که در اینجا ما از این واقعیت استفاده کرده‌ایم که N شامل غیر پایانه‌های بی‌فایده نیست، همانطور که برای همه گرامرهای مورد بررسی فرض می‌شود.) اگر |x|< k ; то y = z = e . Так как , то G не LL (k)- грамматика .

کفایت. اجازه دهید فرض کنیم که G یک دستور زبان LL(k) نیست.

سپس دو نتیجه وجود دارد

که زنجیره های x و y در اولین موقعیت های k منطبق هستند، اما . بنابراین و قوانین متفاوت از P و هر یک از مجموعه ها هستند و شامل زنجیره FIRST k (x) منطبق با زنجیره FIRST k (y) است.

مثال 4.8. یک دستور زبان G متشکل از دو قانون S -> aS | a یک دستور زبان LL(1) نخواهد بود، زیرا

FIRST 1 (aS) = FIRST 1 (a) = a.

به طور شهودی، این را می توان به صورت زیر توضیح داد: با دیدن تنها این اولین کاراکتر هنگام تجزیه زنجیره ای که با علامت a شروع می شود، نمی دانیم که کدام یک از قوانین S -> aS یا S -> a باید برای S اعمال شود. از سوی دیگر، G یک دستور زبان LL(2) است. در واقع، در نماد قضیه ای که اکنون ارائه شد، اگر ، سپس A = S و . از آنجایی که فقط دو قانون مشخص شده برای S داده شده است، پس . از آنجایی که FIRST2(aS) = aa و FIRST2(a) = a، پس با آخرین قضیه G یک دستور زبان LL (2) خواهد بود.

حذف بازگشت سمت چپ

مشکل اصلی هنگام استفاده از تجزیه و تحلیل پیش بینی، یافتن یک دستور زبان برای زبان ورودی است که می تواند برای ساخت یک جدول تجزیه و تحلیل با ورودی های منحصر به فرد تعریف شده استفاده شود. گاهی اوقات، با برخی تبدیل‌های ساده، گرامر غیر LL(1) را می توان به گرامر LL(1) معادل تقلیل داد. در میان این تبدیل‌ها، مؤثرترین آنها فاکتورسازی چپ و حذف بازگشت چپ است. در اینجا باید به دو نکته اشاره کرد. اولاً، هر گرامر پس از این تبدیل‌ها به LL(1) تبدیل نمی‌شود، و ثانیاً، پس از چنین تبدیل‌هایی گرامر حاصل ممکن است کمتر قابل درک شود.

بازگشت مستقیم سمت چپ، یعنی بازگشت فرم، به روش زیر قابل حذف است. ابتدا قوانین A را گروه بندی می کنیم:

که در آن هیچ یک از خطوط با A شروع نمی شود. سپس این مجموعه قوانین را با

که در آن A" غیرترمینال جدید است. همان زنجیره‌ها را می‌توان از غیرترمینال A استنباط کرد که قبلاً وجود داشت، اما اکنون بازگشت چپ وجود ندارد. این روش همه بازگشت‌های چپ فوری را حذف می‌کند، اما بازگشت سمت چپ شامل دو یا چند مرحله را حذف نمی‌کند. زیر الگوریتم 4.8به شما این امکان را می دهد که تمام بازگشت های سمت چپ را از دستور زبان حذف کنید.

الگوریتم 4.8. حذف بازگشت سمت چپ

ورود. KS-grammar G بدون قوانین الکترونیکی (از شکل A -> e ).

خارج شوید. KS-grammar G" بدون بازگشت چپ، معادل G.

روش. مراحل 1 و 2 را دنبال کنید.

(1) غیر پایانی های دستور G را به هر ترتیبی ترتیب دهید.

(2) روش زیر را انجام دهید:

پس از تکرار (i-1) حلقه بیرونی در مرحله 2 برای هر قانون فرم ، جایی که k< i , выполняется s >ک. در نتیجه، در تکرار بعدی (با i)، حلقه داخلی (با j) به طور متوالی کران پایین m را در هر قانون افزایش می‌دهد. ، تا m >= i وجود داشته باشد. سپس، پس از حذف بازگشت فوری سمت چپ برای قوانین A i، m بزرگتر از i می شود.

LL(k) -خاصیت محدودیت های زیادی بر دستور زبان اعمال می کند. گاهی اوقات می توان یک دستور زبان را به گونه ای تبدیل کرد که گرامر حاصل را داشته باشد دارایی LL(1) . چنین تبدیلی همیشه موفقیت آمیز نیست، اما اگر امکان دستیابی به گرامر LL(1) وجود داشته باشد، برای ساختن یک تحلیلگر می توانید از روش نزول بازگشتی بدون عقب نشینی استفاده کنید.

فرض کنید باید یک تحلیلگر برای زبانی بسازیم که توسط گرامر زیر تولید شده است:

EE + تی | Eتی | تی

T → T * F | T/F | اف

افتعداد | (E)

ترمینال های متعدد FIRST (T)نیز متعلق به مجموعه است FIRST(E+T)بنابراین، تعیین بدون ابهام توالی فراخوانی‌های رویه‌ای که باید هنگام تجزیه و تحلیل زنجیره ورودی انجام شوند، غیرممکن است. مشکل این است که غیر ترمینال Eدر موقعیت اول سمت راست قاعده رخ می دهد که سمت چپ آن نیز می باشد E. در چنین شرایطی، غیر ترمینال Eمستقیماً بازگشتی چپ نامیده می شود.

غیر ترمینال آ KS-گرامرها جیتماس گرفت بازگشتی چپ ، اگر نتیجه ای در دستور زبان وجود داشته باشد آ =>* اوه.

دستور زبانی که حداقل یک قانون بازگشتی سمت چپ داشته باشد نمی تواند باشد LL (1)-گرامر

از سوی دیگر، مشخص است که هر زبان CS حداقل با یک گرامر بازگشتی غیر چپ تعریف می شود.

    1. الگوریتم حذف بازگشتی سمت چپ

اجازه دهید G = (N، T، P، S)– KS-گرامر و قاعده A→Aw 1 | اوه 2 | ... | اوه n | v 1 | v 2 | ... | v مترنشان دهنده تمام قوانین از پحاوی آدر سمت چپ، و هیچ یک از زنجیر v منبا غیر ترمینال شروع نمی شود آ.

بیایید به مجموعه اضافه کنیم نیک غیر ترمینال دیگر آ"و قوانین حاوی آدر سمت چپ، به زیر:

A → v 1 | v 2 | ... | v متر | v 1 آ' | v 2 A' | ... | v متر آ"

A' → w 1 | w 2 | ... | w n | w 1 A' | w 2 A' | ...| w n آ"

می توان ثابت کرد که گرامر حاصل معادل گرامر اصلی است.

در نتیجه اعمال این تبدیل به دستور زبان بالا که عبارات حسابی را توصیف می کند، دستور زبان زیر را به دست می آوریم:

Eتی | T.E."

E" → + تی | + T.E."

تیاف | F.T."

تی"→ * اف | * F.T."

اف → (E) | تعداد

به راحتی می توان نشان داد که گرامر حاصل دارای خاصیت است LL (1).

مشکل مشابه دیگر زمانی رخ می دهد که دو قانون برای یک غیر پایانه با کاراکترهای یکسان شروع می شود.

مثلا،

S → اگر E سپس S دیگر S

اساگر E سپس اس

در این مورد، ما یک غیر پایانه دیگر اضافه می کنیم که با انتهای مختلف این قوانین مطابقت دارد. ما قوانین زیر را دریافت می کنیم:

اساگر E سپس اس اس

اس" →

اس"→ دیگر اس

برای دستور زبان به دست آمده، روش نزول بازگشتی را می توان پیاده سازی کرد.

    1. 9.1.4. نزول بازگشتی با بازگشت.

برای اینکه بتوان روش نزول بازگشتی را اعمال کرد، باید 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 گرامر را به شکلی تبدیل می کند که در آن مجموعه ها اولینتلاقی نکنید، که فرآیند پیچیده ای است، بنابراین در عمل تکنیکی به نام نزول بازگشتی با بازگشت .

برای انجام این کار، تحلیلگر واژگانی به عنوان یک شی نشان داده می شود که علاوه بر روش های سنتی اسکن کنید, بعدو غیره، یک سازنده کپی نیز وجود دارد. سپس، در تمام شرایطی که ممکن است ابهام ایجاد شود، قبل از شروع تجزیه، باید وضعیت فعلی تحلیلگر واژگانی را به خاطر بسپارید (یعنی یک کپی از تحلیلگر واژگانی تهیه کنید) و با توجه به اینکه با اولین مورد روبرو هستیم، به تجزیه متن ادامه دهید. ساخت و سازهای احتمالی در این شرایط اگر این گزینه تجزیه ناموفق بود، پس باید وضعیت تحلیلگر واژگانی را بازیابی کنید و سعی کنید دوباره همان قطعه را با استفاده از گزینه گرامر بعدی و غیره تجزیه کنید. اگر همه گزینه‌های تجزیه با شکست مواجه شوند، خطا گزارش می‌شود.

این روش تجزیه به طور بالقوه کندتر از نزول بازگشتی بدون عقب نشینی است، اما در این حالت می توان گرامر را به شکل اصلی خود حفظ کرد و تلاش برنامه نویس را ذخیره کرد.

ویژگی گرامرهای رسمی این است که به فرد اجازه می دهد با استفاده از مجموعه ای محدود از قوانین، مجموعه ای از زنجیره های یک زبان را تعریف کند (البته، مجموعه زنجیره های یک زبان نیز می تواند محدود باشد، اما حتی برای زبان های واقعی ساده. این شرط معمولاً برآورده نمی شود). گرامر مثال برای اعداد صحیح اعشاری امضا شده در بالا مجموعه بی نهایتی از اعداد صحیح را با استفاده از 15 قانون تعریف می کند.

توانایی استفاده از مجموعه محدودی از قوانین در این شکل از نشانه گذاری دستور زبان از طریق قوانین بازگشتی به دست می آید. بازگشت در قواعد دستور زبان در این واقعیت بیان می شود که یکی از نمادهای غیر پایانی از طریق خود تعریف می شود. بازگشت می تواند مستقیم (صریح) باشد - سپس نماد از طریق خود در یک قانون تعریف می شود یا غیر مستقیم (ضمنی) - سپس همان اتفاق از طریق زنجیره ای از قوانین رخ می دهد.

در دستور زبان G که در بالا مورد بحث قرار گرفت، بازگشت مستقیم در قانون وجود دارد:<чс>-»<чс><цифра>، و در دستور زبان معادل آن G" - در قاعده: T-VTF.

برای اینکه بازگشت بی نهایت نباشد، برای نماد غیر پایانی دستور زبانی که در آن شرکت می کند، باید قوانین دیگری نیز وجود داشته باشد که آن را تعریف می کند، خود را دور می زند، و به فرد اجازه می دهد از یک تعریف بازگشتی بی نهایت اجتناب کند (در غیر این صورت این نماد به سادگی انجام می شود. در گرامر مورد نیاز نیست). این قوانین هستند<чс>-»<цифра>- در دستور زبان G و T->F - در دستور زبان G."

در تئوری زبان‌های رسمی چیزی بیشتر از بازگشت نمی‌توان گفت. اما برای درک کاملتر معنای بازگشت، می توانید به معنای زبان متوسل شوید - در مثالی که در بالا بحث شد، این زبان اعداد صحیح اعشاری است. بیایید معنای آن را در نظر بگیریم.


تعریف گرامر. شکل ekusa-maura "ZO /

اگر بخواهید تعریف کنید که یک عدد چیست، می توانید با این واقعیت شروع کنید که هر عددی خودش یک عدد است. علاوه بر این، می توانید متوجه شوید که هر دو رقمی نیز یک عدد است، سپس سه رقم و غیره. اگر تعریف یک عدد را با استفاده از این روش بسازید، آنگاه هرگز کامل نمی شود (در ریاضیات، ظرفیت رقمی یک عدد نیست. محدود به هر چیزی). با این حال، می توانید متوجه شوید که هر بار که یک عدد جدید تولید می کنیم، به سادگی یک واحد به سمت راست (از آنجایی که عادت داریم از چپ به راست بنویسیم) به سری اعداد از قبل نوشته شده اضافه می کنیم. و این سری اعداد که از یک رقم شروع می شود نیز یک عدد است. سپس تعریف مفهوم "عدد" را می توان به این ترتیب ساخت: "عدد هر رقمی است یا عدد دیگری که هر رقمی به سمت راست به آن اضافه شود." این دقیقاً همان چیزی است که اساس قواعد گرامرهای G و G را تشکیل می دهد و در خط دوم قوانین در قوانین منعکس شده است.<чс>-><цифра> [ <чс><цифра>و T->F | TF. قوانین دیگر در این گرامرها به شما این امکان را می دهد که یک علامت به یک عدد اضافه کنید (خط اول قوانین) و مفهوم "رقم" (خط سوم قوانین) را تعریف کنید. ابتدایی هستند و نیازی به توضیح ندارند.



اصل بازگشت (که گاهی اوقات "اصل تکرار" نامیده می شود، که ماهیت را تغییر نمی دهد) یک مفهوم مهم در ایده گرامرهای رسمی است. به هر شکلی، صریح یا ضمنی، بازگشت همیشه در گرامر هر زبان برنامه نویسی واقعی وجود دارد. دقیقاً همین است که به شما امکان می دهد تعداد بی نهایت زنجیره زبان بسازید و بدون درک اصل بازگشت غیرممکن است که در مورد نسل آنها صحبت کنید. به طور معمول در گرامر یک زبان واقعی؟ برنامه نویسی شامل نه یک، بلکه مجموعه ای کامل از قوانین ساخته شده با استفاده از بازگشت است.

روش های دیگر برای تنظیم گرامر

فرم Backus-Naur از نقطه نظر رسمی یک روش راحت است، اما همیشه برای نوشتن گرامرهای رسمی قابل درک نیست. تعاریف بازگشتی برای تحلیل رسمی رشته‌های زبان خوب هستند، اما از دیدگاه انسانی مناسب نیستند. مثلا چه قوانینی<чс>-><цифра> | <чс><цифра>منعکس کننده توانایی ساخت یک عدد با اضافه کردن هر تعداد رقم در سمت راست، با شروع از یک، که واضح نیست و نیاز به توضیح اضافی دارد.

اما هنگام ایجاد یک زبان برنامه نویسی، مهم است که گرامر آن نه تنها توسط کسانی که کامپایلرهای این زبان را ایجاد می کنند، بلکه توسط کاربران آن زبان - توسعه دهندگان برنامه های آینده نیز درک شود. بنابراین، راه‌های دیگری برای توصیف قواعد دستور زبان رسمی وجود دارد که هدف آن درک بیشتر انسان است.

نوشتن قواعد گرامری

با استفاده از متاکاراکترها

نوشتن قوانین گرامر با استفاده از متاکراکترها فرض می کند که رشته قوانین دستور زبان ممکن است دارای کاراکترهای خاصی باشد - متا


358 فصل 9. زبان‌ها و دستور زبان‌های رسمی

نمادها - که معنای خاصی دارند و به گونه ای خاص تفسیر می شوند. متاکاراکترهایی که معمولاً استفاده می شوند عبارتند از () (پرانتز)، (پرانتز)، () (پرانتز مجعد)، «» (کاما) و «» (نقل قول). این متا کاراکترها به معنای زیر هستند:

□ پرانتز به معنای تمام زنجیره های فهرست شده در داخل آنها است
کاراکترها در یک مکان معین از قاعده گرامر فقط یک ce می تواند وجود داشته باشد
جوانه؛

□ براکت های مربع به این معنی است که زنجیره مشخص شده در آنها می تواند رخ دهد
قواعد دستور زبان ممکن است در یک مکان خاص رخ دهد یا نباشد (یعنی ممکن است
ممکن است یک بار در آن باشد یا اصلا نباشد)

□ پرانتزهای فرفری به این معنی است که رشته مشخص شده در داخل آنها ممکن است رخ ندهد
قوانین دستور زبان در یک مکان معین بیش از یک بار ظاهر می شوند، یک بار رخ می دهند
یک بار یا چند بار به دلخواه؛

□ یک کاما برای جدا کردن رشته‌های کاراکتر در دور استفاده می‌شود
براکت؛

□ نقل قول ها در مواردی که به یکی از متاکاراکترها نیاز است استفاده می شود
شامل در زنجیره به روش معمول - است که، زمانی که یکی از براکت یا پشت
مورد پنجم باید در زنجیره کاراکتر زبان وجود داشته باشد (اگر خود نقل قول باشد
باید در زنجیره ای از شخصیت ها گنجانده شود، سپس باید دو بار تکرار شود - این
این اصل برای توسعه دهندگان برنامه آشنا است).

اگر با استفاده از متاکراکترها نوشته شود، قواعد گرامر G که در بالا مورد بحث قرار گرفت باید به این صورت باشد:

<число> -» [(+.-)]<цифра>{<цифра>}

<цифра> ->0|1|2|3|4|5|6|7|8|9

خط دوم قوانین نیازی به توضیح ندارد و قانون اول به این صورت است: "عدد زنجیره ای از کاراکترها است که می تواند با علامت + یا - شروع شود، سپس باید یک رقم داشته باشد که می تواند به دنبال آن یک رقم باشد. دنباله ای از هر تعداد رقم." برخلاف شکل Backus-Naur، همانطور که می بینید، در شکل نوشتن با استفاده از متاسامبول ها، ابتدا یک علامت غیر پایانی مبهم از دستور زبان حذف می شود.<чс>و ثانیاً ما موفق شدیم بازگشت را به طور کامل حذف کنیم. دستور زبان در نهایت واضح تر شد.

شکل نوشتن قواعد با استفاده از متاسامبول ها روشی مناسب و قابل درک برای نمایش قواعد دستور زبان است. در بسیاری از موارد، به شما این امکان را می دهد که با جایگزین کردن آن با نماد تکرار () (پرانتزهای مجعد) از شر بازگشت به طور کامل خلاص شوید. همانطور که از مطالب بعدی مشخص خواهد شد، این شکل برای یکی از انواع گرامرها - گرامرهای معمولی - رایج است.

ثبت قواعد گرامری به صورت گرافیکی

هنگام نوشتن قوانین به صورت گرافیکی، کل دستور زبان در قالب مجموعه ای از نمودارهای ساخته شده ویژه ارائه می شود. این شکل هنگام توصیف دستور زبان پاسکال پیشنهاد شد و سپس در ادبیات رایج شد. برای همه انواع گرامرها در دسترس نیست، اما فقط


تعریف گرامر. Backus-Naur فرم 359

برای انواع بدون متن و معمولی، اما این کافی است تا بتوان از آن برای توصیف گرامر زبان های برنامه نویسی معروف استفاده کرد.

در این شکل نمادگذاری، هر نماد غیر پایانی دستور زبان مربوط به نموداری است که در قالب یک گراف جهت دار ساخته شده است. این نمودار دارای انواع رئوس زیر است:

□ نقطه ورود (به هیچ وجه در نمودار نشان داده نشده است، به سادگی از آنجا شروع می شود)
قوس ورودی نمودار)؛

□ نماد غیر پایانی (با یک مستطیل در نمودار مشخص می شود که در آن
که نام نماد وارد شده است)؛

□ زنجیره ای از نمادهای پایانه (در نمودار نشان داده شده با یک بیضی، یک دایره
یا یک مستطیل با لبه های گرد که داخل آن حک شده است
جوانه)؛

□ نقطه گره (در نمودار نشان داده شده با یک نقطه پررنگ یا سایه دار
دایره)؛

□ نقطه خروج (به هیچ وجه مشخص نشده، قوس خروجی نمودار به سادگی وارد آن می شود).

هر نمودار فقط یک نقطه ورود و یک نقطه خروج دارد، اما هر تعداد راس از سه نوع دیگر. راس ها توسط کمان های گراف جهت دار (خطوط با فلش) به یکدیگر متصل می شوند. آرک ها فقط می توانند از نقطه ورودی خارج شوند و فقط وارد نقطه ورودی شوند. رئوس باقی مانده از کمان هم می توانند وارد شوند و هم خارج شوند (در یک دستور زبان درست ساخته شده، هر راس باید حداقل یک ورودی و حداقل یک خروجی داشته باشد).

برای ساخت زنجیره ای از نمادها مربوط به هر نماد غیر پایانی گرامر، باید نمودار این نماد را در نظر بگیرید. سپس، با شروع از نقطه ورود، باید در امتداد کمان های نمودار نمودار از هر رئوس تا نقطه خروج حرکت کنید. در این حالت، با عبور از یک راس مشخص شده توسط یک نماد غیر پایانی، این نماد باید در زنجیره حاصل قرار گیرد. هنگام عبور از یک راس که با زنجیره ای از نمادهای انتهایی نشان داده شده است، این نمادها نیز باید در زنجیره حاصل قرار گیرند. هنگام عبور از نقاط گره ای نمودار، نیازی به انجام هیچ عملی روی زنجیره حاصل نیست. بسته به مسیر احتمالی حرکت، می‌توانید از هر رأس نمودار نمودار یک بار عبور کنید، نه یک بار، یا هر چند بار که دوست دارید. به محض اینکه به نقطه خروجی نمودار رسیدیم، ساخت زنجیره حاصل به پایان می رسد.

زنجیره حاصل به نوبه خود ممکن است حاوی نمادهای غیر پایانی باشد. برای جایگزینی آنها با رشته هایی از نمادهای پایانه، دوباره باید نمودارهای مربوطه را در نظر بگیرید. و به همین ترتیب تا زمانی که فقط کاراکترهای پایانه در زنجیره باقی بمانند. بدیهی است که برای ساخت زنجیره ای از نمادهای یک زبان معین، باید با نمودار نماد دستور زبان هدف شروع به بررسی کرد.

این یک روش راحت برای توصیف قواعد گرامر، عملکرد با تصاویر است، و بنابراین منحصراً روی افراد متمرکز است. حتی یک ارائه ساده از اصول اولیه آن در اینجا کاملاً دست و پا گیر بود، در حالی که ماهیت



فصل 9. زبان‌ها و دستور زبان‌های رسمی


روش کاملا ساده است. این را می توان به راحتی مشاهده کرد اگر به شرح مفهوم "عدد" از دستور G با استفاده از نمودارهای شکل 1 نگاه کنید. 9.1.

برنج. 9.1. نمایش گرافیکی گرامر اعداد صحیح اعشاری امضا شده: در بالا - برای مفهوم "عدد"؛ در زیر - برای مفهوم "رقم"

همانطور که در بالا ذکر شد، این روش عمدتا در ادبیات هنگام ارائه گرامر زبان های برنامه نویسی استفاده می شود. برای کاربران - توسعه دهندگان برنامه - راحت است، اما کاربرد عملیهنوز در کامپایلرها وجود ندارد.

طبقه بندی زبان ها و گرامرها

انواع مختلفی از گرامرها قبلاً در بالا ذکر شده است ، اما مشخص نشده است که چگونه و بر چه اساسی آنها به انواع تقسیم می شوند. برای یک فرد، زبان ها می توانند ساده یا پیچیده باشند، اما این یک نظر کاملاً ذهنی است که اغلب به شخصیت فرد بستگی دارد.

برای کامپایلرها، زبان ها را نیز می توان به ساده و پیچیده تقسیم کرد، اما در این مورد معیارهای سختگیرانه ای برای این تقسیم بندی وجود دارد. همانطور که در زیر نشان داده خواهد شد، بستگی به نوع زبان برنامه نویسی خاص دارد.


رووانیا، پیچیدگی تشخیص دهنده این زبان بستگی دارد. هرچه زبان پیچیده تر باشد، هزینه های محاسباتی کامپایلر برای تجزیه و تحلیل زنجیره های برنامه منبع نوشته شده به این زبان بیشتر می شود و بنابراین، خود کامپایلر و ساختار آن پیچیده تر است. برای برخی از انواع زبان ها، اصولاً ساخت کامپایلری که متن های مبدأ را در این زبان ها در زمان قابل قبولی بر اساس منابع محاسباتی محدود تجزیه و تحلیل کند غیرممکن است (به همین دلیل است که هنوز امکان ایجاد برنامه در زبان های طبیعی وجود ندارد. به عنوان مثال، به زبان روسی یا انگلیسی).

طبقه بندی گرامرها

گرامر حاوی بازگشت چپ، گرامر LL(1) نیست. بیایید به قوانین نگاه کنیم

آAa(بازگشت سمت چپ در A)

آآ

اینجا آنماد پیشین برای هر دو نوع غیر پایانی آ. به طور مشابه، گرامر حاوی یک حلقه بازگشتی چپ نمی تواند یک گرامر LL(1) باشد، برای مثال

آقبل از میلاد مسیح.

بسی دی

سیA.E.

یک دستور زبان حاوی یک حلقه بازگشتی چپ را می توان به یک دستور زبان حاوی بازگشت مستقیم سمت چپ تبدیل کرد و سپس با معرفی غیر پایانه های اضافی، بازگشت چپ را می توان به طور کامل حذف کرد (در واقع با بازگشت راست جایگزین می شود، که مشکلی در رابطه با LL(1) -خواص).

به عنوان مثال، یک دستور زبان را با قواعد تولیدی در نظر بگیرید


اسAa

آBb

برونوشت

سیDD

سیه

Dآز


که دارای یک حلقه بازگشتی سمت چپ شامل آ ب پ ت. برای جایگزینی این حلقه با بازگشت مستقیم سمت چپ، غیرترمینال ها را به صورت زیر مرتب می کنیم: S، A، B، C، D.

اجازه دهید تمام قوانین تولید فرم را در نظر بگیریم

شیXj γ،

جایی که شیو Xjغیر ترمینال هستند و γ - رشته ای از کاراکترهای پایانی و غیر پایانی. با توجه به قوانینی که برای آن j ≥ i، اقدامی انجام نمی شود. با این حال، اگر یک چرخه بازگشتی سمت چپ وجود داشته باشد، این نابرابری نمی تواند برای همه قوانین برقرار باشد. با ترتیبی که انتخاب کرده‌ایم، با یک قانون واحد روبرو هستیم:

Dآز

زیرا آقبل از Dدر این سفارش حالا بیایید جایگزینی را شروع کنیم آ، با استفاده از تمام قوانینی که دارند آدر سمت چپ در نتیجه بدست می آوریم

DBbz

از آنجا که بقبل از Dدر سفارش، روند تکرار می شود و این قانون را می دهد:

DCCbz

سپس دوباره خود را تکرار می کند و دو قانون می دهد:

Decbz

DDdcbz

گرامر تبدیل شده اکنون به شکل زیر است:

اسAa

آBb

برونوشت

سیDD

سیه

DDdcbz

Decbz

همه این قوانین تولید فرم مورد نیاز را دارند و حلقه بازگشتی سمت چپ با بازگشت مستقیم چپ جایگزین می شود. برای حذف بازگشت مستقیم سمت چپ، یک نماد غیر پایانی جدید معرفی می کنیم زو قوانین را تغییر دهید

Decbz

DDdcbz

Decbz

DecbzZ

زdcbz

زdcbzZ

توجه داشته باشید که قبل و بعد از تبدیل Dیک عبارت منظم تولید می کند

(ecbz) (dcbz)*

با تعمیم، می توانیم نشان دهیم که اگر یک غیر پایانی باشد آدر سمت چپ ظاهر می شود r+ سایجاد قوانین، rکه از بازگشت مستقیم چپ استفاده می شود، و س- نه، یعنی

آ 1, آ 2,..., آ r

آβ 1, آβ 2,..., آβ س

سپس این قوانین را می توان با موارد زیر جایگزین کرد:

یک دلیل غیررسمی این است که قبل و بعد از تحول آیک عبارت منظم تولید می کند ( β 1 | β 2 |... | β س) ( α 1 | α 2 |... | α ر) *

لازم به ذکر است که با حذف بازگشت چپ (یا حلقه بازگشتی چپ)، هنوز گرامر LL(1) را بدست نمی آوریم، زیرا برای برخی از غیر پایانه ها، سمت راست جایگزین در سمت چپ قواعد دستور زبان های حاصل وجود دارد که با همان نمادها شروع می شود. بنابراین، پس از حذف بازگشت چپ، باید تبدیل گرامر به فرم LL(1) را ادامه دهیم.

17.تبدیل گرامرها به فرم LL(1). فاکتورسازی.

فاکتورسازی

در بسیاری از موقعیت ها، گرامرهایی که ویژگی LL(1) را ندارند، می توانند با استفاده از فرآیند فاکتورسازی به گرامرهای LL(1) تبدیل شوند. بیایید به مثالی از چنین وضعیتی نگاه کنیم.

پ→ شروع کنید D; باپایان

Dد, D

Dد

باس; با

باس

در فرآیند فاکتورسازی، چندین قانون را برای یک غیرترمینال در سمت چپ جایگزین می‌کنیم، که سمت راست آن با همان نماد (زنجیره‌ای از کاراکترها) با یک قانون شروع می‌شود، جایی که در سمت راست، شروع مشترک با یک علامت اضافه دنبال می‌شود. غیر ترمینال گرامر همچنین با قوانینی برای یک غیر پایانی اضافی تکمیل می شود که بر اساس آن «بقایای» مختلف سمت راست اصلی قانون از آن مشتق می شود. برای گرامر بالا، گرامر LL(1) زیر را به دست می دهد:

پ→ شروع کنید D; باپایان

Dd X ایکس)

ایکس→ , D(طبق قانون 1 برای Dدستور زبان اصلی برای دباید D)

ایکسε (طبق قانون 2 برای Dدستور زبان اصلی برای دهیچی (خط خالی))

باs Y(یک غیر ترمینال اضافی معرفی کنید Y)

Y→ ; با(طبق قانون 1 برای سیدستور زبان اصلی برای سبه شرح زیر است سی)

Yε (طبق قانون 2 برای سیدستور زبان اصلی برای سهیچی (خط خالی))

به همین ترتیب، قوانین زایشی

اسaSb

اسaSc

اسε

را می توان با فاکتورسازی به قوانین تبدیل کرد

اسaSX

اسε

ایکسب

ایکسج

و گرامر حاصل LL(1) است. با این حال، فرآیند فاکتورسازی را نمی توان با گسترش آن به حالت کلی خودکار کرد. مثال زیر نشان می دهد که چه اتفاقی می تواند بیفتد. بیایید به قوانین نگاه کنیم


1. پQx

2. پرای

3. سمتر مربع

4. سq

5. آرsRn

6. آرr


هر دو مجموعه از شخصیت های راهنما برای دو گزینه پحاوی س، و تلاش برای "تحمل کردن سخارج از براکت» را جایگزین می کنیم سو آردر سمت راست قوانین 1 و 2:


پsQmx

پsRny

پqx

پرای


این قوانین را می توان با موارد زیر جایگزین کرد:


پqx

پرای

پsP 1

پ 1 → Qmx

پ 1 → Rny


قوانین برای P1مشابه قوانین اصلی برای پو دارای مجموعه های متقاطع شخصیت های راهنما هستند. ما می‌توانیم این قوانین را به همان شیوه‌ای تغییر دهیم که قوانین برای پ:


پ 1 → sQmmx

پ 1 → qmx

پ 1 → srnny

پ 1 → rny


فاکتورینگ، دریافت می کنیم