محلل أسبقية العمليات

في علوم الحاسوب ، يُعد محلل أسبقية العمليات محللاً تصاعدياً يُفسر قواعد أسبقية العمليات . على سبيل المثال، تستخدم معظم الآلات الحاسبة محللات أسبقية العمليات للتحويل من صيغة التدوين الوسطي المقروءة بشرياً والتي تعتمد على ترتيب العمليات إلى صيغة مُحسَّنة للتقييم مثل تدوين ريفيرس بولندي (RPN).

تُستخدم خوارزمية ساحة التحويل الخاصة بإدسكر ديكسترا بشكل شائع لتنفيذ محللات أسبقية العمليات.

العلاقة مع المحللات الأخرى

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

لا تُستخدم محللات أسبقية المعاملات كثيرًا في التطبيقات العملية؛ إلا أنها تتمتع ببعض الخصائص التي تجعلها مفيدة ضمن تصميم أوسع. أولًا، يسهل كتابتها يدويًا، وهو ما لا ينطبق عادةً على محللات الإزاحة والاختزال الأكثر تعقيدًا. ثانيًا، يمكن كتابتها للاستعانة بجدول المعاملات أثناء التشغيل ، مما يجعلها مناسبة للغات التي تسمح بإضافة معاملات أو تغييرها أثناء التحليل. (مثال على ذلك لغة هاسكل ، التي تسمح بمعاملات وسيطة مُعرَّفة من قِبل المستخدم مع ترابط وأسبقية مخصصة؛ وبالتالي، يجب تشغيل محلل أسبقية المعاملات على البرنامج بعد تحليل جميع الوحدات النمطية المُشار إليها).

تُدمج مكتبة Raku محلل أسبقية المعاملات بين محللين انحداريين تكراريين لتحقيق توازن بين السرعة والديناميكية. يتم تسريع محللي لغة C وC++ في GCC ، وهما محللان انحداريان تكراريان مكتوبان يدويًا، بواسطة محلل أسبقية المعاملات الذي يمكنه فحص التعبيرات الحسابية بسرعة. كما يتم تضمين محللات أسبقية المعاملات داخل المحللات التي يُنشئها المُصرّف -المُصرّف لتسريع أسلوب الانحدار التكراري لتحليل التعبيرات بشكل ملحوظ. [ 1 ]

طريقة تسلق الأسبقية

طريقة تسلق الأسبقية هي خوارزمية مضغوطة وفعالة ومرنة لتحليل التعبيرات، وقد وصفها لأول مرة مارتن ريتشاردز وكولين ويتبي-ستريفنز. [ 2 ]

عادةً ما تبدو قواعد التعبير باستخدام تدوين الوسط في صيغة EBNF على النحو التالي:

التعبير :: = تعبير-مساواة تعبير-مساواة :: = تعبير-جمع ( ( ' == ' | '! = ' ) تعبير-جمع ) * تعبير-جمع :: = تعبير-ضرب ( ( '+' | '-' ) تعبير-ضرب ) * تعبير-ضرب :: = أولي ( ( ' * ' | ' / ' ) أولي ) * أولي :: = ' ( ' تعبير ' ) ' | عدد | متغير | '-' أولي

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

يمكن لمحلل أسبقية العمليات أن يؤدي المهمة نفسها بكفاءة أكبر. [ 1 ] الفكرة هي أنه يمكننا ربط العمليات الحسابية من اليسار طالما وجدنا عوامل لها نفس الأسبقية، ولكن علينا حفظ نتيجة مؤقتة لتقييم عوامل ذات أسبقية أعلى. لا تحتاج الخوارزمية المعروضة هنا إلى مكدس صريح؛ بل تستخدم استدعاءات متكررة لتنفيذ المكدس.

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

الشفرة الزائفة

الشفرة الزائفة للخوارزمية هي كما يلي. يبدأ المحلل اللغوي من الدالة parse_expression . مستويات الأسبقية أكبر من أو تساوي صفرًا.

parse_expression() return parse_expression_1(parse_primary(), 0)
parse_expression_1(lhs, min_precedence) lookahead := peek next token while lookahead is binary operator who their precedence >= min_precedence op := lookahead انتقل إلى الرمز التالي rhs := parse_primary () lookahead := peek next token while lookahead هو عامل ثنائي تكون أسبقيته أكبر من عامل التشغيل ، أو عامل التجميع الأيمن الذي تكون أسبقيته مساوية لأسبقية العملية `op`، ` rhs := parse_expression_1 ( rhs , precedence of op + (1 if lookahead precedence is greater, else 0)) lookahead := peek next token lhs := the result of applied op with operators lhs and rhs return lhs `

لاحظ أنه في حالة قاعدة إنتاج كهذه (حيث لا يمكن أن يظهر العامل إلا مرة واحدة):

