Transcript (E) -(E+E)

‫تحلیل نحوی‬
‫‪‬هر زبان برنامه نویس ی قوانینی دارد که ساختار برنامه هایی با شکل مناسب را توصیف می کنند ‪.‬‬
‫‪‬ویژگی نحوی ساختارهای برنامه سازی با استفاده از یک گرامر مستقل از متن یا روش نشان گذاری‬
‫‪ BNF‬که قبال معرفی کردیم توصیف می گردد ‪.‬‬
‫ً‬
‫‪‬از آنجایی که برنامه ها معموال حاوی خطاهای نحوی هستند ‪،‬روش های تجزیه ‪،‬به منظور پوشش‬
‫خطاهای متداول ‪،‬توسعه داده می شوند ‪.‬‬
‫‪‬تجزیه کننده ‪،‬رشته ای از نشانه ها را از تحلیلگر لغوی دریافت نموده و بازبینی می نماید که این رشته‬
‫می تواند توسط گرامر ‪،‬برای زبان مبدا تولید شود ‪.‬‬
‫‪‬از تجزیه کننده انتظار می رود که هر خطای نحوی را به شکل قابل فهم گزارش دهد ‪.‬همچنین باید بر‬
‫اساس خطاهای متداول ‪،‬به گونه ای تصحیح انجام شود که امکان پردازش باقیمانده‌ی ورودی وجود‬
‫داشته باشد ‪.‬‬
‫‪1‬‬
‫موقعیت تجزیه کننده در مدل کامپایلر‬
‫‪2‬‬
‫سه نوع تجزیه کننده عمومی برای گرامر ها وجود دارد ‪:‬‬
‫‪ (1‬روش های تجزیه جهانی مانند الگوریتم ‪ cocke-younger-kasami‬و الگوریتم‬
‫‪( Earley‬آنچنان کارایی پایینی دارند که نمی توان در تولید کامپایلر ها از آنها استفاده نمود ‪).‬‬
‫روش هایی که به طور معمول در کامپایلر ها استفاده می شوند ‪:‬‬
‫‪ (1‬روش تجزیه باال به پایین‬
‫‪ (2‬روش تجزیه پایین به باال‬
‫•‬
‫•‬
‫‪3‬‬
‫در هر دو حالت ‪،‬ورودی به تجزیه کننده ‪ ،‬از چپ به راست پویش می گردد ‪،‬یک نماد در هر دفعه ‪.‬‬
‫اکثر روش های باال به پایین و پایین به باال ‪،‬فقط بر روی زیر گروههایی از گرامر ها عمل می کنند‬
‫‪.‬اما تعدادی از این زیر گروهها ‪،‬مانند گرامر های ‪ LL‬و ‪ LR‬آنقدر گویا هستند که قادر به‬
‫توصیف اکثر ساختارهای نحوی در زبانهای برنامه سازی می باشند ‪.‬‬
‫اداره نمودن خطاهای نحوی‬
‫خطاها می توانند در سطوح زیر ظاهر شوند ‪:‬‬
‫‪‬لغوی‪.‬مانند دیکته غلط یک شناسه ‪،‬کلمه کلیدی ‪،‬یا عملگر‬
‫‪‬نحوی‪.‬مانند یک عبارت محاسباتی با پرانتز های نامتعادل‬
‫‪‬معنایی‪.‬مانند استفاده از یک عملگر با عملوند های ناسازگار‬
‫‪‬منطقی‪.‬مانند فراخوانی بازگشتی بی نهایت‬
‫اداره کننده خطا در یک تجزیه کننده اهداف واضحی دارد ‪:‬‬
‫‪‬باید حضور خطاها را بوضوح و با دقت گزارش دهد ‪.‬‬
‫‪‬باید هر خطا را با سرعت کافی پوشش دهد تا امکان آشکارسازی خطاهای بعدی وجود داشته‬
‫باشد ‪.‬‬
‫‪‬نباید بیش از حد ‪،‬سرعت پردازش برنامه های صحیح را کاهش دهد ‪.‬‬
‫چندین روش تجزیه مانند روش های ‪ LL‬و ‪، LR‬خطا را در زودترین حد ممکن آشکار می سازند‬
‫‪.‬آنها دارای خصوصیت پیشوند قابل وقوع هستند ‪.‬به این معنی که وقوع خطا را به محض دیدن‬
‫پیشوندی از ورودی که متعلق به پیشوند های رشته های آن زبان نمی باشد ‪،‬تشخیص می دهند ‪.‬‬
‫‪4‬‬
‫استراتژی های پوشش خطا‬
‫استراتژی های عمومی متعددی وجود دارند که تجزیه کننده می تواند به منظور پ ‌وشش‬
‫خطای نحوی استفاده نماید ‪.‬‬
‫برخی از این استراتژی ها ‪:‬‬
‫‪1.Panic mode‬‬
‫‪2.Phrase level‬‬
‫‪3.Error productions‬‬
‫‪4.Global correction‬‬
‫‪ .1‬ساده ترین روش برای پیاده سازی است و می تواند توسط اکثر روش های تجزیه مورد استفاده قرار‬
‫گیرد ‪.‬در هنگام تشخیص خطا ‪،‬تجزیه کننده در هر مرحله از یک نماد صرف نظر نموده تا زمانی که‬
‫یکی از مجموعه ها نشانه های تعیین شده جهت هماهنگی ‪،‬یافت شود ‪.‬نشانه های هماهنگ کننده‬
‫‪،‬معموال خاتمه دهنده ها هستند مانند سمیکالن یا ‪ end‬که نقش آنها در برنامه مبدا واضح است ‪.‬‬
‫‪ .2‬با یافتن خطا ‪،‬تجزیه کننده ممکن است در باقیمانده ورودی تصحیح موضعی انجام دهد ‪،‬به این‬
‫معنی که ممکن است پیشوندی از باقیمانده‌ی ورودی را جایگزین رشته ای نماید که امکان ادامه کار‬
‫برای تجزیه کننده وجود داشته باشد ‪.‬یک تصحیح موضعی معمول ‪،‬قرار دادن سمیکالن به جای کاما‬
‫‪،‬حذف سمیکالن اضافی یا قرار دادن سمیکالن حذف شده می باشد ‪.‬‬
‫‪5‬‬
‫ادامه‪....‬‬
‫ً‬
‫‪ .3‬اگر ایده ی مناسبی در رابطه با خطاهایی وجود داشته باشد که عمدتا ممکن است‬
‫تشخیص داده شوند ‪،‬می توان به گرامر زبان مورد نظر ‪،‬مولد هایی را اضافه نمود که‬
‫ساختار های مولد خطا را تولید نمایند ‪.‬سپس از گرامری که این مولد های خطا به آن‬
‫اضافه شده ‪،‬برای تولید تجزیه کننده استفاده می شود ‪.‬‬
‫در‬
‫‪ .4‬در حالت ایده آل تمایل بر این است که کامپایلر تا حد امکان تغییرات کمی را ‌‬
‫پردازش ورودی های ناصحیح انجام دهد ‪.‬الگوریتم هایی به منظور انتخاب دنباله ای از‬
‫حداقل تغییرات انجام شده وجود دارند به شکلی که حداقل هزینه اصالحات سراسری‬
‫حاصل شود ‪.‬با دادن رشته ورودی ناصحیح ‪ x‬و گرامر ‪، G‬این الگوریتم ها درحت تجزیه‬
‫ای برای رشته مرتبط ‪ y‬تشکیل می دهند به گونه ای که تعداد درج کردن ها ‪،‬حذف ها‬
‫‪،‬و تغییرات الزم در نشانه ها به منظور تبدیل ‪ x‬به ‪ y‬حداقل ممکن باشد ‪.‬‬
‫‪6‬‬
‫گرامر های مستقل از متن‬
‫ً‬
‫بسیاری از ساختار های زبان برنامه نویس ی ذاتا بازگشتی هستند که توسط گرامر های مستقل از متن‬
‫تعریف می شوند ‪.‬‬
‫برای مثال یک حکم شرطی با استفاده از قانون زیر تعریف می شود ‪:‬‬
‫" ‪“if E then S1 else S2‬‬
‫این شکل از حکم شرطی نمی تواند با استفاده از عبارت های باقاعده تعریف شود ‪.‬دیدیم که عبارت‬
‫های با قاعده قادر به مشخص نمودن ساختار لغوی نشانه ها می باشند ‪.‬‬
‫می توان عبارت باال را با استفاده از مولد گرامر زیر به راحتی نتیجه گرفت ‪:‬‬
‫‪stmt→if expr then stmt else stmt‬‬
‫‪ Stmt‬برای مشخص نمودن رده ی احکام و ‪ expr‬برای رده ی عبارت ها می باشد ‪.‬‬
‫می دانیم که یک گرامر مستقل از متن شامل پایانه ها ‪،‬غیر پایانه ها ‪،‬یک نماد شروع و مولد ها می‬
‫باشد ‪.‬‬
‫در مثال باال هر یک از کلمات کلیدی ‪، else، then، if‬پایانه می باشند ‪.‬‬
‫غیر پایانه ها متغیر های نحوی هستند که مجموعه ای از رشته ها را مشخص می کنند ‪.‬در مثال باال‬
‫‪ stmt‬و ‪ expr‬هر دو غیر پایانه ها هستند ‪.‬‬
‫‪7‬‬
‫گرامری با مولد های زیر ‪،‬عبارت های محاسباتی ساده را تعریف می کند ‪.‬‬
‫‪expr→expr op expr‬‬
‫)‪expr→(expr‬‬
‫‪expr→-expr‬‬
‫‪expr→id‬‬
‫‪op→+‬‬
‫→‪op‬‬‫*→‪op‬‬
‫‪op→/‬‬
‫↑→‪op‬‬
‫خالصه نویس ی گرامر باال‪:‬‬
‫‪E→E A E│(E) │-E │id‬‬
‫↑│ ‪A→+ │- │* │/‬‬
‫‪8‬‬
‫قرار داد های نشانه گذاری‬
‫‪9‬‬
‫‪ -1‬این نماد ها پایانه ها هستند ‪:‬‬
‫الف) حروف کوچک ابتدای حروف الفبا مانند ‪ b، a‬و ‪. c‬‬
‫ب) نماد های عملگر مانند ‪ - ، +‬و غیره ‪.‬‬
‫پ) نمادهای نقطه گذاری مانند پرانتز ‪،‬کاما و غیره ‪.‬‬
‫ت) ارقام ‪ 0‬و ‪ 1‬و‪....‬و‪. 9‬‬
‫ث) رشته های پررنگ شده مانند ‪. id‬‬
‫‪ -2‬این نمادها غیر پایانه هستند ‪:‬‬
‫الف) حروف بزرگ ابتدای حروف الفبا مانند ‪ A‬و ‪. B‬‬
‫ب)حروف ‪ S‬که در صورت ظاهر شدن معموال نماد شروع است ‪.‬‬
‫ت)اسامی حروف کوچک ایتالیک مانند ‪ expr‬یا ‪. stmt‬‬
‫‪ -3‬حروف بزرگ آخر حروف الفبا مانند ‪ Y، X‬و ‪ Z‬نشان دهنده ی نمادهای گرامر می باشند ‪.‬به این‬
‫معنی که می توانند پایانه یا غیر پایانه باشند ‪.‬‬
‫‪ -4‬حروف کوچک آخر حروف الفبا ‪ u، v،...، z‬نمایش دهنده ی رشته هایی از پایانه ها هستند ‪.‬‬
‫‪ -5‬حروف کوچک یونانی ‪،‬برای مثال ‪β،α‬و ‪ γ‬رشته هایی از نماد های گرامر را نشان می دهند ‪.‬‬
‫‪ -6‬اگر ‪ A→β، A→α‬و‪ ...‬همه مولد هایی باشند که سمت چپ آنها ‪ A‬است ‪،‬می توانیم بنویسیم ‪:‬‬
‫…│‪A→α│β‬‬
‫‪ -7‬سمت چپ اولین مولد‪،‬نماد شروع قرار دارد‪،‬در غیر اینصورت باید توضیح داده شده باشد ‪.‬‬
‫اشتقاق ها‬
‫روش های متعددی به منظور مشاهده فرآیندی که گرامر زبانی را تعریف می کند وجود دارد ‪.‬‬
‫در حقیقت ‪،‬این دیدگاه اشتقاقی ‪،‬توصیف دقیقی از ساخت درخت تجزیه به صورت باال به پایین را فراهم می‬
‫نمایند ‪.‬‬
‫ایده‌ی اصلی در اینجا این است که یک مولد به عنوان قانونی برای نوشتن مجدد استفاده می شود که در آن‬
‫‪،‬غیرپایانه‌ی سمت چپ با رشته سمت راست آن مولد جایگزین می شود ‪.‬‬
‫برای مثال در گرامر زیر ‪:‬‬
‫‪E→E + E│ E * E│(E) │-E │id‬‬
‫‪ E=>-E‬خوانده می شود ”‪ -E‬از ‪ E‬مشتق می شود ‪“.‬‬
‫)‪E*E=>E*(E‬‬
‫‪E*E=>(E)*E‬‬
‫)‪E=>-E=> -(E) =>-(id‬‬
‫‪10‬‬
‫به منظور ”مشتق شدن در صفر یا چند مرحله“می باشد ‪.‬‬
‫نماد‬
‫به معنی ”مشتق در یک یا چند مرحله“می باشد ‪.‬‬
‫به طور مشابه‬
‫رشته )‪ –(id+id‬جمله ای از گرامر زیر است ‪:‬‬
‫‪E→E A E│(E) │-E │id‬‬
‫↑│ ‪A→+ │- │* │/‬‬
‫زیرا یک اشتقاق وجود دارد به صورت ‪:‬‬
‫)‪E=>-E=> -(E) =>-(E+E) =>-(id+E)=> -(id+id‬‬
‫تنها نیاز به اشتقاق هایی است که فقط سمت چپ ترین غیر پایانه در هر شبه‬
‫جمله و در هر مرحله ‪،‬جایگزین می شود ‪.‬این اشتقاق ها سمت چپ ترین نامیده‬
‫می شوند ‪.‬اگر ‪ => βα‬در یک مرحله انجام شود که در آن ‪،‬سمت چپ ترین‬
‫غیر پایانه در ‪ α‬جایگزین گردد ‪،‬می نویسیم‬
‫‪.‬و از آنجایی که اشتقاق )‪ –(id+id‬سمت چپ ترین است ‪،‬می توان نوشت‬
‫‪βα‬‬
‫‪:‬‬
‫)‪-(id+id‬‬
‫)‪-(id+E‬‬
‫)‪-(E+E‬‬
‫)‪-(E‬‬
‫‪-E‬‬
‫‪E‬‬
‫تعاریف مشابه برای سمت راست ترین اشتقاق وجود دارد که در آن سمت راست‬
‫ترین غیر پایانه در هر مرحله جایگزین می شود ‪.‬سمت راست ترین اشتقاق ها‬
‫گاهی اشتقاق های متعارفی نامیده می شوند ‪.‬‬
‫‪11‬‬
‫درخت های تجزیه و اشتقاق ها‬
‫هر گره ی داخلی از یک درخت تجزیه با یک غیر پایانه مانند ‪ A‬در آن اشتقاق برچسب زده شده است‬
‫‪،‬و اینکه فرزندان این گره از چپ به راست با نمادهای سمت راست مولدی که توسط آن ‪،‬غیر پایانه‬
‫‪ A‬جایگزین شده ‪،‬برچسب زده شده اند ‪.‬برگ های این درخت تجزیه با غیر پایانه ها یا پایانه ها‬
‫برچسب زده شده اند و از چپ به راست خوانده می شوند ‪.‬این برگ ها مجموعا یک شبه جمله را‬
‫تشکیل می دهند ‪.‬‬
‫درخت تجزیه برای )‪ –(id+id‬در زیر آمده است ‪:‬‬
‫‪12‬‬
‫ساختن درخت تجزیه از اشتقاق‬
‫‪13‬‬
‫دو درخت تجزیه برای ‪id+id*id‬‬
‫‪14‬‬
‫ابهام‬
‫گرامری که بیش از یک درخت تجزیه برای یک جمله تولید می کند مبهم نامیده می شود ‪.‬‬
‫به بیان دیگر‪،‬گرامر مبهم ‪،‬گرامری است که بیش از یک سمت چپ ترین یا بیش از یک سمت راست ترین‬
‫اشتقاق را برای یک جمله تولید نماید ‪.‬‬
‫برای انواع خاص تجزیه کننده ها ‪،‬مطلوب است که گرامر رفع ابهام شده باشد ‪،‬زیرا اگر چنین نباشد‬
‫ً‬
‫‪،‬نمی توان منحصرا تعیین نمود کدام درخت تجزیه برای یک جمله انتخاب شود ‪.‬‬
‫نوشتن گرامر ها‬
‫‪15‬‬
‫محدودیت های خاص بر روی ورودی مانند لزوم اعالن شناسه ها قبل از استفاده ‪،‬توسط گرامر مستقل‬
‫از متن قابل توصیف نمی باشند ‪.‬بنابراین دنباله ای از نشانه ها که مجموعه ای فراتر از زبان برنامه‬
‫نویس ی هستند ‪،‬توسط تجزیه کننده پذیرفته می شوند ‪.‬‬
‫فاز های بعدی باید خروجی تجزیه کننده را تحلیل نموده تا از انجام عمل کامپایل بر اساس قوانینی که‬
‫توسط تجزیه کننده بررس ی نشده اند ‪،‬مطمین شوند ‪.‬‬
‫هر روش تجزیه قادر به اداره نمودن گرامرهایی با شکل خاص می باشد‪ ،‬بنابراین گرامر اولیه ممکن است‬
‫بازنویس ی شود تا توسط روش انتخاب شده قابل تجزیه باشد‪ .‬گرامر های مناسب برای عبارت ها می‬
‫توانند با استفاده از اطالعات شرکت پذیری و اولویت ایجاد شوند‪ .‬در این بخش‪ ،‬تبدیالتی مورد توجه‬
‫قرار می گیرد که برای بازنویس ی گرامرها مفید بوده و آنها را برای انجام تجزیه باال به پایین مناسب می‬
‫سازند ‪.‬‬
‫عبارت های باقاعده در مقابل گرامر های مستقل از متن‬
‫هر ساختاری که توسط عبارت با قاعده قابل توصیف است ‪،‬گرامر نیز می تواند آن را توصیف‬
‫کند ‪.‬‬
‫اگر عبارت با قاعده ‪ (a│b)*abb‬باشد آنگاه گرامر آن برابر است با ‪:‬‬
‫‪A0 →aA0│bA0 │aA1‬‬
‫‪A1→bA2‬‬
‫‪A2→bA3‬‬
‫‪A3→λ‬‬
‫می توان به طور مکانیکی یک ماشین خودکار محدود غیر قطعی )‪ (NFA‬را به‬
‫گرامری تبدیل نمود که همان زبان تشخیص داده شده توسط ‪ NFA‬را تولید نماید ‪.‬‬
‫‪16‬‬
‫بازبینی زبان تولید شده توسط گرامر‬
‫اثبات اینکه گرامری مانند ‪، G‬زبان ‪ L‬را تولید می کند ‪،‬دارای دو بخش است ‪:‬باید نشان دهید‬
‫که هر رشته ی تولید شده توسط ‪ G‬در ‪ L‬وجود دارد و برعکس هر رشته ‪ L‬توسط ‪ G‬تولید‬
‫می شود ‪.‬‬
‫رفع ابهام‬
‫گاهی امکان بازنویس ی مجدد گرامر مبهم به منظور رفع ابهام آن وجود دارد ‪.‬‬
‫به عنوان مثال ‪،‬می توان ابهام را از گرامر ”‪ else‬معلق“زیر حذف نمود ‪:‬‬
‫‪Stmt→if expr then stmt‬‬
‫‪│ if expr then stmt else stmt‬‬
‫‪│other‬‬
‫در اینجا ”‪ ” other‬به جای هر حکم دیگر قرار می گیرد ‪.‬بر طبق گرامر ‪،‬حکم شرطی ترکیبی‬
‫‪if E1 then S1 else if E2 then S2 else S3‬‬
‫دارای درخت تجزیه نشان داده شده در شکل زیر می باشد ‪:‬‬
‫‪17‬‬
‫گرامر صفحه قبل مبهم است زیرا رشته ی زیر دارای دو درخت است ‪:‬‬
‫‪if E1 then if E2 then S1 else S2‬‬
‫‪18‬‬
‫در تمام زبانهای برنامهسازی با احکام شرطی از این نوع‪ ،‬اولین درخت تجزیه ترجیح داده میشود‬
‫‪.‬قانون عمومی این است که هر ‪ else‬متعق به نزدیکترین ‪ then‬فاقد ‪ else‬است ‪.‬این قانون‬
‫رفع ابهام می تواند مستقیما در گرامر منظور گردد ‪.‬‬
‫برای مثال گرامر صفحه ی قبل را می توان به صورت یک گرامر غیر مبهم ‪،‬مشابه زیر نوشت ‪.‬‬
‫‪Stmt→matched_stmt‬‬
‫‪│unmatched _stmt‬‬
‫‪matched_stmt→if expr then matched_stmt else matched_stmt‬‬
‫‪│other‬‬
‫‪unmatched_stmt→if expr then stmt‬‬
‫‪│if expr then matched_stmt else unmatched_stmt‬‬
‫‪19‬‬