۳۰ شهریور ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

کامپایلر چیست؟ چگونه کد منبع به کد ماشین تبدیل می شود

نحوه کامپایل شدن کد منبع برای زبان های برنامه نویسی مختلف و معماری کامپیوتر، از جمله تکامل از FORTRAN به CLR و کامپایلرهای JIT را بیابید.

نحوه کامپایل شدن کد منبع برای زبان های برنامه نویسی مختلف و معماری کامپیوتر، از جمله تکامل از FORTRAN به CLR و کامپایلرهای JIT را بیابید.

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

کامپایلرها، ترانسپایلرها، مفسرها و کامپایلرهای JIT

کامپایلرها اغلب کد منبع یک زبان سطح بالا مانند C++ را به کد شیء معماری فعلی رایانه مانند Intel x64 ترجمه می کنند. سپس ماژول های شی تولید شده از چندین فایل زبان سطح بالا به یک فایل اجرای پیوند می شوند.

کامپایلرهایی که برای تولید کد شیء برای معماری‌هایی که با معماری اجراکننده کامپایلر متفاوت هستند، مجموعه‌های متقابل نامیده می‌شوند. استفاده از کامپایلرهای متقابل که بر روی رایانه های رومیزی (یا بزرگتر) اجرا می شوند برای تولید فایل های اجرایی برای سیستم های جاسازی شده معمول است. کامپایلرهایی که از یک زبان سطح بالا به زبان دیگر مانند از TypeScript به JavaScript یا از C++ به C ترجمه می‌کنند transpilers نامیده می‌شوند. کامپایلرهایی که به زبانی که در حال کامپایل کردن هستند نوشته شده اند کامپایلرهای بوت استرپ نامیده می شوند.

اسمبلرها چطور؟

اسمبلرها از نظر مفهومی با کامپایلرها مرتبط هستند اما متفاوت هستند. ما در این مقاله درباره اسمبلرها صحبت نمی کنیم.

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

از لحاظ تاریخی، مفسرهایی وجود داشته اند که از کد بایتی استفاده نمی کرده اند، مانند مفسر BASIC که با رایانه های شخصی اولیه ارائه شده است. آنها در زمان اجرا نسبت به مفسرانی که کد بایت فشرده را اجرا می کردند کندتر بودند و در زمان اجرا بسیار کندتر از کدهای بومی کامپایل شده بودند. با این حال، آنها اغلب برای چرخه عمر کلی توسعه نرم افزار بسیار مفید بودند، زیرا برنامه نویسان می توانستند به سرعت کد، آزمایش، اشکال زدایی، اصلاح و اجرای مجدد کد را انجام دهند.

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

FORTRAN

FORTRAN (مترجم فرمول، املای Fortran از سال ۱۹۷۷ به بعد) اولین زبان موفق سطح بالا بود که برای کاربردهای علمی و مهندسی در نظر گرفته شد. کامپایلر FORTRAN I از سال ۱۹۵۴ تا ۱۹۵۷ برای IBM 704 توسط همه توسعه داده شد. تیم ستاره ای به رهبری John W. Backus که یکی از طراحان خود IBM 704 نیز بود. این یک کامپایلر بهینه‌سازی بود که به زبان اسمبلی نوشته شده بود و ۲۳ هزار دستورالعمل داشت. کامپایلر FORTRAN I بهینه‌سازی‌های قابل‌توجهی انجام داد: تجزیه عبارات حسابی و اعمال اولویت عملگر، انتشار کپی و حذف کد مرده، افزایش عبارات فرعی رایج برای حذف محاسبات اضافی، بهینه‌سازی حلقه‌های do... و زیرنویس انجام شد. محاسبات و تخصیص بهینه ثبت فهرست.

معرفی HTMX: HTML پویا بدون جاوا اسکریپت

در حال حاضر، بیش از دوازده کامپایلر FORTRAN وجود دارد که چهار تای آنها منبع باز هستند، و بسیاری از آنها رایگان هستند حتی اگر به صورت تجاری ارائه شوند.

LISP

جان مک کارتی LISP (پردازنده فهرست) را در MIT طراحی کرد و مشخصات آن را در سال ۱۹۶۰ منتشر کرد. ارتباط نزدیکی با جامعه هوش مصنوعی (AI) داشته و دارد. اندکی پس از انتشار مشخصات، استیو راسل متوجه شد که تابع eval LISP می تواند در کد ماشین پیاده سازی شود و این کار را برای IBM 704 انجام داد (در کمال تعجب مک کارتی). که اولین مترجم LISP شد. تیم هارت و مایک لوین در MIT اولین کامپایلر LISP را در LISP در سال ۱۹۶۲ ایجاد کردند. خود کامپایلر با اجرای مفسر LISP Russell بر روی کد منبع کامپایلر کامپایل شده است. LISP کامپایل شده ۴۰ برابر سریعتر از LISP تفسیر شده در IBM 704 اجرا شد. این اولین کامپایلر بوت استرپ بود. همچنین کامپایل افزایشی را معرفی کرد که به کدهای کامپایل شده و تفسیر شده اجازه می‌دهد تا ترکیب شوند.