تعبير المساواة :: = تعبير الجمع ( ' == ' | '! = ' ) تعبير الجمع

يجب تعديل الخوارزمية لقبول عوامل التشغيل الثنائية فقط التي تكون أسبقيتها أكبر من min_precedence .

مثال على تنفيذ الخوارزمية

فيما يلي مثال على تنفيذ التعبير 2 + 3 * 4 + 5 == 19. نُعطي الأولوية 0 للتعبيرات المساواتية، و1 للتعبيرات الجمعية، و2 للتعبيرات الضربية.

parse_expression_1 ( lhs = 2, min_precedence = 0)

  • رمز التطلع هو +، وله أسبقية 1. يتم الدخول إلى حلقة while الخارجية.
  • العملية هي + (الأولوية 1) والمدخل متقدم
  • اليمين هو 3
  • رمز التوقع هو *، وله أولوية 2. يتم الدخول إلى حلقة while الداخلية. parse_expression_1 ( lhs = 3, min_precedence = 2)
  • رمز التطلع هو *، وله الأسبقية 2. يتم الدخول إلى حلقة while الخارجية.
  • العملية هي * (الأولوية 2) والمدخل متقدم
  • اليمين هو 4
  • الرمز التالي هو +، وله أولوية 1. لم يتم الدخول إلى حلقة while الداخلية.
  • تم تخصيص 3 × 4 = 12 للطرف الأيسر
  • الرمز التالي هو +، وله أولوية 1. يتم ترك حلقة while الخارجية.
  • تم إرجاع الرقم 12.
  • رمز التطلع هو +، وله أسبقية 1. لم يتم الدخول إلى حلقة while الداخلية.
  • تم تعيين الطرف الأيسر 2+12 = 14
  • رمز التطلع هو +، وله أسبقية 1. حلقة while الخارجية غير موجودة.
  • العملية هي + (الأولوية 1) والمدخل متقدم
  • الجانب الأيمن هو 5
  • الرمز التالي هو ==، وله أسبقية 0. لم يتم الدخول إلى حلقة while الداخلية.
  • تم تعيين الطرف الأيسر 14 + 5 = 19
  • الرمز التالي هو ==، وله أسبقية 0. لم يتم ترك حلقة while الخارجية.
  • العملية تساوي (الأسبقية 0) والمدخل متقدم
  • اليمين هو 19
  • الرمز المميز التالي هو نهاية السطر ، وهو ليس عاملاً. لم يتم الدخول إلى حلقة while الداخلية.
  • يتم تعيين نتيجة تقييم 19 == 19 للطرف الأيسر ، على سبيل المثال 1 (كما هو الحال في معيار C).
  • الرمز التالي هو نهاية السطر ، وهو ليس عاملًا. تم ترك حلقة while الخارجية.

يتم إرجاع الرقم 1.

تحليل برات

وصف فوغان برات لأول مرة محللاً آخر للأسبقية يُعرف باسم تحليل برات في بحثه المنشور عام 1973 بعنوان "أسبقية العمليات من أعلى إلى أسفل" [ 3 ] ، وهو يعتمد على الانحدار التكراري . ورغم أنه يسبق تحليل تسلق الأسبقية، إلا أنه يُمكن اعتباره تعميماً له. [ 4 ]

صمم برات المحلل اللغوي في الأصل لتنفيذ لغة البرمجة CGOL ، وتم تناوله بمزيد من التفصيل في رسالة ماجستير تحت إشرافه. [ 5 ]

الدروس والتطبيقات:

طرق بديلة

توجد طرق أخرى لتطبيق قواعد أسبقية العمليات. إحداها هي بناء شجرة للتعبير الأصلي ثم تطبيق قواعد إعادة كتابة الشجرة عليها.

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

الأقواس الكاملة

ثمة طريقة أخرى تتمثل في وضع التعبير بين قوسين كاملين أولاً، وذلك بإضافة عدد من الأقواس حول كل عامل، بحيث تؤدي إلى الترتيب الصحيح حتى عند تحليلها باستخدام محلل خطي من اليسار إلى اليمين. وقد استُخدمت هذه الخوارزمية في مُصرّف FORTRAN I المبكر : [ 7 ]

كان مُترجم لغة فورتران 1 يُوسّع كل مُعامل بسلسلة من الأقواس. في شكل مُبسّط للخوارزمية، كان سيفعل

  • استبدل +و بـ ))+((و ))-((، على التوالي؛
  • استبدل *و /بـ )*(و )/(، على التوالي؛
  • أضف ((في بداية كل تعبير وبعد كل قوس مفتوح في التعبير الأصلي؛ و
  • أضف ))في نهاية التعبير وقبل كل قوس أيمن في التعبير الأصلي.

على الرغم من أن الأمر لم يكن واضحًا، إلا أن الخوارزمية كانت صحيحة، وعلى حد تعبير كنوت ، "الصيغة الناتجة موضوعة بين قوسين بشكل صحيح، صدق أو لا تصدق." [ 8 ]

مثال على كود لتطبيق C بسيط يتعامل مع وضع الأقواس في عوامل الرياضيات الأساسية ( +،،،،، و -) :*/^()

#include <stdio.h> #include <string.h>// حدود وسيط سطر الأوامر هي محللنا المعجمي. int main ( int argc , char * argv []) { int i ; printf ( "((((" ); for ( i = 1 ; i != argc ; i ++ ) { // strlen(argv[i]) == 2 if ( argv [ i ] && ! argv [ i ][ 1 ]) { switch ( * argv [ i ]) { case '(' : printf ( "((((" ); continue ; case ')' : printf ( "))))" ); continue ; case '^' : printf ( ")^(" ); continue ; case '*' : printf ( "))*((") ; continue ; case '/' : printf ( "))/((" ); continue ; case '+' : // فحص أحادي: إما الأول أو كان لديه عامل يتوقع وسيطًا ثانويًا if ( i == 1 || strchr ( "(^*/+-" , * argv [ i -1 ])) printf ( "+" ); else printf ( ")))+(((" ); continue ; case '-' : if ( i == 1 || strchr ( "(^*/+-" , * argv [ i -1 ])) printf ( "-" ); else printf ( ")))-(((" ); continue ; } } printf ( "%s" ,argv [ i ]); } printf ( ")))) \n " ); return0 ; }

أولاً، عليك تجميع برنامجك. بافتراض أن برنامجك مكتوب بلغة C وأن شفرة المصدر موجودة في ملف باسم program.c، ستستخدم الأمر التالي:

gcc program.c -o program

يُخبر الأمر أعلاه gcc بتجميع program.c وإنشاء ملف تنفيذي باسم program.

أمر لتشغيل البرنامج مع المعاملات، على سبيل المثال: a * b + c ^ d / e

./program a '*' b + c '^' d / e

ينتج

((((أ))*((ب)))+(((ج)^(د))/((ه))))

كما يظهر في مخرجات وحدة التحكم.

من عيوب هذه الاستراتيجية أن المعاملات الأحادية يجب أن تكون لها أسبقية أعلى من المعاملات الوسطية. فالمعامل "السالب" في الكود أعلاه له أسبقية أعلى من الأس. تشغيل البرنامج بهذه المدخلات

- أ ^ 2

ينتج هذا المخرج

((((-a)^(2))))

وهو ما قد لا يكون المقصود.

مراجع

  1. 1 2 هارويل، سام (29-08-2008). "محلل أسبقية المعاملات" . ويكي ANTLR3 . تم الاسترجاع في 25-10-2017 .
  2. ريتشاردز، مارتن؛ ويتبي-ستريفنز، كولين (1979). BCPL - اللغة ومترجمها . مطبعة جامعة كامبريدج. ISBN 9780521219655.
  3. برات، فوغان. " أسبقية عامل التشغيل من أعلى إلى أسفل ". وقائع الندوة السنوية الأولى لـ ACM SIGACT-SIGPLAN حول مبادئ لغات البرمجة (1973).
  4. نورفيل، ثيودور. " تحليل التعبيرات بالانحدار التكراري" . www.engr.mun.ca. الغرض من هذه المقالة هو [...] البدء بتسلق الأسبقية وإعادة هيكلتها لاستخدام نمط الأمر حتى نصل إلى محلل برات. [هذا هو المؤلف الذي صاغ مصطلح "تسلق الأسبقية"].
  5. فان دي فانتر، مايكل ل. " صياغة رسمية وبرهان صحة نظام لغة CGOL ". (رسالة ماجستير). تقرير فني لمختبر علوم الحاسوب في معهد ماساتشوستس للتكنولوجيا MIT-LCS-TR-147 (كامبريدج، ماساتشوستس). 1975.
  6. كروكفورد، د (2007-02-21). "أسبقية المشغل من أعلى إلى أسفل" .
  7. بادوا، ديفيد (2000). "مترجم فورتران 1" (ملف PDF) . الحوسبة في العلوم والهندسة . 2 (1): 70-75 . رمز Bibcode : 2000CSE.....2a..70P . doi : 10.1109/5992.814661 . مؤرشف من الأصل (ملف PDF) بتاريخ 17 يونيو 2020. تم الاطلاع عليه بتاريخ 29 مارس 2016 .
  8. كنوت، دونالد إي. (1962). "تاريخ كتابة المترجمات" . الحواسيب والأتمتة . 11 (12). إدموند سي. بيركلي: 8-14 .