فن تحليل 2 أو حرفي من العلامات الخاصة بك

+ BONUS: إدراج المتبادل من الطبقات في بعضها البعض في C ++


مرحبا يا هبر! هذه المقالة هي امتداد مباشر للمقال The Art of Parsing أو DOM بأيدينا ، حيث قمنا بتحليل مستند HTML وبنينا على أساسه شجرة بناء جملة مجردة (AST) مع إمكانية الوصول إلى أي عنصر من خلال الفهرسة باستخدام مكتبة C ++ القياسية فقط ، بمعنى آخر ، لقد تعلمنا التحليل من تلقاء أنفسنا أشياء تشبه XML. اسمحوا لي أن أذكرك بأن عملية التحليل أو التحليل / التحليل ، تتكون من مرحلتين: التحليل اللغوي (تحليل النص في الرموز) وبناء AST. إذا فحصنا الأول بتفصيل كبير ، مع أمثلة ورموز المصدر ، فإن وصف الثاني يبدو وكأنه دمية فراشة فارغة ، والتي تحتوي على غلاف فقط ، واستخرج المؤلف محتوى ممتازًا قبل النشر. كان هناك سبب ، لأن HTML من السهل جدًا إنشاء شجرة ، فأنت بحاجة إلى 4 فئات فقط: علامة فارغة ، كتلة ، عقدة نصية وجذر المستند الموروث من الكتلة. اليوم سوف نترك مثل هذه البساطة وراء وبناء شجرة حيث خصائص الخصائص ، سواء فارغة أو كتلة ، لن تكون مضمنة في سمات العلامات ، ولكن مباشرة في الطبقات ، ولهذا سيكون هناك الكثير من الطبقات لخلق. حقا كثير لن نبني ليس من لغات ترميز بسيطة معروفة ، ولكننا سننشئ لغتنا الخاصة ، مع القواعد الموضحة في الصورة أسفل المقطع. بالإضافة إلى ذلك ، في النهاية ، سنقوم بترجمة المستند ، أو بشكل أكثر صحة ، مع المقالة السابقة ، المحددة بلغتنا ، بتنسيق HTML ، وكمكافأة ، سأجيب على مبرمجي C ++ المبتدئين على سؤال تافه ولكن يصعب العثور عليه: كيفية دمج الفصول الدراسية في بعضها البعض؟



ملاحظات القواعد


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

... <ordered_list_item> = <number_marker> <div> <number_marker> = <number> "." {<number> "."} " " <number> = <digit> {<digit>} !! link ending ">" and image/span ending "]" can't follow "\n" or document start 

الترجمة: نهاية رابط ">" وعنصر الصورة / العنصر المضمن "]" لا يمكن أن يتبعا مباشرة بداية السطر أو المستند .

أي أنه في بداية السطر يصادف lexer "]" أو ">" ، يجب أن نأمره بتجاهل المعنى الخاص لهذه الأحرف والعمل معهم كما هو الحال مع النص العادي. هذه الطريقة لإضافة التعليقات إلى القواعد ليست الطريقة الوحيدة ؛ يمكنك القيام بذلك بطريقتك الخاصة. في النهاية ، الملف الذي يحتوي على وصف بناء الجملة ليس عبارة عن ورقة مصطلح ، لا أحد يفرض عليك اتباع جميع القواعد ومن المهم فقط أن يكون ملائماً لك للعمل بها. الشيء الرئيسي هو عدم نسيان التعليقات المقدمة وإظهارها في الأقسام الصحيحة من الكود.

دعونا نلقي نظرة على وصف كامل لهذه اللغة:

 <article> = {<article_item>} <article_item> = <underline> | <section> (* ARTICLE ITEMS *) <underline> = "___" {"_"} "\n" <section> = <div> {<div>} <div> = <paragraphs> | <title> | <quote> | <cite> | <unordered_list> | <ordered_list> (* SECTION ITEMS *) <paragraphs> = <paragraph> {"\n" <paragraph>} <paragraph> = <span> {<span>} ("\n" | <END>) <span> = <bold> | <italic> | <underlined> | <overlined> | <throwlined> | <subscript> | <superscript> | <marked> | <monospace> | <text> | <image> | <link> | <notification> <title> = <number signs> <left_angle_bracket> {<span>} <right_angle_bracket> ("\n" | <END>) <number signs> "######" | "#####" | "####" | "###" | "##" | "#" <quote> = "> " {<span>} ("\n" | <END>) <cite> = ">>" <number> ("\n" | <END>) <number> = <digit> {<digit>} (* PARAGRAPH ITEMS *) <bold> = "*[" {<span>} "]" <italic> = "%[" {<span>} "]" <underlined> = "_[" {<span>} "]" <overlined> = "^[" {<span>} "]" <throwlined> = "~[" {<span>} "]" <subscript> = "&[" {<span>} "]" <superscript> = "+[" {<span>} "]" <marked> = "=[" {<span>} "]" <monospace> = "`[" {<span>} "]" <text> = <textline> "\n" {<textline> "\n"} <textline> = <symbol> {<symbol>} <symbol> = /^[\n]/ <link> = "<<" <text> ">" {<span>} ">" <image> = "[<" <text> ">" [<text>] "]" <notification> = (" " | "\n") "@" <word> (" " | "\n" | <END>) <word> = (<letter> | <digit>) {<letter> | <digit>} <letter> = "a" | "b" | "c" | "d" | ... | "_" | "-" <digit> = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" (* LISTS *) <unordered_list> = <unordered_list_item> {<unordered_list_item>} <ordered_list> = <ordered_list_item> {<ordered_list_item>} <unordered_list_item> = <marker> <div> <marker> = ("*" {"*"}) | ("+" {"+"}) " " <ordered_list_item> = <number_marker> <div> <number_marker> = <number> "." {<number> "."} " " <number> = <digit> {<digit>} !! link ending ">" and image/span ending "]" can't follow "\n" or document start 

في المرة الأخيرة ، كان من الضروري كتابة المحطات الطرفية والتحقق من كل شخصية واردة للتأكد من توافقها مع أحدها. ولكن بعد ذلك كانت المحطات ذات طابع واحد! الآن ، بالإضافة إلى تسليط الضوء على المحطات الطرفية ، من الضروري تقسيمها بأنفسهم إلى مفاتيح - أي أحرف. لماذا هي "المفاتيح"؟ هم مفتاح lexer. نتيجة لجميع الإجراءات ، ستظهر الأسطر التالية في ملف القواعد:

 (* TERMINALS *) "___...", "\n", "\n\n", "> ", ">>...", "###...[", "*[", "%[", "_[", "^[", "~[", "&[", "+[", "=[", "`[", "]", "<<", "[<", ">", " @... ", "\n@...\n", " @...\n", "\n@... ", "***... ", "+++... ", "123.56. " (* KEYS *) "_", "\n" ">", "#", "*", "%", "^", "~", "&", "+", "=", "`", "<", "[", "]", " ", "@", "1..9", ".", <END> 

كومة من الأنواع المتوقعة من الرموز


