استكمال SQL. الجزء 1. تعقيد التحليل. قصص حول إنهاء ملف ANTLR

أنشر المقال الأصلي عن هبر ، وترجمت ترجمته إلى مدونة Codingsight .

ماذا سيحدث في هذه المقالة؟


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

عندما أنشر ، سأضيف روابط للأجزاء التالية:

الجزء 1. تعقيد التحليل. قصص حول إنهاء ANTLR بملف
الجزء 2. تحسين العمل مع السلاسل وفتح الملفات
الجزء 3. عمر ملحقات Visual Studio. العمل مع IO. استخدام غير عادي
لجزء SQL 4. العمل مع استثناءات ، تأثير البيانات على عملية التطوير. باستخدام ML.NET

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

في هذا الجزء ، سوف أركز على مشاكل تحليل SQL ، ومكافحة هذه المشاكل والأخطاء التي ارتكبت في هذه المعركة.



بالنسبة لأولئك الذين يهتمون بجزء فقط من هذا ولمجرد التنقل السهل ، فإن محتوى المقالة:

المحتوى




من أنا؟


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

بطريقة ما اتضح أنه بالإضافة إلى الألعاب ، تم جذبني أيضًا لإنشاء ضبط مختلف لنفسي أو لمطورين آخرين. في بعض الأحيان ، كان قريبًا مما كان علي القيام به في العمل بعد ذلك بقليل. على سبيل المثال ، أحد المشاريع التي قمت بها عند دراسة Win32 API كان برنامجًا يبرز كود XML في عنصر تحكم التحرير الغني. بالإضافة إلى ذلك ، كان من الممكن تحميل كود بإضاءة خلفية إلى رموز BMP أو HTML أو BB التي كانت رائجة في ذلك الحين في منتديات مختلفة.

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

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

ما هي الصعوبات؟


هذه الكتلة ضرورية لتغمر القارئ في سياق ما نقوم به بالفعل.



تطوير سطح المكتب


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


تحليل SQL واللهجات


لقد كتبت أيضًا محللات صغيرة للغات مختلفة قبل هذا العمل. لبعض الوقت قمت بتدريس دورات .NET. بالنسبة لبعض المجموعات ، كمهمة إضافية ، كجزء من موضوع "السلسلة" ، اقترحوا كتابة محلل JSON البسيط الخاص بهم. فقط SQL ومتغيراتها بعيدة عن XML أو JSON المصممة لتكون مفهومة بشكل متساوٍ لدى المحللين والأشخاص. علاوة على ذلك ، فإن SQL أكثر تعقيدًا من الناحية اللغوية من C / C ++ ، مع العديد من وظائفها المتراكمة عبر تاريخ طويل. تم تصميم SQL بشكل مختلف ، فقد حاولوا جعلها تبدو وكأنها لغة طبيعية ، بالمناسبة ، تمامًا. تحتوي اللغة على عدة آلاف من الكلمات الرئيسية (حسب اللهجة). في كثير من الأحيان ، لتمييز تعبير واحد عن آخر ، تحتاج إلى إلقاء نظرة خاطفة على كلمتين (أو رموز) إلى الأمام. يسمى هذا النهج lookahead. هناك تصنيف للمحللين حسبإلى أي مدى يمكنهم النظر إلى الأمام: LA (1) أو LA (2) أو LA (*) ، مما يعني أن المحلل اللغوي يمكن أن ينظر إلى أبعد ما يمكن أن يستغرقه لتحديد الفرع الصحيح. في بعض الأحيان تتزامن النهاية الاختيارية لعبارة داخل عبارة SQL مع بداية فقرة أخرى ، وهي اختيارية أيضًا: مثل هذه المواقف تجعل المحللين أكثر تعقيدًا. يصب T-SQL الماء في النار ، حيث تكون الفاصلة المنقوطة اختيارية ، وقد تتعارض النهاية المحتملة ، ولكن غير الإلزامية لبعض عبارات SQL مع بداية عبارات أخرى.تعقد مثل هذه المواقف إلى حد كبير المحللين. يصب T-SQL الماء في النار ، حيث تكون الفاصلة المنقوطة اختيارية ، وقد تتعارض النهاية المحتملة ، ولكن غير الإلزامية لبعض عبارات SQL مع بداية عبارات أخرى.تعقد مثل هذه المواقف إلى حد كبير المحللين. يصب T-SQL الماء في النار ، حيث تكون الفاصلة المنقوطة اختيارية ، وقد تتعارض النهاية المحتملة ، ولكن غير الإلزامية لبعض عبارات SQL مع بداية عبارات أخرى.

