+奖金:C ++中彼此相互包含类
哈Ha! 本文是
我们亲手进行“解析的
艺术”或DOM的文章的直接延续,在该文章中,我们解析了HTML文档,并在其基础上构建了抽象语法树(AST),该树仅通过使用标准C ++库进行索引即可访问任何元素,换句话说,我们学会
了自行
解析类似XML的东西。 让我提醒您,解析或
解析/分析的过程包括两个阶段:
词法分析 (将文本分析成标记)和AST的构建。 如果我们通过示例和源代码对第一个进行了详细的研究,那么对第二个的描述就好像是一个空的蝴蝶娃娃,只有一个外壳,作者在出版之前就提取了出色的内容。 有一个原因,对于HTML来说,树的构建非常容易,您只需要4个类:空标记,块,文本节点和从块继承的文档根。 今天,我们将留下这样的简单性,并建立一棵树,其中元素的属性(空元素和块元素)将不包含在标签的属性中,而是直接包含在类中,为此,您将必须创建许多类。 真的很多 我们将不使用简单的众所周知的标记语言进行构建,而是使用剪切下图像中显示的规则创建自己的标记语言。 另外,最后,我们将翻译或更正确地
翻译上一篇文章,并用我们的语言,HTML进行标记,此外,我将向C ++初学者回答一个琐碎但难以发现的问题:如何将类彼此合并?

语法笔记
在直接开始构建树之前,让我们刷新一下记忆并阐明初步工作的一些细节。 您是否还记得该语言的整个语法需要以一种无上下文形式语法(例如BNF)的形式编写? 只是对于初学者来说,很难立即掌握它们,而且,不能描述这些语法的所有可能规则。 在这种情况下,如果您陷入困境,并且没有以正确的形式制定特定的规则,则可以将其记为自然人类语言的注释,例如,如下所示:
... <ordered_list_item> = <number_marker> <div> <number_marker> = <number> "." {<number> "."} " " <number> = <digit> {<digit>} !! link ending ">" and image/span ending "]" can't follow "\n" or document start
翻译:
“>”链接的
末尾和image / inline元素“]”不能立即跟在行或文档的开头 。
也就是说,如果词法分析器在该行的开头遇到“]”或“>”,我们必须指示它忽略这些字符的特殊含义,并像处理纯文本一样使用它们。 这种向语法添加注释的方法并不是唯一的方法;您可以按照自己的方式来做。 最后,带有语法描述的文件不是术语纸,没有人强迫您遵守所有规则,并且重要的是要方便使用它。 最主要的是不要忘记所做的注释,并将其反映在代码的正确部分中。
让我们看一下这种语言的完整描述:
<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
上一次,有必要写出终端并检查每个输入字符是否符合其中之一。 但是那时终端是单个字符! 现在,除了突出显示终端外,还需要将它们本身划分为
按键 -即字符。 为什么是“钥匙”? 它们是词法分析器的关键。 作为所有操作的结果,以下行将显示在语法文件中:
(* TERMINALS *) "___...", "\n", "\n\n", "> ", ">>...", "###...[", "*[", "%[", "_[", "^[", "~[", "&[", "+[", "=[", "`[", "]", "<<", "[<", ">", " @... ", "\n@...\n", " @...\n", "\n@... ", "***... ", "+++... ", "123.56. " (* KEYS *) "_", "\n" ">", "#", "*", "%", "^", "~", "&", "+", "=", "`", "<", "[", "]", " ", "@", "1..9", ".", <END>
预期类型的代币堆栈
上一次,一切都变得更加简单,我们只有10种类型的代币,还不包括结局,而且在这个代币动物园中迷失的机会更少。 现在显然有更多类型。 让我提醒您,词法分析器的任务是让解析器尽可能少地工作,理想情况下,仅构建一棵树。 因此,令牌类型集应尽可能准确地反映其本质。 在第一篇文章中,我给出了一个很好的例子,在此我将给出一个“反例”。 看到终端以内联文本元素开始(粗体-粗体,斜体-斜体等)吗? 我们可以将它们解析为一对标记:主标记(“ *”,“%”等)和从标记(“ [”),并将其以格式传递给解析器。 容易猜测,最好在词法分析器级别对文本元素进行精确定义,即 将“ * [”定义为“ bold_start”,将“%[”定义为“ italic_start”,依此类推。 类型越多,它们反映自己的准确度就越高。 而且,第二个比第一个更重要。 例如,我们可以解析“ @”符号和用户名的通知,但是显然,最好将它们组合在一个令牌中。
好吧,我们决定了类型。 从哪里开始将文本解析为令牌的过程? 然后,从头开始。 紧随已解析文档的开头之后会发生什么? 不要急于弯曲手指。 与HTML不同,这里所有22种类型都可以开始。 没关系,有了一点点的统一,我们这样写:
curr_token_type = TEXT | UNDERLINE | TITLE_START | QUOTE_START | CITE | BOLD_START | ...
并在符号处理功能中:
case TEXT | UNDERLINE | TITLE_START | QUOTE_START | CITE | ...
如果您不了解要解决的问题,请阅读
第一篇文章 。
不要担心期望令牌的长泛型类型。 字符串的第一个字符立即将其长度减少到2-4种。 由于我们的终端是多字符,因此定义基于键。
很简单,自己看看:
if (c == '_') { buffer.push_back('_'); curr_token_type = TEXT | UNDERLINE | UNDERLINED_START;
下划线立即将正在构造的令牌确定为以下三种类型之一:纯文本,水平线或带下划线的文本的开头(“ _ [”)。
回到问题,如何跟踪所有泛型并记住对它们进行处理? 在笔记本上叠一叠! 没错,在列表中写下出现在“ curr_token_type = ...”之后的所有泛型类型,处理完其中一种后,从末尾取下另一种。 您可以使用列表和队列来组织工作,这无关紧要。 最主要的是,您不会忘记哪些类型已经被处理,哪些类型仍需要处理。
类树
最后,我们开始解析。 在这里,您需要以与确定令牌类型相同的方式来确定未来树的节点(节点)的类。 为此,请再次打开笔记本并输入以下内容:
Node { Node * parent, Node_type type } #- Root { Root_item[] children, ulong children_count }
因此,我们定义了所有节点的将来基类及其派生类-树的根,即文档本身。 文档(请参见上面的BPF)由两种类型的节点组成:节和水平线(下划线)。 我们为它们定义基类Root_item,并以与描述根相同的方式描述它们。 另外,在这里,我们在记事本中立即指示类的所有其他字段(如果有)。 从根本上讲,这是“孩子”的数量,即 内部部分和水平线。 本节由一些元素组成,我们将为其定义基类Div,依此类推,在语法中递归移动,我们将确定所需的所有类。 在编写代码之前,我们在这里定义所有标头。 这很简单:基本广义类的所有直接后代必须包含在包含它们的类中。
在晶格之后以列表的形式表示这些依赖关系,我们得到以下文档:
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 } #-
在这里,我将“#-”标记为不依赖,并删除了类本身。
我们注意到,所有内置的格式设置类(粗体,斜体,...)都相互依赖,此外,Link类也相互依赖! 处于类似位置的是Unordered_list和Ordered_list。 相互之间包含标头不仅会导致忽略其中的一个,正如预期的那样,而且也不会通过预处理器的验证,并且单面包含将不允许我们在包含的类中声明打开类元素并返回指向它的链接的功能。 如何成为 有两种方法。
相互包含类
首先,查看Monospace的类Bold,Italic等。 他们是一样的。 如此之多,以至于可以将它们组合为一个“内联”类。 也许这个决定会引起怀疑。 这也引起了我的注意,但实际上,它们之间的差异仅影响终端中的树状结构和HTML中的标记形式的表示形式。 如果您看到某些类包含相同的字段,具有相同的依存关系并且在形式语法中通常具有相似的描述,请随意组合它们。 因此,您可以使自己和处理器变得更容易。
但是,这种技巧不适用于Link类,因为它包含一个附加字段-URL字符串。 我们将使用第二种方法。
大家都知道在C ++编程中将类分为声明和定义是一种好方法吗? 在扩展名为.h或.hpp的标头中,在扩展名为.cpp的源代码中,对吗? 现在,我转向编程的新手:坐下来并系好安全带,因为这会令人不快。 毕竟,我们在扩展名为.h的文件中所指定的仅
是类的
定义 。 在.cpp文件中,已经有此类
的方法的
实现 。 不明白吗? 我们在学校被骗了。 如果一个类不包含模板,则在一行中将其声明为一个函数。
它比函数更简单,因为它没有参数。 这是一个典型的类
声明 :
class MyClass;
就是这样! 字段和方法的声明已经是其
定义 。
我们将利用这一点。 我们将Inline类的标题包含在Link类的标题中,并在
定义 Inline类之前先声明Link类本身。 inline.h文件应如下所示:
#ifndef INLINE_H #define INLINE_H #include "AST/span.h" #include "AST/text.h" #include "AST/image.h" #include "AST/notification.h" class Link; class Inline : public Span { public: static const unsigned long MAX_CHILDREN_COUNT = 0xFFFFFF; private: Span ** children; unsigned long children_count; unsigned long extended; void extend(); public: Inline(const Node * parent, const Node_type &type); Inline(const Span * span); ~Inline(); Inline * add_text(const string &text); Inline * add_image(const string &src, const string &alt); Inline * add_notification(const string &user); Link * open_link(const string &URL); ...
Inline类仍然对Link类,其字段和方法一无所知,但可以肯定地知道其存在。 因此,我们可以声明返回
指向 Link类对象的
指针或将其作为参数接受的方法。 单词
指针不是随机选择的,Inline类尚不知道如何构建Link类型的对象,因为它没有访问其构造函数的权限,但可以使用所有指针,因为 它们都有相同的界面。 但是我们在这里不需要对象。 但是在open_link方法的实现中,将创建Link类型的对象并返回指向它的指针,这意味着在预处理器进入该方法时,应声明open_link方法可能需要的构造函数和其他Link方法。 在这里,我们利用将源代码分为带有标头和实现的单独文件的优势。 inline.h文件包含在inline.cpp文件(“ undercloud”)中,但link.h文件不包含在inline.h中。 因此,将其包含在inline.cpp中将成为预处理器的第一个包含项。 然后inline.cpp文件将像这样开始:
#include "inline.h" #include "link.h" ...
我重复以上所有内容。 类Ah的标题照常包含在类Bh的标题中,并且类B在类A之前声明,我们将其标题包含在源A.cpp中。 我认为,这种方法不是唯一的,而是最简单的。
我注意到,如果我们在类A的
定义之前写下它的
声明 ,则类的这种相互包含并不能阻止类B从类A继承。这正是我所做的,是从Unordered_list继承Ordered_list。
建树
因此,我们开始构建抽象语法树。 在上一篇文章中,该函数适合50行。 剧透:这次增加到了1400个左右。操作原理是相同的:我们检查每个令牌的类型,并根据它执行特定的代码段,将一个开放树节点存储在内存中。 但是,如果要解析HTML,几乎所有节段都只包含三个命令中的一个,那就是:在打开的命令中添加一个空节点,在打开的命令中打开一个新节点并关闭该打开的节点,返回其父节点,那么此处所需的操作也取决于打开的节点的类型。 例如,如果正在处理“水平线”令牌,并且打开节点是文档根目录,那么只需使用浇铸和条件名称为add_line()的函数向该打开节点添加一行,如下所示:
if (type == Node::ROOT) static_case<Root*>(open_node)->add_line();
但是,如果打开节点是一个段落(段落),则首先需要关闭它和所有可能的祖先(项目列表和编号列表),直到打开节点变为“节”类型,然后将其关闭:
else if (type == Node::PARAGRAPH) { open_node = static_cast<Paragraph*>(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast<Unordered_list*>(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast<Unordered_list*>(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->close(); } open_node = static_cast<Section*>(open_node)->close(); open_node = tree->add_line(); }
如果开放节点是图像的标题,则水平线将完全破坏语法,并且必须引发异常,并且如果开放节点不是链接,并且传入令牌“>”类型为“ LINK_FINISH”,则不应将其作为链接的结尾进行处理,而是如何处理文字等
因此,检查传入令牌类型的交换机/案例树必须包含另一个交换机/案例树,后者检查开放节点的类型。 起初很难解决这样的问题,但是没有必要从头开始,从第一个条件开始。 您可以创建用您的语言标记的标准文档/包含使用您的语言编写的脚本,并在文档过程中实现条件,并通过向终端输出伪树来检查结果。 我将上一篇文章作为这样的文档,收到的第一个令牌是标题的开头。 因此,我们以TITLE_START类型处理令牌。 以下是标题文本和右方括号,我们处理TEXT和SPAN_OR_IMAGE_FINISH类型的令牌。
在那之后,我们将已经有一个这样的迷你树:
<article> | +-<section> | +-<h1> | +-" DOM "
在此过程中,您会注意到某些类包含具有相同算法的相同方法。 例如,段落段落类和引号引号以相同的方式打开链接并向其中添加文本。 在这种情况下,重构时最好的解决方案是使用这些方法创建一个类并从中继承必要的节点。 我尝试实现这一点,但是我的技能还不够,在转换时我对模棱两可感到困惑,因此我只给出词法分析器和解析器的结果:
文章本身 @2che >>442964 #[ DOM ] , ! markdown, , — « », . , , , , LibreOffice Writer, %[ ], — %[]. , «parser example», «html to DOM», «how to parse html» . , , , flex, bison, llvm yacc. , , (gumbo, jsoup, rapidjson, Qt .) , C++ , . , AST ( ), , , . , — — , . . , . , , . HTML, . , , %[ ] — . : 1. *[ ] — , . 2. *[ ] — %[ ] (AST — abstract syntax tree), %[ ] (DOM — document object model). . , IDE , . - — %[ - ()] %[ -]. , . : > `[<> = <_1> <_> <_2>] , . , , «» .. ? : %[] %[]. *[] — , : > `[<_1> = <> (<_> | <_>) <>] *[] , . : > `[<> = <_1> "+" <_2> <_1> = <> ("*" | "/") <>] "+", "*", "/" — . , , — . <<https://ru.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D0%BC%D0%B0_%D0%91%D1%8D%D0%BA%D1%83%D1%81%D0%B0_%E2%80%94_%D0%9D%D0%B0%D1%83%D1%80%D0%B0>> <<https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D1%81%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D0%B0_%D0%91%D1%8D%D0%BA%D1%83%D1%81%D0%B0_%E2%80%94_%D0%9D%D0%B0%D1%83%D1%80%D0%B0>>. — , . , . , , , . , , , . , . HTML5 : > `[stub] , ( , .. , ). : , , ? , , . . , disassemble(ifsteam &file) , process(const char &c), . , process switch, . : switch , . , , . , : , , , HTML ( PHP, "<?… ?>". case. ? . ( — , — ). (1, 2, 4, 8 .). : 0001, 0010, 0100 .., . , . : > `[enum Token_type { END = 1, TEXT = 2, OPENING_BLOCK_TAG_NAME = 4, CLOSING_BLOCK_TAG_NAME = 8, EMPTY_TAG_NAME = 16, COMMENT = 32, MACRO_TAG = 64, ATTRIBUTE_NAME = 128, UNQUOTED_ATTRIBUTE_VALUE = 256, SINGLE_QUOTED_ATTRIBUTE_VALUE = 512, DOUBLE_QUOTED_ATTRIBUTE_VALUE = 1024 };] process: > `[stub] switch ( ), case . , : , , (), . . () , «» .. gedit: [<https://hsto.org/webt/72/fw/tw/72fwtwt_waeie4ulzftkxua356w.png>] , . disassemble: > `[stub] TEXT, END ( , ). HTML- , - PHP, "[ "<_>": <_> ]". : > =[ `[stub]] =[ `[stub]] — . , -. DOM, . HTML-? — , , — «Node», «Block» (, ) «Root». , , , <p>, <li>, <strong> , . . , — : , , . , , Node, , . %[ ]. : > `[stub] ! , : `[| +--<ROOT> | +--<!DOCTYPE> | +--<html> | +--<head> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<meta> | | | +--<title> | | | +--<link> | | | +--<link> | | | +--<COMMENT> | +--<body> | +--<header> | | | +--<div> | +--<nav> | | | +--<ul> | | | +--<li> | | | | | +--<a> | | | +--<li> | | | | | +--<a> | | | +--<li> | | | +--<a> | +--<main> | | | +--<MACRO> | +--<footer> | +--<hr> | +--<small>] , DOM, jQuery, Jsoup, beautifulsoup Gumbo , , , <style> <script>, . , . . PS <<https://gitlab.com/2che/nyHTML>>. , , .
来自词法分析器的令牌 0:[“ 2che”:通知]
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形式表示此树。一切都很简单:我们在root方法中以主要标记的开头(打开html和body元素,一个head块)创建一行,并开始附加从相似子元素返回的行。在这里,我们再次处理递归关系:每个类在调用to_HTML()虚拟方法时创建一行,将其主要标记放入其中,然后在其每个后代中调用相同的方法,将各行连接起来,完成主要标记并将其返回给调用的父代。例如,这里的Inline类看起来像下面的方法(结合格式化的inline元素): string Inline::to_HTML (const unsigned int &level) { string HTML;
仅此而已。
我希望现在阅读了这两篇文章后,您可以轻松实现标记或编程语言的翻译器。如有任何疑问,请在评论中提问。这是资源。成功。PS我忘了提到屏蔽。它的实现很简单:如果词法分析过程中的下一个字符是反斜杠(“ \”),则将其忽略并处理下一个字符,但除此之外,还将布尔值true发送给字符处理函数,从而使命令转义。然后,例如,如果该符号为“ [”,则其特殊含义将被忽略,并且仅将正在构造的标记作为文本加入。否则,该函数将返回false并照常处理字符。