كلمه مترجم من الكلمات التي نسمعها كثيرا في عالم البرمجة ، خصوصاً عندما نكتب برنامج بأي لغه كجافا أو سي++ أو باسكال . لكن للأسف يخطئ البعض ويظن أن المترجم مهمته التبليغ الخطأ ، وأننا نترجم البرنامج لكي نعرف هل يوجد به أخطاء أم لا . إضافه إلى وجود خلل في مفاهيم الترجمة والربط ، فالبعض قد لا يفرق كثيراً بينهم ، وقد لا يعرف أهميه وجود الرابط Linker من أساسه … لذلك كتب هذا المقال لكي يعرف المبرمجين الجدد بأهميه المترجم Compiler وبعض مهامه الأساسيه اضافه الى بضعه أمور أخرى وجب معرفتها حتى تتشرب مفهوم البرمجه بشكل صحيح وبدون خلل . فالنهايه الصحيحه تأتي تبعا للبدايه الصحيحه بالطبع .

 
المترجم هو :

محول من لغة لأخرى ، فاذا كان لدينا شخص عربي يتحدث باللغة العربيه فقط ، ولدينا شخص من اليابان ينطق باللغه اليابانيه فقط ، وأراد أن يتحادثا مع بعضهما فبالتأكيد سوف يحتاج هذين الشخصين على مترجم يحول من اللغة العربيه إلى اليابانية والعكس أيضاً .

التعريف السابق بنفس الشكل والصوره هو الذي يحدث في عالم البرمجه ، فجميعنا نعرف أن الحاسب (المعالج والذاكره) لا يتعاملان إلا مع الأرقام الثنائيه 0 و 1 (سيران تيار أو عدم سيرانه) ، لذلك أي برنامج نكتبه يجب أن يتحول إلى هذه اللغة ( لغه الآلة Machine Langauge ) ، وهو بالضبط وظفيه المترجم ، التحويل من لغة إلى لغة أخرى (قد تكون لغة الآلة أو لغة أخرى على حسب نوع المترجم والغرض المصمم من أجله) .

 

إلى الآن ، هذا المفهوم يعرفه أغلب المبرمجين ، حتى الجدد منهم ، وهو مهمه التحويل (الصندوق الأسود) الذي يبينه الشكل التالي :

 


 

فموضوعنا الآن هو كشف الستار وإزالة اللون الأسود من الصندوق ونعرف مالذي يجري بالضبط من خلف الكواليس .

 

قبل أن نبدأ وندخل في التفاصيل ، يجب أن نسأل لماذا نحتاج إلى مترجم ؟ وهل يمكن الاستغناء عنه ؟ “أسئله مهمه” .. ولكي نجيب على هذه الأسئله علينا أن نعود الى بدايات عصر البرمجة ، حيث لم يكن هناك شيئ يسمى لغة برمجة بالشكل المعروف ، وكانت البرمجة عبارة عن تشغيل مفاتيح واغلاقها في أجهزه ضخمة للغاية ، مروراً بالبطاقات المثقبة التي كان يتم ادخالها للتلك الأجهزة الضخمة، حتى جاء عصر الترانزستور وبعدها الدارات المتكامله IC والتي تحتوي على ملايين الترانزستورات ، ومن هنا كانت ولادة ال Microprocessor أو ما يعرف الآن بالمعالج ، الذي أصبحنا نراه في كل جهاز ، غسالة ، لعبة أطفال ، وجميع الأجهزة الأخرى ..

 
فالمعالج يحتوي على أمور كثيره أهمها هي وحدة الحساب والمنطق وهي المسؤولة عن تنفيذ جميع العمليات الحسابية والمنطقية ، ونستطيع إعطاء هذا المعالج أوامر بتنفيذ أي مهام نريدها وذلك بواسطه لغة يفهمها هذا المعالج . فمثلاً لو ذكرنا له 001 0101 101 فمعناه أجمع على محتويات المسجل الفلاني القيمه الفلانية .. ومن هنا كانت لغة الآلة هي اللغة الوحيدة التي يمكن أن نكتب بها برنامجاً يقوم المعالج بتنفيذه . (البرامج في بداية ذلك الوقت ، كانت جميعها تنصب في العمليات الحسابية ، وحساب المثلثات والدوال الرياضية مثل الجيب جيب التمام وما إلى ذلك ) .

 

