المشروع 10: المصرِّف I: التحليل الصياغيّ
المشروع 10: مصرِّف I - التحليل الصياغيّ
خلفية
مصرِّف Jack، مثل تلك الخاصة بلغتَي Java وC#، ذو طبقتين: تُرجم الواجهة الأمامية للمصرِّف من اللغة عالية المستوى إلى لغة VM وسيطة؛ وتُترجم الواجهة الخلفية للمصرِّف بدورها من لغة VM إلى الشيفرة الأصلية للمنصة المضيفة. في المشروعين 7 و8 بنينا الواجهة الخلفية للمصرِّف (مترجم VM)؛ وننتقل الآن إلى بناء الواجهة الأمامية للمصرِّف. وسيمتد هذا التطوير على مشروعين: التحليل الصياغيّ (هذا المشروع)، وتوليد الشيفرة (المشروع التالي). مرحبًا بك في التحليل الصياغيّ.
الهدف
نبني في هذا المشروع مُحَلِّلًا صياغيًا يفكّك برامج Jack وفقًا لقواعد Jack النحوية، منتجًا ملف XML يظهر بنية البرنامج باستخدام نص مُوسَّم بعلامات. وفي المشروع التالي، ستتحوّل المنطق الذي يولّد خرج XML إلى منطق يولّد شيفرة VM.
العقد
اكتب مُحَلِّلًا صياغيًا للغة Jack. واستخدمه لفكّك جميع ملفات أصناف .jack المرفقة أدناه. وبالنسبة لكل ملف .jack مُدخل، يجب أن يولّد مُحَلِّلك ملف خرج .xml. ويجب أن تكون الملفات المولّدة مطابقة لملفات المقارنة المرفقة، باستثناء المسافات البيضاء.
الموارد
القراءة ذات الصلة بهذا المشروع هي الفصل 10 من الكتاب. وستحتاج إلى أداتين: لغة البرمجة التي ستُنفّذ بها مُحَلِّلك الصياغيّ، وأداة TextComparer المرفقة، المتوفرة في مجلد nand2tetris/tools خاصتك. وسيساعدك هذا البرنامج على مقارنة ملفات الخرج التي يولّدها مُحَلِّلك الصياغيّ بملفات المقارنة التي نرفقها. وقد ترغب أيضًا في فحص ملفات الخرج المولّدة والمرفقة بصريًا، باستخدام عارض XML ما. ولعمل ذلك، ما عليك سوى تحميل هذه الملفات في متصفّح ويب أو محرّر نصوص. وبعض هذه الأدوات، مثل Chrome، مصمّم لعرض نص XML بشكل جميل، فجرّبه. وجميع الملفات الضرورية لهذا المشروع متوفرة في nand2tetris/projects/10 على حاسوبك.
التنفيذ المقترح
يتضمّن الفصل 10 واجهة برمجة تطبيقات (API) مقترحة لمُحَلِّل صياغيّ مستقلة عن اللغة، يمكن أن تكون بمثابة مخطط لتنفيذك. ونقترح تنفيذ المُحَلِّل الصياغيّ في مرحلتين. أولًا، اكتب وحدة Tokenizer واختبرها. ثم اكتب وحدة CompilationEngine واختبرها، وهي تُنفّذ المُحَلِّل النحويّ الموصوف في الفصل.
المرحلة الأولى: Tokenizer
إنّ المعجمنة، وهي خدمة أساسية لأي مُحَلِّل صياغيّ، تتمثّل في تقسيم مُدخل نصّي معطى إلى تدفّق من الـ tokens. وأثناء قيامها بذلك، يمكن للمُحَلِّل المعجمي أيضًا تصنيف الـ tokens إلى فئات معجمية. ومع وضع ذلك في الحسبان، فإن مهمّتك الأولى هي تنفيذ واختبار وحدة JackTokenizer المحدّدة في الفصل 10. وتحديدًا، عليك تطوير (i) تنفيذ Tokenizer، و(ii) برنامج اختبار يمرّ بملف مُدخل معطى (ملف .jack) وينتج تدفّقًا من الـ tokens باستخدام تنفيذ Tokenizer خاصتك. ويجب طبع كل token في سطر منفصل، مع تصنيفه: رمز، أو كلمة مفتاحية، أو مُعرّف، أو ثابت صحيح، أو ثابت نصّي. وإليك مثالًا:
| شيفرة المصدر (مُدخل) | خرج Tokenizer |
|---|---|
| if (x < 0) { let state = "negative"; } |
ولاحظ أنه في حالة الثوابت النصية، يستبعد المُحَلِّل المعجمي علامتَي التنصيص المزدوجتين. وهذا السلوك مقصود، وهو جزء من مواصفة المُحَلِّل المعجمي خاصتنا.
ولاحظ أيضًا أن أربعة من الرموز المستخدمة في لغة Jack (<, >, "، و&) تُستخدم أيضًا في وسم XML، وبالتالي لا يمكن أن تظهر حرفيًا كبيانات XML. ولحلّ المشكلة، ووفقًا للعُرف، نطلب من المُحَلِّل المعجمي إخراج هذه الرموز على الشكل <, >, "، و& على الترتيب. فمثلًا، حتى يظهر الرمز "less than" كما ينبغي في متصفّح ويب، يجب توليده على الشكل "
وأخيرًا، لاحظ أنه على خلاف وحدة Tokenizer، فإن برنامج اختبار المُحَلِّل المعجمي الذي عليك كتابته ليس جزءًا من المُحَلِّل الصياغيّ. ويمثّل هذا البرنامج الاختباري مرحلة اختبار وسيطة، تركّز على الاختبار الوحدوي لـ Tokenizer فقط. وبمجرد إتمام هذا الاختبار بنجاح، لم يعُد برنامج الاختبار ضروريًا.
المرحلة الثانية: المُحَلِّل النحويّ (CompilationEngine)
في سياق هذا المشروع، يُعرَّف التفكيك (parsing) بصورة ضيقة على أنه المرور على المُدخل المعجمي وعرض بنيته النحوية باستخدام صيغة متّفق عليها. أمّا المُحَلِّل النحويّ المحدّد الذي نُنفّذه هنا فيستند إلى قواعد Jack النحوية، وهو مصمّم لإنتاج خرج XML. وقواعد Jack النحوية وعلامات XML المتّفق عليها موصوفة كلتاها في الفصل 10.
يُنفّذ مُحَلِّل Jack النحويّ بوحدة CompilationEngine، التي تُعطى واجهة برمجة تطبيقاتها في الفصل 10. ومهمّتك هي تنفيذ واجهة برمجة التطبيقات هذه: اكتب كل واحدة من الدوالّ المحدّدة، وتأكّد من أنها تُخرج XML الصحيح. ولصالح الاختبار الوحدوي، نوصي بالبدء بكتابة محرّك تصريف يتعامل مع أي شيفرة Jack معطاة باستثناء التعابير؛ ثم وسّع محرّك التصريف ليتعامل مع التعابير أيضًا. وبرامج الاختبار المرفقة أدناه مصممة لدعم استراتيجية الاختبار المتدرّج هذه.
برامج الاختبار
إنّ طريقة طبيعية لاختبار مُحَلِّلك الصياغيّ هي أن تجعله يفكّك بعض برامج Jack تمثيلية. ونحن نرفق برنامجي اختبار من هذا القبيل: Square Dance وArray Test. ويتضمّن الأول جميع السمات النحوية للغة Jack باستثناء معالجة المصفوفات، التي تظهر في الثاني. ونوفّر أيضًا نسخة خالية من التعابير من برنامج Square Dance، كما هو موضّح أدناه.
Square Dance: تطبيق تفاعلي بسيط، موصوف في المشروع 9. والتنفيذ منظّم في ثلاثة أصناف:
| خرج Tokenizer | خرج المُحَلِّل النحويّ | ملف الصنف المصدري | الوصف (غير ذي صلة بهذا المشروع تمامًا) |
|---|---|---|---|
| MainT.xml | Main.xml | Main.jack | يُهيّئ جلسة "square dance" جديدة ويبدأها". |
| SquareT.xml | Square.xml | Square.jack | يُنفّذ مربّعًا متحرّكًا. ويمتلك كائن Square موقعًا وحجمًا على الشاشة، ودالّة للرسم والمحو والتحريك وتغيير الحجم. |
| SquareGameT.xml | Square.xml | Square.jack | يُدير العرض وفقًا لقواعد اللعبة. |
ملاحظة: ملفات Jack المصدريّة الثلاثة التي تشكّل تطبيق Square Dance مطابقة لتلك المخزّنة في مجلد projects/09/Square. ولاستكمال الصورة، تتوفّر نسخة مطابقة من هذه الملفات أيضًا في مجلد projects/10/Square.
Square Dance الخالي من التعابير: في هذه النسخة من Square Dance، استُبدل كل تعبير في شيفرة المصدر الأصلية بمُعرّف واحد (اسم متغيّر ما في النطاق). وقد صُمّم هذا الإصدار من البرنامج لتسهيل الاختبار الوحدوي لقدرة مُحَلِّلك الصياغيّ على تفكيك كل شيء باستثناء التعابير. ولاحظ أن استبدال التعابير بمتغيّرات قد أفضى إلى شيفرة لا معنى لها، لكنها صحيحة نحوًا. وللسهولة، تحمل الملفات الخالية من التعابير الأسماء نفسها الخاصة بالملفات الأصلية، لكنها مخزّنة في مجلد منفصل هو projects/10/ExpressionlessSquare.
Array Test: برنامج Jack من صنف واحد، مصمّم لاختبار كيفية تعامل المُحَلِّل الصياغيّ مع معالجة المصفوفات:
| ملف الصنف المصدري | الوصف (غير ذي صلة بهذا المشروع تمامًا) |
|---|---|
| Main.jack | يحسب متوسط تتابع من الأعداد الصحيحة التي يُدخلها المستخدم، باستخدام بنية بيانات مصفوفة وأوامر معالجة مصفوفات. |
| خرج Tokenizer | خرج المُحَلِّل النحويّ |
|---|---|
| MainT.xml | Main.xml |
التجريب مع برامج الاختبار: إذا أردت، يمكنك تصريف برنامجَي SquareDance وTestArray المرفقين باستخدام مصرِّف Jack المرفق، ثم استخدام مُحاكٍ الآلة الافتراضية المرفق لتشغيل الشيفرة المترجمة. وهذا النشاط غير ذي صلة بالمشروع الحالي. لكنه يخدم إظهار أن برامج الاختبار ليست مجرد نصّ صرف؛ بل لها أيضًا دلالات، أو معنى، وهو أمر لا يهتمّ به المُحَلِّل الصياغيّ.
الاختبار
اختبار Tokenizer:
-
اختبر مُحَلِّلك المعجمي على برنامجَي Square Dance وTestArray.
-
بالنسبة لكل ملف مصدري Xxx.jack، اجعل برنامج اختبار المُحَلِّل المعجمي خاصتك يعطي ملف الخرج الاسم XxxT.xml. وطبّق اختبار المُحَلِّل المعجمي على كل ملف صنف في برامج الاختبار، ثم استخدم أداة TextComparer المرفقة لمقارنة الخرج المولّد بملفات المقارنة .xml المرفقة.
-
وبما أن ملفات الخرج التي يولّدها برنامج اختبار المُحَلِّل المعجمي ستكون لها الأسماء والامتدادات نفسها الخاصة بملفات المقارنة المرفقة، فنقترح وضعها في مجلدات منفصلة.
اختبار المُحَلِّل النحويّ:
-
طبّق مُحَلِّلك الصياغيّ على برامج الاختبار المرفقة، ثم استخدم أداة TextComparer المرفقة لمقارنة الخرج المولّد بملفات المقارنة .xml المرفقة.
-
وبما أن ملفات الخرج التي يولّدها مُحَلِّلك الصياغيّ ستكون لها الأسماء والامتدادات نفسها الخاصة بملفات المقارنة المرفقة، فنقترح وضعها في مجلدات منفصلة.
-
ولاحظ أن إزاحة خرج XML هي للقراءة فقط. ومتصفّحات الويب وأداة TextComparer المرفقة تتجاهل المسافات البيضاء.