کامپایلر تک‌گذره

**کامپایلر تک‌گذره** (one-pass compiler) کامپایلری است که بخش های کامپایل شونده را فقط یک بار می‌خواند که  در این خوانش فورا هر بخش از کد را به زبان ماشین ترجمه می‌کند. این نوع کامپایلر در مقابل کامپایلر های چندگذره قرار می‌گیرد. کامپایر های چندگذره قبل از تبدیل نهایی کد به زبان ماشین ، آن را به چند نمایش میانی تبدیل میکنند و در هر کدام از این تبدیل ها از همه بخش های کامپایل شونده استفاده می‌کنند.

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

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

## ویژگی‌ها
کامپایلر های تک‌گذره کوچکتر و سریعتر از کامپایلر های چندگذره هستند.

کامپایلر تک گذره به دلیل حوزه محدود اطلاعاتی که در اختیار دارد توانایی تولید کردن برنامه های کارا به مانند کامپایلر چندگذره را ندارد. بسیاری از بهینه‌سازی های کامپایلر نیازمند عبور چندباره از روی بلوک پایه،حلقه(به ویژه حلقه های تودرتو)،زیرروال و کل ماژول هستند حتی بعضی از این بهینه‌سازی ها نیازمند گذر از کل برنامه هستند. بعضی از زبان‌های برنامه نویسی به دلیل طراحی خاصشان امکان کامپایل شدن در یک گذر را ندارند. برای مثال PL/I امکان تعریف داده را در هرجای کد به برنامه نویس می‌دهد. بطور مشخص تر،می‌توان قبل از تعریف یک داده چند ارجاع به نام آن داد و سپس خود داده را تعریف کرد که به این سبب هیچ کد ماشینی تا قبل از پایان کامل اسکن نمی‌تواند تولید شود. همچنین تعریف زبان دارای عبارات پیش پردازشی است که به سورس کد توان کامپایل شدن می دهند.

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

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

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

### متن محلی
برای مثال، فرض کنید نماد >بجای بزرگتر از نشان دهنده کوچکتر از باشد. به دلیل محدودیت در کد کردن کاراکتر‌ها، ممکن است نماد => در یک سیستم کدگذار استاندارد وجود نداشته باشد; به همین دلیل به صورت نمایش ترکیبی مجار است. درست است که این نمایش به وسیله نماد بعدی تعیین می‌شود منتها وقتی که ما به نماد > برمی‌خوریم نمادهای بعدی ناشناخته هستند. بطور مشابه نماد = همیشه نشانگر برابری نیست مانند زمانی که در یک نماد پیچیده به کار برده می‌شوند. نماد‌های پیچیده دیگر ممکن است دربردارنده‌ی ".lt." باشند برای زمانی که نماد > ناشناخته است. با این وجود احتمال دیگر برای زمانی که نماد ¬("نفی") ناموجود باشد، استفاده از  بجای ¬= ("نابرابری") است(در بعضی از سیستم ها از ! یا ~ بجای ¬ در نسخه های بعد استفاده شد.). یک روش ادامه دادن اسکن بعد از مشاهده > و برخورد کردن با = است که نام این روش، روش پس‌گرد است. که این طبیعتا به این معناست که از آن قسمت از متن سورس‌کد دوبار رد خواهیم شد که کاری نهی‌شده است.

### متن داخل عبارت‌ها
زبانهایی که اصطلاحات حسابی را مجاز می دانند، معمولاً از نحو نماد گذاری پیوند با قوانین تقدم پیروی می کنند. این بدان معناست که تولید کد برای ارزیابی عبارت به راحتی انجام نمی شود زیرا نشانه های عبارت از متن منبع استخراج می شوند. برای مثال عبارت x+ y*(u - v) منجر به معادل " x را بار کن، y را اضافه کن" نمی‌شود، زیرا x به y اضافه نمی شود. اگر از طرح پشته ای برای حساب استفاده شده باشد، کد ممکن است با بار کردن x شروع شود اما کدی که با توکن + در ادامه مطابقت دارد، دنبال نمی شود. در عوض، کد (u - v) تولید می شود و به دنبال آن ضرب در y می شود و فقط x اضافه می شود. تجزیه کننده ی عبارات در طول تجزیه و تحلیل خود در طول منبع حرکت نمی کند. آن یک دسته محلی از عملیات به تعویق انداخته را که توسط قوانین تقدم هدایت می شوند به کار می گیرد. با استفاده از عبارات حسابی که در نشانه‌گذاری لهستانی معکوس یا موارد مشابه ارائه شده، می توان از این رقص جلوگیری کرد. برای مثال فوق چیزی مانند + u v - y * x که کاملاً چپ به راست اسکن می شود.