في المرة الأخيرة ، مرة أخرى ، كان كل شيء أكثر بساطة ، كان لدينا 10 أنواع فقط من الرموز ، دون حساب النهاية ، وكانت هناك فرصة أقل للتشويش في حديقة الحيوانات الرمزية هذه. الآن من الواضح أن هناك المزيد من الأنواع. اسمحوا لي أن أذكركم بأن مهمة lexer هي ترك المحلل اللغوي أقل قدر ممكن من العمل ، من الناحية المثالية ، فقط بناء شجرة. لذلك ، يجب أن تعكس مجموعة الرموز المميزة جوهرها بأكبر قدر ممكن من الدقة. في المقالة الأولى ، أعطيت مثالًا على مجموعة جيدة ، وفي هذا سأقدمها مع "مثال مضاد". راجع المحطات الطرفية التي تبدأ عناصر النص المضمن (غامق - غامق ، مائل - مائل ، إلخ)؟ يمكننا تحليلها في زوج من الرموز: المعلم ("*" ، "٪" ، إلخ) والعبد ("[") وتمريره في النموذج إلى المحلل اللغوي. من السهل تخمين أنه من الأفضل وضع تعريف دقيق لعنصر النص على مستوى lexer ، أي قم بتعريف "* [" كـ "bold_start" ، "٪ [" كـ "italic_start" ، إلخ. كلما زاد عدد الأنواع وأكثر دقة تعكس نفسها - كلما كان ذلك أفضل. وعلاوة على ذلك ، والثاني هو أكثر أهمية من الأول. على سبيل المثال ، يمكننا تحليل الإشعار الخاص بالرمز "@" واسم المستخدم ، لكن من الواضح أنه من الأفضل تركهما مدمجين في رمز واحد.
حسنًا ، قررنا الأنواع. من أين تبدأ الإجراء الخاص بتحليل النص إلى رموز؟ كما في ذلك الوقت ، ابدأ من البداية. ما الذي يمكن أن يتبع مباشرة بداية المستند الذي تم تحليله؟ لا تتعجل لثني أصابعك. على عكس HTML ، يمكن أن تبدأ جميع الأنواع الـ 22 هنا. لا بأس ، مسلحين بتوحيد الشيء ، نكتب هكذا:

 curr_token_type = TEXT | UNDERLINE | TITLE_START | QUOTE_START | CITE | BOLD_START | ... 

وفي وظيفة معالجة الرمز:

 case TEXT | UNDERLINE | TITLE_START | QUOTE_START | CITE | ... 

إذا كنت لا تفهم ما هو على المحك ، اقرأ المقال الأول .

لا تخافوا من النوع العام الطويل للرمز المميز. الحرف الأول من السلسلة على الفور يقلل طوله إلى 2-4 أنواع. نظرًا لأن محطاتنا متعددة الأحرف ، يعتمد التعريف على المفاتيح.