کامپایلرها و مفسرهای متعددی برای نسخه‌های بعدی LISP و فرزندان آن، مانند Common Lisp، Emacs Lisp، Scheme و Clojure وجود داشته است.

COBOL

COBOL (زبان تجاری متداول) توسط کمیته ای طراحی شده است، CODASYL، از سال ۱۹۵۹ به دستور وزارت دفاع ایالات متحده شروع شد و بر اساس سه زبان موجود: FLOW-MATIC (طراحی شده توسط گریس هاپر)، AIMACO (مشتق شده از FLOW-MATIC)، و COMTRAN (از باب بمر از IBM). هدف اصلی COBOL این بود که یک زبان سطح بالا قابل حمل برای پردازش عمومی داده ها باشد. اولین برنامه COBOL در سال ۱۹۶۰ اجرا شد.

در سال ۱۹۶۲، یک مطالعه نیروی دریایی نشان داد که COBOL 3 تا ۱۱ بیانیه در دقیقه جمع آوری می کند. این در طول سالها با به روز شدن مشخصات زبان و کامپایلرها بهبود یافت. تا سال ۱۹۷۰، COBOL پرکاربردترین زبان برنامه نویسی در جهان بود.

در حال حاضر، چهار کامپایلر اصلی COBOL باقی مانده است: Fujitsu NetCOBOL به زبان میانی دات نت (کد بایت) کامپایل می شود و روی NET CLR (زمان اجرای زبان مشترک) اجرا می شود. GnuCOBOL به کد C کامپایل می‌شود که می‌توان آن را کامپایل و پیوند داد. IBM COBOL به کدهای شیء برای رایانه‌های اصلی و میان رده IBM کامپایل می‌شود و سپس کد، مشابه کامپایلرهای اولیه COBOL، پیوند داده می‌شود. Micro Focus COBOL به کد بایت .NET یا JVM (ماشین مجازی جاوا) کامپایل می شود.

ALGOL

پزشکان Edsger Dijkstra و Jaap Zonneveld اولین کامپایلر ALGOL 60 به زبان اسمبلی X1 طی نه ماه بین سال‌های ۱۹۵۹ تا ۱۹۶۰ در مرکز ریاضی آمستردام. X1، طراحی داخلی، توسط کارخانه کامپیوتر هلندی Electrologica جدید ساخته شده است. ALGOL (زبان الگوریتمی) خود پیشرفت عظیمی در زبان های کامپیوتری برای علم و مهندسی بیش از FORTRAN بود و در توسعه زبان های امری مانند CPL، Simula، BCPL، B، Pascal و C تاثیرگذار بود.

ارکستراسیون و رقص در میکروسرویس های دات نت

خود کامپایلر حدود ۲۰۰۰ دستورالعمل داشت و کتابخانه زمان اجرا (نوشته شده توسط M.J.H. Römgens و S.J. Christen) 2000 دستورالعمل دیگر بود. کامپایلر از نوارهای کاغذی بارگیری می‌شود، همچنین کد منبع برنامه و کتابخانه‌ها. کامپایلر دو بار از کد عبور کرد. اولی (پیش اسکن) برای جمع آوری شناسه ها و بلوک ها، و دومی (اسکن اصلی) برای تولید کد شی روی نوار کاغذی دیگر. بعداً، این فرآیند با استفاده از یک “فروشگاه” (احتمالا یک درام مغناطیسی) به جای نوار کاغذی تسریع شد. در نهایت حدود ۷۰ مورد از ALGOL 60 و گویش های آن اجرا شد.

ALGOL 68 برای جایگزینی ALGOL 60 در نظر گرفته شده بود و بسیار تأثیرگذار بود، اما آنقدر پیچیده بود که اجراهای کمی داشت و پذیرش کمی داشت. زبان های تحت تأثیر ALGOL 68 عبارتند از C، C++، Bourne shell، KornShell، Bash، Steelman، Ada و Python.

PL/I

PL/I (زبان برنامه نویسی یک) در اواسط دهه ۱۹۶۰ توسط IBM و SHARE (گروه کاربران علمی IBM) طراحی شد تا یک زبان یکپارچه برای کاربران علمی و تجاری باشد. اولین پیاده سازی، PL/I F، برای IBM S/360 بود که به طور کامل به زبان اسمبلی System/360 نوشته شد و در سال ۱۹۶۶ عرضه شد. کامپایلر F شامل یک مرحله کنترل و تعداد زیادی فاز کامپایلر (نزدیک به ۱۰۰) بود. چندین اجرای بعدی PL/I در IBM و همچنین برای Multics (به عنوان زبان سیستم) و DEC VAX وجود داشت.

پاسکال