أما زلت لا تصدق؟ هناك آلية لوصف اللغات الرسمية من خلال القواعد النحوية . النحو هو رمز بلغة تصف لغة أخرى. من القواعد ، يمكنك غالبًا إنشاء محلل باستخدام أداة. أشهر أدوات وصف القواعد اللغوية هي YACC و ANTLR . يتم استخدام موزعي YACC المولدين مباشرة في محركات MySQL و MariaDB و PostgreSQL. يمكنك محاولة أخذها مباشرة من المصدر المفتوح وتطوير إكمال التعليمات البرمجية ووظائف أخرى بناءً على تحليل SQL بناءً عليها. علاوة على ذلك ، سيحصل مثل هذا التنفيذ على تحديثات مجانية من حيث التطوير ، وسيضمن المحلل اللغوي أن يكون مطابقًا لمحرك قاعدة البيانات. فلماذا نستخدم ANTLR؟ يدعم نوعيًا C # /. NET ، وهناك أدوات جيدة للعمل معه ، بناءه أسهل بكثير في القراءة والكتابة. اتضح أن بناء جملة ANTLR مريح للغاية لدرجة أن Microsoft استخدمته مؤخرًا في وثائق C # الرسمية .

دعونا نعود إلى برهاني على تعقيد SQL ، مقارنة باللغات الأخرى ، من حيث التحليل. للقيام بذلك ، أريد مقارنة أحجام القواعد اللغوية للغات المختلفة المتاحة للجمهور. في dbForge نستخدم القواعد النحوية الخاصة بنا ، فهي أكثر اكتمالًا من تلك المتاحة علنًا ، ولكن للأسف ، فهي مسدودة جدًا بإدخالات رمز C # لدعم وظائف مختلفة ، المزيد عن هذا في قسم "التحليل بدون أشجار" في قسم "الأخطاء".

فيما يلي أحجام القواعد اللغوية للغات مختلفة:

JS - 475 خطوط محلل + 273 lexer = 748 خطوط
Java - 615 خطوط محلل + 211 lexer = 826 خطوط
C # - 1159 خطوط محلل + 433 lexer = 1592 خطوط
C ++ - 1933 خطوط

MySQL- 2515 سطرًا محلل + 1189 lexer = 3704 سطر
T-SQL - 4035 سطرًا محلل + 896 lexer = 4931 سطر
PL SQL - 6719 سطر محلل + 2366 lexer = 9085 سطرًا

في نهاية بعض lexers هناك تعداد أحرف unicode المتاحة في اللغة ، وهذا غير مفيد في تقييم مدى تعقيد اللغة. أخذت عدد الخطوط قبل البدء في مثل هذه التحويلات.

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


هذا ليس كل شيء ، لأننا لا نحتاج فقط إلى تحليل عدة ملفات في SQL. نقوم بعمل IDE ، مما يعني أننا يجب أن نعمل على نصوص غير كاملة أو غير صالحة. حتى إذا قمت بكتابة نصوصك دون أخطاء ، ربما تكتبها بشكل غير متسق ، فمن غير المحتمل أن يكون البرنامج النصي صالحًا طوال عملية تطويره. على سبيل المثال ، أكتب أولاً "SELECT FROM" ، وبعد ذلك سأكون سعيدًا لرؤية قائمة الجداول المتاحة. عندما أقوم بتحديد جدول ، سأعيد ترتيب حامل الخراطيش إلى SELECT ، اضغط على مفتاح المسافة وانتظر قائمة الأعمدة من هذا الجدول المعين. هذا مثال بسيط للغاية ، ولكنه يوضح أن المحلل اللغوي الذي يوفر إكمال التعليمات البرمجية في IDE لا يمكن أن يتعطل باستثناء مواجهة برنامج نصي غير صالح. كان علينا أن نتوصل إلى الكثير من الحيل لضمان عمل تلميح الأدوات بشكل صحيح في العديد من هذه السيناريوهات ،لكن لا يزال المستخدمون يرسلون سيناريوهات مختلفة للعمل مع النصوص البرمجية غير المكتملة ، مما يعني أننا يجب أن نبتكر حيلًا جديدة.

الحروب المسنده


عند تحليل الشفرة ، أحيانًا ما تكون هناك حالات لا توضح فيها الكلمة التالية أيًا من الخيارين المختارين. في بعض الأحيان يكون من الكافي إلقاء نظرة خاطفة على عدد محدد مسبقًا من الكلمات مسبقًا ويمكنك بالتأكيد اختيار بديل. آلية حل هذا النوع من عدم الدقة تسمى ANTLR lookahead. يتم إنشاء طريقة المحلل في هذه الحالة كسلسلة مضمنة من ifs ، كل منها يبحث عن كلمة واحدة أخرى. فيما يلي مثال على القواعد المولدة للشك من هذا النوع.

