تلاش رایانه برای درک برنامه‌

هفته گذشته در مورد کامپایلرها و مراحل تولید برنامه با استفاده از آنها صحبت‌هایی داشتیم. گفتیم که کامپایل از دو بخش تحلیل و سنتز تشکیل شده است. در ادامه قصد داریم کمی دقیق‌تر به اولین بخش مرحله تحلیل یعنی تحلیل لغوی بپردازیم.
کد خبر: ۲۰۵۹۴۹

تحلیل لغوی‌

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

کامپایلر در این فاز از ابتدا شروع به خواندن می‌کند و پس از رسیدن به هر کاراکتر توجه می‌کند که آیا آن یک کاراکتر حرفی، عددی علامت، فاصله و  ... است. معمولا کامپایلر بعد از رسیدن به یک کاراکتر فاصله، آن‌قدر جلو می‌رود تا به یک کاراکتر از نوع دیگر برسد. بنابراین در طول برنامه می‌توانید به تعداد دلخواه tab ,space  یا enter  بزنید. (البته واضح است که در رشته‌های کاراکتری، space ‌ها معنی خواهند داشت)‌. پس از آخرین کاراکتر فاصله بعد از رسیدن به یک کاراکتر حرفی، کامپایلر کاراکتر بعدی را نگاه می‌کند. اگر آن نیز حرفی یا عددی باشد آن را به کاراکتر قبلی می‌چسباند و در غیر این‌ صورت فرض می‌کند یک نشانه یا token  را شناخته است. مثلا while ، 123 Ali یا sum  نمونه‌هایی از یک نشانه هستند که در فاز تحلیل لغوی شناسایی می‌شوند. در مراحل بعد از تحلیل لغوی ممکن است هر کدام از این نشانه‌ها در مفهوم خاصی به کار روند. مثلا while کلمه کلیدی،123 Ali متغیر و Sum مثلا نام یک تابع باشد.

کاراکتر عددی‌

بعد از یک یا چند کاراکتر فاصله اگر کامپایلر به یک کاراکتر عددی رسید تا زمانی که کاراکترهای بعد نیز عددی باشند پیش می‌رود. در صورتی که به کاراکتر فاصله یا علامت برسد. آن‌گاه کل ارقام را به عنوان یک نشانه در نظر خواهد گرفت. مثلا 31249 به عنوان یک عدد خواهد بود. اما اگر بعد از این عدد بلافاصله یک کاراکتر حرفی آمده باشد با این که این کاراکتر نیز در نشانه حاصل ثبت می‌شود، اما چون این نشانه در زبان مفهومی ندارد، اینجاست که تحلیلگر لغوی یک خطا اعلام می‌کند. مثلا 123ab منجر به اعلام خطا در کامپایلر خواهد شد. یعنی برنامه‌نویس باید ab  را حذف کند یا بین ab  و 123 یک علامت یا فاصله قرار دهد. به هر ترتیب اگر این نشانه تغییر نکند کامپایلر دلیل کافی خواهد داشت که برنامه نهایی را تولید نکند! زیرا همان‌طور که قبلا گفتیم، وجود یک خطا کافی است تا برنامه اجرایی نهایی توسط کامپایلر تولید نشود.

کاراکتر علامت‌

حال فرض کنیم بعد از یک کاراکتر حرفی، عددی یا فاصله، کامپایلر به یک کاراکتر علامتی رسیده است. اگر آن علامت از علائم تعریف‌نشده آن زبان باشد، کامپایلر بلافاصله وجود یک خطا را اعلام می‌کند. اما اگر آن کاراکتر در آن زبان معتبر باشد، به کاراکتر بعد نگاه می‌کند، وجود یا عدم وجود خطا در آن صورت به کاراکتر یا کاراکترهای بعد از آن علامت بستگی دارد. به عنوان مثال در زبان دلفی، َ و> دو کاراکتر علامتی معتبرند. اما وجود خطا به کاراکتر بعدی وابسته است. مثلا اگر بعد ازَ یک علامت دیگر آمده باشد در مجموع یک ترکیب نامعتبر رخ داده است و منجر به اعلام خطا خواهد. اما بعد از کاراکتری مثل > باید توجه کرد که علامتی مثل = یا > می‌تواند بیاید و ترکیب حاصل => یا ><‌ خواهد بود که هر دو در دلفی با معنی هستند. در این صورت خطایی اعلام نمی‌شود اما اگر ترکیبی مثل‌
!<آمده باشد، منجر به اعلام خطا خواهد شد. ضمن این‌که اگر بعد از =< یا  >< علامت دیگری بیاید باز هم منجر به اعلام خطا خواهد شد. زیرا در دلفی سه کاراکتر علامت (به جز در رشته‌ها)‌ نمی‌توانند پشت سر هم بیایند.

تحلیلگر لغوی تنها قادر به اعلام خطاهایی از این دسته‌است و سایر خطاها توسط این بخش از کامپایلر قابل تشخیص نیست به عنوان یک مثال در متن یک برنامه، فرض کنیم که عبارتی همچون عبارت زیر داشته باشیم ;1000grams:=kilograms*
نشانه‌ها یاtoken هایی که در تحلیلگر لغوی کامپایلر تشخیص داده می‌شود به این ترتیب خواهد بود:

Grams به عنوان یک شناسه‌
=: نماد انتساب‌
Kilograms  به عنوان یک شناسه‌
*‌ علامت ضرب‌
1000 به عنوان یک عدد
;  پایان دهنده دستور

تجزیه کننده‌

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

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

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

تولید خطا

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

در مورد نحوه کار اولین بخش کامپایلر صحبت کردیم. در آینده در مورد دیگر قسمت‌های یک کامپایلر به تفصیل سخن خواهیم گفت.

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

newsQrCode
ارسال نظرات در انتظار بررسی: ۰ انتشار یافته: ۰

نیازمندی ها