بعد ذلك بدأت بضعة شركات مثل أنتل وموتورلا بإنتاج المعالجات الخاصة بها ، وبالطبع لكل معالج تعلميات Instruction Set تحتلف عن الآخر، كما أن تركيب المعالج من الداخل وعدد المسجلات وطريقة العمل تختلف من معالج لآخر .. في البداية أول معالج ظهر 4004 يتعامل مع 4 بت (ال ALU يتعامل مع 4 بت ، وحجم ال Data Bus 4 -Bit ) . وبعدها وفي زمن قياسي بدأ العصر الثاني للمعالجات 8085 Intel ، و Intel 8086 ولم تتعدى 5 سنوات وظهر الثالث وحالياً نحن في الجيل الخامس للمعالجات ..

بدأ المبرمجين بعدها بالاستفادة من قدرات هذه المعالجات وبدأوا بكتابة البرامج (أغلبها رياضية وحسابية كما ذكرت) ولكن سرعان ما بدأت المشاكل بالظهور ، فالمبرمج لم يستطيع حفظ مجموعة صماء من الأرقام (التعليمات) ،إضافه في حال أراد أن يعدل على برنامج كتبه أو يضيف أمور أخرى Maintenance فهذه الأمور أصبحت كابوس nightmere لمبرمجي لغة الآلة وخاصة الجدد منهم !

 
ومن هنا بدأ ظهور الأسبملي (لاحظ أن دائما الظهور في عالم البرمجة ، يكون نتيجة لمشكلة ما ، فلا توجد فائدة في حال ظهرت لغة أخرى واللغة الحالية تفي بالغرض ولا تأخذ منا شيئا) .

 

الأسمبلي هي عباره عن Mnimonic رموز للغة الآلة ، فبدلاً أن يقوم المبرمج بكتابة تلك الأرقام الطويلة والعريضة ، يقوم بكتابة رموز مثلا MOVE للدلاله على هذه الأرقام ، وبعدها باستخدام برنامج مخصص يسمى Assembler يقوم بتحويل هذه الرموز إلى لغة الآلة حتى تعمل على المعالج المعين وننفذ البرنامج .

 

ومن هنا كانت ولادة مفهوم التحويل أو الترجمة في عالم البرمجة ، وبدأ المبرمجين بالارتياح في التعامل مع البرمجة بلغة الأسبملي ، فبدل أن كانوا يتعاملوا مع لغة الآلة الصماء لمعالجات Motorola ، الآن يستطيعوا استخدام لغة الأسمبلي الخاصة بمعالجات Motorola وهي فقط لا تتعدى 70 تعليمه (في بدايات ظهور المعالج ، ومع كل جيل جديد تتولد العديد من التعليمات أيضا) ، إضافه على ذلك وهو الأهم أن البرمج لن يهتم بالعنوان الفلاني في الذاكرة الذي يحفظ في قيمة ما ، فقط سوف يتذكر اسم متغير Variable ويتولى الأسمبلر مهمه تحويل المتغير إلى عنوان “قابل للتعديل Relocatble” ماذا تعنى الجمله الأخيرة؟  لا عليك منها الآن ، سوف نتعرف عليها بعد قليل .

 

إذاً مهمه ال Assembler تحويل الكود من لغة الأسمبلي إلى لغة الآلة ، تحويل المتغيرات إلى عنواين قابلة للتعديل من قبل الرابط ، أيضاً سوف يقوم الأسمبلر بتحويل أي Label إلى عنوان بالنيابة عنك ،إضافة اإى تجاهل التعليقات Comments التي تكتبها في برنامجك (والتي هي ضرورية لفهم عمل البرنامج خصوصاً في البرامج الكبيرة ) .
 
ومع تطور قدرات المعالج من 4 بت الى 8 الى 16 بت ، تغيرت متطلبات البرمجة أيضاً ، فبدلاً من أن تكون مجرد إجراء عمليات حسابية ، أصبحت هناك متطلبات أخرى كبرامج لمعالجة النصوص ، برامج لتخزين البيانات ، ألعاب بسيطة للترفيه ، أصبحت الخوارزميات أكثر تعقيدا ًويصعب كتابتها بلغة الآلة .. ومن هنا كانت لغة الأسمبلي أيضا كابوس لكتابة أحد هذه البرامج خصوصاً عند صيانة البرامج ..

 