rule1:
    'a' rule2 | rule3
    ;

rule2:
    'b' 'c' 'd'
    ;

rule3:
    'b' 'c' 'e'
    ;

في منتصف القاعدة 1 ، بعد تمرير الرمز المميز 'a' بالفعل ، سيتعين على المحلل أن ينظر إلى الرمز المميز 2 لاختيار القاعدة التي يجب اتباعها. مرة أخرى ، سيتم إجراء هذا الفحص داخل القاعدة. يمكن إعادة كتابة هذه القواعد النحوية بحيث لا توجد هذه النظرة ، للأسف ، يعاني الهيكل غالبًا من مثل هذه التحسينات ، ومكاسب الأداء ليست عالية نسبيًا.

توجد آليات أكثر تعقيدًا لحل حالات عدم اليقين الأكثر تعقيدًا. واحد منهم هو آلية المسند النحوي (synpred) في ANTLR3.

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

تأمل في مثال مبسط. هناك 3 نقاط عدم اليقين (أ ، ب ، ج).

  1. يدخل المحلل A ، يتذكر الموضع في النص ، يبدأ ممرًا افتراضيًا من المستوى الأول.
  2. B, , 2- .
  3. C, , 3- .
  4. 3- , 2 .
  5. 2 , 1 B .
  6. , A, B .

وبالتالي ، سيتم إجراء جميع عمليات الفحص داخل C 4 مرات ، ب - 3 مرات ، أ - 2 مرات. ولكن ماذا لو كان البديل المناسب هو الثاني أو الثالث في القائمة؟ ثم ستفشل في مرحلة ما من أحد المسندات ، وسيتراجع الموضع في النص وسيبدأ مسند آخر في التنفيذ.

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

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

في حالات نادرة ، قمنا بكتابة المسندات الخاصة بنا في C # للتغلب على تلك التي يولدها ANTLR. لحسن الحظ ، توجد مثل هذه الآلية أيضًا.

حلول الدراجة باردة




الوراثة النحوية


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

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

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

ANTLR يجعل أداة ممتعة للتطوير عن طريق الضبط - هناك امتداد لـ VS ، وهناك ANTLRWorks. إدخال آلية الميراث ، لا أريد أن أفقد هذه الفرصة. ولكن كيف تشير بعد ذلك إلى القواعد الأساسية؟ يمكنك التوصل إلى نوع من الاصطلاح لتسمية الملفات ، ولكن هذا ليس واضحًا على الإطلاق. يمكن أن يكون الخيار الآخر هو الإشارة إلى هذه المعلومات الإضافية في ملف منفصل ، ولكن حتى الآن ، عند كتابة هذه السطور ، شعرت برائحة هذا الحل. كان الناتج مؤشرا على القواعد الأساسية في قواعد الوريث في شكل تعليق ANTLR. ستتجاهل جميع الأدوات هذا النص ، ويمكننا بسهولة سحب الشفرة التي تهمنا.

لقد تم تشكيل المتطلبات وحان الوقت لتنفيذها. كتبنا مهمة MsBuild ، والتي تم تضمينها في نظام البناء العام كإجراء مسبق للبناء. نفذت المهمة عمل المعالج النحوي المسبق لقواعد ANTLR ، لتوليد القواعد الناتجة من القاعدة والموروثة. تمت معالجة القواعد الناتجة بالفعل بواسطة ANTLR نفسها. إذا تم العثور على قاعدة بالاسم نفسه كما في الأصل في القواعد اللاحقة ، تمت إعادة تسمية القاعدة الأساسية: تمت إضافة اسم القواعد الأم إلى اسمها بعد التسطير السفلي. بهذا الاسم يمكن الاتصال به في الوريث.

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

ANTLR آخر بعد المعالجة


