+ BONUS: inclusión mutua de clases entre sí en C ++
Hola Habr! Este artículo es una continuación directa del artículo The
Art of Parsing o DOM con nuestras propias manos , donde analizamos un documento HTML y construimos sobre una base un árbol de sintaxis abstracta (AST) con acceso a cualquier elemento a través de la indexación usando solo la biblioteca estándar de C ++, en otras palabras, aprendimos a
analizar por nuestra cuenta Cosas similares a XML. Permítame recordarle que el proceso de análisis, o
análisis / análisis, consta de dos etapas:
análisis léxico (análisis de texto en tokens) y creación de un AST. Si examinamos el primero con gran detalle, con ejemplos y códigos fuente, la descripción del segundo parece una muñeca de mariposa vacía, que solo tiene una concha, y el autor extrajo un excelente contenido antes de la publicación. Había una razón, para HTML es realmente fácil construir un árbol, solo necesitas 4 clases: una etiqueta vacía, un bloque, un nodo de texto y la raíz del documento heredada del bloque. Hoy dejaremos atrás esa simplicidad y crearemos un árbol donde las propiedades de los elementos, tanto vacías como de bloque, no estarán contenidas en los atributos de las etiquetas, sino directamente en las clases, y para esto tendrá que crear muchas clases. Realmente mucho Construiremos no a partir de simples lenguajes de marcado conocidos, sino que crearemos el nuestro, con las reglas que se muestran en la imagen debajo del corte. Además, al final, traduciremos o, más correctamente,
traduciremos el documento con el artículo anterior, marcado en nuestro lenguaje, en HTML, y como beneficio adicional, responderé a los programadores novatos de C ++ a una pregunta trivial pero difícil de encontrar: ¿cómo incorporar clases entre sí?