كنتيجة لهذا الأمر احتاج المبرمجين إلى لغة أكثر سهولة في وصف البرنامج وأقرب إلى لغة الإنسان حتى يتم تطبيق الخوارزميات المعقدة بأسهل أسلوب ، ومن هنا ظهرت أول لغة برمجة من هذا النوع “عالية المستوى High Level” وهي اللغة فورتران وبعدها تبعتها بقية اللغات مثل Basic ، وباسكال وسي ، وكل من هذه اللغات كان لها سبب ما في ظهورها ، فمنها ما كان كتطبيق لمنهج Paradigms مختلف في البرمجة مثل OO ، أو كان نتيجة لعيب في اللغة السابقة ، أو كان سبب تعليمي بحت .

 
الآن لكي نقوم بتنفيذ برنامج مكتوب بلغة عالية المستوى في معالج معين ، نحتاج إلى أن نحوله Compile it إلى لغة الآلة مباشره ، أو إلى لغة الأسمبلي للمعالج المعين ، وبعدها نستخدم Assembler لكي نحول من الأسمبلي إلى لغة الآلة .

 
تميزت اللغات عالية المستوى HLL بالسهوله في الكتابة وفي الصيانة أيضاً ، حيث يمكن أن أنفذ مهمة كتبت في لغة الأسمبلي بعشرة أسطر بسطرين في اللغه HL .
لكن بالطبع، الكود الناتج سيكون أطول في حالة أستخدمنا اللغة HL ، حيث أن كل سطر بالأسمبلي سيتحول إلى سطر آخر في لغة الآلة (أي تعليمة تتحول إلى تعلمية واحدة فقط) لكن في حالة HLL أي تعليمة سوف تتحول إلى عدة تعليمات قد تصل إلى 7 أو 10 تعليمات .
لو نظرنا قليلاً فسوف ندرك ميزة نادرة في اللغات HLL ، حيث سنجد أنها تعمل على أي معالج بشرط توفر مترجم لهذه اللغة Compiler ، فإذا قمنا بكتابة برنامج بلغة السي يعمل تحت معالجات أنتل ، فسوف يعمل هذا البرنامج في معالجات موتورلا عندما نجد مترجم للغة سي تعمل على هذا النوع من المعالجات . هذه الميزه تسمى Portability ويترجمها البعض بالمحمولية.

 

باختصار ، البرنامج سوف يترجم في أي معالج بشرط أن يحتوي على مترجم لهذه اللغة . حسناً جميل للغاية ، إذاً سوف نقوم بتكملة الجملة السابقة ونقول بأن الناتج من البرنامج سوف يعمل مباشرة (بدون ترجمة البرنامج) على أي معالج من نفس نوع المعالج الأول .

الكلام “قد” يكون صحيح في حالات وحالات أخرى لا ، والسبب هنا هو نظام التشغيل Operating System .

مثال بسيط ، أكتب برنامج بلغة السي أو أي لغة HLL في نظام Windows ، وترجم البرنامج وخذ الناتج ملف exe في أي نظام ويندوز أخر يعمل بنغس معالج النظام الأول ، وسوف يعمل ملف exe مباشره بدون ترجمة الملف الأصلي … لكن خذ مثلاً هذا الملف واذهب به إلى أي نظام تشغيل آخر ، ولن يعمل بالطبع . السبب في هذا الأمر هو تعليمات اللغة في الأصل وخاصة الإدخال والإخراج تعتمد على نظام التشغيل ، فمثلاً printf في ويندوز قد تقوم بمناداة دوال في النظام System Call تختلف بالطبع عن الدوال في نظام آخر .

إذاً لغات ال HLL تتميز بالسهولة Simplicity و Portability و Readablity أيضاً فالبرنامج المكتوب بها يكون أكثر مقروئية من المكتوب بلغة الأسمبلي أو الآلة . ولكنه بالطبع أكبر حجماً وأقل كفائه effecincy !

 