في العديد من لغات البرمجة ، إذا كانت الكلمة هي المفتاح ، فلا يمكن استخدامها بعد ذلك كاسم الكائن. في SQL ، اعتمادًا على اللهجة ، من 800 إلى 3000 كلمة رئيسية. ترتبط معظمها ارتباطًا وثيقًا بموضوع الموضوع ، بالإضافة إلى ذلك ، لم يتم إدخالها جميعًا على الفور ، لذلك فإن حظر استخدامها جميعًا كأسماء الكائنات سيقابله موجة من السخط. يقدم SQL مفهوم الكلمات الرئيسية المحجوزة وغير المحجوزة. لا يمكنك تسمية كائن بنفس الطريقة التي تستخدمها لكلمة رئيسية محجوزة (SELECT ، FROM إلخ) دون اقتباسها ، لأنها ليست كلمة رئيسية محجوزة (محادثة ، التوفر ، إلخ) - يمكنك ذلك. هذا السلوك يعقد تطور المحلل اللغوي. في وقت التحليل المعجمي ، كان السياق غير معروف ، لكن المحلل اللغوي يتطلب أرقامًا مختلفة للمعرف والكلمة الرئيسية. لحل هذه المشكلة ، أضفنا معالجة إضافية واحدة إلى محلل ANTLR.تستبدل المعالجة اللاحقة جميع الشيكات الواضحة بمعرف ، باستدعاء طريقة خاصة. تطبق هذه الطريقة فحصًا أصعب. إذا تم إدخال المعرف وكان من المتوقع وجود معرّف أكثر من ذلك ، فكل شيء على ما يرام ، ولكن إذا تم توفير كلمة رئيسية غير محجوزة للمدخلات ، فيجب التحقق منها بشكل إضافي. التحقق الإضافي هو أن الطريقة قد تم فحصها في السياق الحالي في البحث عن الفروع ، حيث يمكن استخدام هذه الكلمة الرئيسية غير المحجوزة تمامًا ككلمة رئيسية ، وإذا لم تكن هناك مثل هذه الفروع ، فيمكن استخدامها كمعرف.ولكن إذا تم إدخال كلمة رئيسية غير محجوزة ، فيجب فحصها بشكل إضافي. التحقق الإضافي هو أن الطريقة قد تم فحصها في السياق الحالي في البحث عن الفروع ، حيث يمكن استخدام هذه الكلمة الرئيسية غير المحجوزة تمامًا ككلمة رئيسية ، وإذا لم تكن هناك مثل هذه الفروع ، فيمكن استخدامها كمعرف.ولكن إذا تم إدخال كلمة رئيسية غير محجوزة ، فيجب فحصها بشكل إضافي. التحقق الإضافي هو أن الطريقة قد تم فحصها في السياق الحالي في البحث عن الفروع ، حيث يمكن استخدام هذه الكلمة الرئيسية غير المحجوزة تمامًا ككلمة رئيسية ، وإذا لم تكن هناك مثل هذه الفروع ، فيمكن استخدامها كمعرف.

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

أخطاء



تحليل عديم الأطوار




نتيجة المحلل ، كقاعدة ، هي شجرة بناء الجملة. شجرة بناء الجملة ( مجردة أو ملموسة ) هي بنية بيانات تعكس نص البرنامج من خلال منظور القواعد الرسمية. إذا كنت ترغب في تنفيذ محرر التعليمات البرمجية مع الإكمال التلقائي للغة التي توصلت إليها مؤخرًا ، بعد دراسة المشكلة ، فمن المحتمل أن تقوم بتنفيذ الخوارزمية التالية تقريبًا:

  1. تحليل النص في المحرر. احصل على شجرة النحو.
  2. ابحث عن العقدة أسفل حامل الخراطيش. تطابقه مع القواعد. تعرف على الكلمات الرئيسية وأنواع الكائنات التي ستكون متاحة عند هذه النقطة.

في هذه الحالة ، يتم تمثيل القواعد بشكل ملائم على شكل رسم بياني أو آلة حالة محدودة.

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

لكن كل شيء ليس واضحًا كما قد يبدو. والحقيقة أن ANTLR3 أسرع بكثير من ANTLR4. وفقا لقياساتنا ، الاختلافات حوالي 6 مرات. بالإضافة إلى ذلك ، يمكن لشجرة البنية للبرامج النصية الكبيرة أن تستهلك مساحة كبيرة من ذاكرة الوصول العشوائي ، وطالما أنه يتعين علينا البقاء على قيد الحياة في مساحة العنوان 32 بت لاستوديوهات Visual and SqlServer Management ، فقد يكون هذا أمرًا بالغ الأهمية.

استنتاج


قد تكون المجاميع الفرعية كما يلي:

  • ANTLR أداة قوية لبناء محللات
  • ميزتها على الآخرين هي أدوات ، بناء جملة مناسب ، عدد كبير من اللغات المدعومة
  • تمت إعادة كتابة ANTLR4 من الصفر ويتضمن العمل مع المحلل اللغوي بشكل مختلف عن الإصدار الثالث
  • هناك دائمًا طريقة للحصول على المزيد من مكتبات ThirdParty أكثر مما تقدم
  • لغة خاصة بـ SQL ، بناء محللات ليست مهمة سهلة
  • كود التحليل للمهام المتعلقة ببناء IDE له خصائصه الخاصة: تحتاج إلى التفكير في العمل على البرامج النصية غير المشفرة أو غير الصالحة

نراكم في الجزء التالي!

All Articles