Apuntes de gramática
Antes de pasar directamente a construir un árbol, refresquemos nuestra memoria y aclaremos algunos de los detalles del trabajo preliminar. ¿Todavía recuerdas que toda la sintaxis del lenguaje debe escribirse en forma de una de las gramáticas formales libres de contexto, por ejemplo, BNF? Es solo que es difícil para los programadores principiantes dominarlos de inmediato, y además, no se pueden describir todas las reglas posibles con estas gramáticas. En tales casos, si se encuentra en un callejón sin salida y no formula una determinada regla en la forma correcta, puede escribirla como comentarios en lenguaje humano natural, por ejemplo, así:
... <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
Traducción: el
final del enlace ">" y el elemento de imagen / en línea "]" no pueden seguir inmediatamente al inicio de una línea o documento .
Es decir, si al principio de la línea el lexer encuentra "]" o ">", debemos indicarle que ignore el significado especial de estos caracteres y trabaje con ellos como si fuera texto sin formato. Esta forma de agregar comentarios a la gramática no es la única; puede hacerlo a su manera. Al final, el archivo con la descripción de la sintaxis no es un documento final, nadie lo obliga a seguir todas las reglas y solo es importante que se sienta cómodo trabajando con él. Lo principal es no olvidarse de los comentarios realizados y reflejarlos en las secciones correctas del código.
Veamos una descripción completa de este idioma:
<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
La última vez, fue necesario escribir los terminales y verificar que cada carácter entrante cumpla con uno de ellos. ¡Pero entonces las terminales eran de un solo carácter! Ahora, además de resaltar los terminales, es necesario dividirlos en
teclas , es decir, caracteres. ¿Por qué son las "llaves"? Son clave para el lexer. Como resultado de todas las acciones, aparecerán las siguientes líneas en el archivo de gramática:
(* TERMINALS *) "___...", "\n", "\n\n", "> ", ">>...", "###...[", "*[", "%[", "_[", "^[", "~[", "&[", "+[", "=[", "`[", "]", "<<", "[<", ">", " @... ", "\n@...\n", " @...\n", "\n@... ", "***... ", "+++... ", "123.56. " (* KEYS *) "_", "\n" ">", "#", "*", "%", "^", "~", "&", "+", "=", "`", "<", "[", "]", " ", "@", "1..9", ".", <END>
Pila de tipos esperados de tokens
La última vez, nuevamente, todo fue más simple, solo teníamos 10 tipos de tokens, sin contar el final, y había menos posibilidades de confundirnos en este zoológico de tokens. Ahora, obviamente, hay más tipos. Permítame recordarle que la tarea del lexer es dejar el analizador con el menor trabajo posible, idealmente, solo construyendo un árbol. Por lo tanto, el conjunto de tipos de tokens debe reflejar su esencia con la mayor precisión posible. En el primer artículo di un ejemplo de un buen conjunto, en este lo daré junto con un "anti-ejemplo". ¿Ver terminales que comienzan con elementos de texto en línea (negrita - negrita, cursiva - cursiva, etc.)? Podríamos analizarlos en un par de tokens: el maestro ("*", "%", etc.) y el esclavo ("[") y pasarlo en forma al analizador. Es fácil adivinar que es mejor hacer una definición exacta de un elemento de texto a nivel lexer, es decir. defina "* [" como "bold_start", "% [" como "italic_start", etc. Cuantos más tipos y con mayor precisión se reflejen, mejor. Además, el segundo es más importante que el primero. Por ejemplo, podríamos analizar la notificación para el símbolo "@" y el nombre de usuario, pero obviamente, es mejor dejarlos combinados en un token.
Bueno, decidimos los tipos. ¿Dónde comenzar el procedimiento para analizar el texto en tokens? Como entonces, comience desde el principio. ¿Qué puede seguir inmediatamente al comienzo del documento analizado? No te apresures a doblar los dedos. A diferencia de HTML, los 22 tipos aquí pueden comenzar. Está bien, armado con un poco de unificación, escribimos así:
curr_token_type = TEXT | UNDERLINE | TITLE_START | QUOTE_START | CITE | BOLD_START | ...
y en la función de procesamiento de símbolos:
case TEXT | UNDERLINE | TITLE_START | QUOTE_START | CITE | ...
Si no comprende lo que está en juego, lea el
primer artículo .
No tengas miedo del tipo genérico largo de token esperado. El primer carácter de la cadena reduce inmediatamente su longitud a 2-4 tipos. Dado que nuestros terminales son de varios caracteres, la definición se basa en las teclas.
Es simple, compruébelo usted mismo:
if (c == '_') { buffer.push_back('_'); curr_token_type = TEXT | UNDERLINE | UNDERLINED_START;
El guión bajo determinó de inmediato el token en construcción en uno de tres tipos: texto plano, línea horizontal o el comienzo del texto subrayado ("_ [").
Volviendo al problema, ¿cómo hacer un seguimiento de todos los tipos genéricos y recordar procesarlos todos? ¡Obtén una pila ... en un cuaderno! Así es, escriba todos los tipos genéricos que aparecen después de "curr_token_type = ..." en la lista, y después de procesar uno, tome el otro de la lista desde el final. Puede organizar el trabajo con la lista y, como con la cola, no importa mucho. Lo principal es que no olvidará qué tipos ya están procesados y cuáles aún deben procesarse.
Árbol de clase
Finalmente, llegamos al análisis. Aquí debe determinar las clases de nodos (nodos) del árbol futuro de la misma manera que determinamos con los tipos de tokens. Para hacer esto, abra el cuaderno nuevamente y escriba lo siguiente:
Node { Node * parent, Node_type type } #- Root { Root_item[] children, ulong children_count }
Así que definimos la futura clase base de todos los nodos y su derivada: la raíz del árbol, es decir, el documento en sí. Un documento (consulte el BPF anterior) consta de dos tipos de nodos: una sección y una línea horizontal (subrayado). Definimos la clase base Root_item para ellos y describimos cada uno de la misma manera que describimos la raíz. Además, aquí, en el bloc de notas, indicamos inmediatamente todos los demás campos de las clases, si los hay. Para la raíz, este es el número de "hijos", es decir, secciones internas y lineas horizontales. La sección consta de elementos para los cuales definiremos la clase base Div y así sucesivamente, moviéndonos recursivamente a través de la gramática, determinaremos todas las clases que son necesarias. Antes de escribir el código, definimos aquí toda la inclusión de encabezados. Es simple: todos los descendientes directos de las clases básicas generalizadas deben incluirse en las clases que los contienen.
Denotamos estas dependencias en forma de listas después de la red, y obtenemos el siguiente documento:
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 } #-
Aquí marqué "# -" la ausencia de dependencias y eliminé la inclusión de clases en sí mismos.
Notamos que todas las clases de formato incorporadas (negrita, cursiva, ...) dependen unas de otras y, además, de la clase Link, que también depende de ellas. En una posición similar están Unordered_list y Ordered_list. Incluir encabezados entre sí no solo llevará a ignorar uno de ellos, como se esperaba, sino que no pasará la validación por parte del preprocesador, y la inclusión unidireccional no nos permitirá declarar dentro de la clase incluida la función de abrir el elemento de clase y devolverle el enlace. Como ser Hay dos formas
Inclusión de clases entre sí.
Primero, mire las clases en negrita, cursiva, etc. en Monospace. Son iguales Tanto es así que se pueden combinar en una clase "en línea". Quizás esta decisión suscite dudas. También me causó, pero en la práctica, la diferencia entre ellos solo afectó la forma de presentación en forma de árbol en el terminal y las etiquetas en HTML. Si ve que algunas clases contienen los mismos campos, tienen las mismas dependencias y generalmente tienen una descripción similar en la gramática formal, no dude en combinarlas. Entonces lo hace más fácil para usted y el procesador.
Pero tal truco no funcionará con la clase Link, porque contiene un campo adicional: la cadena URL. Usaremos el segundo método.
¿Todos saben que separar clases en declaraciones y definiciones es una buena forma en la programación en C ++? En el encabezado con la extensión .h o .hpp - declaración, en la fuente con la extensión .cpp - definición, ¿verdad? Y ahora recurro a los recién llegados a la programación: siéntense y abróchense los cinturones de seguridad, porque será desagradable. Después de todo, lo que prescribimos en un archivo con la extensión .h no es más que
una definición de clase. Y en el archivo .cpp, ya hay una
implementación de los métodos de esta clase. No entiendo? Fuimos engañados en la escuela. Una clase se declara como una función, en una sola línea, si no contiene plantillas.
Incluso más fácil que una función, porque no tiene argumentos. Aquí hay una
declaración de clase típica:
class MyClass;
¡Y eso es todo! Y las declaraciones de campos y métodos ya son su
definición .
Aprovecharemos esto. Incluimos el título de la clase Inline en el título de la clase Link, y en él declaramos la clase Link antes de
definir la clase Inline. El archivo inline.h debería verse así:
#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); ...
La clase Inline todavía no sabe nada sobre la clase Link, sus campos y métodos, pero sabe con certeza sobre su existencia. Por lo tanto, podemos declarar métodos que devuelven un
puntero a un objeto de la clase Link, o aceptarlo como argumento. La palabra
puntero no se seleccionó al azar, la clase Inline aún no sabe cómo construir objetos de tipo Link, ya que no tiene acceso a su constructor, pero puede funcionar con todos los punteros, porque Todos tienen la misma interfaz. Pero no necesitamos objetos aquí. Pero en la implementación del método open_link, se crea un objeto de tipo Link y se devuelve un puntero al mismo, lo que significa que para cuando el preprocesador ingrese a este método, el constructor y otros métodos Link que el método open_link pueda necesitar deberían declararse. Aquí aprovechamos la división del código fuente en archivos separados con encabezados e implementación. El archivo inline.h está incluido en el archivo inline.cpp ("undercloud"), pero el archivo link.h no está incluido en inline.h. Por lo tanto, incluirlo en inline.cpp será la primera inclusión para el preprocesador. Entonces el archivo inline.cpp comenzará así:
#include "inline.h" #include "link.h" ...
Repito todo lo anterior. Incluimos el título de la clase Ah en el título de la clase Bh como de costumbre, y declaramos la clase B frente a la clase A e incluimos su título en la fuente A.cpp. Este método no es el único, sino el más simple, en mi opinión.
Observo que esta inclusión mutua de clases no evita que la clase B herede de la clase A, si escribimos su
declaración antes de la
definición de la clase A. Eso es exactamente lo que hice, heredar Ordered_list de Unordered_list.
Construir un árbol
Entonces, llegamos a la construcción de un árbol de sintaxis abstracta. En el último artículo, la función encaja en 50 líneas. Spoiler: esta vez ha crecido hasta casi 1400. El principio de funcionamiento es el mismo: verificamos el tipo de cada token y, dependiendo de ello, ejecutamos una determinada sección de código, almacenando un nodo de árbol abierto en la memoria. Pero solo si, para analizar HTML, casi todas las secciones contienen uno y solo uno de los tres comandos: agregue un nodo vacío dentro del abierto, abra un nuevo nodo en el abierto y cierre el nodo abierto, devolviendo su padre, entonces la acción deseada aquí todavía depende del tipo de nodo abierto. Por ejemplo, si el token de "línea horizontal" entró en proceso y el nodo abierto es la raíz del documento, entonces todo lo que se necesita es agregar una línea a este nodo abierto usando la conversión y la función con el nombre condicional add_line (), algo así:
if (type == Node::ROOT) static_case<Root*>(open_node)->add_line();
Pero si el nodo abierto es un párrafo (Párrafo), primero debe cerrarlo y todos los posibles antepasados (listas con viñetas y numeradas) hasta que el nodo abierto se vuelva del tipo "sección", y luego también ciérrelo:
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(); }
Si el nodo abierto es un título de la imagen, entonces la línea horizontal rompe la gramática por completo, y se debe lanzar una excepción, y si el nodo abierto no es un enlace, y el token entrante ">" tiene el tipo "LINK_FINISH", debe procesarse no como el final del enlace, sino cómo texto, etc.
Por lo tanto, el árbol de cambio / caso, que verifica el tipo de token entrante, debe contener otro árbol de cambio / caso, que verifica el tipo de nodo abierto. Al principio es difícil abordar una construcción de este tipo, pero no es necesario comenzar desde el principio, desde la primera condición. Puede crear un documento estándar marcado por su idioma / que contenga un script en su idioma e implementar condiciones a lo largo del documento, verificando el resultado enviando un árbol pseudográfico al terminal. Tomé el artículo anterior como tal documento, el primer token recibido es el comienzo del título. Entonces, procesamos el token con el tipo TITLE_START. Los siguientes son el texto del encabezado y el corchete de cierre, procesamos tokens de los tipos TEXT y SPAN_OR_IMAGE_FINISH.
Después de eso, ya tendremos ese mini árbol:
<article> | +-<section> | +-<h1> | +-" DOM "
En el camino, notará que algunas clases incluyen los mismos métodos con los mismos algoritmos. Por ejemplo, las clases de párrafo de párrafo y las citas de citas abren enlaces de la misma manera y les agregan texto. En tales casos, la mejor solución cuando se refactoriza es crear una clase con estos métodos y heredar de ella los nodos necesarios. Traté de implementar esto, pero mis habilidades no fueron suficientes, y me confundí con la ambigüedad al lanzar, así que solo doy los resultados del lexer y el analizador:
El articulo mismo @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>>. , , .
Fichas del lexer 0: ["2che": NOTIFICACIÓN]
1: ["
": NEWLINE]
2: ["442964": CITA]
3: ["# [": TITLE_START]
4: ["El arte de analizar o DOM de bricolaje": TEXTO]
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 ]
Árbol de sintaxis <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>
Todo es genial, pero hay demasiados nodos de texto en cadena uno tras otro. Además, me gustaría que las citas seguidas se combinen en una sola. Para hacer esto, debemos atravesar nuevamente el árbol y realizar la concatenación , es decir, la adhesión de elementos homogéneos entre sí. No explicaré los detalles de este proceso, adjuntaré la fuente, pero por ahora solo mire cómoÁrbol después de la concatenación: <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;
Eso es todo
Espero que ahora, después de leer ambos artículos, pueda implementar fácilmente un traductor para su marcado o lenguaje de programación. Si tiene alguna pregunta, pregunte en los comentarios. Y aquí están las fuentes . ÉxitosPD: olvidé mencionar el blindaje . Se implementa simplemente: si el siguiente carácter en el procedimiento de análisis léxico es la barra invertida ("\"), se ignora y se procesa el siguiente carácter, pero además de esto, el valor booleano verdadero se envía a la función de procesamiento de caracteres, dando el comando para escapar. Entonces, si este símbolo, por ejemplo, es "[", su significado especial se ignora y simplemente se une al token en construcción como texto. De lo contrario, la función devuelve falso y el carácter se procesa como de costumbre.