430 likes | 725 Views
به نام خدا. طراحی کامپایلرها 414-40. 4. مشکلات تحلیل نحوی بالا به پایین. چپگردی در گرامر مستقل از متن، میتواند تحلیلگر نحوی را در حلقهی نامتناهی بیاندازد مثلاً برای قاعدهی A → A α رویهی زیر را داریم: راه حل: حذف چپگردی البته بدون این که زبان متناظر گرامر تغییر کند. procedure A
E N D
به نام خدا طراحی کامپایلرها 414-40 4
مشکلات تحلیل نحوی بالا به پایین • چپگردی در گرامر مستقل از متن، میتواند تحلیلگر نحوی را در حلقهی نامتناهی بیاندازد • مثلاً برای قاعدهی A → A α رویهی زیر را داریم: • راه حل: حذف چپگردی • البته بدون این که زبان متناظر گرامر تغییر کند procedureA begin if lookahead is in First(Aα)then call procedure A end 1
مواجهه با چپگردی • الگوریتمی برای حذف چپگردی • ایدهی اولیه: • مثال: 2
حل مشکلات: چپگردی (1) • گرامر دارای چپگردی، قاعدهای دارد که به کمک آن اشتقاقی مثل A →* A α برای بعضی α ها قابل انجام است • تحلیل نحوی بالا به پایین نمیتواند با چنین گرامرهایی کنار بیاید، زیرا باید تصمیم ثابتی بگیرد که نتیجتاً باعث خاتمهنیافتن آن خواهد شد • به صورت کلی: … A A α A αα A ααα گرامر دارای چپگردی گرامر بدون چپگردی 3
حل مشکلات: چپگردی (2) • به شکل غیررسمی: • همهی قواعد مربوط به A را در نظر بگیرید و به این شکل مرتب کنید (به طوری که هیچ βi با A آغاز نشود): • حالا روشی را که پیشتر گفته شد روی آنها اعمال کنید: • با این حساب، در مثال ما: 4
حل مشکلات: چپگردی (3) • مشکل: اگر چپگردی دو یا چند مرحله عمق داشته باشد، روش گفتهشده کافی نیست S A a S d a ورودی: گرامر G که غیرپایانههای آن به صورت A1, A2, … , An مرتب شدهاند خروجی: گرامر معادلی که چپگردی ندارد 1ـ غیرپایانهها را به شکل A1, A2, …, An مرتب کنید (که A1 نماد شروع است) 2ـ برای i از 1 تا n شروع برای j از 1 تا i - 1 شروع هر قاعده به شکل Ai → Ajγ را با قاعدهای به شکل Ai → δ1γ | δ2γ | … | δkγ به طوری که Aj → δ1 | δ2 | … | δk قاعدههای فعلی مربوط به Aj هستند، جایگزین کنید پایان چپگردی مستقیم را از همهی قاعدههای مربوط به Ai حذف کنید پایان 5
حل مشکلات: چپگردی (4) • استفاده از الگوریتم در مثال: در مورد A1 هیچ چپگردیای وجود ندارد i = 1 برای j از 1 تا 1 قاعدههای به شکل A2 → A1γ را با قاعدههایی به شکل A2 → δ1γ | δ2γ | … | δkγ به طوری که A1 → δ1 | δ2 | … | δk قاعدههای فعلی مربوط به A1 هستند، جایگزین میکنیم بنابراین در مثال، A2 → A1 d به A2 → A2 a d | b d | d تبدیل میشود i = 2 آنچه باقی میماند: آیا کار تمام شده است؟ 6
حل مشکلات: چپگردی (5) • نه، کار تمام نشده. هنوز باید چپگردی را حذف کنیم: • باید این قاعده را که پیشتر گفته شد، اعمال کنیم: 7
حل مشکلات: فاکتورگیری چپ • مشکل: کدامیک از دو قاعدهی زیر باید انتخاب شود؟ • حالت کلی چنین مشکلی: α if expr then stmt rest تبدیل میشود به β1 else stmt در مثال ما ε β2 8
تحلیل نحوی مبتنی بر جدول • (1) پویش (تحلیل لغوی) چپ به راست • (2) یافتن اشتقاق چپگرد • گرامر: • ورودی: • اشتقاق: • انباره (پشته) پردازش خاتمهدهنده id + id $ E 9
گرامرهای LL(1) • L: پویش ورودی از چپ به راست • L: ساخت اشتقاقچپگرد • 1: برای تصمیمگیری در تحلیل نحوی، علاوه بر انباره، تنها به «یک» نشانهی پیش رو از ورودی نگاه میکند • در جدول تحلیل گرامرهایLL(1)، در هیچ خانهای 2 قاعده به چشم نمیخورد • ویژگیهایگرامرهایLL(1): • مبهم نیستند و چپگردی ندارند • برای قاعدههایی به شکل A → α | β: • هیچ دو رشته از رشتههایی که از α و β مشتق میشوند، نباید با نماد یکسان (مثلاً a) شروع شوند. به عبارت دیگر اشتراک First(α) و First(β) باید تهی باشد. • ε حداکثر از یکی از α یا β ممکن است مشتق شود • اگر ε از αمشتق می شود، آنگاه اشتراک First(β) و Follow(A) باید تهی باشد. • همهیگرامرها را نمیتوان به شکل LL(1) تبدیل کرد 10
روش غیربازگشتی و مبتنی بر جدول b ورودی (رشتهی اصلی + خاتمهدهنده) a + $ • رفتار کلی تحلیلگر با توجه به: (ورودی فعلی)، و (بالای انباره) • وقتی X = a = $، کار پایان مییابد، و رشتهی ورودی پذیرفته میشود • وقتی X = a≠ $، X را از روی انباره برمیداریم، نشانهی بعدی را از ورودی میگیریم و به قدم (1) برمیگردیم • وقتی X یک غیرپایانه باشد، خانهی M[X,a] در جدول بررسی میشود: • اگر خطا بود، رویهی برخورد با خطا فراخوانی میشود • اگر قاعدهای به شکل X → U V W بود، X را از روی انباره برمیداریم و به ترتیب W، V و U را روی انباره قرار میدهیم (به ورودی کاری نداریم) انباره (غیرپایانهها و پایانههای گرامر) X تحلیلگر نحوی پیشگو خروجی Y Z $ مشخص میکند که با توجه به ورودی و انباره، تحلیلگر باید چه تصمیمی بگیرد جدول تحلیل M[A,a] نشانهی انتهای انباره X a 11
تحلیل نحوی غیربازگشتی (1) • مثال: جدول M 13
تحلیل نحوی غیربازگشتی (2) • مثال روند تحلیل نحوی: گسترش ورودی 14
تحلیل نحوی غیربازگشتی (3) • اشتقاق چپگرد مثال قبلی: id + T E’ id T’ E’ E T E’ F T’ E’ id E’ id + F T’ E’ id + id T’ E’ id + id * F T’ E’ id + id * id id + id * id T’ E’ id + id * id E’ 15
چه چیزی کم داریم؟ • جدول تحلیل M هنوز ساخته نشده است! • یک ـ مجموعههایFirst و Follow را برای گرامر به دست آورید. • دو ـ الگوریتم زیر را جهت ساخت جدول تحلیل اعمال کنید: • 1ـ قدمهای (2) و (3) را به ازای هر قاعده به شکل A → α تکرار میکنیم: • 2ـ اگر پایانهیaدر First(α) باشد، A → α را در خانهیM[A, a]میگذاریم • 3ـ اگر ε عضو First(α) باشد، A → α را در تمام خانههایM[A, b] • میگذاریم که bعضو Follow(A) است • 4ـ همهیخانههایباقیماندهی جدول که خالیاند، معرّفخطای نحوی هستند. 16
ساخت جدول تحلیل (2) • مثال 1: First(S) = Follow(S) = { i, a } { e, $ } First(S’) = Follow(S’) = { e, ε} { e, $ } First(E) = Follow(E) = { b } { t } S → a S → i E t S S’ E → b { a } { i } First(a) = First(i E t S S’) = { b } First(b) = S’ → e S S’ → ε { e } First(e S) = { ε} { e, $ } First(ε) = Follow(S’) = 18
ساخت جدول تحلیل (3) • مثال 2: First(E, F, T) = Follow(E, E’) = { (, id } { ), $ } First(E’) = Follow(F) = { +, ε} { *, +, ), $ } First(T’) = Follow(T, T’) = { *, ε} { +, ), $ } E→ + T E’ E → T E’ E → b { +} { (, id } First(+ T E’) = First(T E’) = First(T) = { b } First(b) = E’ → ε T’ → ε { ε} First(ε) = { ε} First(ε) = با توجه به قدم (2) در الگوریتم با توجه به قدم (3) در الگوریتم 19
حل مشکلات: گرامرهای مبهم (1) • این گرامر را در نظر بگیرید: • مشکل چیست؟ • یک درخت تحلیل ساده: stmt else expr if then stmt stmt E1 else expr if then stmt S1 stmt else باید به then قبلی مربوط شود E2 S2 S3 20
حل مشکلات: گرامرهای مبهم (2) • درختهای تحلیل مثال: • شکل 1: • شکل 2: • اینجا چه مشکلی وجود دارد؟ stmt expr if then stmt E1 else expr if then stmt stmt E2 S1 S2 stmt expr stmt if then stmt else E1 expr if then stmt S2 E2 S1 21
حذف ابهام (1) • اگر این گرامر را در نظر بگیریم: • یا اگر بخواهیم سادهتر بگوییم: • رشتهای که مشکل ایجاد میکند: i a t i a t s e s 22
حذف ابهام (2) • گرامر را اصلاح میکنیم تا ابهام حذف شود: • گرامر اصلاحشده را روی میآزماییم • گرامر اصلاحشده به صورت خواناتر: i a t i a t s e s 23
پردازش خطا • شناسایی خطاها • پیداکردن جایی که خطا در آن رخ داده است (مثلاً خطی از کد) • اطلاعرسانی دقیق و روشن • مواجهه با (یا عبور از) خطا برای ادامهی کار و یافتن خطاهای احتمالی آینده • در کامپایل برنامههای صحیح نباید تغییری ایجاد شود 24
راهبردهای مواجهه با خطا (1) • حالت ترس (Panic Mode): دور انداختن نشانهها تا جایی که به یک نشانهی «همگامسازی» (Synchronizing) بربخوریم • نشانههایهمگامسازی مثل: «end» و «;» و «}» در زبانهایبرنامهسازی • بسته به تصمیم طراح کامپایلر • کاستیها: • دور انداختن ورودی باعث عدم تعریف صحیح (مثلاً تعریف متغیرها) و به این ترتیب ایجاد خطاهای بیشترمیشود • خطاهای احتمالی در بخشی که دور انداختهایم شناسایی نمیشوند • مزایا: • سادگی (به ویژه برای حالتی که در هر عبارت «یک» خطا وجود دارد مناسب است) • سطح عبارت (Phrase Level): تصحیح محلی ورودی • مثلاً در برخورد با «,» به جای «;»، «,» حذف و «;» اضافه میشود • بسته به تصمیم طراح کامپایلر • برای همهی خطاها مناسب نیست • می تواند به همراه حالت ترس استفاده میشود تا ورودی کمتری دور انداخته شود 25
راهبردهای مواجهه با خطا (2) • قواعد خطا (Error Productions) • افزودن قواعدی به گرامر • به منظور ساخت یا تولید تحلیلگر نحوی • مثلاً قاعدهای برای علامت := (انتساب در پاسکال) به گرامر زبان C میافزاییم • خطا گزارش داده میشود اما فرآیند کامپایل ادامه مییابد • تصحیح داخلی (گرامر) و پیامهای عیبیابی • تصحیح سراسری (Global Correction) • افزودن، حذف کردن، یا جایگزینی نشانهها نتیجهای نامشخص دارد و ممکن است به تغییرات زیادی منجر شود • الگوریتمهایی وجود دارند که میکوشند این تغییرات را در سطح برنامه به حداقل برسانند 26
اصلاح خطا • خطا در چه صورتی رخ میدهد؟ یادآوری تحلیلگر نحوی: • (1) در صورتی که X پایانه باشد و با ورودی انطباق نداشته باشد • (2) در صورتی که [ورودی X,]M خالی باشد • دو روش اصلاح: • حالت ترس • سطح عبارت b ورودی a + $ تحلیلگر نحوی پیشگو انباره X خروجی Y Z جدول تحلیل M[A,a] $ 27
اصلاح خطا: روش حالت ترس (1) • فرض کنید A یک غیرپایانه در بالای انباره باشد • ایده: ورودیها را دور بیاندازیم تا به یکی از نشانههایمجموعهی از پیشتعریفشدهیهمگامسازی برسیم • انتخاب اعضای مجموعهیهمگامسازی مهم است؛ مثلاً: • مجموعهیهمگامسازی را Follow(A) در نظر بگیریم و ورودیها را دور بیاندازیم تا به عضوی از این مجموعه برسیم. A را از بالای انباره برداریمو تحلیل نحوی را ادامه دهیم • مجموعهیهمگامسازی را First(A) در نظر بگیریم و ورودیها را دور بیاندازیم تا به عضوی از این مجموعه برسیم. تحلیل نحوی را از همینجا ادامه دهیم • ممکن است بتوان از قاعدههای منتهی به ε هم استفاده کرد • اگر پایانهای بالای انباره باشد که با ورودی نخواند، آن را از روی انباره برمیداریم و در پیغامی میگوییم که آن پایانه را اضافه کردهایم 28
اصلاح خطا: روش حالت ترس (2) • ایدهی کلی: خانههای خالی جدول تحلیل را تغییر دهیم • اگر خانهی M[A,a] خالی، و a عضو Follow(A) بود، M[A,a] را برابر “sync” (همگامسازی) قرار میدهیم • بنابراین اگر A عنصر بالای انباره، و a ورودی فعلی باشد: • اگر Aغیرپایانه، و M[A,a]خالی بود، a را از ورودی دور میاندازیم • اگر Aغیرپایانه، و M[A,a] برابر “sync”بود، A را از روی انباره برمیداریم • اگر Aپایانه، ولی نامساویa بود، A را از روی انباره برمیداریم (در واقع به این معنی است که آن را در ورودی اضافه کردهایم) 29
اصلاح خطا: روش حالت ترس (3) • مثال جدول تحلیل تغییریافته: همگامسازی (“sync”). بر اساس مجموعهی Follow. غیرپایانهی بالای انباره را برمیداریم ورودی را دور میاندازیم 30
اصلاح خطا: روش حالت ترس (4) • مثال روندتغییریافتهی تحلیل نحوی: پیغام خطای نمونه: «+ به اشتباه واردشده است، و دور انداخته میشود» پیغام خطای نمونه: «جمله (Term) پیدا نشد» 31
نوشتن پیغامهای خطا (1) • شمارندهای برای ورودی در نظر میگیریم • یادآوری: هر غیرپایانه، معرّف یک ساخت انتزاعی زبان است • مثالهایی از پیغامهای خطا برای گرامر ما: • اگر E معرّف «عبارت» باشد: • با فرض این که E روی انباره، و + ورودی فعلی است: «خطا در محل i: عبارت نمیتواند با ‘+’ آغاز شود» یا «خطا در محل i: عبارت نادرست است» • به طور مشابه برای E روی انباره، و * به عنوان ورودی فعلی • اگر E’ معرّف «انتهای عبارت» باشد: • با فرض این که E’ بالای انباره، و ورودی فعلی * یا id است: «خطا: عبارتی که در محل j شروع شده است، در محل i ظاهری نادرست دارد» • نکته: هر بار E را از روی انباره برمیداریم، محل فعلی را جایی ذخیره میکنیم 32
نوشتن پیغامهای خطا (2) • مثالهایی از پیغام خطا برای خانهی“sync” • فرض کنید F بالای انباره، و + ورودی فعلی است: • «خطا در محل i: بر خلاف انتظار، عملوند جمع یا ضرب پیدا نشد» • فرض کنید E بالای انباره، و ) ورودی فعلی است: • «خطا در محل i: بر خلاف انتظار، عبارتی پیدا نشد» 33
نوشتن پیغامهای خطا (3) • مثالهایی از حالتی که بالای انباره پایانهای است که با ورودی نمیخوانَد • فرض کنید id بالای انباره، و + ورودی فعلی است: • «خطا در محل i: بر خلاف انتظار، شناسهای پیدا نشد» • فرض کنید ) بالای انباره، و ورودی فعلی پایانهای غیر از ) است: • هر وقت به یک ( برخوردیم، محل آن را در «انبارهی ویژه پرانتز باز» ذخیره میکنیم • وقتی که حالت فوق اتفاق افتاد، به انبارهی پرانتز باز نگاه میکنیم تا محل آن پرانتز باز را که بسته نشده است ، بیابیم • «خطا در محل i: برای پرانتز بازی که در محل m واقع شده، هیچ پرانتز بستهای پیدا نشد» (مثلاً در صورتی که ورودی ( id * + ( id id ) $ باشد) 34
تجمیع پیغامهای خطا با جدول تحلیل • با توجه به آنچه گفته شد، خانههای خالی جدول تحلیل را میتوانیم با روش مناسب صدور پیغام خطا پر کنیم 35
اصلاح خطا: سطح عبارت (1) • خانههای خالی جدول تحلیل را با رویّههای مدیریت خطا پر میکنیم. این رویّهها نه تنها خطاها را گزارش میکنند، بلکه: • نمادهای روی انباره یا ورودی را تغییر میدهند یا درج / حذف میکنند • پیغام خطای مناسب را صادر میکنند • کاستیها: • هر گونه تغییر انباره باید با احتیاط انجام شود تا مطمئن شویم اشتقاقی که اصولاً در زبان ممکن نیست، توسط تحلیلگر نحوی انجام نمیشود • باید مراقب حلقههای نامتناهی بود • در واقع، حالت ترس را گسترش میدهیم تا مدیریت خطا به نحو کاملتری انجام شود 36
اصلاح خطا: سطح عبارت (2) • چهطور پیادهسازی کنیم؟ • به هر قاعده در خانههای پر جدول تحلیل، و همینطور به حالت “sync” و خانههای خالی، شمارهای یکتا اختصاص میدهیم 37
اصلاح خطا: سطح عبارت (3) 9 تا 17: همگامسازی (“sync”) 18 تا 25: مدیریت خطا 38
حل مشکلات گرامر • همهی ویژگیهای یک زبان برنامهسازی را نمیتوان با گرامرها (زبانها) ی مستقل از متن توصیف کرد، مثلاً: • تعریف یک شناسه (مثلاً نام متغیر) پیش از استفاده از آن در ادامهی برنامه • رعایت تجانس نوعها در عبارتها (مثلاً جمع عدد صحیح با عدد صحیح) • تطابق پارامترها در زمان تعریف تابع، با آرگومانها در زمان فراخوانی آن • این ویژگیها و نظایر آنها «حساس به متن» اند و دستهی دیگری از زبانها را معرفی میکنند: زبانهای حساس به متن 39
زبانهای حساس به متن • مثال: • تعریف شناسه پیش از استفاده • تطابق پارامترها (anbm) و آرگومانها (cndm) = L1 { w c w | w (a|b)* } = L2 {an bmcn dm | n ≥ 1, m ≥ 1 } 40
زبانهای مستقل از متن (1) • مثال: = L3 { w c wR | w (a|b)* } = L4 {an bmcm dn | n ≥ 1, m ≥ 1 } = L5 {an bncm dm | n ≥ 1, m ≥ 1 } = L6 {an bn | n ≥ 1 } 41
زبانهای مستقل از متن (2) • مثال (نمایش به کمک گرامر): = L3 { w c wR | w (a|b)* } = L4 {an bmcm dn | n ≥ 1, m ≥ 1 } = L5 {an bncm dm | n ≥ 1, m ≥ 1 } = L6 {an bn | n ≥ 1 } 42