Die Kunst, 2 zu analysieren oder Ihr eigenes Markup zu transliterieren

+ BONUS: gegenseitige Einbeziehung von Klassen in C ++


Hallo Habr! Dieser Artikel ist eine direkte Fortsetzung des Artikels The Art of Parsing oder DOM mit unseren eigenen HĂ€nden , in dem wir ein HTML-Dokument analysiert und auf seiner Grundlage einen abstrakten Syntaxbaum (AST) mit Zugriff auf jedes Element erstellt haben, indem wir nur die Standard-C ++ - Bibliothek indiziert haben. Mit anderen Worten, wir haben gelernt, selbst zu analysieren XML-Ă€hnliches Zeug. Ich möchte Sie daran erinnern, dass der Prozess des Parsens oder Parsens / Parsens aus zwei Schritten besteht: dem lexikalischen Parsen (Parsen von Text in Token) und dem Erstellen eines AST. Wenn wir die erste mit Beispielen und Quellcodes ausfĂŒhrlich untersucht haben, dann sieht die Beschreibung der zweiten wie eine leere Schmetterlingspuppe aus, die nur eine Muschel hat, und der Autor hat vor der Veröffentlichung exzellenten Inhalt extrahiert. Es gab einen Grund, warum es fĂŒr HTML wirklich einfach ist, einen Baum zu erstellen. Sie benötigen nur 4 Klassen: ein leeres Tag, einen Block, einen Textknoten und den vom Block geerbten Dokumentstamm. Heute werden wir diese Einfachheit hinter uns lassen und einen Baum erstellen, in dem die Eigenschaften von Elementen, sowohl leer als auch block, nicht in den Attributen von Tags enthalten sind, sondern direkt in den Klassen, und dafĂŒr mĂŒssen Sie viele Klassen erstellen. Wirklich viel. Wir werden nicht aus einfachen bekannten Markup-Sprachen bauen, sondern unsere eigenen erstellen, mit den Regeln, die im Bild unter dem Schnitt gezeigt werden. Außerdem ĂŒbersetzen oder ĂŒbersetzen wir am Ende das Dokument mit dem vorherigen Artikel, der in unserer Sprache markiert ist, in HTML. Als Bonus beantworte ich unerfahrene C ++ - Programmierer eine triviale, aber schwer zu findende Frage: Wie können Klassen ineinander integriert werden?



Grammatiknotizen


Bevor wir direkt zum Bauen eines Baumes ĂŒbergehen, aktualisieren wir unser GedĂ€chtnis und klĂ€ren einige Details der Vorarbeiten. Erinnern Sie sich noch daran, dass die gesamte Syntax der Sprache in Form einer der kontextfreien formalen Grammatiken geschrieben werden muss, zum Beispiel BNF? Es ist nur schwierig fĂŒr AnfĂ€ngerprogrammierer, sie sofort zu beherrschen, und außerdem können nicht alle möglichen Regeln mit diesen Grammatiken beschrieben werden. In solchen FĂ€llen, wenn Sie sich in einer Sackgasse befinden und eine bestimmte Regel nicht in der richtigen Form formulieren, können Sie sie beispielsweise als Bemerkungen in natĂŒrlicher menschlicher Sprache aufschreiben:

... <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 

Übersetzung: Das Ende des Links ">" und des Bild- / Inline-Elements "]" kann nicht unmittelbar auf den Beginn einer Zeile oder eines Dokuments folgen .

Das heißt, wenn der Lexer am Anfang der Zeile auf "]" oder ">" trifft, mĂŒssen wir ihn anweisen, die besondere Bedeutung dieser Zeichen zu ignorieren und mit ihnen wie mit einfachem Text zu arbeiten. Diese Art, Kommentare zur Grammatik hinzuzufĂŒgen, ist nicht die einzige, Sie können es auf Ihre eigene Weise tun. Am Ende ist eine Datei mit einer Beschreibung der Syntax keine Hausarbeit, niemand zwingt Sie, alle Regeln zu befolgen, und es ist nur wichtig, dass Sie bequem damit arbeiten können. Die Hauptsache ist, die gemachten Kommentare nicht zu vergessen und sie in den richtigen Abschnitten des Codes wiederzugeben.

