مُجمِّع مرور واحد
من المحتمل أن تحتوي هذه المقالة على أبحاث أصلية . ( يناير 2017 ) |
في برمجة الكمبيوتر ، المترجم ذو المرور الواحد هو مترجم يمر عبر أجزاء كل وحدة تجميع مرة واحدة فقط، ويترجم كل جزء على الفور إلى الكود الآلي النهائي الخاص به. وهذا على النقيض من المترجم متعدد المرور الذي يحول البرنامج إلى تمثيل وسيط واحد أو أكثر في خطوات بين الكود المصدري والكود الآلي، والذي يعيد معالجة وحدة التجميع بأكملها في كل مرور متسلسل.
يشير هذا إلى الأداء المنطقي للمترجم، وليس القراءة الفعلية لملف المصدر مرة واحدة فقط. على سبيل المثال، يمكن قراءة ملف المصدر مرة واحدة في وحدة تخزين مؤقتة ولكن يمكن بعد ذلك مسح هذه النسخة عدة مرات. قام مترجم فورتران IBM 1130 بتخزين المصدر في الذاكرة واستخدم العديد من التمريرات؛ على النقيض من ذلك، كان المجمع، في الأنظمة التي تفتقر إلى وحدة تخزين الأقراص، يتطلب تقديم مجموعة بطاقات المصدر مرتين إلى قارئ البطاقات/الثقب.
ملكيات
هذا القسم يحتاج إلى التوسعة ، يمكنك المساعدة بإضافة المزيد إليه. ( فبراير 2018 ) |
تعتبر المترجمات ذات المرور الواحد أصغر وأسرع من المترجمات ذات المرور المتعدد. [1]
لا تستطيع برامج التجميع ذات المرور الواحد توليد برامج فعّالة مثل برامج التجميع ذات المرور المتعدد بسبب النطاق المحدود للمعلومات المتاحة. تتطلب العديد من تحسينات برنامج التجميع الفعّالة عمليات تمرير متعددة على كتلة أساسية أو حلقة (خاصة الحلقات المتداخلة) أو برنامج فرعي أو وحدة كاملة. تتطلب بعضها عمليات تمرير على برنامج كامل. لا يمكن تجميع بعض لغات البرمجة ببساطة في عملية تمرير واحدة، نتيجة لتصميمها. على سبيل المثال، يسمح PL/I بوضع إعلانات البيانات في أي مكان داخل البرنامج، على وجه التحديد، بعد بعض الإشارات إلى العناصر التي لم يتم الإعلان عنها بعد، لذلك لا يمكن إنشاء أي كود حتى يتم مسح البرنامج بالكامل. يتضمن تعريف اللغة أيضًا عبارات ما قبل المعالج التي تولد كود المصدر المراد تجميعه: عمليات التمرير المتعددة مؤكدة. على النقيض من ذلك، تم تصميم العديد من لغات البرمجة خصيصًا ليتم تجميعها باستخدام برامج تجميع ذات مرور واحد، وتتضمن هياكل خاصة للسماح بالتجميع في عملية تمرير واحدة.
الصعوبات
لا يستشهد هذا القسم بأي مصادر . ( ديسمبر 2023 ) |
المشكلة الأساسية هي المراجع الأمامية. قد يعتمد التفسير الصحيح لرمز ما في نقطة ما في ملف المصدر على وجود أو غياب رموز أخرى في ملف المصدر، وحتى يتم مواجهتها، لا يمكن إنتاج الكود الصحيح للرمز الحالي. هذه هي مشكلة الاعتماد على السياق، ويمكن أن يكون النطاق في أي مكان من الرموز المجاورة إلى كميات كبيرة بشكل تعسفي من نص المصدر.
السياق المحلي
This section does not cite any sources. (December 2023) |
لنفترض أن الرمز < يتم التعرف عليه باعتباره للمقارنة "أقل من"، على عكس "أكبر من" على سبيل المثال. نظرًا لقيود ترميز الأحرف، قد لا يتوفر الرمز ≤ في الترميز القياسي، لذا يجب السماح بالتمثيل المركب، "<=". على الرغم من أن هذا السياق يتم تحديده من خلال الرمز التالي مباشرة، إلا أنه من غير المعروف متى يتم مواجهة "<". وبالمثل، لا يعني الرمز "=" دائمًا "="، كما هو الحال عندما يكون جزءًا من رمز مركب. قد تتضمن الرموز المركبة الأخرى ".lt." في حالة عدم توفر الرمز الخاص "<". هناك احتمال آخر حيث لا يتوفر رمز حرف للرمز ¬ ("ليس") وهو "<>" لـ "¬=" أو "ليس مساويًا" - تستخدم بعض الأنظمة ~ أو ! لـ ¬ كتنويع إضافي. أحد الأساليب هو تقديم المسح بعد "<" وعند مواجهة "="، قم بالرجوع للخلف. هذا يعني بالطبع أنه سيكون هناك مروران على هذا الجزء من النص، وهو ما يجب تجنبه. في هذا الصدد، قد يأتي ملف المصدر من جهاز لا يدعم عملية الرجوع وإعادة القراءة، مثل قارئ البطاقات. وبدلاً من اتخاذ قرار مبكر قد يتعين التراجع عنه لاحقًا، يمكن للمحلل المعجمي الحفاظ على تفسيرات متعددة مثل مفهوم التراكب الكمومي، حيث ينهار إلى خيار محدد فقط عند ملاحظة الرمز المحدد لاحقًا. ومن الجدير بالذكر أن مترجمي COBOL يخصصون تمريرة للتمييز بين النقاط الكاملة التي تظهر في الثوابت العشرية والنقاط الكاملة التي تظهر في نهاية العبارات. مثل هذا المخطط غير متاح لمترجم تمريرة واحدة.
وبالمثل مع أسماء العناصر. هناك عدد قليل من اللغات التي تقتصر على أسماء مكونة من حرف واحد، وبالتالي فإن الحرف "x" كاسم مكون من حرف واحد يختلف تمامًا عن الحرف "x" داخل اسم مثل "text" - الآن يمتد السياق إلى ما هو أبعد من الأحرف المجاورة مباشرة. إن مهمة المحلل المعجمي هي فصل عناصر مجرى المصدر المتسلسل إلى رموز اللغة. ليس فقط الكلمات، لأن "<" و "<=" هي رموز أيضًا. تبدأ الأسماء عادةً بحرف وتستمر بالأحرف والأرقام، وربما بعض الرموز الإضافية مثل "_". إن بناء الجملة المسموح به لتحديد الأرقام معقد بشكل مدهش، على سبيل المثال +3.14159E+0 يمكن أن يكون صالحًا. من المعتاد السماح بعدد عشوائي من أحرف المسافة بين الرموز، ولغة فورتران غير عادية في السماح (وتجاهل) المسافات داخل الرموز الظاهرة أيضًا بحيث يكون "GO TO" و "GOTO" متكافئين مثل "<=" و "< ="". ومع ذلك، قد تتطلب بعض الأنظمة مسافات لتحديد رموز معينة، بينما تستخدم أنظمة أخرى، مثل Python، مسافات بادئة للإشارة إلى نطاق كتل البرنامج التي قد يشار إليها عادةً بعلامات Begin ... End أو علامات مماثلة.
السياق داخل التعبيرات
This section does not cite any sources. (December 2023) |
تتبع اللغات التي تسمح بالتعبيرات الحسابية عادةً قواعد تدوين البادئة مع قواعد الأسبقية. وهذا يعني أن إنشاء الكود لتقييم التعبير لا يتم بسلاسة حيث يتم استنباط رموز التعبير من النص المصدر. على سبيل المثال، لا يؤدي التعبير x + y*(u - v) إلى ما يعادل تحميل x، إضافة y، لأن x لم تتم إضافته إلى y. إذا تم استخدام مخطط مكدس للحساب، فقد يبدأ الكود بتحميل x، لكن الكود الذي يتوافق مع الرمز + التالي لا يتبعه. بدلاً من ذلك، يتم إنشاء كود لـ (u - v)، متبوعًا بالضرب في y، وبعد ذلك فقط تتم إضافة x. لا يتحرك محلل التعبيرات الحسابية ذهابًا وإيابًا على طول المصدر أثناء تحليله، بل يستخدم كومة محلية من العمليات المؤجلة التي تحركها قواعد الأسبقية. يمكن تجنب هذا الرقص من خلال اشتراط تقديم التعبيرات الحسابية بالتدوين البولندي العكسي أو ما شابه ذلك؛ بالنسبة للمثال أعلاه، شيء مثل uv - y * x + والذي سيتم مسحه ضوئيًا من اليسار إلى اليمين تمامًا.
قد يقوم المترجم المحسن بتحليل شكل تعبير حسابي لتحديد التكرار وإزالته أو إجراء تحسينات محتملة أخرى. ضع في اعتبارك
أ*جيب(x) + ب*جيب(x)
تسمح بعض اللغات بالتعيينات داخل تعبير حسابي، لذا كان بإمكان المبرمج أن يكتب شيئًا مثل
أ*(ت:=خطيئة(س)) + ب*ت
ولكن بصرف النظر عن الجهد المطلوب للقيام بذلك، فإن شكل العبارة الناتجة يكون فوضويًا ولن يكون من السهل مقارنته بالتعبير الرياضي الذي يتم ترميزه. سيكون من السهل ارتكاب الأخطاء. بدلاً من ذلك، يمكن للمترجم تمثيل شكل التعبير بالكامل (باستخدام بنية شجرة عادةً)، وتحليل هذه البنية وتعديلها، ثم إصدار الكود للشكل المحسن، ربما شيء مثل (a + b)*sin(x). سيكون هناك امتداد واضح لكتل عبارات التعيين المتعاقبة. هذا لا يتضمن مرورًا ثانيًا عبر نص المصدر، على هذا النحو.
سياق المدى المتوسط
This section does not cite any sources. (December 2023) |
على الرغم من أن المحلل المعجمي قد قسم مجرى الإدخال إلى مجرى من الرموز (وتجاهل أي تعليق)، فإن تفسير هذه الرموز وفقًا لقواعد اللغة قد يعتمد على السياق. ضع في اعتبارك العبارات التالية في الكود الزائف لفورتران:
إذا ( التعبير ) = الخ . إذا ( التعبير ) label1 ، label2 ، label3 إذا ( التعبير ) x = .true. إذا ( تعبير ) إذن
الأول هو تعيين قيمة تعبير حسابي ( إلخ ) إلى عنصر من مصفوفة أحادية البعد تسمى "إذا". فورتران غير عادية في أنها لا تحتوي على كلمات محجوزة، لذلك فإن الرمز "كتابة" لا يعني بالضرورة أن هناك عبارة كتابة قيد التقدم. العبارات الأخرى هي في الواقع عبارات إذا - الثانية هي إذا حسابية تفحص علامة نتيجة التعبير وبناءً على كونها سلبية أو صفرية أو موجبة تقفز إلى التسمية 1 أو 2 أو 3؛ والثالثة هي إذا منطقية، وتتطلب أن تكون نتيجة تعبيرها منطقية ("منطقية" في مصطلحات فورتران) والتي إذا كانت صحيحة تعني أنه سيتم تنفيذ جزء العبارة التالي (هنا، تعيين صحيح إلى x، و"صحيح" ليست كلمة محجوزة، يتم الإشارة إلى المعنى الخاص من خلال النقاط التي تميزها)؛ والرابع هو بداية تسلسل إذا ... ثم ... وإلا ... نهاية إذا والذي يتطلب أيضًا أن يعطي التعبير نتيجة منطقية.
وبالتالي، لا يمكن إجراء التفسير الصحيح للرمز "إذا" الناشئ عن المحلل المعجمي إلا بعد مسح التعبير وبعد القوس الختامي يظهر إما علامة يساوي أو رقم (وهو نص label1 : بينما يستخدم فورتران الأعداد الصحيحة فقط كعناوين، يمكن تسمية العناوين عبر عبارة ASSIGN، وبالتالي يجب أن يعتمد المسح على إيجاد الفاصلتين)، أو بداية عبارة التعيين (أو عبارة الكتابة، وما إلى ذلك)، أو "ثم" (يجب ألا يتبعها نص آخر)، وبالتالي، يمتد السياق الآن إلى كمية عشوائية من نص المصدر لأن التعبير عشوائي . ومع ذلك، في جميع الحالات الأربع، يمكن للمترجم إنشاء الكود لتقييم التعبير أثناء تقدم المسح. وبالتالي، لا يمكن للتحليل المعجمي تحديد معنى الرموز التي حددها للتو دائمًا بسبب تقلبات بناء الجملة المسموح به، وبالتالي يجب أن يحافظ تحليل بناء الجملة على تراكب الحالات المحتملة إذا كان من المفترض تجنب التراجع.
مع انجراف تحليل بناء الجملة في ضباب من الحالات المتراكبة، في حالة مواجهة خطأ (أي العثور على رمز لا يمكن وضعه في أي إطار نحوي صالح) قد يكون إنتاج رسالة مفيدة أمرًا صعبًا. على سبيل المثال، كان مُجمِّع B6700 Algol سيئ السمعة بسبب رسائل الخطأ مثل "من المتوقع وجود فاصلة منقوطة" إلى جانب قائمة بسطر المصدر بالإضافة إلى علامة توضح موقع المشكلة - غالبًا ما تكون علامة فاصلة منقوطة. في حالة عدم وجود فاصلة منقوطة، إذا تم وضعها بالفعل كما هو موضح، فقد تظهر عند إعادة التجميع رسالة "فاصلة منقوطة غير متوقعة" لها. غالبًا ما تكون رسالة الخطأ الأولى فقط من المُجمِّع جديرة بالاهتمام، لأن الرسائل اللاحقة سارت بشكل خاطئ. يعد إلغاء التفسير الحالي ثم استئناف الفحص في بداية العبارة التالية أمرًا صعبًا عندما يكون ملف المصدر به خطأ، وبالتالي فإن الرسائل اللاحقة غير مفيدة. يتم بالطبع التخلي عن إنتاج التعليمات البرمجية الإضافية.
يمكن تقليل هذه المشكلة من خلال استخدام الكلمات المحجوزة، بحيث تكون "if" و"then" و"else" دائمًا أجزاء من عبارة if ولا يمكن أن تكون أسماء لمتغيرات، ولكن قد يصبح عدد كبير بشكل مدهش من الكلمات المفيدة غير متاح نتيجة لذلك. هناك نهج آخر وهو "stropping"، حيث يتم تمييز الكلمات المحجوزة، على سبيل المثال عن طريق وضعها بين أحرف خاصة مثل النقاط الكاملة أو علامات الاقتباس كما في بعض إصدارات Algol. وهذا يعني أن 'if'و ifهي رموز مختلفة، والأخيرة هي اسم عادي، ولكن توفير كل هذه العلامات الاقتباسية سرعان ما يصبح أمرًا مزعجًا. بالنسبة للعديد من اللغات، توفر المسافات معلومات كافية على الرغم من أن هذا قد يكون معقدًا. غالبًا ما لا تكون المسافة فقط (أو علامة التبويب، وما إلى ذلك) ولكن حرفًا آخر غير حرف أو رقم ينهي نص الرمز المحتمل. في المثال أعلاه، يجب أن يكون تعبير عبارة if بين قوسين بحيث ينهي "(" بالتأكيد تحديد "if" وبالمثل، ")" تمكين تحديد "then"؛ علاوة على ذلك، يجب أن تظهر أجزاء أخرى من عبارة if المركبة في أسطر جديدة: "else" و"end if" (أو "endif") و"else if". وعلى النقيض من ذلك، مع Algol وغيرها، لا تكون الأقواس ضرورية ويمكن أن تكون جميع أجزاء عبارة if في سطر واحد. مع Pascal، إذا كانت a أو b، فإن إلخ. صحيحة، ولكن إذا كانت a و b تعبيرات، فيجب وضعها بين قوسين.
يمكن جعل قوائم ملفات المصدر التي ينتجها المترجم أسهل للقراءة من خلال وضع الكلمات المحجوزة التي يحددها مسطرة أو بخط غامق أو مائلDO 12 I = 1,15 ، ولكن كانت هناك انتقادات: "Algol هي اللغة الوحيدة التي تميز بين النقطة المائلة والعادية". في الواقع هذه ليست مزحة. في فورتران، يتم تمييز بداية عبارة do مثل DO 12 I = 1.15(تعيين القيمة 1.15 إلى متغير يسمى DO12I؛ تذكر أن المسافات غير ذات صلة) فقط من خلال الفرق بين الفاصلة والنقطة، وقد لا تكون رموز القائمة المطبوعة جيدة التكوين.
إن الاهتمام الدقيق بتصميم لغة ما يمكن أن يعزز وضوح وبساطة التعبير بهدف إنشاء مُجمِّع موثوق به يسهل فهم سلوكه. ومع ذلك، فإن الاختيارات السيئة شائعة. على سبيل المثال، يشير ماتلاب إلى نقل المصفوفة باستخدام علامة اقتباس كما في A' وهو أمر لا يمكن الاعتراض عليه ويتبع الاستخدام الرياضي عن كثب. حسنًا وجيدًا، ولكن بالنسبة لعناوين سلسلة نصية، يتجاهل ماتلاب الفرصة التي يقدمها رمز الاقتباس المزدوج لأي غرض ويستخدم علامات الاقتباس لهذا الغرض أيضًا. على الرغم من أن أوكتاف يستخدم علامات الاقتباس المزدوجة لسلاسل النصوص، إلا أنه يسعى جاهدًا لقبول عبارات ماتلاب أيضًا، وبالتالي تمتد المشكلة إلى نظام آخر.
توسعات ما قبل المعالج
This section does not cite any sources. (December 2023) |
في هذه المرحلة يتم ممارسة خيارات ما قبل المعالجة، والتي تسمى بهذا الاسم لأنها تُمارس قبل معالجة المترجم للمصدر الوارد. وهي تعكس خيارات "التوسع الكلي" لأنظمة التجميع، ونأمل أن يكون ذلك باستخدام بناء جملة أكثر رقة. الترتيب الأكثر شيوعًا هو الاختلاف في
إذا كانت الحالة هي هذا المصدر وإلا فإن المصدر الآخر هو
غالبًا ما يكون هناك ترتيب ما للتمييز بين عبارات مصدر ما قبل المعالج وعبارات المصدر "العادية"، مثل العبارة التي تبدأ برمز % في pl/i، أو #، وما إلى ذلك. خيار بسيط آخر هو تنويعة من
عرف هذا = ذلك
ولكن الحذر مطلوب، كما هو الحال في
عرف SumXY = (x + y) المجموع:=3*مجموعXY؛
نظرًا لأنه بدون الأقواس، ستكون النتيجة هي المجموع:=3*x + y؛ وبالمثل، يلزم توخي الحذر عند تحديد حدود النص البديل وكيفية مسح النص الناتج. ضع في اعتبارك
#تعريف ثلاثة = 3؛ #تعريف نقطة = .؛ #تعريف واحد = 1؛ x:=ثلاثة فاصلة واحد؛
هنا يتم إنهاء عبارة التعريف بفاصلة منقوطة، والفاصلة المنقوطة ليست في حد ذاتها جزءًا من الاستبدال. لا يمكن أن يكون الاستدعاء x:=threepointone;لأن هذا اسم مختلف، ولكن three point oneسيكون كذلك 3 . 1وقد يكون الفحص اللاحق قادرًا أو غير قادر على اعتبار ذلك رمزًا واحدًا.
تسمح بعض الأنظمة بتعريف إجراءات ما قبل المعالجة التي يكون ناتجها نصًا مصدريًا يتم تجميعه، وقد تسمح حتى لمثل هذا المصدر بتعريف عناصر ما قبل المعالجة بشكل أكبر. يسمح الاستخدام الماهر لمثل هذه الخيارات بإعطاء الثوابت أسماء توضيحية، واستبدال التفاصيل الغامضة بوسائل سهلة للتذكر، وظهور أشكال جديدة من العبارات، وإنشاء كود مضمن لاستخدامات محددة لإجراء عام (مثل الفرز)، بدلاً من ابتكار إجراءات فعلية. مع انتشار المعلمات وأنواع المعلمات، ينمو عدد التركيبات المطلوبة بشكل كبير.
علاوة على ذلك، يمكن استخدام نفس بنية المعالجة المسبقة للغات متعددة مختلفة، حتى اللغات الطبيعية كما هو الحال في توليد قصة من قالب قصة باستخدام اسم شخص أو لقب أو اسم كلب أليف، وما إلى ذلك، وقد يكون الإغراء هو ابتكار برنامج معالجة مسبقة يقبل ملف المصدر، وينفذ إجراءات المعالجة المسبقة ويخرج النتيجة جاهزة للمرحلة التالية، التجميع. ولكن هذا يشكل بوضوح مرورًا إضافيًا واحدًا على الأقل عبر المصدر، وبالتالي فإن مثل هذا الحل لن يكون متاحًا لمترجم مرور واحد. وبالتالي، فإن التقدم عبر ملف المصدر الفعلي للإدخال قد يتقدم بشكل متقطع، لكنه لا يزال أحادي الاتجاه.
سياق بعيد المدى
This section does not cite any sources. (December 2023) |
يواجه توليد الكود بواسطة المترجم أيضًا مشكلة الرجوع إلى الأمام، بشكل مباشر في أمثال الانتقال إلى التسمية حيث تكون تسمية الوجهة على مسافة غير معروفة في ملف المصدر، وبالتالي فإن تعليمات القفز للوصول إلى موقع تلك التسمية تتضمن مسافة غير معروفة عبر كود لم يتم إنشاؤه بعد. بعض تصميمات اللغة، المتأثرة ربما بـ "GOTOs تعتبر ضارة" ، لا تحتوي على عبارة GOTO، لكن هذا لا يتجنب المشكلة حيث يوجد العديد من مكافئات GOTO الضمنية في البرنامج. ضع في اعتبارك
إذا كان الشرط صحيحًا ، فإن الكود صحيح وإلا فإن الكود خاطئ
كما ذكرنا من قبل، يمكن إنشاء كود لتقييم الشرط على الفور. ولكن عند مواجهة رمز then ، يجب وضع كود عملية JumpFalse الذي يكون عنوان وجهته هو بداية الكود لعبارات الكود false ، وعلى نحو مماثل، عند مواجهة رمز else ، يجب أن يتبع الكود المكتمل للتو لعبارات الكود true عملية قفز على غرار GOTO تكون وجهتها هي الكود الذي يتبع نهاية عبارة if، والتي يتم تمييزها هنا برمز fi . لا يمكن معرفة هذه الوجهات إلا بعد إنشاء قدر عشوائي من الكود للمصدر غير الممسوح ضوئيًا حتى الآن. تنشأ مشاكل مماثلة لأي عبارة تمتد أجزاؤها على كميات عشوائية من المصدر، مثل عبارة الحالة .
إن المترجم الذي يعتمد على مبدأ الانحدار التكراري يقوم بتنشيط إجراء لكل نوع من أنواع العبارات، مثل عبارة الشرط، فيقوم بدوره باستدعاء الإجراءات المناسبة لتوليد الكود الخاص بعبارات الأجزاء الصحيحة والخاطئة من عباراته، وبالمثل بالنسبة للعبارات الأخرى وفقًا لقواعدها النحوية. وفي وحدة التخزين المحلية الخاصة به، فإنه يقوم بتتبع موقع حقل العنوان لعملية JumpFalse غير المكتملة، وعند مواجهة رمزه ، فإنه يضع العنوان المعروف الآن، وبالمثل عند مواجهة رمز fi للقفزة المطلوبة بعد رمز true الخاص بالعبارات . وتختلف عبارة GoTo في أن الكود الذي سيتم القفز فوقه ليس داخل شكل عباراتها، وبالتالي فإن إدخالاً في جدول مساعد من "الإصلاحات" مطلوب لاستخدامه عند مواجهة علامته في النهاية. ويمكن توسيع هذه الفكرة. ويمكن إجراء جميع القفزات إلى وجهات غير معروفة عبر إدخال في جدول القفز (يتم ملء عناوينه لاحقًا عند مواجهة الوجهات)، ومع ذلك فإن الحجم اللازم لهذا الجدول غير معروف حتى نهاية التجميع.
أحد الحلول لهذه المشكلة هو أن يقوم المترجم بإصدار مصدر التجميع (مع تسميات تم إنشاؤها بواسطة المترجم كوجهات للقفزات، وما إلى ذلك)، وسيقوم المترجم بتحديد العناوين الفعلية. ولكن من الواضح أن هذا يتطلب مرورًا إضافيًا (نسخة من) ملف المصدر وبالتالي فهو غير مسموح به بالنسبة للمترجمين الذين يستخدمون مرورًا واحدًا.
قرارات مؤسفة
This section does not cite any sources. (December 2023) |
على الرغم من أن الوصف أعلاه استخدم فكرة مفادها أنه يمكن إنشاء الكود مع ترك حقول معينة لإصلاحها لاحقًا، فقد كان هناك افتراض ضمني بأن حجم تسلسلات الكود هذه كان مستقرًا. قد لا يكون هذا هو الحال. تحتوي العديد من أجهزة الكمبيوتر على ترتيب للعمليات التي تشغل كميات مختلفة من التخزين، ولا سيما العنونة النسبية حيث إذا كانت الوجهة ضمن خطوات عنونة -128 أو +127، فيمكن استخدام حقل عنوان مكون من ثماني بتات، وإلا فإن حقل عنوان أكبر كثيرًا مطلوب للوصول. وبالتالي، إذا تم إنشاء الكود بحقل عنوان قصير، فقد يصبح من الضروري لاحقًا الرجوع وتعديل الكود لاستخدام حقل أطول، مع النتيجة المترتبة على ذلك أنه سيتعين تعديل مواقع مراجع الكود السابقة بعد التغيير أيضًا. وبالمثل، سيتعين إصلاح المراجع اللاحقة التي تعود للخلف عبر التغيير، حتى تلك التي كانت لعناوين معروفة. وكذلك، سيتعين إصلاح معلومات الإصلاح نفسها بشكل صحيح. من ناحية أخرى، يمكن استخدام العناوين الطويلة لجميع الحالات عندما لا يكون القرب مؤكدًا، لكن الكود الناتج لن يكون مثاليًا بعد الآن.
إدخال متسلسل بمرور واحد، إخراج متسلسل غير منتظم
This section does not cite any sources. (December 2023) |
لقد تم ذكر بعض الاحتمالات للتحسين ضمن بيان واحد. تتطلب التحسينات عبر بيانات متعددة الاحتفاظ بمحتوى مثل هذه البيانات في نوع ما من بنية البيانات التي يمكن تحليلها والتلاعب بها قبل إصدار التعليمات البرمجية. في مثل هذه الحالة، فإن إنتاج التعليمات البرمجية المؤقتة، حتى مع السماح بالإصلاحات، سيكون عائقًا. في الحد الأقصى، يعني هذا أن المترجم سيولد بنية بيانات تمثل البرنامج بالكامل في شكل داخلي، ولكن يمكن التشبث بقشة والادعاء بأنه لا يوجد تمريرة ثانية فعلية لملف المصدر من البداية إلى النهاية. ربما في وثيقة العلاقات العامة التي تعلن عن المترجم.
ومن الجدير بالملاحظة أن المترجم لا يستطيع توليد الكود الخاص به في تسلسل واحد مستمر، ناهيك عن أن يقوم بذلك فورًا عند قراءة كل جزء من المصدر. ولا يزال من الممكن كتابة الناتج بشكل متسلسل، ولكن فقط إذا تم تأجيل إخراج قسم ما حتى يتم إجراء جميع الإصلاحات المعلقة لهذا القسم.
إعلان قبل الاستخدام
This section does not cite any sources. (December 2023) |
عند إنشاء كود للتعبيرات المختلفة، يحتاج المترجم إلى معرفة طبيعة المتغيرات. على سبيل المثال، يمكن لبيان مثل A:=B; أن ينتج كودًا مختلفًا إلى حد ما اعتمادًا على ما إذا كانت A وB عبارة عن أعداد صحيحة أو متغيرات ذات فاصلة عائمة (وما هو الحجم: دقة مفردة أو مزدوجة أو رباعية) أو أرقام مركبة أو مصفوفات أو سلاسل أو أنواع محددة من قبل المبرمج، إلخ. في هذه الحالة، سيكون النهج البسيط هو نقل عدد مناسب من كلمات التخزين، ولكن بالنسبة للسلاسل قد لا يكون هذا مناسبًا لأن المتلقي قد يكون أصغر من المورد وفي كل الأحوال، قد يتم استخدام جزء فقط من السلسلة - ربما يكون لديه مساحة لألف حرف، لكنه يحتوي حاليًا على عشرة أحرف. ثم هناك إنشاءات أكثر تعقيدًا، كما هو الحال في COBOL و pl/i، مثل في هذه الحالة، A وB عبارة عن مجموعات (أو هياكل) حيث A:=B by name;يحتوي A على سبيل المثال على أجزاء A.xو بينما يحتوي B على أجزاء و و و بهذا الترتيب. تعني ميزة "حسب الاسم" ما يعادل ولكن لأنه ليس لها نظير في أ، وليس لها نظير في ب، فهي غير متورطة.
A.yA.otherB.yB.cB.xA.y:=B.y; A.x:=B.x;B.cA.other
يمكن التعامل مع كل هذا من خلال المتطلب الذي ينص على إعلان العناصر قبل استخدامها. لا تتطلب بعض اللغات إعلانات صريحة، مما يؤدي إلى إنشاء إعلان ضمني عند مواجهة اسم جديد أولاً. إذا واجه مُجمِّع فورتران اسمًا غير معروف سابقًا يكون الحرف الأول منه أحد الأحرف I,J,...,N، فسيكون المتغير عددًا صحيحًا، وإلا فسيكون متغيرًا من النوع ذي الفاصلة العائمة. وبالتالي، DO12Iسيكون الاسم متغيرًا من النوع ذي الفاصلة العائمة. هذا أمر مريح، ولكن بعد بضع تجارب مع الأسماء المكتوبة بشكل خاطئ، يتفق معظم المبرمجين على أنه يجب استخدام خيار المُجمِّع "implicit none".
تستخدم أنظمة أخرى طبيعة اللقاء الأول لتحديد النوع، مثل سلسلة أو مصفوفة وما إلى ذلك. يمكن أن تكون اللغات المفسرة مرنة بشكل خاص، حيث يتم اتخاذ القرار في وقت التشغيل، على النحو التالي إلى حد ما
إذا كانت الحالة هي pi:="3.14" وإلا pi:=3.14 fi ؛ اطبع pi؛
إذا كان هناك مُجمِّع لهذه اللغة، فسوف يتعين عليه إنشاء كيان معقد لتمثيل المتغير pi، والذي يحتوي على إشارة إلى نوعه الحالي والتخزين المرتبط به لتمثيل هذا النوع. هذا مرن بالتأكيد، لكنه قد لا يكون مفيدًا للحوسبة المكثفة كما في حل Ax = b حيث A هي مصفوفة من الدرجة مائة، وفجأة، قد يكون أي عنصر من عناصرها من نوع مختلف.
الإجراءات والوظائف
This section does not cite any sources. (December 2023) |
كما أن الإعلان قبل الاستخدام يعد متطلبًا سهلًا يجب تلبيته للإجراءات والوظائف، وينطبق هذا أيضًا على تعشيش الإجراءات داخل الإجراءات. وكما هو الحال مع ALGOL وPascal وPL/I والعديد من الأنظمة الأخرى، فإن MATLAB وFortran (منذ عام 1995) تسمحان للدالة (أو الإجراء) باحتواء تعريف دالة (أو إجراء) أخرى، والتي لا يمكن رؤيتها إلا داخل الدالة المحتوية، ولكن هذه الأنظمة تتطلب تعريفها بعد نهاية الإجراء المحتوي.
ولكن عندما يُسمح بالتكرار، تنشأ مشكلة. لا يمكن إعلان إجراءين يستدعي كل منهما الآخر قبل الاستخدام. يجب أن يكون أحدهما أولاً في ملف المصدر. لا يهم هذا إذا كان من الممكن، كما هو الحال في مواجهة متغير غير معروف، استنتاج ما يكفي من المواجهة حتى يتمكن المترجم من إنشاء كود مناسب لاستدعاء الإجراء غير المعروف، مع وجود جهاز "الإصلاح" بالطبع في مكانه للعودة وملء العنوان الصحيح للوجهة عند مواجهة تعريف الإجراء. ستكون هذه هي الحال بالنسبة لإجراء بدون معلمات، على سبيل المثال. قد تكون النتيجة المرتجعة من استدعاء دالة من النوع الذي يمكن تمييزه من الاستدعاء، ولكن هذا قد لا يكون صحيحًا دائمًا: يمكن أن تعيد الدالة نتيجة ذات فاصلة عائمة ولكن قيمتها مُعينة إلى عدد صحيح.
تحل باسكال هذه المشكلة من خلال اشتراط "الإعلان المسبق". يجب إعطاء أحد إعلانات الإجراء أو الوظيفة أولاً، ولكن بدلاً من نص الإجراء أو الوظيفة، يتم إعطاء الكلمة الأساسية " forward ". بعد ذلك، يمكن إعلان الإجراء أو الوظيفة الأخرى وتحديد نصها. في مرحلة ما، يتم إعادة إعلان الإجراء أو الوظيفة "forward"، جنبًا إلى جنب مع نص الوظيفة.
بالنسبة لاستدعاء إجراء (أو وظيفة) مع معلمات، سيكون نوعها معروفًا (يتم إعلانها قبل الاستخدام) ولكن استخدامها في استدعاء الإجراء قد لا يكون معروفًا. على سبيل المثال، تمرر فورتران جميع المعلمات بالإشارة (أي بالعنوان) لذلك لا توجد صعوبة فورية في إنشاء الكود (كما هو الحال دائمًا، مع تحديد العناوين الفعلية لاحقًا)، ولكن باسكال واللغات الأخرى تسمح بتمرير المعلمات بطرق مختلفة حسب اختيار المبرمج ( بالإشارة ، أو بالقيمة ، أو ربما حتى "بالاسم" ) وهذا يُشار إليه فقط في تعريف الإجراء، والذي يكون غير معروف قبل مواجهة التعريف. بالنسبة لباسكال على وجه التحديد، في تحديد المعلمات، تشير البادئة "Var" إلى أنه يجب استلامها بالإشارة، ويشير غيابها بالقيمة. في الحالة الأولى، يجب على المترجم إنشاء كود يمرر عنوان المعلمة، بينما في الحالة الثانية يجب أن يولد كودًا مختلفًا يمرر نسخة من القيمة، عادةً عبر مكدس. كما هو الحال دائمًا، يمكن استدعاء آلية "الإصلاح" للتعامل مع هذا، لكن هذا سيكون فوضويًا للغاية. يمكن لمُجمِّعي المرور المتعدد بالطبع تجميع كل المعلومات المطلوبة أثناء تنقلهم ذهابًا وإيابًا، لكن لا يمكن لمُجمِّعي المرور الفردي القيام بذلك. يمكن إيقاف إنشاء التعليمات البرمجية مؤقتًا أثناء تقدم المسح (وحفظ نتائجه في وحدة تخزين داخلية) حتى يتم العثور على الكيان المطلوب، وقد لا يُنظر إلى هذا على أنه يؤدي إلى مرور ثانٍ عبر المصدر لأن مرحلة إنشاء التعليمات البرمجية ستلحق بها قريبًا، فقد توقفت لفترة من الوقت فقط. لكن هذا سيكون معقدًا. بدلاً من ذلك يتم تقديم بناء خاص، حيث يتم إعلان تعريف الإجراء لاستخدام المعلمات "أمامًا" لتعريفه الكامل اللاحق حتى يتمكن المُجمِّع من معرفته قبل الاستخدام، كما يتطلب الأمر.
منذ أول فورتران (1957) فصاعدًا، أصبح التجميع المنفصل لأجزاء من البرنامج ممكنًا، مما يدعم إنشاء مكتبات من الإجراءات والوظائف. يجب أن يعرف الإجراء الموجود في ملف المصدر الذي يتم تجميعه والذي يستدعي وظيفة من مثل هذه المجموعة الخارجية نوع النتيجة التي تم إرجاعها بواسطة الوظيفة غير المعروفة، ولو فقط لتوليد كود يبحث في المكان الصحيح للعثور على النتيجة. في الأصل، عندما كانت هناك فقط أعداد صحيحة ومتغيرات ذات فاصلة عائمة، يمكن ترك الاختيار لقواعد الإعلان الضمني، ولكن مع انتشار الأحجام والأنواع أيضًا، سيحتاج الإجراء المستدعي إلى إعلان نوع للوظيفة. هذا ليس أمرًا خاصًا، حيث يكون له نفس الشكل كما هو الحال بالنسبة للمتغير المعلن داخل الإجراء.
الشرط المطلوب هو أنه في النقطة الحالية في عملية تجميع ذات مرور واحد، تكون المعلومات حول الكيان مطلوبة حتى يمكن إنتاج الكود الصحيح له الآن، إذا تم إصلاح العنوان لاحقًا. سواء كانت المعلومات المطلوبة ستتم مواجهتها لاحقًا في ملف المصدر أو سيتم العثور عليها في ملف كود تم تجميعه بشكل منفصل، يتم توفير المعلومات بواسطة بعض البروتوكولات هنا.
إن التحقق من توافق جميع استدعاءات الإجراء (أو الوظيفة) مع بعضها البعض ومع تعريفاتها هو أمر منفصل. في اللغات المنحدرة من إلهام يشبه Algol، يكون هذا الفحص صارمًا عادةً، ولكن يمكن أن تكون الأنظمة الأخرى غير مبالية. بصرف النظر عن الأنظمة التي تسمح للإجراء بامتلاك معلمات اختيارية، فإن الأخطاء في عدد ونوع المعلمات ستتسبب عادةً في تعطل البرنامج. يجب على الأنظمة التي تسمح بالتجميع المنفصل لأجزاء من برنامج كامل يتم "ربطها" لاحقًا معًا التحقق أيضًا من النوع والعدد الصحيحين للمعلمات والنتائج حيث يسهل ارتكاب الأخطاء، لكنها غالبًا لا تحدث. بعض اللغات (مثل Algol) لديها مفهوم رسمي لـ "الترقية" أو "التوسيع" أو "الترقية"، حيث يمكن استدعاء إجراء يتوقع على سبيل المثال معلمة ذات دقة مزدوجة معها كمتغير دقة واحد، وفي هذه الحالة يقوم المترجم بإنشاء كود يخزن متغير الدقة الفردي في متغير دقة مزدوجة مؤقت يصبح المعلمة الفعلية. ولكن هذا يغير آلية تمرير المعلمات إلى نسخ داخل ونسخ خارج مما قد يؤدي إلى اختلافات دقيقة في السلوك. والعواقب أقل دقة بكثير عندما يتلقى الإجراء عنوان متغير دقة واحد بينما يتوقع معلمة دقة مزدوجة أو اختلافات أخرى في الحجم. فعندما تتم قراءة قيمة المعلمة داخل الإجراء، سيتم قراءة مساحة تخزين أكبر من مساحة المعلمة المعطاة ومن غير المرجح أن تكون القيمة الناتجة تحسنًا. والأسوأ من ذلك بكثير عندما يغير الإجراء قيمة معلمته: فمن المؤكد أن شيئًا ما سيتضرر. ويمكن بذل الكثير من الصبر في العثور على هذه الإغفالات وتصحيحها.
مثال باسكال
This section does not cite any sources. (December 2023) |
من الأمثلة على مثل هذا البناء الإعلان الأمامي في باسكال . يتطلب باسكال الإعلان عن الإجراءات أو تعريفها بالكامل قبل الاستخدام. يساعد هذا المترجم الذي يعمل بمرور واحد في فحص النوع : استدعاء إجراء لم يتم الإعلان عنه في أي مكان هو خطأ واضح. تساعد الإعلانات الأمامية الإجراءات المتكررة المتبادلة على استدعاء بعضها البعض بشكل مباشر، على الرغم من قاعدة الإعلان قبل الاستخدام:
دالة فردية ( n : عدد صحيح ) : منطقية ؛ تبدأ إذا كان n = 0 ، فإن فردي := خطأ وإلا إذا كان n < 0 ، فإن فردي := زوجي ( n + 1 ) {خطأ في المترجم: لم يتم تعريف "زوجي" } وإلا فإن فردي := زوجي ( n - 1 ) النهاية ؛
دالة زوجية ( n : عدد صحيح ) : منطقية ؛ تبدأ إذا كان n = 0 فإن الزوجي := صحيح وإلا إذا كان n < 0 فإن الزوجي := فردي ( n + 1 ) وإلا فإن الزوجي := فردي ( n - 1 ) النهاية ؛
من خلال إضافة إعلان أمامي للوظيفة evenقبل الوظيفة odd، يتم إخبار المترجم أحادي المرور أنه سيكون هناك تعريف evenلاحقًا في البرنامج.
دالة حتى ( n : عدد صحيح ) : منطقية ؛ للأمام ؛
دالة فردية ( n : عدد صحيح ) : منطقية ؛ {وإلخ}
عندما يتم الإعلان الفعلي عن جسم الوظيفة، إما أن يتم حذف المعلمات أو يجب أن تكون متطابقة تمامًا مع الإعلان الأمامي الأصلي، أو سيتم الإشارة إلى خطأ.
تكرار ما قبل المعالج
This section does not cite any sources. (December 2023) |
عند إعلان مجموعات بيانات معقدة، قد ينشأ استخدام محتمل للدالتين Odd وEven. ربما إذا كان حجم تخزين مجموعة بيانات X هو عدد فردي من البايتات، فيمكن إضافة عنصر بايت واحد إليها تحت سيطرة اختبار على Odd(ByteSize(X)) بحيث يتم الحصول على عدد زوجي. ونظرًا للإعلانات المكافئة لـ Odd وEven كما هو مذكور أعلاه، فربما لن تكون هناك حاجة إلى إعلان "مباشر" لأن استخدام المعلمات معروف للمعالج المسبق والذي من غير المرجح أن يقدم فرصًا للاختيار بين المرجع والقيمة. ومع ذلك، لا يمكن استدعاء هذه الوظائف في الكود المصدر (خارج تعريفاتها) حتى بعد تعريفها الفعلي، لأن نتيجة الاستدعاء مطلوبة أن تكون معروفة. ما لم يكن المعالج المسبق منخرطًا في تمريرات متعددة لملف المصدر الخاص به.
التصريحات المسبقة تعتبر ضارة
This section does not cite any sources. (December 2023) |
إن أي شخص حاول الحفاظ على التماسك بين الإعلانات واستخدامات الإجراءات في برنامج كبير واستخدامه لمكتبات الروتينات، وخاصة تلك التي تخضع للتغييرات، سوف يجد صعوبة في استخدام الإعلانات الإضافية المباشرة أو الإعلانات المماثلة للإجراءات التي يتم استدعاؤها ولكن لم يتم تعريفها في التجميع الحالي. إن الحفاظ على التزامن بين المواقع المنفصلة على نطاق واسع وخاصة عبر ملفات المصدر المختلفة يتطلب الاجتهاد. إن الإعلانات التي تستخدم الكلمة المحجوزة من السهل العثور عليها، ولكن إذا لم يتم تمييز الإعلانات المفيدة عن الإعلانات العادية، فإن المهمة تصبح مزعجة. قد يبدو مكسب التجميع الأسرع المفترض غير كافٍ عندما يؤدي التخلي ببساطة عن هدف التجميع بمرور واحد إلى إزالة هذا الفرض.
انظر أيضا
مراجع
- ^ "مترجمات ذات تمريرة واحدة، ومرورتين، ومرور متعدد". GeeksforGeeks . 2019-03-13 . تم الاسترجاع في 2023-05-15 .