یک کامپایلر بهینه ساز ممکن است شکل یک عبارت محاسباتی را تجزیه و تحلیل کند ، تا تکرار را شناسایی و حذف کند یا سایر پیشرفت های بالقوه را انجام دهد. عبارت زیر را در نظر بگیرید
```
a*sin(x) + b*sin(x)a*sin(x)
```
بعضی از زبانها، مانند Algol، واگذاری ها را در یک عبارت حسابی مجاز می دانند، بنابراین برنامه نویس می تواند چیزی مانند
```
a*(t:=sin(x)) + b*t
```
نوشته باشد.

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

### متن محدوده میانی
اگرچه تحلیل گر واژگان جریان ورودی را به جریانی از نشانه ها تقسیم کرده است (و هرگونه تفسیر را کنار گذاشته است) ، اما تفسیر این نشانه ها با توجه به نحو زبان هنوز ممکن است به زمینه بستگی داشته باشد. عبارات زیر را در شبه کد fortran در نظر بگیرید
```fortran
if (expression) = etc.
if (expression) label1,label2,label3
if (expression) then
```
اولین مورد اختصاص مقدار برخی از عبارات حسابی (و غیره) به عنصری از آرایه یک بعدی به نام "if" است. Fortran از آن جهت غیرمعمول است که کلمات اختصاصی ندارد، بنابراین نشانه "write" لزوماً به معنی اینکه نوشتن در دست انجام است، نیست. گزاره های دیگر در واقع عبارت های شرطی هستند - جمله دوم شرطی-محاسباتی است که علامت نتیجه عبارت را بررسی می کند و بر اساس منفی بودن ، صفر یا مثبت بودن آن به برچسب 1 ، 2 یا 3 می‌پرد. مورد سوم منطقی-شرطی است ، و مستلزم آن است که نتیجه بیان آن بولین باشد - بنابراین ، تفسیر صحیح نشانه "if" که از تحلیلگر لغوی ظاهر می شود ، نمی تواند تا پس از اسکن کردن عبارت و دنبال کردن براکت بسته شود در اینجا یا یک علامت تساوی وجود دارد، یا یک رقم (متن label1 است: fortran فقط از اعداد صحیح به عنوان برچسب استفاده می کند، گرچه اگر حروف مجاز بودند ، اسکن باید به پیدا کردن ویرگول ها متکی باشد) یا چیزی که با یک حرف شروع می شود (که باید "then" باشد)، و به همین صورت، متن مقدار دلخواهی از متن منبع را شامل می شود زیرا این عبارت دلخواه است. با این حال ، در هر سه مورد ، کامپایلر می تواند کدی را برای ارزیابی عبارت با پیشرفت اسکن آن تولید کند. بنابراین، تحلیل لغوی به دلیل مبهم بودن نحو مجاز همیشه نمی تواند معنای نشانه هایی را که به تازگی مشخص کرده است، تعیین کند. و بنابراین در صورت جلوگیری از عقبگرد ، تجزیه و تحلیل نحو باید یک برتری از حالت های احتمالی را حفظ کند.

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

## منابع

Hand-Written One-Pass Compilers, Jan Midtgaard, Michael I. Schwartzbach

What-is-Single-Pass-Compiler-and-its-example

What is the difference between a single pass and multipass compiler?

رده:کامپایلرها
رده:ویکی‌سازی رباتیک