Schauen wir uns eine vollstÀndige Beschreibung dieser Sprache an:

 <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 

Beim letzten Mal war es notwendig, die Terminals auszuschreiben und jedes eingehende Zeichen auf Übereinstimmung mit einem von ihnen zu ĂŒberprĂŒfen. Aber dann waren die Terminals einstellig! ZusĂ€tzlich zum Hervorheben der Terminals mĂŒssen diese nun selbst in SchlĂŒssel unterteilt werden, dh in Zeichen. Warum sind die "SchlĂŒssel"? Sie sind der SchlĂŒssel zum Lexer. Als Ergebnis aller Aktionen werden die folgenden Zeilen in der Grammatikdatei angezeigt:

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

Stapel der erwarteten Arten von Token


Auch beim letzten Mal war alles einfacher, wir hatten nur 10 Arten von Token, ohne das Ende zu zĂ€hlen, und es gab weniger Chancen, in diesem Zoo von Token verloren zu gehen. Jetzt gibt es offensichtlich mehr Typen. Ich möchte Sie daran erinnern, dass es die Aufgabe des Lexers ist, dem Parser so wenig Arbeit wie möglich zu lassen, im Idealfall nur einen Baum zu bauen. Daher sollte der Satz von Token-Typen ihre Essenz so genau wie möglich widerspiegeln. Im ersten Artikel habe ich ein Beispiel fĂŒr ein gutes Set gegeben, in diesem werde ich es zusammen mit einem "Anti-Beispiel" geben. Siehe Terminals, die mit Inline-Textelementen beginnen (fett - fett, kursiv - kursiv usw.)? Wir könnten sie in ein Paar Token analysieren: den AnfĂŒhrer ("*", "%" usw.) und den Sklaven ("[") und in dieser Form an den Parser weitergeben. Es ist leicht zu erraten, dass es besser ist, eine genaue Definition eines Textelements auf Lexerebene vorzunehmen, d. H. Definieren Sie "* [" als "fett_start", "% [" als "kursiv_start" usw. Je mehr Typen und je genauer sie sich selbst widerspiegeln, desto besser. DarĂŒber hinaus ist der zweite wichtiger als der erste. Zum Beispiel könnten wir die Benachrichtigung fĂŒr das "@" - Symbol und den Benutzernamen analysieren, aber natĂŒrlich ist es besser, sie in einem Token zusammengefasst zu lassen.
Nun, wir haben uns fĂŒr die Typen entschieden. Wo soll das Verfahren zum Parsen von Text in Token gestartet werden? Beginnen Sie dann von vorne. Was kann unmittelbar nach dem Beginn des analysierten Dokuments erfolgen? Beeilen Sie sich nicht, um Ihre Finger zu beugen. Im Gegensatz zu HTML können hier alle 22 Typen beginnen. Es ist okay, bewaffnet mit ein bisschen Vereinigung, wir schreiben so:

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

und in der Symbolverarbeitungsfunktion:

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

Wenn Sie nicht verstehen, worum es geht, lesen Sie den ersten Artikel .

Haben Sie keine Angst vor dem langen generischen Typ des erwarteten Tokens. Das erste Zeichen der Zeichenfolge reduziert ihre LĂ€nge sofort auf 2-4 Typen. Da unsere Terminals mehrstellig sind, basiert die Definition auf den SchlĂŒsseln.

Überzeugen Sie sich selbst:

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

Der Unterstrich bestimmte sofort das im Aufbau befindliche Token fĂŒr einen von drei Typen: Klartext, horizontale Linie oder den Anfang des unterstrichenen Textes ("_ [").

ZurĂŒck zum Problem: Wie kann man alle generischen Typen im Auge behalten und daran denken, sie alle zu verarbeiten? Holen Sie sich einen Stapel ... in ein Notizbuch! Notieren Sie sich alle generischen Typen, die nach "curr_token_type = ..." in der Liste erscheinen, und nehmen Sie nach der Verarbeitung den anderen vom Ende der Liste. Sie können die Arbeit mit der Liste organisieren und wie bei der Warteschlange spielt es keine Rolle. Hauptsache, Sie werden nicht vergessen, welche Typen bereits verarbeitet werden und welche noch verarbeitet werden mĂŒssen.

