دقت در جمله‌بندی‌ صحیح‌

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

 تحلیل لغوی یا lexical analyze توسط بخشی به نام اسکنر(Scanner)  و تحلیل نحوی یا  Syntatic analyzeتوسط بخشی به نام پارسر (Parser) انجام می‌شود.

تحلیل نحوی

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

تقسیم‌بندی به دو بخش لغوی و نحوی، یک مساله اختیاری است. معمولا آن نوع تقسیم‌بندی انتخاب می‌شود که تمامی اعمال تحلیل را آسان کند. یک عامل در تعیین این تقسیم‌بندی آن است که آیا ساختار زبان مبدا ذاتا بازگشتی است یا خیر؟ ساختارهای لغوی نیازی به بازگشتی بودن ندارند در حالی که ساختارهای نحوی اغلب به آن نیاز دارند. به عنوان مثال برای تشخیص شناسه‌ها که به طور معمول رشته‌ای از حروف و ارقام هستند و با یک حرف شروع می‌شوند، نیازی به خاصیت بازگشتی نیست. به طور معمول شناسه‌ها با یک پویش ساده رشته ورودی تشخیص داده می‌شوند. به منظور تشخیص یک نشانه (Token) از نوع شناسه (identifier) باید منتظر دریافت کاراکتری بجز حرف و رقم بود. سپس باید تمام کاراکترهای یافت شده تا آن مکان را گروه‌بندی کرد. کاراکترهایی که به این ترتیب گروه‌بندی شده‌اند، در یک جدول به نام جدول نماد ثبت می‌شوند و سپس از ورودی حذف شده، به نحوی که پردازش نشانه بعدی بتواند آغاز شود.

گرامر

هر زبان برنامه‌سازی قوانینی دارد که ساختار برنامه‌هایی با شکل مناسب را توصیف می‌کنند. به عنوان مثال، در پاسکال، هر برنامه از بلوک‌ها، هر بلوک از دستورات، هر دستور از عبارت‌‌ها، هر عبارت از نشانه‌ها و هر نشانه از کاراکترها تشکیل شده است. ویژگی نحوی ساختارهای برنامه‌سازی با استفاده از یک گرامر یا روش نشان‌گذاری توصیف می‌شود.

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

گرامری که بدرستی طراحی شده باشد، ساختاری را به زبان برنامه‌سازی می‌دهد که برای ترجمه برنامه‌های مبدا، به کد مقصد صحیح و آشکارسازی خطاها مناسب باشد.

زبان‌هایی که بتدریج در یک دوره‌ای از زمان رشد یافته‌اند، ساختارهای جدیدی دارند و کارهای اضافه‌ای را انجام می‌دهند. اگر یک پیاده‌سازی برای زبان، براساس توصیف گرامری آن وجود داشته باشد، این ساختارهای جدید، آسان‌تر به زبان اضافه می‌شوند.

تجزیه‌کننده

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

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

اعلام خطا

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

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

در عبارت‌های محاسباتی برای الویت دادن به محاسبات از پرانتز استفاده می‌شود. مثلا نتیجه دو عبارت ‌(2+85x( و‌2+(5(8x از نظر ریاضی متفاوت خواهد بود. معمولا در عبارات پیچیده تودرتو ممکن است تعداد پرانتزها آن‌قدر زیاد شود که برنامه‌نویس در تعداد آنها اشتباه کند. در صورتی که پرانتزها نامتعادل باشند (تعداد پرانتزهای باز و بسته یکی نباشد)‌ این خطا در مرحله تحلیل نحوی به کاربر اعلام می‌شود.

برخی خطاها نیز ممکن است در مرحله تحلیل معنایی که بعد از تحلیل نحوی توسط کامپایلر انجام می‌شود، اعلام ‌شود. به عنوان مثال فرض کنید یک دستور به شکل زیر داشته باشیم:

2+var1sum= var

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

اما اگر‌ 1 var و  2 var از نوع اعشاری و sum  از نوع عدد صحیح باشد یا یکی از سه متغیر یاد شده از نوع رشته‌ای و بقیه از نوع عددی باشند آن‌گاه به علت این ناسازگاری خطایی در مرحله تحلیل معنایی از سوی کامپایلر اعلام خواهد شد.

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

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

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

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

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

نیازمندی ها