انها بسيطة ، انظر لنفسك:

 if (c == '_') { buffer.push_back('_'); curr_token_type = TEXT | UNDERLINE | UNDERLINED_START; 

حدد تسطير أسفل السطر الرمز المميز قيد الإنشاء على الفور إلى ثلاثة أنواع: نص عادي أو خط أفقي أو بداية النص المسطر ("_ [").

بالعودة إلى المشكلة ، كيفية تتبع جميع الأنواع العامة وتذكر معالجتها جميعًا؟ الحصول على كومة ... في دفتر! هذا صحيح ، اكتب جميع الأنواع العامة التي تظهر بعد "curr_token_type = ..." في القائمة ، وبعد معالجة أحدها ، أخرج الآخر من القائمة من النهاية. يمكنك تنظيم العمل مع القائمة وكما هو الحال مع قائمة الانتظار ، لا يهم كثيرًا. الشيء الرئيسي هو أنك لن تنسى أي الأنواع تمت معالجتها بالفعل وما زال يتعين معالجتها.

شجرة الطبقة


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

 Node { Node * parent, Node_type type } #- Root { Root_item[] children, ulong children_count } 

لذلك حددنا الفئة الأساسية المستقبلية لجميع العقد ومشتقاتها - جذر الشجرة ، أي المستند نفسه. يتكون المستند (راجع BPF أعلاه) من نوعين من العقد: مقطع وخط أفقي (تسطير). نحدد الفئة الأساسية Root_item لهم ونصف كل منها بالطريقة نفسها التي وصفنا بها الجذر. بالإضافة إلى ذلك ، هنا ، في المفكرة ، نشير على الفور إلى جميع الحقول الأخرى للفئات ، إن وجدت. بالنسبة للجذر ، هذا هو عدد "الأطفال" - وهذا هو ، الأقسام الداخلية والخطوط الأفقية. يتكون القسم من عناصر سنعرف عليها Div الفئة الأساسية Div وما إلى ذلك ، مع الانتقال بشكل متكرر خلال القواعد ، سنحدد جميع الفئات المطلوبة. قبل كتابة الكود ، نحدد هنا جميع تضمين الرؤوس. الأمر بسيط: يجب إدراج جميع الأحفاد المباشرين للصفوف المعممة الأساسية في الفصول التي تحتوي عليها.

نشير إلى هذه التبعيات في شكل قوائم بعد الشبكة ، ونحصل على المستند التالي:

 Node { Node * parent, Node_type type } #- Root { Root_item[] children, ulong children_count } #Underline, #Section Root_item {} #- Underline {} Section { Div[] children, ulong children_count } #Paragraph, #Title, #Quote, #Cite, #Unordered_list, #Ordered_list Div {} #- Paragraph { Span[] children, ulong children_count } #Bold, #Italic, #Underlined, #Overlined, #Throwlined, #Subscript, #Superscript, #Marked, #Monospace, #Text, #Image, #Link, #Notification Title { char level, Span[] children, ulong children_count } #Bold, #Italic, #Underlined, #Overlined, #Throwlined, #Subscript, #Superscript, #Marked, #Monospace, #Text, #Image, #Link, #Notification Quote { Span[] children, ulong children_count } #Bold, #Italic, #Underlined, #Overlined, #Throwlined, #Subscript, #Superscript, #Marked, #Monospace, #Text, #Image, #Link, #Notification Cite { ulong number } #- Unordered_list { Div } #Paragraph, #Title, #Quote, #Cite, #Ordered_list Ordered_list { Div } #Paragraph, #Title, #Quote, #Cite, Unordered list Span {} #- Bold { Span[] children, ulong children_count } #Italic, #Underlined, #Overlined, #Throwlined, #Subscript, #Superscript, #Marked, #Monospace, #Text, #Image, #Link, #Notification Italic { Span[] children, ulong children_count } #Bold, #Underlined, #Overlined, #Throwlined, #Subscript, #Superscript, #Marked, #Monospace, #Text, #Image, #Link, #Notification Underlined { Span[] children, ulong children_count } #Bold, #Italic, #Overlined, #Throwlined, #Subscript, #Superscript, #Marked, #Monospace, #Text, #Image, #Link, #Notification Overlined { Span[] children, ulong children_count } #Bold, #Italic, #Underlined, #Throwlined, #Subscript, #Superscript, #Marked, #Monospace, #Text, #Image, #Link, #Notification Throwlined { Span[] children, ulong children_count } #Bold, #Italic, #Underlined, #Overlined, #Subscript, #Superscript, #Marked, #Monospace, #Text, #Image, #Link, #Notification Subscript { Span[] children, ulong children_count } #Bold, #Italic, #Underlined, #Overlined, #Throwlined, #Superscript, #Marked, #Monospace, #Text, #Image, #Link, #Notification Superscript { Span[] children, ulong children_count } #Bold, #Italic, #Underlined, #Overlined, #Throwlined, #Subscript, #Marked, #Monospace, #Text, #Image, #Link, #Notification Marked { Span[] children, ulong children_count } #Bold, #Italic, #Underlined, #Overlined, #Throwlined, #Subscript, #Superscript, #Monospace, #Text, #Image, #Link, #Notification Monospace { Span[] children, ulong children_count } #Bold, #Italic, #Underlined, #Overlined, #Throwlined, #Subscript, #Superscript, #Marked, #Text, #Image, #Link, #Notification Text { string text } #- Image { string src, string alt } #- Link { string URL, Span[] children, ulong children_count } #Bold, #Italic, #Underlined, #Overlined, #Throwlined, #Subscript, #Superscript, #Marked, #Monospace, #Text, #Image, #Notification Notification { string user } #- 

أنا هنا وضعت علامة "# -" على عدم وجود التبعيات وإزالة إدراج الطبقات في حد ذاتها.
نلاحظ أن جميع فئات التنسيق المدمجة (Bold ، Italic ، ...) تعتمد على بعضها البعض ، بالإضافة إلى فئة Link ، التي تعتمد عليها أيضًا! في وضع مماثل ، Unordered_list و Ordered_list. تضمين الرؤوس في بعضها البعض لن يؤدي فقط إلى تجاهل أحدها ، كما هو متوقع ، ولكن لن يمر التحقق من قبل المعالج ، ولن يسمح لنا التضمين أحادي الاتجاه بأن نعلن داخل الفصل المتضمّن وظيفة فتح عنصر الفصل وإعادة الرابط إليه. كيف تكون هناك طريقتان.

إدراج الطبقات في بعضها البعض


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

لكن هذه الخدعة لن تعمل مع فئة Link ، لأنها تحتوي على حقل إضافي - سلسلة URL. سوف نستخدم الطريقة الثانية.

هل يعلم الجميع أن فصل الفئات إلى تعريفات وتعريفات هو شكل جيد في برمجة C ++؟ في الرأس بالملحق .h أو .hpp - الإعلان ، في المصدر بالملحق .cpp - التعريف ، أليس كذلك؟ والآن أنتقل إلى القادمين الجدد إلى البرمجة: الجلوس وربط أحزمة المقاعد الخاصة بك ، لأنها ستكون غير سارة. بعد كل شيء ، ما نصفه في ملف بالملحق .h ليس أكثر من تعريف فئة. وفي ملف .cpp ، يوجد بالفعل تطبيق لأساليب هذه الفئة. لا أفهم؟ لقد خدعنا في المدرسة. يتم تعريف فئة كدالة ، في سطر واحد ، إذا كان لا يحتوي على قوالب.

إنها أبسط من وظيفة ، لأنها لا تحتوي على وسيطات. هنا إعلان فئة نموذجي:

 class MyClass; 

وهذا كل شيء! وإعلانات الحقول والأساليب هي بالفعل تعريفها .

سوف نستفيد من هذا. ندرج عنوان فئة Inline في عنوان فئة Link ، ونعلن فيه فئة Link نفسها قبل تعريف الفئة Inline. يجب أن يبدو الملف inline.h كما يلي:

 #ifndef INLINE_H #define INLINE_H #include "AST/span.h" #include "AST/text.h" #include "AST/image.h" #include "AST/notification.h" class Link; class Inline : public Span { public: static const unsigned long MAX_CHILDREN_COUNT = 0xFFFFFF; private: Span ** children; unsigned long children_count; unsigned long extended; void extend(); public: Inline(const Node * parent, const Node_type &type); Inline(const Span * span); ~Inline(); Inline * add_text(const string &text); Inline * add_image(const string &src, const string &alt); Inline * add_notification(const string &user); Link * open_link(const string &URL); ... 

لا تزال فئة Inline لا تعرف شيئًا عن فئة Link وحقولها وأساليبها ، لكنها تعرف بالتأكيد عن وجودها. لذلك ، يمكننا إعلان الأساليب التي تُرجع المؤشر إلى كائن من فئة Link ، أو تقبله كوسيطة. لم يتم تحديد مؤشر الكلمة عشوائيًا ، ولا تعرف الفئة المضمنة بعد كيفية إنشاء كائنات من النوع Link ، نظرًا لعدم تمكنها من الوصول إلى مُنشئها ، لكن يمكنها العمل مع جميع المؤشرات ، لأن لديهم جميعا نفس الواجهة. لكننا لسنا بحاجة إلى أشياء هنا. ولكن في تطبيق أسلوب open_link ، يتم إنشاء كائن من النوع Link ويتم إرجاع مؤشر إليه ، مما يعني أنه بحلول الوقت الذي يدخل فيه المعالج الأولي هذه الطريقة ، يجب إعلان المُنشئ وأساليب Link الأخرى التي قد تحتاج إليها طريقة open_link. نحن هنا نستفيد من تقسيم الكود المصدري إلى ملفات منفصلة مع الرؤوس والتنفيذ. يتم تضمين ملف inline.h في ملف inline.cpp ("undercloud") ، ولكن لم يتم تضمين ملف link.h في inline.h. لذلك ، بما في ذلك في inline.cpp سيكون أول تضمين للمعالج المسبق. ثم سيبدأ ملف inline.cpp بهذا الشكل:

 #include "inline.h" #include "link.h" ... 

أكرر كل ما سبق. يتم تضمين عنوان الفئة Ah في عنوان الفئة Bh كالمعتاد ، ويتم الإعلان عن الفئة B قبل الفئة A ونضمّن عنوانها في المصدر A.cpp. هذه الطريقة ليست هي الطريقة الوحيدة ، ولكن أبسط ، في رأيي.

ألاحظ أن هذا الإدراج المتبادل للفئات لا يمنع الفئة B من وراثة الفئة A ، إذا قمنا بتدوين إعلانها قبل تعريف الفئة A. هذا هو بالضبط ما فعلته ، ورث Ordered_list من Unordered_list.

بناء شجرة


لذلك ، وصلنا إلى بناء شجرة بناء جملة مجردة. في المقالة الأخيرة ، تناسب الوظيفة 50 سطرًا. Spoiler: هذه المرة نمت إلى ما يقرب من 1400. مبدأ التشغيل هو نفسه: نحن نتحقق من نوع كل رمز ، وننفذ ، بناءً عليه ، قسم معين من التعليمات البرمجية ، وتخزين عقدة شجرة مفتوحة في الذاكرة. ولكن إذا كانت لغة HTML تقريبًا تتضمن جزءًا واحدًا فقط من الأوامر الثلاثة: أضف عقدة فارغة داخل العقدة المفتوحة ، ثم افتح عقدة جديدة في العقدة المفتوحة وأغلق العقدة المفتوحة ، ثم ترجع أصلها ، ثم يعتمد الإجراء المطلوب هنا أيضًا على نوع العقدة المفتوحة. على سبيل المثال ، إذا تم تشغيل الرمز المميز "الخط الأفقي" ، وكانت العقدة المفتوحة هي جذر المستند ، فكل ما هو مطلوب هو إضافة سطر إلى هذه العقدة المفتوحة باستخدام casting والدالة ذات الاسم الشرطي add_line () ، شيء من هذا القبيل:

 if (type == Node::ROOT) static_case<Root*>(open_node)->add_line(); 

ولكن إذا كانت العقدة المفتوحة هي فقرة (فقرة) ، فأنت بحاجة أولاً لإغلاقها وجميع الأسلاف المحتملين (القوائم النقطية والمرقمة) حتى تصبح العقدة المفتوحة من نوع "القسم" ، ثم أغلقها:

 else if (type == Node::PARAGRAPH) { open_node = static_cast<Paragraph*>(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast<Unordered_list*>(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast<Unordered_list*>(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->close(); } open_node = static_cast<Section*>(open_node)->close(); open_node = tree->add_line(); } 

إذا كانت العقدة المفتوحة هي تعليق على الصورة ، فإن الخط الأفقي يكسر النحوي تمامًا ، ويجب إلقاء استثناء ، وإذا كانت العقدة المفتوحة ليست رابطًا ، والرمز المميز الوارد ">" من النوع "LINK_FINISH" ، فيجب ألا تتم معالجته على أنه نهاية الارتباط ، ولكن كيف النص ، الخ

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

بعد ذلك ، سيكون لدينا بالفعل شجرة صغيرة:

 <article> | +-<section> | +-<h1> | +-"   DOM  " 

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

المادة نفسها
 @2che >>442964 #[   DOM  ] , !          markdown,       ,   —           « »,     .   ,    ,    , ,  LibreOffice Writer,  %[ ],   — %[].     ,        «parser example», «html to DOM», «how to parse html»  .   ,              ,    ,   flex, bison, llvm  yacc. ,      ,    (gumbo, jsoup, rapidjson,  Qt  .)  ,              C++     ,              .  ,        AST (  ),    ,      ,       .  , —    —       ,       .           .           ,      .    ,    ,     .    HTML,      .  , ,  %[ ] —         .      : 1. *[ ]    —    ,    . 2. *[ ] —        %[  ] (AST — abstract syntax tree),  %[  ] (DOM — document object model).    .  ,     IDE   ,     .   -    — %[ - ()]  %[  -].    ,     .        : > `[<> = <_1> <_> <_2>]       ,    . ,   ,     «»   ..   ?            : %[]  %[]. *[] — ,  : > `[<_1> = <> (<_> | <_>) <>] *[] ,    .      : > `[<> = <_1> "+" <_2> <_1> = <> ("*" | "/") <>]  "+", "*", "/" — .      ,          , —   .       <<https://ru.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D0%BC%D0%B0_%D0%91%D1%8D%D0%BA%D1%83%D1%81%D0%B0_%E2%80%94_%D0%9D%D0%B0%D1%83%D1%80%D0%B0>>  <<https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D1%81%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D0%B0_%D0%91%D1%8D%D0%BA%D1%83%D1%81%D0%B0_%E2%80%94_%D0%9D%D0%B0%D1%83%D1%80%D0%B0>>.    —    ,   .          ,     . ,     , ,        .     ,             ,        ,   . ,    .     HTML5   : > `[stub]   ,      (   , ..  ,      ).     :  ,                , ? ,       ,  .  .  ,  disassemble(ifsteam &file)   ,             process(const char &c),    . ,   process   switch,              .     :    switch    ,     .  ,       ,   . ,      : , ,  ,      HTML    ( PHP,   "<?… ?>".        case.   ?    .       (  —  ,      —      ).         (1, 2, 4, 8  .).        : 0001, 0010, 0100  ..,           .      ,  .   : > `[enum Token_type { END = 1, TEXT = 2, OPENING_BLOCK_TAG_NAME = 4, CLOSING_BLOCK_TAG_NAME = 8, EMPTY_TAG_NAME = 16, COMMENT = 32, MACRO_TAG = 64, ATTRIBUTE_NAME = 128, UNQUOTED_ATTRIBUTE_VALUE = 256, SINGLE_QUOTED_ATTRIBUTE_VALUE = 512, DOUBLE_QUOTED_ATTRIBUTE_VALUE = 1024 };]   process: > `[stub]    switch    ( ),    case       .    ,    :     ,      ,      (),   .               .       ()    ,      «»  ..         gedit: [<https://hsto.org/webt/72/fw/tw/72fwtwt_waeie4ulzftkxua356w.png>]     ,           .     disassemble: > `[stub]        TEXT,       END    ( ,  ).         HTML-  ,    - PHP,         "[ "<_>": <_> ]".   : > =[ `[stub]] =[ `[stub]]        —   .     ,             -.         DOM,    .        HTML-?   —      ,         ,     —   «Node»,     «Block» (,     )       «Root».      ,    , ,  <p>, <li>, <strong>  ,      .    .      ,    —            :     ,     ,    .   ,   ,    Node,   ,    .    %[  ].  : > `[stub]   !     ,      : `[| +--<ROOT> | +--<!DOCTYPE> | +--<html> | +--<head> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<title> | | | +--<link> | | | +--<link> | | | +--<COMMENT> | +--<body> | +--<header> | | | +--<div> | +--<nav> | | | +--<ul> | | | +--<li> | | | | | +--<a> | | | +--<li> | | | | | +--<a> | | | +--<li> | | | +--<a> | +--<main> | | | +--<MACRO> | +--<footer> | +--<hr> | +--<small>] ,       DOM,   jQuery, Jsoup, beautifulsoup  Gumbo   ,   ,       ,     <style>  <script>,      .   ,     . . PS     <<https://gitlab.com/2che/nyHTML>>. , ,      . 

الرموز من lexer
 0: ["2che": الإخطار]
1: ["
": NEWLINE]
2: ["442964": CITE]
3: ["# [": TITLE_START]
4: ["فن التحليل أو القيام بنفسك دوم": النص]
5: ["]": SPAN_OR_IMAGE_FINISH]
6: ["

": DOUBLE_NEWLINE]
7: [ ", !          markdown,       ,   —           « »,     .   ,    ,    , ,  LibreOffice Writer,  " : TEXT ]
8: [ "%[" : ITALIC_START ]
9: [ " " : TEXT ]
10: [ "]" : SPAN_OR_IMAGE_FINISH ]
11: [ ",   — " : TEXT ]
12: [ "%[" : ITALIC_START ]
13: [ "" : TEXT ]
14: [ "]" : SPAN_OR_IMAGE_FINISH ]
15: [ ".     ,        «parser example», «html to DOM», «how to parse html»  .   ,              ,    ,   flex, bison, llvm  yacc. ,      ,    (gumbo, jsoup, rapidjson,  Qt  .)  ,              C++     ,              .  ,        AST (  ),    ,      ,       ." : TEXT ]
16: [ "

" : DOUBLE_NEWLINE ]
17: [ " , —    —       ,       .           .           ,      .    ,    ,     .    HTML,      ." : TEXT ]
18: [ "

" : DOUBLE_NEWLINE ]
19: [ " , ,  " : TEXT ]
20: [ "%[" : ITALIC_START ]
21: [ " " : TEXT ]
22: [ "]" : SPAN_OR_IMAGE_FINISH ]
23: [ " —         .      :" : TEXT ]
24: [ "
" : NEWLINE ]
25: [ "1. " : ORDERED_LIST_ITEM_MARKER ]
26: [ "*[" : BOLD_START ]
27: [ " " : TEXT ]
28: [ "]" : SPAN_OR_IMAGE_FINISH ]
29: [ "    —    ,    ." : TEXT ]
30: [ "
" : NEWLINE ]
31: [ "2. " : ORDERED_LIST_ITEM_MARKER ]
32: [ "*[" : BOLD_START ]
33: [ " " : TEXT ]
34: [ "]" : SPAN_OR_IMAGE_FINISH ]
35: [ " —        " : TEXT ]
36: [ "%[" : ITALIC_START ]
37: [ "  " : TEXT ]
38: [ "]" : SPAN_OR_IMAGE_FINISH ]
39: [ " (AST — abstract syntax tree),  " : TEXT ]
40: [ "%[" : ITALIC_START ]
41: [ "  " : TEXT ]
42: [ "]" : SPAN_OR_IMAGE_FINISH ]
43: [ " (DOM — document object model)." : TEXT ]
44: [ "

" : DOUBLE_NEWLINE ]
45: [ "   .  ,     IDE   ,     .   -    — " : TEXT ]
46: [ "%[" : ITALIC_START ]
47: [ " - ()" : TEXT ]
48: [ "]" : SPAN_OR_IMAGE_FINISH ]
49: [ "  " : TEXT ]
50: [ "%[" : ITALIC_START ]
51: [ "  -" : TEXT ]
52: [ "]" : SPAN_OR_IMAGE_FINISH ]
53: [ ".    ,     .        :" : TEXT ]
54: [ "
" : NEWLINE ]
55: [ "> " : QUOTE_START ]
56: [ "`[" : MONOSPACE_START ]
57: [ "<" : TEXT ]
58: [ ">" : LINK_FINISH ]
59: [ " = <_1" : TEXT ]
60: [ ">" : LINK_FINISH ]
61: [ " <_" : TEXT ]
62: [ ">" : LINK_FINISH ]
63: [ " <_2" : TEXT ]
64: [ ">" : LINK_FINISH ]
65: [ "]" : SPAN_OR_IMAGE_FINISH ]
66: [ "

" : DOUBLE_NEWLINE ]
67: [ "      ,    . ,   ,     «»   .." : TEXT ]
68: [ "

" : DOUBLE_NEWLINE ]
69: [ "  ?" : TEXT ]
70: [ "

" : DOUBLE_NEWLINE ]
71: [ "           : " : TEXT ]
72: [ "%[" : ITALIC_START ]
73: [ "" : TEXT ]
74: [ "]" : SPAN_OR_IMAGE_FINISH ]
75: [ "  " : TEXT ]
76: [ "%[" : ITALIC_START ]
77: [ "" : TEXT ]
78: [ "]" : SPAN_OR_IMAGE_FINISH ]
79: [ ". " : TEXT ]
80: [ "*[" : BOLD_START ]
81: [ "" : TEXT ]
82: [ "]" : SPAN_OR_IMAGE_FINISH ]
83: [ " — ,  :" : TEXT ]
84: [ "
" : NEWLINE ]
85: [ "> " : QUOTE_START ]
86: [ "`[" : MONOSPACE_START ]
87: [ "<_1" : TEXT ]
88: [ ">" : LINK_FINISH ]
89: [ " = <" : TEXT ]
90: [ ">" : LINK_FINISH ]
91: [ " (<_" : TEXT ]
92: [ ">" : LINK_FINISH ]
93: [ " | <_" : TEXT ]
94: [ ">" : LINK_FINISH ]
95: [ ") <" : TEXT ]
96: [ ">" : LINK_FINISH ]
97: [ "]" : SPAN_OR_IMAGE_FINISH ]
98: [ "

" : DOUBLE_NEWLINE ]
99: [ "*[" : BOLD_START ]
100: [ "" : TEXT ]
101: [ "]" : SPAN_OR_IMAGE_FINISH ]
102: [ " ,    .      :" : TEXT ]
103: [ "
" : NEWLINE ]
104: [ "> " : QUOTE_START ]
105: [ "`[" : MONOSPACE_START ]
106: [ "<" : TEXT ]
107: [ ">" : LINK_FINISH ]
108: [ " = <_1" : TEXT ]
109: [ ">" : LINK_FINISH ]
110: [ " "+" <_2" : TEXT ]
111: [ ">" : LINK_FINISH ]
112: [ "
" : NEWLINE ]
113: [ "<_1" : TEXT ]
114: [ ">" : LINK_FINISH ]
115: [ " = <" : TEXT ]
116: [ ">" : LINK_FINISH ]
117: [ " ("*" | "/") <" : TEXT ]
118: [ ">" : LINK_FINISH ]
119: [ "]" : SPAN_OR_IMAGE_FINISH ]
120: [ "

" : DOUBLE_NEWLINE ]
121: [ " "+", "*", "/" — ." : TEXT ]
122: [ "
" : NEWLINE ]
123: [ "     ,          , —   ." : TEXT ]
124: [ "

" : DOUBLE_NEWLINE ]
125: [ "      " : TEXT ]
126: [ "<<" : LINK_START ]
127: [ "https://ru.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D0%BC%D0%B0_%D0%91%D1%8D%D0%BA%D1%83%D1%81%D0%B0_%E2%80%94_%D0%9D%D0%B0%D1%83%D1%80%D0%B0" : TEXT ]
128: [ ">" : LINK_FINISH ]
129: [ "" : TEXT ]
130: [ ">" : LINK_FINISH ]
131: [ "  " : TEXT ]
132: [ "<<" : LINK_START ]
133: [ "https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D1%81%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D0%B0_%D0%91%D1%8D%D0%BA%D1%83%D1%81%D0%B0_%E2%80%94_%D0%9D%D0%B0%D1%83%D1%80%D0%B0" : TEXT ]
134: [ ">" : LINK_FINISH ]
135: [ "" : TEXT ]
136: [ ">" : LINK_FINISH ]
137: [ ".    —    ,   .          ,     . ,     , ,        .     ,             ,        ,   . ,    .     HTML5   :" : TEXT ]
138: [ "
" : NEWLINE ]
139: [ "> " : QUOTE_START ]
140: [ "`[" : MONOSPACE_START ]
141: [ "stub" : TEXT ]
142: [ "]" : SPAN_OR_IMAGE_FINISH ]
143: [ "

" : DOUBLE_NEWLINE ]
144: [ "  ,      (   , ..  ,      ).     :  ,                , ? ,       ,  .  .  ,  disassemble(ifsteam &file)   ,             process(const char &c),    . ,   process   switch,              .     :    switch    ,     .  ,       ,   . ,      : , ,  ,      HTML    ( PHP,   "<?… ?" : TEXT ]
145: [ ">" : LINK_FINISH ]
146: [ "".        case.   ?    .       (  —  ,      —      ).         (1, 2, 4, 8  .).        : 0001, 0010, 0100  ..,           .      ,  .   :" : TEXT ]
147: [ "
" : NEWLINE ]
148: [ "> " : QUOTE_START ]
149: [ "`[" : MONOSPACE_START ]
150: [ "enum Token_type {" : TEXT ]
151: [ "
" : NEWLINE ]
152: [ " END = 1, TEXT = 2," : TEXT ]
153: [ "
" : NEWLINE ]
154: [ " OPENING_BLOCK_TAG_NAME = 4, CLOSING_BLOCK_TAG_NAME = 8, EMPTY_TAG_NAME = 16, COMMENT = 32, MACRO_TAG = 64," : TEXT ]
155: [ "
" : NEWLINE ]
156: [ " ATTRIBUTE_NAME = 128, UNQUOTED_ATTRIBUTE_VALUE = 256, SINGLE_QUOTED_ATTRIBUTE_VALUE = 512, DOUBLE_QUOTED_ATTRIBUTE_VALUE = 1024" : TEXT ]
157: [ "
" : NEWLINE ]
158: [ "};" : TEXT ]
159: [ "]" : SPAN_OR_IMAGE_FINISH ]
160: [ "

" : DOUBLE_NEWLINE ]
161: [ "  process:" : TEXT ]
162: [ "
" : NEWLINE ]
163: [ "> " : QUOTE_START ]
164: [ "`[" : MONOSPACE_START ]
165: [ "stub" : TEXT ]
166: [ "]" : SPAN_OR_IMAGE_FINISH ]
167: [ "

" : DOUBLE_NEWLINE ]
168: [ "   switch    ( ),    case       .    ,    :     ,      ,      (),   .               .       ()    ,      «»  ..         gedit:" : TEXT ]
169: [ "
" : NEWLINE ]
170: [ "[<" : IMAGE_START ]
171: [ "https://hsto.org/webt/72/fw/tw/72fwtwt_waeie4ulzftkxua356w.png" : TEXT ]
172: [ ">" : LINK_FINISH ]
173: [ "]" : SPAN_OR_IMAGE_FINISH ]
174: [ "

" : DOUBLE_NEWLINE ]
175: [ "    ,           .     disassemble:" : TEXT ]
176: [ "
" : NEWLINE ]
177: [ "> " : QUOTE_START ]
178: [ "`[" : MONOSPACE_START ]
179: [ "stub" : TEXT ]
180: [ "]" : SPAN_OR_IMAGE_FINISH ]
181: [ "

" : DOUBLE_NEWLINE ]
182: [ "       TEXT,       END    ( ,  )." : TEXT ]
183: [ "

" : DOUBLE_NEWLINE ]
184: [ "        HTML-  ,    - PHP,         "[ "<_" : TEXT ]
185: [ ">" : LINK_FINISH ]
186: [ "": <_" : TEXT ]
187: [ ">" : LINK_FINISH ]
188: [ " " : TEXT ]
189: [ "]" : SPAN_OR_IMAGE_FINISH ]
190: [ "".   :" : TEXT ]
191: [ "
" : NEWLINE ]
192: [ "> " : QUOTE_START ]
193: [ "=[" : MARKED_START ]
194: [ " " : TEXT ]
195: [ "`[" : MONOSPACE_START ]
196: [ "stub" : TEXT ]
197: [ "]" : SPAN_OR_IMAGE_FINISH ]
198: [ "]" : SPAN_OR_IMAGE_FINISH ]
199: [ "
" : NEWLINE ]
200: [ "=[" : MARKED_START ]
201: [ " " : TEXT ]
202: [ "`[" : MONOSPACE_START ]
203: [ "stub" : TEXT ]
204: [ "]" : SPAN_OR_IMAGE_FINISH ]
205: [ "]" : SPAN_OR_IMAGE_FINISH ]
206: [ "

" : DOUBLE_NEWLINE ]
207: [ "       —   .     ,             -.         DOM,    ." : TEXT ]
208: [ "

" : DOUBLE_NEWLINE ]
209: [ "       HTML-?" : TEXT ]
210: [ "

" : DOUBLE_NEWLINE ]
211: [ "  —      ,         ,     —   «Node»,     «Block» (,     )       «Root».      ,    , ,  <p" : TEXT ]
212: [ ">" : LINK_FINISH ]
213: [ ", <li" : TEXT ]
214: [ ">" : LINK_FINISH ]
215: [ ", <strong" : TEXT ]
216: [ ">" : LINK_FINISH ]
217: [ "  ,      .    .      ,    —            :     ,     ,    .   ,   ,    Node,   ,    .    " : TEXT ]
218: [ "%[" : ITALIC_START ]
219: [ "  " : TEXT ]
220: [ "]" : SPAN_OR_IMAGE_FINISH ]
221: [ "." : TEXT ]
222: [ "

" : DOUBLE_NEWLINE ]
223: [ " :" : TEXT ]https://gitlab.com/2che/markedit
224: [ "
" : NEWLINE ]
225: [ "> " : QUOTE_START ]
226: [ "`[" : MONOSPACE_START ]
227: [ "stub" : TEXT ]
228: [ "]" : SPAN_OR_IMAGE_FINISH ]
229: [ "

" : DOUBLE_NEWLINE ]
230: [ "  !     ,      :" : TEXT ]
231: [ "
" : NEWLINE ]
232: [ "`[" : MONOSPACE_START ]
233: [ "| " : TEXT ]
234: [ "
" : NEWLINE ]
235: [ "+--<ROOT" : TEXT ]
236: [ ">" : LINK_FINISH ]
237: [ "
" : NEWLINE ]
238: [ " | " : TEXT ]
239: [ "
" : NEWLINE ]
240: [ " +--<!DOCTYPE" : TEXT ]
241: [ ">" : LINK_FINISH ]
242: [ "
" : NEWLINE ]
243: [ " | " : TEXT ]
244: [ "
" : NEWLINE ]
245: [ " +--<html" : TEXT ]
246: [ ">" : LINK_FINISH ]
247: [ "
" : NEWLINE ]
248: [ " | " : TEXT ]
249: [ "
" : NEWLINE ]
250: [ " +--<head" : TEXT ]
251: [ ">" : LINK_FINISH ]
252: [ "
" : NEWLINE ]
253: [ " | | " : TEXT ]
254: [ "
" : NEWLINE ]
255: [ " | +--<meta" : TEXT ]
256: [ ">" : LINK_FINISH ]
257: [ "
" : NEWLINE ]
258: [ " | | " : TEXT ]
259: [ "
" : NEWLINE ]
260: [ " | +--<meta" : TEXT ]
261: [ ">" : LINK_FINISH ]
262: [ "
" : NEWLINE ]
263: [ " | | " : TEXT ]
264: [ "
" : NEWLINE ]
265: [ " | +--<meta" : TEXT ]
266: [ ">" : LINK_FINISH ]
267: [ "
" : NEWLINE ]
268: [ " | | " : TEXT ]
269: [ "
" : NEWLINE ]
270: [ " | +--<meta" : TEXT ]
271: [ ">" : LINK_FINISH ]
272: [ "
" : NEWLINE ]
273: [ " | | " : TEXT ]
274: [ "
" : NEWLINE ]
275: [ " | +--<meta" : TEXT ]
276: [ ">" : LINK_FINISH ]
277: [ "
" : NEWLINE ]
278: [ " | | " : TEXT ]
279: [ "
" : NEWLINE ]
280: [ " | +--<meta" : TEXT ]
281: [ ">" : LINK_FINISH ]
282: [ "
" : NEWLINE ]
283: [ " | | " : TEXT ]
284: [ "
" : NEWLINE ]
285: [ " | +--<meta" : TEXT ]
286: [ ">" : LINK_FINISH ]
287: [ "
" : NEWLINE ]
288: [ " | | " : TEXT ]
289: [ "
" : NEWLINE ]
290: [ " | +--<meta" : TEXT ]
291: [ ">" : LINK_FINISH ]
292: [ "
" : NEWLINE ]
293: [ " | | " : TEXT ]
294: [ "
" : NEWLINE ]
295: [ " | +--<meta" : TEXT ]
296: [ ">" : LINK_FINISH ]
297: [ "
" : NEWLINE ]
298: [ " | | " : TEXT ]
299: [ "
" : NEWLINE ]
300: [ " | +--<title" : TEXT ]
301: [ ">" : LINK_FINISH ]
302: [ "
" : NEWLINE ]
303: [ " | | " : TEXT ]
304: [ "
" : NEWLINE ]
305: [ " | +--<link" : TEXT ]
306: [ ">" : LINK_FINISH ]
307: [ "
" : NEWLINE ]
308: [ " | | " : TEXT ]
309: [ "
" : NEWLINE ]
310: [ " | +--<link" : TEXT ]
311: [ ">" : LINK_FINISH ]
312: [ "
" : NEWLINE ]
313: [ " | | " : TEXT ]
314: [ "
" : NEWLINE ]
315: [ " | +--<COMMENT" : TEXT ]
316: [ ">" : LINK_FINISH ]
317: [ "
" : NEWLINE ]
318: [ " | " : TEXT ]
319: [ "
" : NEWLINE ]
320: [ " +--<body" : TEXT ]
321: [ ">" : LINK_FINISH ]
322: [ "
" : NEWLINE ]
323: [ " | " : TEXT ]
324: [ "
" : NEWLINE ]
325: [ " +--<header" : TEXT ]
326: [ ">" : LINK_FINISH ]
327: [ "
" : NEWLINE ]
328: [ " | | " : TEXT ]
329: [ "
" : NEWLINE ]
330: [ " | +--<div" : TEXT ]
331: [ ">" : LINK_FINISH ]
332: [ "
" : NEWLINE ]
333: [ " | " : TEXT ]
334: [ "
" : NEWLINE ]
335: [ " +--<nav" : TEXT ]
336: [ ">" : LINK_FINISH ]
337: [ "
" : NEWLINE ]
338: [ " | | " : TEXT ]
339: [ "
" : NEWLINE ]
340: [ " | +--<ul" : TEXT ]
341: [ ">" : LINK_FINISH ]
342: [ "
" : NEWLINE ]
343: [ " | | " : TEXT ]
344: [ "
" : NEWLINE ]
345: [ " | +--<li" : TEXT ]
346: [ ">" : LINK_FINISH ]
347: [ "
" : NEWLINE ]
348: [ " | | | " : TEXT ]
349: [ "
" : NEWLINE ]
350: [ " | | +--<a" : TEXT ]
351: [ ">" : LINK_FINISH ]
352: [ "
" : NEWLINE ]
353: [ " | | " : TEXT ]
354: [ "
" : NEWLINE ]
355: [ " | +--<li" : TEXT ]
356: [ ">" : LINK_FINISH ]
357: [ "
" : NEWLINE ]
358: [ " | | | " : TEXT ]
359: [ "
" : NEWLINE ]
360: [ " | | +--<a" : TEXT ]
361: [ ">" : LINK_FINISH ]
362: [ "
" : NEWLINE ]
363: [ " | | " : TEXT ]
364: [ "
" : NEWLINE ]
365: [ " | +--<li" : TEXT ]
366: [ ">" : LINK_FINISH ]
367: [ "
" : NEWLINE ]
368: [ " | | " : TEXT ]
369: [ "
" : NEWLINE ]
370: [ " | +--<a" : TEXT ]
371: [ ">" : LINK_FINISH ]
372: [ "
" : NEWLINE ]
373: [ " | " : TEXT ]
374: [ "
" : NEWLINE ]
375: [ " +--<main" : TEXT ]
376: [ ">" : LINK_FINISH ]
377: [ "
" : NEWLINE ]
378: [ " | | " : TEXT ]
379: [ "
" : NEWLINE ]
380: [ " | +--<MACRO" : TEXT ]
381: [ ">" : LINK_FINISH ]
382: [ "
" : NEWLINE ]
383: [ " | " : TEXT ]
384: [ "
" : NEWLINE ]
385: [ " +--<footer" : TEXT ]
386: [ ">" : LINK_FINISH ]
387: [ "
" : NEWLINE ]
388: [ " | " : TEXT ]
389: [ "
" : NEWLINE ]
390: [ " +--<hr" : TEXT ]
391: [ ">" : LINK_FINISH ]
392: [ "
" : NEWLINE ]
393: [ " | " : TEXT ]
394: [ "
" : NEWLINE ]
395: [ " +--<small" : TEXT ]
396: [ ">" : LINK_FINISH ]
397: [ "]" : SPAN_OR_IMAGE_FINISH ]
398: [ "
" : NEWLINE ]
399: [ " " : TEXT ]
400: [ "
" : NEWLINE ]
401: [ ",       DOM,   jQuery, Jsoup, beautifulsoup  Gumbo   ,   ,       ,     <style" : TEXT ]
402: [ ">" : LINK_FINISH ]
403: [ "  <script" : TEXT ]
404: [ ">" : LINK_FINISH ]
405: [ ",      .   ,     . ." : TEXT ]
406: [ "

" : DOUBLE_NEWLINE ]
407: [ "PS     " : TEXT ]
408: [ "<<" : LINK_START ]
409: [ "https://gitlab.com/2che/nyHTML" : TEXT ]
410: [ ">" : LINK_FINISH ]
411: [ "" : TEXT ]
412: [ ">" : LINK_FINISH ]
413: [ ". , ,      ." : TEXT ]
414: [ "
" : NEWLINE ]
415: [ "" : END ]


شجرة بناء الجملة
 <pre><article> | +-<section> | +-<p> | | | +-@2che | | | +-"\n" | +->>442964 | +-<h1> | | | +-"   DOM  " | +-<p> | | | +-", !       ..." | | | +-<i> | | | | | +-" " | | | +-",   — " | | | +-<i> | | | | | +-"" | | | +-".     ,   ..." | +-<p> | | | +-" , —    —   ..." | +-<p> | | | +-" , ,  " | | | +-<i> | | | | | +-" " | | | +-" —        ..." | | | +-"\n" | | | +-<b> | | | | | +-" " | | | +-"    —    ,  ..." | | | +-"\n" | | | +-<b> | | | | | +-" " | | | +-" —        " | | | +-<i> | | | | | +-"  " | | | +-" (AST — abstract syntax tree),  " | | | +-<i> | | | | | +-"  " | | | +-" (DOM — document object model)." | +-<p> | | | +-"   .  ,     ..." | | | +-<i> | | | | | +-" - ()" | | | +-"  " | | | +-<i> | | | | | +-"  -" | | | +-".    ,     .  ..." | | | +-"\n" | +-<blockquote> | | | +-<pre> | | | +-"<" | | | +-">" | | | +-" = <_1" | | | +-">" | | | +-" <_" | | | +-">" | | | +-" <_2" | | | +-">" | +-<p> | | | +-"      , ..." | +-<p> | | | +-"  ?" | +-<p> | | | +-"      ..." | | | +-<i> | | | | | +-"" | | | +-"  " | | | +-<i> | | | | | +-"" | | | +-". " | | | +-<b> | | | | | +-"" | | | +-" — ,  :" | | | +-"\n" | +-<blockquote> | | | +-<pre> | | | +-"<_1" | | | +-">" | | | +-" = <" | | | +-">" | | | +-" (<_" | | | +-">" | | | +-" | <_" | | | +-">" | | | +-") <" | | | +-">" | +-<p> | | | +-<b> | | | | | +-"" | | | +-" ,    .   ..." | | | +-"\n" | +-<blockquote> | | | +-<pre> | | | +-"<" | | | +-">" | | | +-" = <_1" | | | +-">" | | | +-" "+" <_2" | | | +-">" | | | +-"\n" | | | +-"<_1" | | | +-">" | | | +-" = <" | | | +-">" | | | +-" ("*" | "/") <" | | | +-">" | +-<p> | | | +-" "+", "*", "/" — ." | | | +-"\n" | | | +-"     ,  ..." | +-<p> | | | +-"      " | | | +-<a> | | | | | +-"" | | | +-"  " | | | +-<a> | | | | | +-"" | | | +-".    —    ..." | | | +-"\n" | +-<blockquote> | | | +-<pre> | | | +-"stub" | +-<p> | | | +-"  ,     ..." | | | +-">" | | | +-"".        case.   ..." | | | +-"\n" | +-<blockquote> | | | +-<pre> | | | +-"enum Token_type {" | | | +-"\n" | | | +-" END = 1, TEXT = 2," | | | +-"\n" | | | +-" OPENING_BLOCK_TAG_NAME = 4, CLOSING_BLOCK_TAG_NAME = 8, EMPTY_TAG_NAME = 16, COMMENT = 32, MACRO..." | | | +-"\n" | | | +-" ATTRIBUTE_NAME = 128, UNQUOTED_ATTRIBUTE_VALUE = 256, SINGLE_QUOTED_ATTRIBUTE_VALUE = 512, DOUBL..." | | | +-"\n" | | | +-"};" | +-<p> | | | +-"  process:" | | | +-"\n" | +-<blockquote> | | | +-<pre> | | | +-"stub" | +-<p> | | | +-"   switch    (  ..." | | | +-"\n" | +-<p> | | | +-<img /> | +-<p> | | | +-"    ,   ..." | | | +-"\n" | +-<blockquote> | | | +-<pre> | | | +-"stub" | +-<p> | | | +-"      ..." | +-<p> | | | +-"        HTML- ..." | | | +-">" | | | +-"": <_" | | | +-">" | | | +-" " | | | +-"]" | | | +-"".   :" | | | +-"\n" | +-<blockquote> | | | +-<mark> | | | | | +-" " | | | | | +-<pre> | | | | | +-"stub" | | | +-"\n" | | | +-<mark> | | | +-" " | | | +-<pre> | | | +-"stub" | +-<p> | | | +-"       —  ..." | +-<p> | | | +-"       HTML-..." | +-<p> | | | +-"  —      ,  ..." | | | +-">" | | | +-", <li" | | | +-">" | | | +-", <strong" | | | +-">" | | | +-"  ,      .  ..." | | | +-<i> | | | | | +-"  " | | | +-"." | +-<p> | | | +-" :" | | | +-"\n" | +-<blockquote> | | | +-<pre> | | | +-"stub" | +-<p> | | | +-"  !     ,   ..." | | | +-"\n" | | | +-<pre> | | | | | +-"| " | | | | | +-"\n" | | | | | +-"+--<ROOT" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | " | | | | | +-"\n" | | | | | +-" +--<!DOCTYPE" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | " | | | | | +-"\n" | | | | | +-" +--<html" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | " | | | | | +-"\n" | | | | | +-" +--<head" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<meta" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<meta" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<meta" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<meta" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<meta" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<meta" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<meta" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<meta" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<meta" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<title" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<link" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<link" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<COMMENT" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | " | | | | | +-"\n" | | | | | +-" +--<body" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | " | | | | | +-"\n" | | | | | +-" +--<header" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<div" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | " | | | | | +-"\n" | | | | | +-" +--<nav" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<ul" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<li" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | | " | | | | | +-"\n" | | | | | +-" | | +--<a" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<li" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | | " | | | | | +-"\n" | | | | | +-" | | +--<a" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<li" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<a" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | " | | | | | +-"\n" | | | | | +-" +--<main" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | | " | | | | | +-"\n" | | | | | +-" | +--<MACRO" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | " | | | | | +-"\n" | | | | | +-" +--<footer" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | " | | | | | +-"\n" | | | | | +-" +--<hr" | | | | | +-">" | | | | | +-"\n" | | | | | +-" | " | | | | | +-"\n" | | | | | +-" +--<small" | | | | | +-">" | | | +-"\n" | | | +-" " | | | +-"\n" | | | +-",       ..." | | | +-">" | | | +-"  <script" | | | +-">" | | | +-",      .    ..." | +-<p> | +-"PS     " | +-<a> | | | +-"" | +-". , ,     ..." | +-"\n" </pre> 

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

شجرة بعد سلسلة:
 <pre><article> | +-<section> | +-<p> | | | +-@2che | | | +-"\n" | +->>442964 | +-<h1> | | | +-"   DOM  " | +-<p> | | | +-", !       ..." | | | +-<i> | | | | | +-" " | | | +-",   — " | | | +-<i> | | | | | +-"" | | | +-".     ,   ..." | +-<p> | | | +-" , —    —   ..." | +-<p> | | | +-" , ,  " | | | +-<i> | | | | | +-" " | | | +-" —        ..." | | | +-<b> | | | | | +-" " | | | +-"    —    ,  ..." | | | +-<b> | | | | | +-" " | | | +-" —        " | | | +-<i> | | | | | +-"  " | | | +-" (AST — abstract syntax tree),  " | | | +-<i> | | | | | +-"  " | | | +-" (DOM — document object model)." | +-<p> | | | +-"   .  ,     ..." | | | +-<i> | | | | | +-" - ()" | | | +-"  " | | | +-<i> | | | | | +-"  -" | | | +-".    ,     .  ..." | +-<blockquote> | | | +-<pre> | | | +-"<> = <_1> <_> <_2>" | +-<p> | | | +-"      , ..." | +-<p> | | | +-"  ?" | +-<p> | | | +-"      ..." | | | +-<i> | | | | | +-"" | | | +-"  " | | | +-<i> | | | | | +-"" | | | +-". " | | | +-<b> | | | | | +-"" | | | +-" — ,  :\n" | +-<blockquote> | | | +-<pre> | | | +-"<_1> = <> (<_> | <_>) < ..." | +-<p> | | | +-<b> | | | | | +-"" | | | +-" ,    .   ..." | +-<blockquote> | | | +-<pre> | | | +-"<> = <_1> "+" <_2>\n<_1> = <..." | +-<p> | | | +-" "+", "*", "/" — .\n    ..." | +-<p> | | | +-"      " | | | +-<a> | | | | | +-"" | | | +-"  " | | | +-<a> | | | | | +-"" | | | +-".    —    ..." | +-<blockquote> | | | +-<pre> | | | +-"stub" | +-<p> | | | +-"  ,     ..." | +-<blockquote> | | | +-<pre> | | | +-"enum Token_type {\n END = 1, TEXT = 2,\n OPENING_BLOCK_TAG_NAME = 4, CLOSING_BLOCK_TAG_NAME = ..." | +-<p> | | | +-"  process:\n" | +-<blockquote> | | | +-<pre> | | | +-"stub" | +-<p> | | | +-"   switch    (  ..." | +-<p> | | | +-<img /> | +-<p> | | | +-"    ,   ..." | +-<blockquote> | | | +-<pre> | | | +-"stub" | +-<p> | | | +-"      ..." | +-<p> | | | +-"        HTML- ..." | +-<blockquote> | | | +-<mark> | | | | | +-" " | | | | | +-<pre> | | | | | +-"stub" | | | +-"\n" | | | +-<mark> | | | +-" " | | | +-<pre> | | | +-"stub" | +-<p> | | | +-"       —  ..." | +-<p> | | | +-"       HTML-..." | +-<p> | | | +-"  —      ,  ..." | | | +-<i> | | | | | +-"  " | | | +-"." | +-<p> | | | +-" :\n" | +-<blockquote> | | | +-<pre> | | | +-"stub" | +-<p> | | | +-"  !     ,   ..." | | | +-<pre> | | | | | +-"| \n+--<ROOT>\n | \n +--<!DOCTYPE>\n | \n +--<html>\n | \n +--<head>\n | | \n | +--<..." | | | +-"\n \n,     ..." | +-<p> | +-"PS     " | +-<a> | | | +-"" | +-". , ,     ..." </pre> 

الخطوة الأخيرة المتبقية هي تمثيل هذه الشجرة في نموذج HTML. كل شيء بسيط هنا: نقوم بإنشاء سطر في طريقة الجذر مع بداية الترميز الأساسي (فتح html وعناصر الجسم ، كتلة رأس) ونبدأ في إرفاق الخطوط التي تم إرجاعها من العناصر الفرعية المشابهة. نحن هنا نتعامل مع نزول عودي مرة أخرى: كل فئة ، عندما يتم استدعاء الأسلوب الظاهري to_HTML () ، تنشئ خطًا ، وتضع علامة الترميز الأساسية فيه ، ثم تستدعي الطريقة نفسها على كل من نسلها ، وتسلسل السطور ، وتُكمل العلامة الأولية وتعيدها إلى الوالد المتصل. هنا ، على سبيل المثال ، يشبه هذا الأسلوب لفئة Inline (دمج عناصر مضمّنة في السطر):
 string Inline::to_HTML (const unsigned int &level) { string HTML; // ******    -   ****** switch (type) { case BOLD: { HTML.append("<b>"); break; } case ITALIC: { HTML.append("<i>"); break; } case UNDERLINED: { HTML.append("<ins>"); break; } case OVERLINED: { HTML.append("<span class=\"overlined\">"); break; } case THROWLINED: { HTML.append("<del>"); break; } case SUBSCRIPT: { HTML.append("<sub>"); break; } case SUPERSCRIPT: { HTML.append("<sup>"); break; } case MARKED: { HTML.append("<mark>"); break; } case MONOSPACE: { HTML.append("<pre>"); break; } default: throw string("invalid inline type: " + type_str() + "!"); } // *** *** *** *** // ******   -    ****** for (unsigned long i(0); i < children_count; i++) HTML.append(children[i]->to_HTML(level+1)); // *** *** *** *** // ******    -   ****** switch (type) { case BOLD: { HTML.append("</b>"); break; } case ITALIC: { HTML.append("</i>"); break; } case UNDERLINED: { HTML.append("</ins>"); break; } case OVERLINED: { HTML.append("</span>"); break; } case THROWLINED: { HTML.append("</del>"); break; } case SUBSCRIPT: { HTML.append("</sub>"); break; } case SUPERSCRIPT: { HTML.append("</sup>"); break; } case MARKED: { HTML.append("</mark>"); break; } case MONOSPACE: { HTML.append("</pre>"); break; } default: throw string("invalid inline type: " + type_str() + "!"); } // *** *** *** *** return HTML; } 

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

PS لقد نسيت أن أذكر التدريع . يتم تنفيذه ببساطة: إذا كانت الحرف التالي في إجراء تحليل المعجمية هي الخط المائل العكسي ("\") ، يتم تجاهله ومعالجة الحرف التالي ، ولكن بالإضافة إلى ذلك ، يتم إرسال قيمة Boolean true إلى وظيفة معالجة الأحرف ، مع إعطاء الأمر للهروب. ثم ، إذا كان هذا الرمز ، على سبيل المثال ، هو "[" ، يتم تجاهل معناه الخاص ، وهو ببساطة يجمع الرمز المميز قيد الإنشاء كنص. خلاف ذلك ، ترجع الدالة false وتتم معالجة الحرف كالمعتاد.

Source: https://habr.com/ru/post/ar444876/


All Articles