Klassenbaum


Schließlich kamen wir zum Parsen. Hier mĂŒssen Sie die Klassen von Knoten (Knoten) des zukĂŒnftigen Baums auf dieselbe Weise bestimmen, wie wir sie mit den Token-Typen ermittelt haben. Öffnen Sie dazu das Notizbuch erneut und schreiben Sie Folgendes:

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

Also haben wir die zukĂŒnftige Basisklasse aller Knoten und ihre Ableitung definiert - die Wurzel des Baums, dh das Dokument selbst. Ein Dokument (siehe BPF oben) besteht aus zwei Knotentypen: einem Abschnitt und einer horizontalen Linie (Unterstreichung). Wir definieren die Basisklasse Root_item fĂŒr sie und beschreiben sie auf dieselbe Weise wie wir die Wurzel beschrieben haben. Außerdem geben wir hier im Editor sofort alle anderen Felder der Klassen an, falls vorhanden. FĂŒr die Wurzel ist dies die Anzahl der „Kinder“ - das heißt, Innenschnitte und horizontale Linien. Der Abschnitt besteht aus Elementen, fĂŒr die wir die Basisklasse Div definieren usw. Wenn wir uns rekursiv durch die Grammatik bewegen, bestimmen wir alle Klassen, die benötigt werden. Bevor wir den Code schreiben, definieren wir hier die gesamte Einbeziehung von Headern. Es ist einfach: Alle direkten Nachkommen grundlegender verallgemeinerter Klassen mĂŒssen in den Klassen enthalten sein, die sie enthalten.

Wir bezeichnen diese AbhÀngigkeiten in Form von Listen nach dem Gitter und erhalten das folgende Dokument:

 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 } #- 

Hier habe ich das Fehlen von AbhÀngigkeiten mit "# -" markiert und die Einbeziehung von Klassen in sich selbst entfernt.
Wir stellen fest, dass alle integrierten Formatierungsklassen (Fett, Kursiv, ...) voneinander und zusĂ€tzlich von der Link-Klasse abhĂ€ngig sind, die auch von ihnen abhĂ€ngig ist! In einer Ă€hnlichen Position befinden sich Unordered_list und Ordered_list. Das Einschließen von Headern ineinander fĂŒhrt nicht nur dazu, dass einer von ihnen wie erwartet ignoriert wird, sondern besteht auch nicht die Validierung durch den PrĂ€prozessor, und das einseitige Einschließen ermöglicht es uns nicht, innerhalb der eingeschlossenen Klasse die Funktion zu deklarieren, das Klassenelement zu öffnen und den Link zu ihm zurĂŒckzugeben. Wie man ist Es gibt zwei Möglichkeiten.

Einbeziehung von Klassen ineinander


Schauen Sie sich zunĂ€chst die Klassen Fett, Kursiv usw. fĂŒr Monospace an. Sie sind gleich. So sehr, dass sie zu einer Klasse "Inline" zusammengefasst werden können. Vielleicht wird diese Entscheidung Zweifel aufkommen lassen. Es hat mich auch verursacht, aber in der Praxis wirkte sich der Unterschied zwischen ihnen nur auf die Darstellungsform in Form eines Baums im Terminal und die Tags in HTML aus. Wenn Sie feststellen, dass einige Klassen dieselben Felder enthalten, dieselben AbhĂ€ngigkeiten aufweisen und im Allgemeinen eine Ă€hnliche Beschreibung in der formalen Grammatik haben, können Sie sie gerne kombinieren. So machen Sie es sich und dem Prozessor leichter.

Ein solcher Trick funktioniert jedoch nicht mit der Link-Klasse, da er ein zusÀtzliches Feld enthÀlt - die URL-Zeichenfolge. Wir werden die zweite Methode verwenden.