نعود إلى الإجابة للسؤال السابق : “هل نستطيع الاستنغناء عن المترجم” ؟
نعم ، إذا كنت تستطيع كتابة برامجك بلغة الأسمبلي.
نعم ، إذا كنت تستطيع تعديل أنظمة متقدمة كتبت بلغة الأسمبلي .
نعم ، إذا كنت تستطيع كتابة ملاييييييين الأسطر من الشفرة ، وتستطيع تعديل أي منها في ثواني ، وقراءتها وفهمها في ثواني !!!
لا ، غير ذلك ..

 
بعدما عرفنا فائدة المترجم الموجود في الصندوق الأسود ، وعرفنا أننا لن نستغني عنه أبدا ، دعنا الآن نحاول معرفة ما يجري في الداخل بشكل جدي أكثر ،

نعود لصديقنا المترجم بين أخينا العربي والأخ الياباني ، فحتى يقوم بالترجمة بشكل صحيح ، عليه أن يفهم مالذي يقوله الشخص الأول (تحليل للكلام) ومن ثم يقوم بترجمة ما فهمه إلى الشخص الثاني (توليد الكلام ) .

 
بنفس الأمر في المترجم ، يجب أن يحلل النص أولاً في مرحلة يمكن أن نطلق عليها إجمالا ب Analysis Phases بعدها يقوم يتحويل اللغة الجديدة المراد الوصول إليها وهي مرحلة Sysntheses Phases (التوليد) . ها هو صندوقنا الأسود بدأ بالأنكشاف ..

 
الآن لماذا يحلل المترجم وبعدها يبدأ بالتوليد ؟ هنا الجواب هنا للتأكد من أن البرنامج صحيح وموافق تماماً للقواعد في اللغة . فاذا كان هناك خطأ ما في هذه المرحلة سيتوقف من العمل ، وسيخبرك بمكان هذا الخطأ (في الأخطاء النحوية -قواعدية- Syntax Error سوف يتوقف المترجم مباشره عن العمل ، أما في الأخطاء الأخرى لن يتوقف عن العمل وسيكمل مرحلة تحليله واكتشاف باقي الأخطاء ، طبعا هذا ما يعرف ب Error Recovery .

هكذا تكون مرحلة التحليل Analysis تتكون من عدة مراحل ، كل واحدة لها دور معين وهي :

 
Lexical Analysis
Sytanx Analysis
Semantic Analysis
Inermedaite Code Generation

 
أما مرحله التوليد ، فهي توليد الكود الهدف Target Code بعدما تأكدنا تماما من خلو البرنامج من الأخطاء ، وهي تتكون من :

 
Code Optimization -قد يحتوي المترجم على محسن أو قد لا يحتوي-
Code Generation

مرحلة التحليل لسيت خاصة فقط بإنتاج مترجمات ، هناك العديد من التطبيقات تتطلب عملية تحليل Analysis للكود ، مثلاً برنامج يقوم بعمل معالجة معينة للكود ، أو برنامج يقوم بتلوين كلمات معينة في النص Syntax Highleight ، أو حتى المفسر Interpreter يقوم بعملية تحليل للنص لكي يقوم تنفيذه مباشره ..

 
المراحل السابقة كما ذكرت هي فقط Model بسيط لعلمية الترجمة ، لكن هناك مرحلة أخرى “مهمه” للغاية مثل التعامل مع جدول يسمى جدول الرموز Symbol Table و مرحلة التعامل مع الأخطاء error Handling .

 
دعنا الآن نكشف الستار عن الصندوق الأسود ، لكي نرى مكان جميع هذه المراحل بالضبط ، وتبقى كل مرحلة من هذه المراحل هي صندوق أسود بحد ذاتها ، حيث أن اسم المرحلة يوضح عملها ، لكن بالطبع ما يجري بالخلف قد يكون مختلف كثيرا عن ما تتصوره :

 

 
ملاحظه أخيره /
الصورة السابقة توضح المراحل التي يعمل عليها المترجم بشكل عام ، وفي التطبيق الفعلي للمترجم ، قد يحتوي مراحل بنفس الشكل أو يدمج بعض من المراحل في مرحلة واحدة . إذاً الصورة السابقة هي Abstract للعملية وليست واجب .