المشروع 8: الآلة الافتراضية II: التحكم في البرنامج
المشروع 8: الآلة الافتراضية II - التحكم في البرنامج
خلفية
نواصل بناء مُترجِم VM - وهو برنامج يترجم البرامج المكتوبة بلغة VM إلى برامج مكتوبة بلغة آلة Hack. وهذه قطعة هندسية محترمة، لذا نؤدّيها على مرحلتَين. مرحبًا بك في المرحلة الثانية.
الهدف
وسّع المترجم الأساسي المبني في المشروع 7 ليصبح مترجم VM متكاملًا. فعلى وجه الخصوص، في المشروع 7 ركّزنا على التعامل مع أوامر الحساب على المكدس والوصول إلى الذاكرة في لغة VM. وننتقل الآن إلى التعامل مع أوامر التفريع واستدعاء الدوال في لغة VM.
العقد
اكتب مترجمًا متكاملًا من VM إلى Hack، موسّعًا للمترجم الأساسي المطوَّر في المشروع 7، ومطابقًا لمواصفة VM الجزء الثاني (قسم 8.2 من الكتاب) ولتعيين VM القياسي على Hack الجزء الثاني (قسم 8.3.1 من الكتاب). واستخدم مترجمك لترجمة برامج VM المرفقة أدناه، منتِجًا برامج مقابلة مكتوبة بلغة التجميع Hack. وعند تشغيلها على محاكي CPU المرفق، يجب أن تُنتِج الشيفرة المترجمة التي يولّدها مترجمك النتائج المطلوبة في سكربتات الاختبار وملفات المقارنة المرفقة أدناه.
لاحِظ أن برنامج الآلة الافتراضية قد يمتد إمّا على ملف .vm واحد أو على مجلد يحتوي على ملف .vm واحد أو أكثر. وفي الحالة الأولى، يُستدعى المترجم بالأمر VMTranslator fileName.vm. ويُنشئ المترجم ملف إخراج باسم fileName.asm، يُخزَّن في نفس مجلد الملف المدخل. وفي الحالة الثانية، يُستدعى المترجم بالأمر VMTranslator dirName. ويُنشئ المترجم ملف إخراج وحيدًا باسم dirName.asm، يُخزَّن في المجلد نفسه. ويحتوي هذا الملف الواحد على شيفرة التجميع الناتجة عن ترجمة كل ملفات .vm في المجلد المدخل. وقد يحتوي اسم الملف أو المجلد المدخل على مسار. فإن لم يُحدَّد مسار، يعمل المترجم على المجلد الحالي افتراضيًّا.
الموارد
القراءة ذات الصلة بهذا المشروع هي الفصل 8. وستحتاج إلى أداتَين: لغة البرمجة التي ستُنفِّذ بها مترجم VM، ومحاكي CPU المرفق. ويتيح هذا المحاكي تنفيذ واختبار شيفرة الآلة التي يولّدها مترجم VM على حاسوبك. وأداة أخرى تأتي في متناول اليد في هذا المشروع هي محاكي VM المرفق. ويتيح محاكي VM (الموصوف أسفل هذه الصفحة) التجريب مع برامج VM المرفقة قبل الشروع في كتابة مترجمك.
الاختبار
نوصي بإكمال تنفيذ مترجم VM على مرحلتَين. أولًا، نَفِّذ واختَر ترجمة أوامر التفريع في لغة VM. ثم نَفِّذ واختَر ترجمة أوامر استدعاء الدوال والإرجاع. وسيتيح لك ذلك اختبار تنفيذك تدريجيًّا، باستخدام برامج الاختبار المرفقة أدناه.
اختبار كيفية تعامُل مُترجِم VM مع أوامر التفريع:
| البرنامج | الوصف | سكربتات الاختبار |
|---|---|---|
| BasicLoop.vm | يحسب المجموع 1+2+...+ n ويدفع الناتج إلى المكدس. وهو يختبر تنفيذ أمرَي التفريع goto و if-goto في لغة VM. | BasicLoopVME.tst BasicLoop.tst BasicLoop.cmp |
| FibonacciSeries.vm | يحسب أول n عناصر من متسلسلة فيبوناتشي ويخزّنها في الذاكرة. وهذا البرنامج النموذجي لمعالجة المصفوفات يمثّل اختبارًا أكثر تحديًّا لأوامر التفريع في VM. | FibonacciSeriesVME.tst FibonacciSeries.tstFibonacciSeries.cmp |
اختبار كيفية تعامُل مُترجِم VM مع أوامر استدعاء الدوال والإرجاع:
| البرنامج | الوصف |
|---|---|
| SimpleFunction.vm | يؤدّي عملية حساب بسيطة ويعيد النتيجة. ويوفّر هذا البرنامج اختبارًا أساسيًّا لتنفيذ أمرَي function و return في VM. |
| NestedCall: Sys.vm اختبار اختياري ومتوسط، قد يكون مفيدًا عندما ينجح SimpleFunction (الاختبار السابق) ويفشل FibonacciElement (الاختبار التالي). | يختبر عدة متطلبات من بروتوكول استدعاء الدوال. لمزيد من المعلومات حول هذا الاختبار الاختياري، انظر هذا الدليل وهذا الرسم التوضيحي للمكدس. ويمكن استخدامه مع شيفرة تهيئة VM أو بدونها. |
| سكربتات الاختبار | البرنامج | الوصف |
|---|---|---|
| SimpleFunctionVME.tst SimpleFunction.tstSimpleFunction.cmp | FibonacciElement: Main.vm Sys.vm تكوّن البرنامج من أكثر من ملف .vm، يجب ترجمة المجلد بأكمله. وينبغي أن تُنتِج الترجمة ملف تجميع وحيدًا باسم FibonacciElement.asm. انظر الملاحظة أدناه لمزيد من المعلومات حول التعامل مع ملفات .vm المتعددة. | يختبر التعامل مع أوامر استدعاء الدوال في VM، وقسم التهيئة (bootstrap)، ومعظم أوامر VM الأخرى. ويتكوّن مجلد البرنامج من ملفَّين كالآتي: يحتوي Main.vm على دالّة واحدة تُسمّى Main.fibonacci. وهذه الدالّة العودية تعيد العنصر رقم n من متسلسلة فيبوناتشي، وهي غير متعلّقة ببرنامج متسلسلة فيبوناتشي الموصوف سابقًا في هذا المشروع. ويحتوي Sys.vm على دالّة وحيدة تُسمّى Sys.init. وهي تستدعي Main.fibonacci بالقيمة n=4، ثم تدور إلى ما لا نهاية (ودالّة Sys.init نفسها ستُستدعى من شيفرة التهيئة التي تولّدها تنفيذات VM). |
| NestedCallVME.tst NestedCall.tst NestedCall.cmp | StaticsTest: Class1.vm Class2.vm Sys.vm | تحتوي Class1.vm و Class2.vm على دوال VM مصمَّمة لضبط قيم static متنوعة وقراءتها؛ وذلك لاختبار التعامل مع مقطع الذاكرة static. ويحتوي Sys.vm على دالّة Sys.init وحيدة تستدعي دوال get/set من Class1 و Class2 |
| FibonacciElementVME.tst FibonacciElement.tst FibonacciElement.cmp بخلاف الاختبارات السابقة، يفترض هذا الاختبار أن المترجم يهيّئ تنفيذ VM. فإن لم تبدأ شيفرة التجميع المولَّدة بشيفرة التهيئة (bootstrap)، فسيفشل الاختبار. | ||
| StaticsTestVME.tst StaticsTest.tst StaticsTest.cmp يفترض هذا الاختبار أن المترجم يهيّئ تنفيذ VM؛ فإن لم تبدأ شيفرة التجميع المولَّدة بشيفرة التهيئة (bootstrap)، فسيفشل الاختبار. |
التنفيذ المقترح
لكل واحد من برامج الاختبار الخمسة، اتّبع الخطوات التالية:
-
للتعرّف على السلوك المقصود لبرنامج الاختبار Xxx.vm المرفق، شغّله على محاكي VM المرفق باستخدام سكربت XxxVME.tst (فإن تكوّن البرنامج من ملف واحد أو أكثر موجودة في مجلد، فحمّل المجلد بأكمله إلى محاكي VM ونفّذ الشيفرة).
-
استخدم مترجم VM لترجمة ملف Xxx.vm المرفق، أو المجلد، حسب الحاجة. ويجب أن تكون النتيجة ملفًا نصّيًا جديدًا يحتوي على شيفرة تجميع Hack. ويجب أن يكون اسم هذا الملف Xxx.asm.
-
افحص برنامج Xxx.asm المترجَم. فإن ظهرت أخطاء في الصياغة (أو أي أخطاء أخرى)، نقِّح وأصلح مترجم VM.
-
وللتحقق من أداء الشيفرة المترجَمة بشكل سليم، استخدم ملفَّي Xxx.tst و Xxx.cmp المرفقَين لتشغيل برنامج Xxx.asm المترجَم على محاكي CPU المرفق. فإن ظهرت أي مشاكل، نقِّح وأصلح مترجم VM.
واجهة برمجة التطبيقات (API): يتضمّن الفصل 8 واجهة برمجة تطبيقات مقترحة ومستقلّة عن اللغة لمترجم VM. ويمكن أن تكون هذه الواجهة مخططًا لتنفيذك.
ترتيب التنفيذ: خُطِّطت برامج الاختبار المرفقة بعناية لاختبار الميزات التدريجية التي تُدخِلها كل مرحلة في تنفيذ VM خاصتك. لذا من المهم تنفيذ المترجم بالترتيب المقترح، واختباره باستخدام برامج الاختبار المرفقة في كل مرحلة. وقد يُسبّب تنفيذ مرحلة لاحقة قبل مرحلة سابقة فشل برامج الاختبار.
التهيئة: لكي تُنفَّذ شيفرة VM المترجمة على منصة الحاسوب المضيف، يجب أن يتضمّن تدفّق الشيفرة المترجمة (المكتوب بلغة آلة المنصة المضيفة) بعض شيفرة التهيئة (bootstrap) التي تُخطِّط المكدس على ذاكرة الحاسوب المضيف وتبدأ تنفيذ الشيفرة الفعلية. وتفترض برامج الاختبار الثلاثة الأولى في هذا المشروع أن شيفرة التهيئة لم تُنفَّذ بعد، وتتضمّن سكربتات اختبار تؤدّي التهيئات اللازمة (كما في المشروع 7). أما برنامجا الاختبار الأخيران فتفترض أن شيفرة التهيئة يولّدها المترجم. وبعبارة أخرى، يجب أن تبدأ الشيفرة التي يولّدها الإصدار النهائي من مترجِم VM بشيفرة تضبط مؤشّر المكدس وتستدعي دالّة Sys.init. ثم تستدعي Sys.init دالّة Main.main، ويبدأ البرنامج بالعمل (كما تفعل JVM في Java دائمًا، إذ تبحث عن main وتبدأ تنفيذها).
الأدوات
قبل الشروع في توسيع مترجم VM الأساسي، نوصي باللعب مع برامج الاختبار .vm المرفقة. وسيتيح لك ذلك التجريب مع أوامر التفريع واستدعاء الدوال والإرجاع، باستخدام محاكي VM المرفق.
محاكي VM: هذا البرنامج المكتوب بلغة Java، الذي يجب أن يكون في مجلد nand2tetris/tools خاصتك، مصمَّم لتنفيذ برامج VM بطريقة مباشرة ومرئية، دون الحاجة إلى ترجمتها أولًا إلى لغة الآلة. فعلى سبيل المثال، يمكنك استخدام محاكي VM المرفق لترى - حرفيًّا - كيف تستدعي دالّة أخرى، وكيف تؤدّي الدالّة المستدعاة عملها وتعيد قيمة إلى المستدعي. ولمزيد من المعلومات، انظر درس محاكي VM (PPT، PDF)
إليك صورة شاشة نموذجية لمحاكي VM أثناء العمل:
