مترجمات
Compilers - Compilateurs
المترجمات
المترجم compiler، هو برنامج حاسوبي، يترجم برنامجاً حاسوبياً مكتوباً بلغة مصدرية source language إلى برنامج مكتوب بلغة حاسوبية أخرى تدعى الخرج أو لغة مستهدفة.
تترجم معظم المترجمات الرماز المصدريsource code، المكتوب بلغة عالية المستوى إلى رماز غرضي object code أو لغة آلة assembly، يمكن أن تنفذ مباشرة من قبل الحاسوب أو من قبل آلة افتراضية (الآلة الافتراضية هي برمجيات تقلد عمل تجهيزة عتادية ما).
يمكن أن تكون الترجمة من لغة منخفضة المستوى إلى لغة عالية المستوى، وتعرف هذه العملية بعكس الترجمة، ويسمى البرنامج الحاسوبي الذي ينجز هذا العمل عاكس الترجمة إذا كان يعيد بناء اللغة عالية المستوى المولّدة للغة منخفضة المستوى.
توجد أيضاً مترجمات تترجم من لغة عالية المستوى high- level language إلى لغة أخرى مختلفة عالية المستوى، أو تترجم في بعض الأحيان إلى لغة وسيطة تحتاج إلى معالجة إضافية، ويسمى هذا النوع من المترجمات في بعض الأحيان المشلشل cascader.
تنتج المترجمات النموذجية ما يدعى بالأغراض، التي تحتوي أساساً رماز آلة مزود بمعلومات عن اسم وموضع نقاط الدخول والاستدعاءات الخارجية (لوظائف غير متضمنة في الغرض). يمكن أن تربط مجموعة ملفات أغراض بعضها مع بعض لتوليد رماز يمكن تنفيذه من قبل المستخدم مباشرة؛ حيث لا يشترط أن تولد ملفات أغراض هذه المجموعة جميعها بوساطة المترجم نفسه بل يمكن أن تولد بوساطة مترجمات مختلفة، شريطة أن تشترك جميع هذه المترجمات بإصاغة خرج output format موحدة.
لمحة تاريخية
طُوِّرت في عام 1950 عدة مترجمات تجريبية، وينسب إلى فريق فورتران الذي قاده جون باكوس John Backus في شركة آي بي إم IBM تسجيل أول مترجم كامل في عام 1957. بعدها سرعان ما تم فهم وإدراك فكرة المترجم، ثم طوّرت مبادىء تصميم المترجمات خلال الستينات من القرن العشرين.
كانت المترجمات البدائية تكتب بلغة التجميع. ثم طور أول مترجم ذاتي الاستضافة (قادر على ترجمة رمازه المصدري الذاتي المكتوب بلغة برمجة عالية المستوى) من أجل لغة ليسبLisp من قبل العالمين هارت Hart وليفين Levin في معهد إم آي تي MIT في عام 1962. ثم اكتسب استخدام اللغات عالية المستوى في كتابة المترجمات قوة دفع إضافية في بداية السبعينات، عندما كتبت مترجمات لغة سي C ولغة باسكال Pascal بنفس لغتيهما. إن بناء مترجمات ذاتية الاستضافة هي مسألة إقلاع - حيث يجب أن يترجم المترجم الأول من هذه المترجمات، إما باستخدام مترجم مكتوب بلغة مختلفة، أو (كما هي الحال في مترجم ليسب)، يترجم بوساطة تنفيذ المترجم من خلال مفسر interpreter.
في أثناء التسعينات من القرن العشرين طُوِّر عدد كبير من المترجمات وأدوات تطويرها من أجل جميع أنواع لغات البرمجة كجزء من مشروع باسم «النو ليس يونكس» Gnu‘s Not Unix (GNU) أطلق عام 1983 من قبل ريتشارد ستولمان Richard Stallman يهدف إلى إيجاد نظام تشغيل كامل سمي GNUS من البرمجيات المجانية برعاية مؤسسة البرمجيات المجانية Free Software Foundation (FSF) ، وكجزء من مبادرات تطوير البرمجيات ذات المصدر المفتوح الأخرى. حيث تعدّ بعض هذه المترجمات وأدوات تطويرها ذات نوعية عالية الجودة، ويتيح رماز مصدرها المفتوح فرصة جيدة للاطلاع عليها لكل من يهتم بالأفكار الحديثة للمترجمات.
أنواع المترجمات
قد ينتج المترجم رمازاً مخصصاً؛ لينفذ على حاسوب ونظام تشغيل (منصة عمل) مماثل لذلك الذي ينفذ عليه المترجم؛ يدعى مثل هذا المترجم أحياناً مترجم رماز أصيلnative code compiler. يمكن أيضاً أن ينتج المترجم رمازاً مصمماً لينفذ على منصة مختلفة؛ يدعى المترجم في هذه الحالة مترجماً تصالبياً cross compiler. إن المترجمات التصالبية ذات فائدة كبيرة عند استخدام منصات مادية لأول مرة. هنالك نوع آخر من المترجمات يدعى مترجماً من مصدر إلى مصدر. يكون دخل هذا المترجم برنامجاً مكتوباً بلغة برمجة عليا وخرجه هو برنامج مكتوب بلغة برمجة عليا أخرى.
ـ مترجم أحادي المرور one-pass compiler : تتم عملية الترجمة في هذا النوع من المترجمات بمرور واحد (أي بمرحلة معالجة واحدة)، لذلك هذا النوع سريع جداً كما في المترجمات البدائية الخاصة بلغة باسكال.
ـ مترجم رماز منيسب threaded code compiler: يعدّ هذا النوع من المترجمات برنامج بحث في قاعدة بيانات، فهو يستعيض عن الرماز الاثناني المحدد binary code بشرائط محارف في المصدر. إن معظم مترجمات لغة فورث Forth تحقق بهذا الشكل.
ـ مترجم تزايدي incremental compiler: تترجم في هذا النوع الوظائف البرمجية المستقلة في بيئة التنفيذ التي تحتوي أيضاً وظائف مفسرة. يرجع تاريخ الترجمة التزايدية إلى عام 1962 لأول مترجم للغة Lisp، و مازال يستخدم في نظم ليسب الشائعة.
ـ مترجم مرحلة stage compiler: يترجم إلى لغة تجميع خاصة بآلة نظرية محددة كما في مترجمات لغة برولوغProlog. مترجمات الرماز الثماني المستخدمة في لغات جافا Java وبايثونPython هي أنواع فرعية من مترجمات مرحلة.
ـ مترجم في أثناء العمل just-in-time compiler: تعطى التطبيقات بالرماز الثماني الذي يترجم إلى رماز الآلة الأصيل قبل التنفيذ مباشرة، كما في نظم الجافا والسمولتوك SmallTalk.
ـ مترجم قابل لإعادة التوجيه retargetable compiler: هو مترجم يمكن أن يعدل بسهولة لتوليد رماز من أجل معالجات مختلفة البنيان. الرماز الغرضي الناتج بوساطة هذا النوع من المترجمات، هو عادة أقل جودة من الرماز الناتج بوساطة مترجم مطور خصيصاً من أجل معالج محدد، والمترجم القابل لإعادة التوجيه هو غالباً مترجم تصالبي.
ـ مترجم مواز parallelizing compiler: يحول المترجم الموازي برنامج دخل تسلسلي إلى شكل مناسب للتنفيذ الفعال على حاسوب ذي بنيان متوازي.
تصميم المترجم
في الماضي قُسِّم عمل المترجم إلى عدة مراحل كل منها دعي مرورpass، وذلك لتوفير الذاكرة. يقصد بالمرور في هذا السياق مرحلة معالجة ينفذها المترجم على الرماز المصدري للبرنامج المراد ترجمته، وكنتيجة لهذا المرور (أي لمرحلة المعالجة هذه) تتم عملية بناء أو تحديث المعطيات والبيانات الداخلية التي يستخدمها المترجم في أثناء الانتقال من مرحلة إلى مرحلة في عملية الترجمة (مثل بناء وتحديث جدول الرموز symbol table). وقد كانت طرق المرور المتعددة في الماضي هي التقانة الشائعة في عملية الترجمة، وذلك بسبب صغر حجم الذاكرة الرئيسة للحواسيب المضيفة (الحواسيب المضيفة هي الحواسيب التي تتم عليها عملية ترجمة البرامج) في ذلك الوقت.
تشترك حالياً كثير من المترجمات الحديثة في تصميم مشترك ذي مرحلتين تدعى الأولى منهما الطرف الجبهي front end، وتدعى الثانية الطرف الخلفيback end. يترجم الطرف الجبهي لغة المصدر إلى تمثيل وسيط، أما الطرف الخلفي فيستخدم التمثيل الوسيط لإنتاج لغة الخرج. يمكن أن يعمل كل منهما كمرورين منفصلين، أو قد يستدعي الطرف الأمامي الطرف الخلفي كمساق فرعي ممرراً له التمثيل الوسيط.
تلطف وتسهل فكرة الطرف الجبهي والطرف الخلفي فكرة تصميم المترجم، حيث تفصل وظائف مرحلة الطرف الجبهي (التي تتركز نموذجياً حول دلالة اللغة، فحص الخطأ، ومثيلاتها) عن وظائف مرحلة الطرف الخلفي (التي تتركز على إنتاج خرج صحيح وفعال).
للطرف الخلفي فائدة أيضاً، وهي استخدام طرف خلفي وحيد من أجل لغات مصدرية متعددة إذا كان المطلوب ترجمتها إلى الهدف نفسه، وبشكل مشابه تستخدم أطراف خلفية مختلفة من أجل الترجمة إلى عدة أهداف مختلفة.
غالباً ما يتشارك الطرف الخلفي والطرف الجبهي بمدقق الخطأ والمستمثلoptimizer إذا صمما ليعملا على لغة وسيطة يمررها الطرف الجبهي إلى الطرف الخلفي. تمكن هذه التقنية (أي التوافق بين الطرفين الجبهي والخلفي) كثيراً من المترجمات من إعادة استخدام مقدار كبير من العمل الذي غالباً ما يذهب إلى محللات الرماز والمستمثلات. هنالك لغات محددة يمكن أن تترجم بمرور وحيد، وذلك طبقاً لتصميم اللغة وطبقاً لقواعد محددة موضوعة للتصريح عن المتغيرات والأغراض الأخرى المستخدمة، والتصريح المسبق عن الإجرائيات التنفيذية قبل المرجع أو الاستخدام، ولغة باسكال معروفة جيداً بهذا الإمكان، وكثير من مترجمات باسكال مكتوبة بلغة باسكال نفسها، بسبب التوصيف الصارم للغة ولتوفر إمكان استخدام مرور وحيد لترجمة برامج لغة باسكال.
الطرف الجبهي للمترجم
يتألف الطرف الجبهي للمترجم من عدة مراحل (أطوار). تحدد كل مرحلة من مراحل الطرف الجبهي بنظرية اللغات الصورية وهذه المراحل هي:
ـ مرحلة التحليل المعجمي (المفرداتي) lexical analysis: يعني التحليل المعجمي تقسيم نص الرماز المصدري إلى قطع صغيرة (علاّمات)، تمثّل كل منها وحدة جزئية مفردة من اللغة، على سبيل المثال كلمة مفتاحية keyword، معيّنidentifier أو أسماء رموز. لغة العلاّم token language هي نموذجياً لغة نظامية، حيث تبنى آلة الحالة المنتهيةfinite state machine من عبارة نظامية يمكن أن تستخدم لتعرّفها. تسمى هذه المرحلة أيضاً مرحلة المسح.
ـ مرحلة تحليل التركيب النحوي syntax analysis: يقوم التحليل النحوي بتعيين البنى الإعرابية للرماز المصدري، ويركزالضوء على البنية. بكلمات أخرى يعيّن التحليل النحوي ترتيب العلاّماتtokens ويفهم البنى التراتبية للرماز. تسمى هذه المرحلة أيضاً التحليل (بمعنى الإعراب).
ـ مرحلة تحليل الدلالةsemantic analysis : وظيفة تحليل الدلالة هي تعرف معنى رماز البرنامج والبدء بتحضير الخرج. في هذه المرحلة يتم فحص نوع المعطيات و إظهار معظم أخطاء المترجم.
ـ مرحلة توليد اللغة الوسيطة: ينتج في هذه المرحلة ما يكافئ البرنامج الأصلي باللغة الوسيطة.
الطرف الخلفي للمترجم
بينما هنالك تطبيقات تستلزم وجود الطرف الجبهي للمترجم فقط كما في أدوات التحقق السكوني من اللغة، يعالج المترجم الحقيقي التمثيل الوسيط الذي يولده الطرف الجبهي من أجل الطرف الخلفي الذي ينتج بدوره برنامجاً مكافئاً وظيفياً بلغة الخرج. يتم إنجاز هذا العمل على عدة خطوات هي:
ـ مرحلة تحليل المترجم: تتلخص هذه العملية بجمع معلومات البرنامج من التمثيل الوسيط الخاص بملفات مصدر الدخل. التحليل النموذجي هو عبارة عن سلسلة متغيرة من عمليات التعريف- الاستخدام والاستخدام- التعريف، تحليل اعتمادية المعطيات، تحليل الأسماء البديلة. التحليل الدقيق هو الأساس من أجل أي استمثالات تالية للمترجم. خلال مرحلة التحليل يتم أيضاً بناء مبيان graph الاستدعاء ومبيان انسياب التحكم.
ـ مرحلة الاستمثال: تنقل مرحلة الاستمثال التمثيل باللغة الوسيطة إلى أشكال مكافئة وظيفياً، ولكن أسرع (أو أصغر بالحجم). من الاستمثالات الشائعة التوسيع المحوري inline copy (وضع مستنسخ من متن الإجراء مكان استدعاء إجراء مستبدل في الرماز الغرضي)، إزالة الرماز الميت (إزالة الرماز الذي يمثّل تعليمات ليس لها فائدة في البرنامج)، الانتشار الثابت، نقل الحلقة، تخصيص سجل register allocation، أو حتى موازاة آليةautomatic parallelizing.
ـ مرحلة توليد الرماز: تترجم اللغة الوسيطة المنقولة إلى لغة خرج عادة ما تكون اللغة الأصلية لآلة النظام. تشمل هذه المرحلة أيضاَ اتخاذ قرارات بشأن المصدر والتخزين، مثل تحديد أي متغيرات يجب توسيعها في سجلات، وأيها يجب توسيعها في الذاكرة، اختيار وجدولة تعليمات الآلة المناسبة طبقاً لأنماط العنونة المستخدمة.
ـ التحليل (الإعراب)parsing : التحليل في علم الحاسوب هو عملية تحليل دفق مستمر من المحارف يأتي من الدخل (مثلاً مقروء من ملف أو من لوحة مفاتيح) لتحديد بنيته القواعدية مقارنة بقواعد معتمدة رسمياً، والمحللparser هو عبارة عن البرنامج الحاسوبي الذي ينفذ هذه المهمة. ويقصد هنا بالتحليل ما يقصد بالقواعد في اللسانيات. التحليل يحول نص الدخل إلى بنية معطيات، عادة ما تكون شجرية، و هي مناسبة للمعالجة اللاحقة و تدرك البنية التراتبية المتضمنة في الدخل. عموماً تعمل المحللات على مرحلتين، الأولى تعيين وتحديد العلاّمات ذات المعنى في الدخل، ثم بناء شجرة التحليل من هذه العلاّّمات.
يوضح المثال الآتي حالة عامة لتحليل لغة على مستويين من القواعد: التحليل المعجمي المفرداتي و تحليل الدلالة.
لتكن لدينا التعليمة الآتية في برنامج حاسوبي ينفذ على آلة حاسبة: ً2 ^ (4+3) * 12 ً.
المرحلة الأولى هي مرحلة توليد العلاّمات، أو مرحلة التحليل المعجمي. تقسّم هذه التعليمة في هذه المرحلة إلى العلاّماتTokens الآتية:
12،*، ( 3 ، + ، 4 )، ^، و 2.
حيث كل من هذه العلاّمات هو رمز له معنى في سياق العبارة الرياضية. سيحتوي المحلل قواعد تخبر أن الرموز (*، +، ^)، وتشير إلى بداية علاّم جديد. أما العلاّمات التي ليس لها معنى مثل ( ً * 12 ً أو ً 3) ً فلن يتم توليدها.
المرحلة التالية هي تحليل التركيب النحوي، وتقوم بالتأكد من أن العلاّمات تشكل عبارات صحيحة ومسموحة. تتم هذه العملية بالرجوع إلى قواعد النحو غير المعتمدة على السياقcontext-free grammar التي تعرّف بدورها مكونات تشكل عبارة وتحدد الترتيب الذي سوف تظهر فيه هذه المكونات (العلاّمات) في هذه العبارة.
المرحلة الأخيرة هي مرحلة تحليل الدلالة و تستنبط فيها المضامين من العبارة التي تم تدقيق صلاحيتها ثم ينفذ الفعل المناسب، والفعل المطلوب في حالة الآلة الحاسبة هو تقييم العبارة الحسابية المعطاة. من ناحية ثانية سيقوم المترجم في هذه المرحلة أيضاً بتوليد لغة الآلة التي سينفذها المعالج لتحقيق الوظيفة المنصوص عنها بالرماز.
أنواع المحلّلات
مما سبق يتلخص عمل المحلل بتحليل دفق مستمر من المحارف، يمثّل تعليمات من برنامج ما مكتوبة بلغة مصدرية؛ لتحديد بنيتها القواعدية مقارنة بقواعد معتمدة مسبقاًً.
تقسم المحلّلات طبقاً لطريقة عملها إلى نوعين:
ـ تحليل من الأعلى إلى الأسفل top-down parsing: يبدأ المحلل في هذا النوع من المحللات ببناء شجرة التحليل بأكبر العناصر و يقسمه إلى أجزاء أصغر، و منها إلى أجزاء أصغر على نحو متزايد وهكذا. ومن ثمّ يتم تشكيل شجرة التحليل في هذه الحالة بداية من أكبر العناصر ثم تقسمها إلى أجزاء أصغر فأصغر.
ـ تحليل من الأسفل إلى الأعلىbottom-up parsing : يبدأ المحلل ببناء شجرة التحليل بدءاً من العناصر الأكثر أساسية، ثم العناصر التي تحتوي العناصر السابقة وهكذا. ومن ثمَّ يتم تشكيل شجرة التحليل بداية من أكثر العناصر صغراً، ثم العناصر الأكبر منها التي تحتويها وهكذا.
عاكس الترجمة decompiler
عاكس الترجمة، هو برنامج حاسوبي يترجم البرامج القابلة للتنفيذ (التي هي خرج المترجم) إلى ما يكافئها بلغة عالية المستوى (رماز مصدري)، وهذا بالضبط عكس عمل المترجم، لكن عاكس الترجمة العام لا ينفذ بالضبط عكس خطوات الترجمة التي يقوم بها مترجم محدد. بالمقارنة يترجم عاكس التجميع برنامجاً قابلاً للتنفيذ إلى لغة تجميع.
يمكن أن يستخدم عاكس الترجمة لاستعادة الرماز المصدري المفقود، وهو مفيد أيضاً في بعض الحالات مثل أمن الحاسوب، التشغيلية البينية interoperability (أي إن هذه البرامج يمكنها التشارك بالموارد والمعطيات)، تصحيح الخطأ وغيرها. يزداد نجاح عملية عكس الترجمة إذا كان البرنامج القابل للتنفيذ مترجماً من أجل آلة افتراضية (مثلاً ملف رماز ثماني bytecode ناتج من ترجمة برنامج مكتوب بلغة جافا) وذلك بسبب احتواء الملف الاثناني للآلة الافتراضية على معلومات إضافية. كما يمكن تحسين النتائج إذا امتلك عاكس الترجمة نقاط دخول المكتبات ومكتبات الربط الديناميكي. إن عكس ترجمة برامج رماز آلة أكثر صعوبة، وكنتيجة عواكس ترجمة رماز الآلة أقل شيوعاً وأقل نجاحاً.
مقارنة بين اللغات المترجمة واللغات المفسرة
يقسم كثير من الناس لغات البرمجة عالية المستوى إلى لغات مترجمة و لغات مفسرة. إن المترجمات والمفسرات هي أشكال لتحقيق اللغات، وليست لغات بحد ذاتها، ونادراً ما يوجد ما يستلزم أن تكون اللغة مترجمة أو مفسرة. أما تصنيف اللغة كمترجمة أو مفسرة فهو يُظهر عادة أكثر التحقيقات للغة ما شيوعاً وانتشاراً، فلغة بيسك Basic هي لغة مفسرة، ولغة سي C مترجمة، على الرغم من وجود مترجمات للغة بيسك ومفسرات للغة سي. هنالك استثناءات حيث تفترض بعض توصيفات اللغة استخدام مترجم كما هي الحال في لغة سي، أو يبين توصيف اللغة بغير لبس أن تحقيقات اللغة يجب أن تتضمن تسهيلاً ما لعملية الترجمة كما هي الحال في لغة ليسب الشائعة؛ من جهة أخرى تحتوي بعض اللغات خصائص يمكن تحقيقها بسهولة كبيرة في المفسر، وتجعل كتابة المترجم أكثر صعوبة (مثال ذلك هو إمكان تنفيذ رماز مصدري ما موجود في شريط محارف يعطى في أثناء تنفيذ البرنامج).
كمال قمر
Compilers - Compilateurs
المترجمات
المترجم compiler، هو برنامج حاسوبي، يترجم برنامجاً حاسوبياً مكتوباً بلغة مصدرية source language إلى برنامج مكتوب بلغة حاسوبية أخرى تدعى الخرج أو لغة مستهدفة.
تترجم معظم المترجمات الرماز المصدريsource code، المكتوب بلغة عالية المستوى إلى رماز غرضي object code أو لغة آلة assembly، يمكن أن تنفذ مباشرة من قبل الحاسوب أو من قبل آلة افتراضية (الآلة الافتراضية هي برمجيات تقلد عمل تجهيزة عتادية ما).
يمكن أن تكون الترجمة من لغة منخفضة المستوى إلى لغة عالية المستوى، وتعرف هذه العملية بعكس الترجمة، ويسمى البرنامج الحاسوبي الذي ينجز هذا العمل عاكس الترجمة إذا كان يعيد بناء اللغة عالية المستوى المولّدة للغة منخفضة المستوى.
توجد أيضاً مترجمات تترجم من لغة عالية المستوى high- level language إلى لغة أخرى مختلفة عالية المستوى، أو تترجم في بعض الأحيان إلى لغة وسيطة تحتاج إلى معالجة إضافية، ويسمى هذا النوع من المترجمات في بعض الأحيان المشلشل cascader.
تنتج المترجمات النموذجية ما يدعى بالأغراض، التي تحتوي أساساً رماز آلة مزود بمعلومات عن اسم وموضع نقاط الدخول والاستدعاءات الخارجية (لوظائف غير متضمنة في الغرض). يمكن أن تربط مجموعة ملفات أغراض بعضها مع بعض لتوليد رماز يمكن تنفيذه من قبل المستخدم مباشرة؛ حيث لا يشترط أن تولد ملفات أغراض هذه المجموعة جميعها بوساطة المترجم نفسه بل يمكن أن تولد بوساطة مترجمات مختلفة، شريطة أن تشترك جميع هذه المترجمات بإصاغة خرج output format موحدة.
لمحة تاريخية
طُوِّرت في عام 1950 عدة مترجمات تجريبية، وينسب إلى فريق فورتران الذي قاده جون باكوس John Backus في شركة آي بي إم IBM تسجيل أول مترجم كامل في عام 1957. بعدها سرعان ما تم فهم وإدراك فكرة المترجم، ثم طوّرت مبادىء تصميم المترجمات خلال الستينات من القرن العشرين.
كانت المترجمات البدائية تكتب بلغة التجميع. ثم طور أول مترجم ذاتي الاستضافة (قادر على ترجمة رمازه المصدري الذاتي المكتوب بلغة برمجة عالية المستوى) من أجل لغة ليسبLisp من قبل العالمين هارت Hart وليفين Levin في معهد إم آي تي MIT في عام 1962. ثم اكتسب استخدام اللغات عالية المستوى في كتابة المترجمات قوة دفع إضافية في بداية السبعينات، عندما كتبت مترجمات لغة سي C ولغة باسكال Pascal بنفس لغتيهما. إن بناء مترجمات ذاتية الاستضافة هي مسألة إقلاع - حيث يجب أن يترجم المترجم الأول من هذه المترجمات، إما باستخدام مترجم مكتوب بلغة مختلفة، أو (كما هي الحال في مترجم ليسب)، يترجم بوساطة تنفيذ المترجم من خلال مفسر interpreter.
في أثناء التسعينات من القرن العشرين طُوِّر عدد كبير من المترجمات وأدوات تطويرها من أجل جميع أنواع لغات البرمجة كجزء من مشروع باسم «النو ليس يونكس» Gnu‘s Not Unix (GNU) أطلق عام 1983 من قبل ريتشارد ستولمان Richard Stallman يهدف إلى إيجاد نظام تشغيل كامل سمي GNUS من البرمجيات المجانية برعاية مؤسسة البرمجيات المجانية Free Software Foundation (FSF) ، وكجزء من مبادرات تطوير البرمجيات ذات المصدر المفتوح الأخرى. حيث تعدّ بعض هذه المترجمات وأدوات تطويرها ذات نوعية عالية الجودة، ويتيح رماز مصدرها المفتوح فرصة جيدة للاطلاع عليها لكل من يهتم بالأفكار الحديثة للمترجمات.
أنواع المترجمات
قد ينتج المترجم رمازاً مخصصاً؛ لينفذ على حاسوب ونظام تشغيل (منصة عمل) مماثل لذلك الذي ينفذ عليه المترجم؛ يدعى مثل هذا المترجم أحياناً مترجم رماز أصيلnative code compiler. يمكن أيضاً أن ينتج المترجم رمازاً مصمماً لينفذ على منصة مختلفة؛ يدعى المترجم في هذه الحالة مترجماً تصالبياً cross compiler. إن المترجمات التصالبية ذات فائدة كبيرة عند استخدام منصات مادية لأول مرة. هنالك نوع آخر من المترجمات يدعى مترجماً من مصدر إلى مصدر. يكون دخل هذا المترجم برنامجاً مكتوباً بلغة برمجة عليا وخرجه هو برنامج مكتوب بلغة برمجة عليا أخرى.
ـ مترجم أحادي المرور one-pass compiler : تتم عملية الترجمة في هذا النوع من المترجمات بمرور واحد (أي بمرحلة معالجة واحدة)، لذلك هذا النوع سريع جداً كما في المترجمات البدائية الخاصة بلغة باسكال.
ـ مترجم رماز منيسب threaded code compiler: يعدّ هذا النوع من المترجمات برنامج بحث في قاعدة بيانات، فهو يستعيض عن الرماز الاثناني المحدد binary code بشرائط محارف في المصدر. إن معظم مترجمات لغة فورث Forth تحقق بهذا الشكل.
ـ مترجم تزايدي incremental compiler: تترجم في هذا النوع الوظائف البرمجية المستقلة في بيئة التنفيذ التي تحتوي أيضاً وظائف مفسرة. يرجع تاريخ الترجمة التزايدية إلى عام 1962 لأول مترجم للغة Lisp، و مازال يستخدم في نظم ليسب الشائعة.
ـ مترجم مرحلة stage compiler: يترجم إلى لغة تجميع خاصة بآلة نظرية محددة كما في مترجمات لغة برولوغProlog. مترجمات الرماز الثماني المستخدمة في لغات جافا Java وبايثونPython هي أنواع فرعية من مترجمات مرحلة.
ـ مترجم في أثناء العمل just-in-time compiler: تعطى التطبيقات بالرماز الثماني الذي يترجم إلى رماز الآلة الأصيل قبل التنفيذ مباشرة، كما في نظم الجافا والسمولتوك SmallTalk.
ـ مترجم قابل لإعادة التوجيه retargetable compiler: هو مترجم يمكن أن يعدل بسهولة لتوليد رماز من أجل معالجات مختلفة البنيان. الرماز الغرضي الناتج بوساطة هذا النوع من المترجمات، هو عادة أقل جودة من الرماز الناتج بوساطة مترجم مطور خصيصاً من أجل معالج محدد، والمترجم القابل لإعادة التوجيه هو غالباً مترجم تصالبي.
ـ مترجم مواز parallelizing compiler: يحول المترجم الموازي برنامج دخل تسلسلي إلى شكل مناسب للتنفيذ الفعال على حاسوب ذي بنيان متوازي.
تصميم المترجم
في الماضي قُسِّم عمل المترجم إلى عدة مراحل كل منها دعي مرورpass، وذلك لتوفير الذاكرة. يقصد بالمرور في هذا السياق مرحلة معالجة ينفذها المترجم على الرماز المصدري للبرنامج المراد ترجمته، وكنتيجة لهذا المرور (أي لمرحلة المعالجة هذه) تتم عملية بناء أو تحديث المعطيات والبيانات الداخلية التي يستخدمها المترجم في أثناء الانتقال من مرحلة إلى مرحلة في عملية الترجمة (مثل بناء وتحديث جدول الرموز symbol table). وقد كانت طرق المرور المتعددة في الماضي هي التقانة الشائعة في عملية الترجمة، وذلك بسبب صغر حجم الذاكرة الرئيسة للحواسيب المضيفة (الحواسيب المضيفة هي الحواسيب التي تتم عليها عملية ترجمة البرامج) في ذلك الوقت.
تشترك حالياً كثير من المترجمات الحديثة في تصميم مشترك ذي مرحلتين تدعى الأولى منهما الطرف الجبهي front end، وتدعى الثانية الطرف الخلفيback end. يترجم الطرف الجبهي لغة المصدر إلى تمثيل وسيط، أما الطرف الخلفي فيستخدم التمثيل الوسيط لإنتاج لغة الخرج. يمكن أن يعمل كل منهما كمرورين منفصلين، أو قد يستدعي الطرف الأمامي الطرف الخلفي كمساق فرعي ممرراً له التمثيل الوسيط.
تلطف وتسهل فكرة الطرف الجبهي والطرف الخلفي فكرة تصميم المترجم، حيث تفصل وظائف مرحلة الطرف الجبهي (التي تتركز نموذجياً حول دلالة اللغة، فحص الخطأ، ومثيلاتها) عن وظائف مرحلة الطرف الخلفي (التي تتركز على إنتاج خرج صحيح وفعال).
للطرف الخلفي فائدة أيضاً، وهي استخدام طرف خلفي وحيد من أجل لغات مصدرية متعددة إذا كان المطلوب ترجمتها إلى الهدف نفسه، وبشكل مشابه تستخدم أطراف خلفية مختلفة من أجل الترجمة إلى عدة أهداف مختلفة.
غالباً ما يتشارك الطرف الخلفي والطرف الجبهي بمدقق الخطأ والمستمثلoptimizer إذا صمما ليعملا على لغة وسيطة يمررها الطرف الجبهي إلى الطرف الخلفي. تمكن هذه التقنية (أي التوافق بين الطرفين الجبهي والخلفي) كثيراً من المترجمات من إعادة استخدام مقدار كبير من العمل الذي غالباً ما يذهب إلى محللات الرماز والمستمثلات. هنالك لغات محددة يمكن أن تترجم بمرور وحيد، وذلك طبقاً لتصميم اللغة وطبقاً لقواعد محددة موضوعة للتصريح عن المتغيرات والأغراض الأخرى المستخدمة، والتصريح المسبق عن الإجرائيات التنفيذية قبل المرجع أو الاستخدام، ولغة باسكال معروفة جيداً بهذا الإمكان، وكثير من مترجمات باسكال مكتوبة بلغة باسكال نفسها، بسبب التوصيف الصارم للغة ولتوفر إمكان استخدام مرور وحيد لترجمة برامج لغة باسكال.
الطرف الجبهي للمترجم
يتألف الطرف الجبهي للمترجم من عدة مراحل (أطوار). تحدد كل مرحلة من مراحل الطرف الجبهي بنظرية اللغات الصورية وهذه المراحل هي:
ـ مرحلة التحليل المعجمي (المفرداتي) lexical analysis: يعني التحليل المعجمي تقسيم نص الرماز المصدري إلى قطع صغيرة (علاّمات)، تمثّل كل منها وحدة جزئية مفردة من اللغة، على سبيل المثال كلمة مفتاحية keyword، معيّنidentifier أو أسماء رموز. لغة العلاّم token language هي نموذجياً لغة نظامية، حيث تبنى آلة الحالة المنتهيةfinite state machine من عبارة نظامية يمكن أن تستخدم لتعرّفها. تسمى هذه المرحلة أيضاً مرحلة المسح.
ـ مرحلة تحليل التركيب النحوي syntax analysis: يقوم التحليل النحوي بتعيين البنى الإعرابية للرماز المصدري، ويركزالضوء على البنية. بكلمات أخرى يعيّن التحليل النحوي ترتيب العلاّماتtokens ويفهم البنى التراتبية للرماز. تسمى هذه المرحلة أيضاً التحليل (بمعنى الإعراب).
ـ مرحلة تحليل الدلالةsemantic analysis : وظيفة تحليل الدلالة هي تعرف معنى رماز البرنامج والبدء بتحضير الخرج. في هذه المرحلة يتم فحص نوع المعطيات و إظهار معظم أخطاء المترجم.
ـ مرحلة توليد اللغة الوسيطة: ينتج في هذه المرحلة ما يكافئ البرنامج الأصلي باللغة الوسيطة.
الطرف الخلفي للمترجم
بينما هنالك تطبيقات تستلزم وجود الطرف الجبهي للمترجم فقط كما في أدوات التحقق السكوني من اللغة، يعالج المترجم الحقيقي التمثيل الوسيط الذي يولده الطرف الجبهي من أجل الطرف الخلفي الذي ينتج بدوره برنامجاً مكافئاً وظيفياً بلغة الخرج. يتم إنجاز هذا العمل على عدة خطوات هي:
ـ مرحلة تحليل المترجم: تتلخص هذه العملية بجمع معلومات البرنامج من التمثيل الوسيط الخاص بملفات مصدر الدخل. التحليل النموذجي هو عبارة عن سلسلة متغيرة من عمليات التعريف- الاستخدام والاستخدام- التعريف، تحليل اعتمادية المعطيات، تحليل الأسماء البديلة. التحليل الدقيق هو الأساس من أجل أي استمثالات تالية للمترجم. خلال مرحلة التحليل يتم أيضاً بناء مبيان graph الاستدعاء ومبيان انسياب التحكم.
ـ مرحلة الاستمثال: تنقل مرحلة الاستمثال التمثيل باللغة الوسيطة إلى أشكال مكافئة وظيفياً، ولكن أسرع (أو أصغر بالحجم). من الاستمثالات الشائعة التوسيع المحوري inline copy (وضع مستنسخ من متن الإجراء مكان استدعاء إجراء مستبدل في الرماز الغرضي)، إزالة الرماز الميت (إزالة الرماز الذي يمثّل تعليمات ليس لها فائدة في البرنامج)، الانتشار الثابت، نقل الحلقة، تخصيص سجل register allocation، أو حتى موازاة آليةautomatic parallelizing.
ـ مرحلة توليد الرماز: تترجم اللغة الوسيطة المنقولة إلى لغة خرج عادة ما تكون اللغة الأصلية لآلة النظام. تشمل هذه المرحلة أيضاَ اتخاذ قرارات بشأن المصدر والتخزين، مثل تحديد أي متغيرات يجب توسيعها في سجلات، وأيها يجب توسيعها في الذاكرة، اختيار وجدولة تعليمات الآلة المناسبة طبقاً لأنماط العنونة المستخدمة.
ـ التحليل (الإعراب)parsing : التحليل في علم الحاسوب هو عملية تحليل دفق مستمر من المحارف يأتي من الدخل (مثلاً مقروء من ملف أو من لوحة مفاتيح) لتحديد بنيته القواعدية مقارنة بقواعد معتمدة رسمياً، والمحللparser هو عبارة عن البرنامج الحاسوبي الذي ينفذ هذه المهمة. ويقصد هنا بالتحليل ما يقصد بالقواعد في اللسانيات. التحليل يحول نص الدخل إلى بنية معطيات، عادة ما تكون شجرية، و هي مناسبة للمعالجة اللاحقة و تدرك البنية التراتبية المتضمنة في الدخل. عموماً تعمل المحللات على مرحلتين، الأولى تعيين وتحديد العلاّمات ذات المعنى في الدخل، ثم بناء شجرة التحليل من هذه العلاّّمات.
يوضح المثال الآتي حالة عامة لتحليل لغة على مستويين من القواعد: التحليل المعجمي المفرداتي و تحليل الدلالة.
لتكن لدينا التعليمة الآتية في برنامج حاسوبي ينفذ على آلة حاسبة: ً2 ^ (4+3) * 12 ً.
المرحلة الأولى هي مرحلة توليد العلاّمات، أو مرحلة التحليل المعجمي. تقسّم هذه التعليمة في هذه المرحلة إلى العلاّماتTokens الآتية:
12،*، ( 3 ، + ، 4 )، ^، و 2.
حيث كل من هذه العلاّمات هو رمز له معنى في سياق العبارة الرياضية. سيحتوي المحلل قواعد تخبر أن الرموز (*، +، ^)، وتشير إلى بداية علاّم جديد. أما العلاّمات التي ليس لها معنى مثل ( ً * 12 ً أو ً 3) ً فلن يتم توليدها.
المرحلة التالية هي تحليل التركيب النحوي، وتقوم بالتأكد من أن العلاّمات تشكل عبارات صحيحة ومسموحة. تتم هذه العملية بالرجوع إلى قواعد النحو غير المعتمدة على السياقcontext-free grammar التي تعرّف بدورها مكونات تشكل عبارة وتحدد الترتيب الذي سوف تظهر فيه هذه المكونات (العلاّمات) في هذه العبارة.
المرحلة الأخيرة هي مرحلة تحليل الدلالة و تستنبط فيها المضامين من العبارة التي تم تدقيق صلاحيتها ثم ينفذ الفعل المناسب، والفعل المطلوب في حالة الآلة الحاسبة هو تقييم العبارة الحسابية المعطاة. من ناحية ثانية سيقوم المترجم في هذه المرحلة أيضاً بتوليد لغة الآلة التي سينفذها المعالج لتحقيق الوظيفة المنصوص عنها بالرماز.
أنواع المحلّلات
مما سبق يتلخص عمل المحلل بتحليل دفق مستمر من المحارف، يمثّل تعليمات من برنامج ما مكتوبة بلغة مصدرية؛ لتحديد بنيتها القواعدية مقارنة بقواعد معتمدة مسبقاًً.
تقسم المحلّلات طبقاً لطريقة عملها إلى نوعين:
ـ تحليل من الأعلى إلى الأسفل top-down parsing: يبدأ المحلل في هذا النوع من المحللات ببناء شجرة التحليل بأكبر العناصر و يقسمه إلى أجزاء أصغر، و منها إلى أجزاء أصغر على نحو متزايد وهكذا. ومن ثمّ يتم تشكيل شجرة التحليل في هذه الحالة بداية من أكبر العناصر ثم تقسمها إلى أجزاء أصغر فأصغر.
ـ تحليل من الأسفل إلى الأعلىbottom-up parsing : يبدأ المحلل ببناء شجرة التحليل بدءاً من العناصر الأكثر أساسية، ثم العناصر التي تحتوي العناصر السابقة وهكذا. ومن ثمَّ يتم تشكيل شجرة التحليل بداية من أكثر العناصر صغراً، ثم العناصر الأكبر منها التي تحتويها وهكذا.
عاكس الترجمة decompiler
عاكس الترجمة، هو برنامج حاسوبي يترجم البرامج القابلة للتنفيذ (التي هي خرج المترجم) إلى ما يكافئها بلغة عالية المستوى (رماز مصدري)، وهذا بالضبط عكس عمل المترجم، لكن عاكس الترجمة العام لا ينفذ بالضبط عكس خطوات الترجمة التي يقوم بها مترجم محدد. بالمقارنة يترجم عاكس التجميع برنامجاً قابلاً للتنفيذ إلى لغة تجميع.
يمكن أن يستخدم عاكس الترجمة لاستعادة الرماز المصدري المفقود، وهو مفيد أيضاً في بعض الحالات مثل أمن الحاسوب، التشغيلية البينية interoperability (أي إن هذه البرامج يمكنها التشارك بالموارد والمعطيات)، تصحيح الخطأ وغيرها. يزداد نجاح عملية عكس الترجمة إذا كان البرنامج القابل للتنفيذ مترجماً من أجل آلة افتراضية (مثلاً ملف رماز ثماني bytecode ناتج من ترجمة برنامج مكتوب بلغة جافا) وذلك بسبب احتواء الملف الاثناني للآلة الافتراضية على معلومات إضافية. كما يمكن تحسين النتائج إذا امتلك عاكس الترجمة نقاط دخول المكتبات ومكتبات الربط الديناميكي. إن عكس ترجمة برامج رماز آلة أكثر صعوبة، وكنتيجة عواكس ترجمة رماز الآلة أقل شيوعاً وأقل نجاحاً.
مقارنة بين اللغات المترجمة واللغات المفسرة
يقسم كثير من الناس لغات البرمجة عالية المستوى إلى لغات مترجمة و لغات مفسرة. إن المترجمات والمفسرات هي أشكال لتحقيق اللغات، وليست لغات بحد ذاتها، ونادراً ما يوجد ما يستلزم أن تكون اللغة مترجمة أو مفسرة. أما تصنيف اللغة كمترجمة أو مفسرة فهو يُظهر عادة أكثر التحقيقات للغة ما شيوعاً وانتشاراً، فلغة بيسك Basic هي لغة مفسرة، ولغة سي C مترجمة، على الرغم من وجود مترجمات للغة بيسك ومفسرات للغة سي. هنالك استثناءات حيث تفترض بعض توصيفات اللغة استخدام مترجم كما هي الحال في لغة سي، أو يبين توصيف اللغة بغير لبس أن تحقيقات اللغة يجب أن تتضمن تسهيلاً ما لعملية الترجمة كما هي الحال في لغة ليسب الشائعة؛ من جهة أخرى تحتوي بعض اللغات خصائص يمكن تحقيقها بسهولة كبيرة في المفسر، وتجعل كتابة المترجم أكثر صعوبة (مثال ذلك هو إمكان تنفيذ رماز مصدري ما موجود في شريط محارف يعطى في أثناء تنفيذ البرنامج).
كمال قمر