Weiß jeder, dass das Trennen von Klassen in Deklarationen und Definitionen eine gute Form in der C ++ - Programmierung ist? In der Kopfzeile mit der Erweiterung .h oder .hpp - Deklaration, in der Quelle mit der Erweiterung .cpp - Definition, richtig? Und jetzt wende ich mich an Programmierneulinge: Setzen Sie sich und schnallen Sie sich an, denn das wird unangenehm. Schließlich ist das, was wir in einer Datei mit der Erweiterung .h vorschreiben, nichts anderes als eine Klassendefinition. In der CPP-Datei sind die Methoden dieser Klasse bereits implementiert . UnverstĂ€ndlich? Wir wurden in der Schule getĂ€uscht. Eine Klasse wird in einer einzelnen Zeile als Funktion deklariert, wenn sie keine Vorlagen enthĂ€lt.

Es ist noch einfacher als eine Funktion, da es keine Argumente enthÀlt. Hier ist eine typische Klassendeklaration:

 class MyClass; 

Und alle! Und Deklarationen von Feldern und Methoden sind bereits ihre Definition .

Wir werden dies nutzen. Wir fĂŒgen den Titel der Inline-Klasse in den Titel der Link-Klasse ein und deklarieren darin die Link-Klasse selbst, bevor wir die Inline-Klasse definieren. Die Datei inline.h sollte folgendermaßen aussehen:

 #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); ... 

Die Inline-Klasse weiß noch nichts ĂŒber die Link-Klasse, ihre Felder und Methoden, aber sie weiß sicher ĂŒber ihre Existenz Bescheid. Daher können wir Methoden deklarieren, die einen Zeiger auf ein Objekt der Link-Klasse zurĂŒckgeben, oder es als Argument akzeptieren. Der Wortzeiger wurde nicht zufĂ€llig ausgewĂ€hlt, die Inline-Klasse weiß noch nicht, wie Objekte vom Typ Link erstellt werden sollen, da sie keinen Zugriff auf ihren Konstruktor hat, aber mit allen Zeigern arbeiten kann, weil Sie haben alle die gleiche Schnittstelle. Aber wir brauchen hier keine Objekte. Bei der Implementierung der open_link-Methode wird jedoch ein Objekt vom Typ Link erstellt und ein Zeiger darauf zurĂŒckgegeben. Dies bedeutet, dass zum Zeitpunkt der Eingabe dieser Methode durch den PrĂ€prozessor der Konstruktor und andere Link-Methoden deklariert werden mĂŒssen, die die open_link-Methode möglicherweise benötigt. Hier nutzen wir den Vorteil, den Quellcode in separate Dateien mit Headern und Implementierung zu unterteilen. Die Datei inline.h ist in der Datei inline.cpp („undercloud“) enthalten, die Datei link.h ist jedoch nicht in inline.h enthalten. Die Aufnahme in inline.cpp ist also die erste Aufnahme fĂŒr den PrĂ€prozessor. Dann beginnt die Datei inline.cpp folgendermaßen:

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

Ich wiederhole alles oben. Die Überschrift der Klasse Ah ist wie ĂŒblich in der Überschrift der Klasse Bh enthalten, und die Klasse B wird vor der Klasse A deklariert, und wir nehmen ihre Überschrift in die Quelle A.cpp auf. Diese Methode ist meiner Meinung nach nicht die einzige, sondern die einfachste.

Ich stelle fest, dass eine solche gegenseitige Einbeziehung von Klassen nicht verhindert, dass Klasse B von Klasse A erbt, wenn wir ihre Deklaration vor der Definition von Klasse A aufschreiben. Genau das habe ich getan, indem ich Ordered_list von Unordered_list geerbt habe.

Einen Baum bauen