Niklaus Wirth از ETH در زوریخ یکی از اعضای کمیته استانداردهایی بود که بر روی جانشین ALGOL 60 کار می کرد و یک زبان کوچکتر به نام ALGOL W را ارائه کرد که رد شد. Wirth از کمیته استعفا داد، به کار بر روی ALGOL W ادامه داد و آن را به شکل ساده شده در سال ۱۹۷۰ با نام پاسکال منتشر کرد. Wirth در ابتدا سعی کرد کامپایلر پاسکال را در FORTRAN 66 پیاده سازی کند، اما نتوانست. او سپس یک کامپایلر پاسکال به زبان C مانند Scallop نوشت و سپس یکی از همکاران آن را برای راه‌اندازی به پاسکال ترجمه کرد.

دو شاخه قابل توجه Wirth Pascal عبارتند از Pascal P-system و Turbo Pascal. کامپایلر سیستم P Zürich “p-code” را برای یک ماشین پشته مجازی تولید کرد که سپس تفسیر شد. که منجر به UCSD Pascal برای IBM PC و Apple Pascal شد. آندرس هیلسبرگ Blue Label Pascal را برای Nascom-2 نوشت، سپس آن را برای کامپیوتر IBM به زبان اسمبلی ۸۰۸۸ دوباره پیاده‌سازی کرد. بورلند آن را خرید و دوباره با نام توربو پاسکال عرضه کرد. بعداً، Hejlsberg توربو پاسکال را به مکینتاش پورت کرد، پسوندهای Object Pascal اپل را اضافه کرد و زبان جدید را به رایانه شخصی بازگرداند، که در نهایت به دلفی برای مایکروسافت ویندوز تبدیل شد.

C

C ابتدا در آزمایشگاه‌های بل توسط دنیس ریچی بین سال‌های ۱۹۷۲ تا ۱۹۷۳ برای ساخت ابزارهای کاربردی در حال اجرا بر روی یونیکس توسعه یافت. کامپایلر اصلی C مانند یونیکس در آن زمان به زبان اسمبلی PDP-7 نوشته شده بود. پورت PDP-11 نیز به زبان اسمبلی بود. بعداً از C برای بازنویسی هسته یونیکس برای قابل حمل کردن آن استفاده شد.

کار با MarkoJS

C++

C++ توسط Bjarne Stroustrup در آزمایشگاه Bell در سال ۱۹۷۹ توسعه داده شد. از آنجایی که C++ تلاشی برای افزودن ویژگی های شی گرا (به اضافه سایر پیشرفت ها) به C است، استراستروپ در ابتدا آن را “C with Objects” نامید. Stroustrup این زبان را به تغییر نام داد. C++ در سال ۱۹۸۳، و این زبان در خارج از آزمایشگاه Bell در سال ۱۹۸۵ در دسترس قرار گرفت. اولین کامپایلر تجاری C++، Cfront، در آن زمان منتشر شد؛ C++ را به C ترجمه کرد، که سپس می‌توان آن را کامپایل و پیوند داد. بعدها کامپایلرهای C++ کد شی تولید کردند. فایل هایی که مستقیماً به یک پیوند دهنده وارد می شوند.

جاوا

جاوا در سال ۱۹۹۵ به عنوان یک زبان قابل حمل (با استفاده از شعار بازاریابی “یک بار بنویس، هر جا اجرا شود”) منتشر شد که برای کد بایتی برای JVM کامپایل شده و سپس تفسیر می شود، مشابه سیستم پاسکال P. کامپایلر جاوا در اصل به زبان C نوشته شده بود و از تعدادی کتابخانه ++C استفاده می کرد. نسخه های بعدی JVM یک کامپایلر JIT برای سرعت بخشیدن به مفسر اضافه کرد. کامپایلر جاوا فعلی در جاوا نوشته شده است، اگرچه زمان اجرا جاوا هنوز به زبان C نوشته شده است.

در اجرای GraalVM جاوا و سایر زبان‌ها، یک کامپایلر AOT در زمان ساخت اجرا می‌شود تا کد بایت را بهینه کرده و زمان راه‌اندازی را کاهش دهد.

C#

C# توسط Anders Hejlsberg که Borland را به مقصد مایکروسافت ترک کرده بود در سال ۱۹۹۹ طراحی و توسط Mads Torgersen در C و C++ برای CLR در سال ۲۰۰۰ پیاده سازی شد. در زمان اجرا تفسیر و با JIT کامپایل شد. کامپایلر سی شارپ، CLR و کتابخانه ها اکنون در سی شارپ نوشته شده اند و کامپایلر از یک نسخه به نسخه دیگر بوت استرپ می شود.

بخشی از انگیزه برای توسعه C#، بر اساس زمان، ممکن است ناتوانی مایکروسافت در مجوز جاوا از Sun باشد، اگرچه مایکروسافت این موضوع را رد می کند. هجلسبرگ می گوید که سی شارپ به همان اندازه که تحت تأثیر C++ بود، تحت تأثیر جاوا قرار گرفت. در هر صورت، زبان‌های جاوا و سی شارپ در طول سال‌ها به طور قابل‌توجهی از هم جدا شده‌اند.

نتیجه گیری

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