Also kamen wir zur Konstruktion eines abstrakten Syntaxbaums. Im letzten Artikel passte die Funktion in 50 Zeilen. Spoiler: Dieses Mal ist es auf fast 1400 angewachsen. Das Funktionsprinzip ist dasselbe: Wir ĂŒberprĂŒfen den Typ jedes Tokens und fĂŒhren abhĂ€ngig davon einen bestimmten Codeabschnitt aus, wobei ein offener Baumknoten im Speicher gespeichert wird. Wenn jedoch zum Parsen von HTML fast alle Abschnitte einen und nur einen von drei Befehlen enthielten: FĂŒgen Sie einen leeren Knoten innerhalb des offenen hinzu, öffnen Sie einen neuen Knoten im offenen und schließen Sie den geöffneten Knoten, wobei Sie den ĂŒbergeordneten Knoten zurĂŒckgeben. Die gewĂŒnschte Aktion hĂ€ngt auch hier vom Typ des geöffneten Knotens ab. Wenn beispielsweise das Token "horizontale Linie" verarbeitet wurde und der offene Knoten das Dokumentstammverzeichnis ist, mĂŒssen Sie diesem offenen Knoten lediglich eine Zeile mit Casting und der Funktion mit dem bedingten Namen add_line () hinzufĂŒgen.

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

Wenn es sich bei dem geöffneten Knoten jedoch um einen Absatz (Paragraph) handelt, mĂŒssen Sie ihn zuerst und alle möglichen Vorfahren (Listen mit AufzĂ€hlungszeichen und Nummern) schließen, bis der geöffnete Knoten vom Typ "Abschnitt" ist, und ihn dann auch schließen:

 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(); } 

Wenn der offene Knoten eine Beschriftung des Bildes ist, bricht die horizontale Linie die Grammatik insgesamt, und eine Ausnahme muss ausgelöst werden. Wenn der offene Knoten kein Link ist und das eingehende Token ">" den Typ "LINK_FINISH" hat, sollte er nicht als Ende des Links verarbeitet werden, sondern wie Text usw.

Daher muss der Switch / Case-Baum, der den Typ des eingehenden Tokens ĂŒberprĂŒft, einen anderen Switch / Case-Baum enthalten, der den Typ des offenen Knotens ĂŒberprĂŒft. ZunĂ€chst ist es schwierig, eine solche Konstruktion in Angriff zu nehmen, aber es ist nicht notwendig, von vorne zu beginnen, von der ersten Bedingung an. Sie können ein Standarddokument erstellen, das durch Ihre Sprache gekennzeichnet ist / ein Skript in Ihrer Sprache enthĂ€lt, und Bedingungen im Verlauf des Dokuments implementieren. ÜberprĂŒfen Sie das Ergebnis, indem Sie einen pseudografischen Baum an das Terminal ausgeben. Ich habe den vorherigen Artikel als solches Dokument genommen. Das allererste erhaltene Token ist der Anfang des Titels. Also verarbeiten wir das Token mit dem Typ TITLE_START. Im Folgenden werden der Kopfzeilentext und die schließende eckige Klammer aufgefĂŒhrt. Wir verarbeiten Token der Typen TEXT und SPAN_OR_IMAGE_FINISH.

Danach haben wir schon einen solchen Minibaum:

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

Unterwegs werden Sie feststellen, dass einige Klassen dieselben Methoden mit denselben Algorithmen enthalten. Beispielsweise öffnen Absatzabsatzklassen und AnfĂŒhrungszeichen Links auf dieselbe Weise und fĂŒgen ihnen Text hinzu. In solchen FĂ€llen besteht die beste Lösung beim Refactoring darin, eine Klasse mit diesen Methoden zu erstellen und die erforderlichen Knoten davon zu erben. Ich habe versucht, dies umzusetzen, aber meine FĂ€higkeiten waren nicht genug, und ich war verwirrt ĂŒber die Mehrdeutigkeit beim Casting. Deshalb gebe ich nur die Ergebnisse des Lexers und des Parsers an:

Der Artikel selbst
 @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>>. , ,      . 

 0: [ "2che" : NOTIFICATION ]
1: [ "
" : NEWLINE ]
2: [ "442964" : CITE ]
3: [ "#[" : TITLE_START ]
4: [ "   DOM  " : TEXT ]
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 body, head) . : 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; } 

Das ist alles , , , . — . . .

PS . : — ("\"), , true, . , , , "[", , . false .

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


All Articles