为什么我们需要虚拟功能

哈Ha 如果您知道标题中问题的答案,那么恭喜,您不需要本文。 它是针对像我这样的编程初学者的,他们不能总是独立地理解C ++和其他类型语言的所有复杂性,并且如果可以的话,最好还是从别人的错误中学习。

在本文中,我将不仅仅回答“ 为什么我们需要C ++中的虚函数 ”这个问题,而是将通过实践给出一个示例。 作为一个简短的答案,您可以转向产生如下内容的搜索引擎:“ 需要虚拟函数来提供多态性-三只OOP鲸鱼之一。由于有了它们,机器本身可以通过指针确定对象的类型,而无需向程序员加载此任务。 ” 好的,但是“为什么”问题仍然存在,尽管现在含义有所不同:“ 为什么要依靠机器,花更多的时间和内存,如果您可以自己播客指针,因为它所指向的对象类型几乎总是已知的? ”的确,乍一看,强制转换会使虚函数失效,而这正是导致误解和错误代码的原因。 在小型项目中,损失是看不见的,但是,正如您将很快看到的那样,随着程序的增长,种姓的增加几乎以几何级数递增。

首先,让我们回顾一下可能根本需要种姓和虚函数的地方。 当为使用类型A声明的对象分配新操作以为与类型A兼容的类型B的对象(通常从A继承)分配内存时,类型就会丢失。通常,该对象不是一个对象,而是整个数组。 相同类型的指针数组,每个指针都在等待分配完全不同类型的对象的存储区。 这是我们将考虑的示例。

我不会拖很长时间了,任务是这样的:基于一个用Markedit超文本标记语言标记的文档(您可以在此处阅读有关内容),构建一个解析树,并创建一个包含相同HTML标记文档的文件。 我的解决方案由三个顺序例程组成:将源文本解析为标记,从标记构建语法树,并基于该语法构建HTML文档。 我们对第二部分感兴趣。
事实是目标树的节点具有不同的类型(节,段落,文本节点,链接,脚注等),但是对于父节点,指向子节点的指针存储在数组中,因此具有一种类型-节点。

解析器本身的简化形式是这样的:它使用Root类型创建树语法的“根”,声明常规类型Nodeopen_node指针(立即为其分配地址)和枚举类型Node_type类型变量,然后循环开始, 从头开始遍历令牌到最后。 每次迭代时,首先将open_node打开节点的类型输入到type变量中(枚举形式的类型存储在节点的结构中),然后是switch语句 ,该语句检查下一个标记的类型(词法分析器已经仔细提供了标记的类型)。 在交换机的每个分支中,都提供了另​​一个分支来检查类型变量,正如我们记得的那样,其中包含打开节点的类型。 根据其值,将执行不同的操作,例如:将某个类型的节点列表添加到一个打开的节点,在一个打开的节点中打开某个类型的另一个节点,并将其地址传递给open_node ,关闭该打开的节点,引发异常。 适用于本文的主题,我们对第二个示例感兴趣。 每个打开的节点(通常是每个可以打开的节点)已经包含一个指向Node类型的节点的指针数组。 因此,当我们在一个打开的节点中打开一个新节点(将另一个类型的对象的内存区域分配给下一个数组指针)时,对于C ++语义分析器,它仍然是Node类型的实例,而无需获取新的字段和方法。 现在将指向它的指针分配给变量open_node ,而不会丢失Node的类型。 但是,当您需要调用方法(例如段落)时,如何使用常规Node类型的指针呢? 例如, open_bold() ,它将在其中打开一个粗体字体节点? 毕竟, open_bold()被声明并定义为Paragraph类的方法,而Node完全不知道它。 另外, open_node也被声明为指向Node的指针,并且它必须接受所有打开节点类型的方法。

这里有两种解决方案:显而易见的解决方案和正确的解决方案。 对于初学者来说显而易见的是static_cast ,并且虚函数是正确的。 我们首先来看一下使用第一种方法编写的开关解析器的一个分支:

case Lexer::BOLD_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_bold(); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_bold(); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_bold(); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_bold(); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_bold(); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_bold(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_bold(); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_bold(); else // INLINE open_node = static_cast<Inline*>(open_node)->open_bold(); break; } 

还不错 现在,我将不再使用它很长时间,我将展示使用虚函数编写的同一部分代码:

  case Lexer::BOLD_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_bold(); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_bold(); } else if (type == Node::UNORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_bold(); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_bold(); break; } 

收益是显而易见的,但是我们真的需要吗? 毕竟,您必须在Node类中将所有派生类的所有方法声明为虚方法,并以某种方式在每个派生类中实现它们。 答案是肯定的。 该程序中没有专门的方法(29),并且在与它们不相关的派生类中的实现仅由一行组成: throw string(“ error!”); 。 您可以启用广告素材模式,并为每次异常抛出提供唯一的一行。 但最重要的是-由于减少了代码,减少了错误数量。 强制转换是导致代码错误的最重要原因之一。 因为在应用static_cast之后,如果调用的类包含在给定的类中,则编译器将停止宣誓。 同时,不同的类可能包含具有相同名称的不同方法。 就我而言,代码中隐藏了6个! 错误,而其中之一在多个开关分支中重复。 这是:

 else if (type == Node:: open_node = static_cast<Title*>(open_node)->open_italic(); 

接下来,在扰流器下,我提供了解析器的第一版和第二版的完整列表。

解析器与转换
 Root * Parser::parse (const Lexer &lexer) { Node * open_node(tree); Node::Node_type type; for (unsigned long i(0), len(lexer.count()); i < len; i++) { type = open_node->get_type(); if (type == Node::CITE || type == Node::TEXT || type == Node::NEWLINE || type == Node::NOTIFICATION || type == Node::IMAGE) throw string("error!"); switch (lexer[i].type) { case Lexer::NEWLINE: { if (type == Node::ROOT || type == Node::SECTION) ; else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->add_text("\n"); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->add_text("\n"); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->add_text("\n"); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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(); } } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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(); } } else if (type == Node::LINK) { open_node = static_cast<Link*>(open_node)->add_text(lexer[i].lexeme); } else // INLINE open_node = static_cast<Inline*>(open_node)->add_text(lexer[i].lexeme); break; } case Lexer::DOUBLE_NEWLINE: { if (type == Node::ROOT || type == Node::SECTION) ; 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(); } } else if (type == Node::QUOTE) { open_node = static_cast<Quote*>(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(); } } else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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(); } } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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(); } } else throw string("unexpected double newline!"); break; } case Lexer::UNDERLINE: { if (type == Node::ROOT) open_node = tree->add_line(); else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->close(); open_node = tree->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(); } else if (type == Node::TITLE) throw string("unexpected underline inside title!"); else if (type == Node::QUOTE) { open_node = static_cast<Quote*>(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(); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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(); } else // INLINE throw string("unexpected underline inside inline span!"); break; } case Lexer::TITLE_START: { if (lexer[i].lexeme.size() > 7) throw string("invalid title: \"" + lexer[i].lexeme + "\"!"); if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_title(lexer[i].lexeme.size()-1); } else if (type == Node::SECTION) open_node = static_cast<Section*>(open_node)->open_title(lexer[i].lexeme.size()-1); 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)->open_title(lexer[i].lexeme.size()-1); } else if (type == Node::TITLE) throw string("title can't contain another title!"); else if (type == Node::QUOTE) { open_node = static_cast<Quote*>(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)->open_title(lexer[i].lexeme.size()-1); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_title(lexer[i].lexeme.size()-1); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_title(lexer[i].lexeme.size()-1); } else if (type == Node::LINK) throw string("link can't contain a title!"); else // INLINE throw string("inline span can't contain a title!"); break; } case Lexer::BOLD_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_bold(); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_bold(); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_bold(); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_bold(); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_bold(); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_bold(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_bold(); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_bold(); else // INLINE open_node = static_cast<Inline*>(open_node)->open_bold(); break; } case Lexer::ITALIC_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_italic(); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_italic(); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_italic(); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_italic(); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_italic(); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_italic(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_italic(); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_italic(); else // INLINE open_node = static_cast<Inline*>(open_node)->open_italic(); break; } case Lexer::UNDERLINED_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_underlined(); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_underlined(); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_underlined(); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_underlined(); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_underlined(); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_underlined(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_underlined(); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_underlined(); else // INLINE open_node = static_cast<Inline*>(open_node)->open_underlined(); break; } case Lexer::OVERLINED_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_overlined(); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_overlined(); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_overlined(); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_overlined(); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_overlined(); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_overlined(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_overlined(); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_overlined(); else // INLINE open_node = static_cast<Inline*>(open_node)->open_overlined(); break; } case Lexer::THROWLINED_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_throwlined(); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_throwlined(); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_throwlined(); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_throwlined(); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_throwlined(); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_throwlined(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_throwlined(); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_throwlined(); else // INLINE open_node = static_cast<Inline*>(open_node)->open_throwlined(); break; } case Lexer::SUBSCRIPT_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_subscript(); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_subscript(); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_subscript(); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_subscript(); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_subscript(); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_subscript(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_subscript(); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_subscript(); else // INLINE open_node = static_cast<Inline*>(open_node)->open_subscript(); break; } case Lexer::SUPERSCRIPT_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_superscript(); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_superscript(); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_superscript(); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_superscript(); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_superscript(); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_superscript(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_superscript(); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_superscript(); else // INLINE open_node = static_cast<Inline*>(open_node)->open_superscript(); break; } case Lexer::MARKED_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_marked(); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_marked(); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_marked(); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_marked(); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_marked(); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_marked(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_marked(); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_marked(); else // INLINE open_node = static_cast<Inline*>(open_node)->open_marked(); break; } case Lexer::MONOSPACE_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_monospace(); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_monospace(); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_monospace(); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_monospace(); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_monospace(); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_monospace(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_monospace(); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_monospace(); else // INLINE open_node = static_cast<Inline*>(open_node)->open_monospace(); break; } case Lexer::SPAN_OR_IMAGE_FINISH: { if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->close(); else if (type == Node::BOLD || type == Node::ITALIC || type == Node::UNDERLINED || type == Node::OVERLINED || type == Node::THROWLINED || type == Node::SUBSCRIPT || type == Node::SUPERSCRIPT || type == Node::MARKED || type == Node::MONOSPACE) open_node = static_cast<Inline*>(open_node)->close(); else if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text("]"); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text("]"); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->add_text("]"); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->add_text("]"); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->add_text("]"); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text("]"); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text("]"); } else // INLINE open_node = static_cast<Inline*>(open_node)->add_text(">"); break; } case Lexer::LINK_START: { if (i > len-3 || lexer[++i].type != Lexer::TEXT || lexer[++i].type != Lexer::LINK_FINISH) throw string("unclosed link!"); if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_link(lexer[i-1].lexeme); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_link(lexer[i-1].lexeme); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->open_link(lexer[i-1].lexeme); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->open_link(lexer[i-1].lexeme); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->open_link(lexer[i-1].lexeme); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_link(lexer[i-1].lexeme); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->open_link(lexer[i-1].lexeme); } else if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->open_link(lexer[i-1].lexeme); else // INLINE open_node = static_cast<Inline*>(open_node)->open_link(lexer[i-1].lexeme); break; } case Lexer::LINK_FINISH: { if (type == Node::LINK) open_node = static_cast<Link*>(open_node)->close(); else if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text(">"); } else if (type == Node::SECTION) { open_node = static_cast<Section>(open_node).open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text(">"); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->add_text(">"); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->add_text(">"); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->add_text(">"); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text(">"); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text(">"); } else // INLINE open_node = static_cast<Inline*>(open_node)->add_text(">"); break; } case Lexer::IMAGE_START: { if (i > len-5 || lexer[++i].type != Lexer::TEXT || lexer[++i].type != Lexer::LINK_FINISH || (lexer[++i].type != Lexer::TEXT && lexer[i].type != Lexer::SPAN_OR_IMAGE_FINISH) || (lexer[i].type == Lexer::TEXT && lexer[i+1].type != Lexer::SPAN_OR_IMAGE_FINISH)) throw string("unclosed image defintion!"); if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, ""); } 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)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::TITLE) { if (lexer[i].type == Lexer::TEXT) { open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::QUOTE) { open_node = static_cast<Quote*>(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)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::LINK) { if (lexer[i].type == Lexer::TEXT) { open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, ""); } else { // INLINE if (lexer[i].type == Lexer::TEXT) { open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast<Paragraph*>(open_node)->add_image(lexer[i-2].lexeme, ""); } break; } case Lexer::CITE: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::SECTION) open_node = static_cast<Section*>(open_node)->add_cite(atoi(lexer[i].lexeme.c_str())); 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)->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->add_image(lexer[i-3].lexeme, lexer[i-1].lexeme); else if (type == Node::QUOTE) { open_node = static_cast<Quote*>(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)->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::LINK) throw string("link can't contain a cite!"); else // INLINE throw string("inline span can't contain a cite!"); break; } case Lexer::QUOTE_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_quote(); } else if (type == Node::SECTION) open_node = static_cast<Section*>(open_node)->open_quote(); 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)->open_quote(); } else if (type == Node::TITLE) { open_node = static_cast<Title*>(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)->open_quote(); } else if (type == Node::QUOTE) { open_node = static_cast<Quote*>(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)->open_quote(); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_quote(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_quote(); } else if (type == Node::LINK) { open_node = static_cast<Link*>(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)->open_quote(); } else { // INLINE open_node = static_cast<Inline*>(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)->open_quote(); } break; } case Lexer::NOTIFICATION: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_notification(lexer[i].lexeme); } 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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::TITLE) { open_node = static_cast<Title*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::QUOTE) { open_node = static_cast<Quote*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::LINK) { open_node = static_cast<Link*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_notification(lexer[i].lexeme); } else { // INLINE open_node = static_cast<Inline*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_notification(lexer[i].lexeme); } break; } case Lexer::TEXT: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text(lexer[i].lexeme); } else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text(lexer[i].lexeme); } else if (type == Node::PARAGRAPH) open_node = static_cast<Paragraph*>(open_node)->add_text(lexer[i].lexeme); else if (type == Node::TITLE) open_node = static_cast<Title*>(open_node)->add_text(lexer[i].lexeme); else if (type == Node::QUOTE) open_node = static_cast<Quote*>(open_node)->add_text(lexer[i].lexeme); else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text(lexer[i].lexeme); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Ordered_list*>(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)->open_paragraph(); open_node = static_cast<Paragraph*>(open_node)->add_text(lexer[i].lexeme); } else if (type == Node::LINK) { open_node = static_cast<Link*>(open_node)->add_text(lexer[i].lexeme); } else // INLINE open_node = static_cast<Inline*>(open_node)->add_text(lexer[i].lexeme); break; } case Lexer::UNORDERED_LIST_ITEM_MARKER: { break; } case Lexer::ORDERED_LIST_ITEM_MARKER: { break; } case Lexer::END: { if (type == Node::ROOT) open_node = tree->close(); else if (type == Node::SECTION) { open_node = static_cast<Section*>(open_node)->close(); open_node = tree->close(); } 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->close(); } else if (type == Node::QUOTE) { open_node = static_cast<Quote*>(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->close(); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast<Unordered_list*>(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->close(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast<Unordered_list*>(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->close(); } else // LINK || INLINE throw string("unexpected ending!"); /// ROOT, /// SECTION, /// PARAGRAPH, TITLE, QUOTE, UNORDERED_LIST, ORDERED_LIST, /// BOLD, ITALIC, UNDERLINED, OVERLINED, THROWLINED, SUBSCRIPT, SUPERSCRIPT, MARKED, MONOSPACE, /// LINK break; } } } concatenate(); return tree; } 

可以访问虚拟方法的解析器
 Root * Parser::parse (const Lexer &lexer) { Node * open_node(tree); Node::Node_type type; for (unsigned long i(0), len(lexer.count()); i < len; i++) { type = open_node->get_type(); if (type == Node::CITE || type == Node::TEXT || type == Node::NEWLINE || type == Node::NOTIFICATION || type == Node::IMAGE) throw string("error!"); switch (lexer[i].type) { case Lexer::NEWLINE: { if (type == Node::ROOT || type == Node::SECTION) ; else if (type == Node::PARAGRAPH || type == Node::TITLE || type == Node::QUOTE || type == Node::TITLE || type == Node::QUOTE) open_node = open_node->add_text("\n"); else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); } else // LINK, INLINE open_node = open_node->add_text(lexer[i].lexeme); break; } case Lexer::DOUBLE_NEWLINE: { if (type == Node::ROOT || type == Node::SECTION) ; else if (type == Node::PARAGRAPH || type == Node::QUOTE || type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); } else throw string("unexpected double newline!"); break; } case Lexer::UNDERLINE: { if (type == Node::ROOT) open_node = tree->add_line(); else if (type == Node::SECTION) { open_node = open_node->close(); open_node = tree->add_line(); } else if (type == Node::PARAGRAPH || type == Node::QUOTE || type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->close(); open_node = tree->add_line(); } else if (type == Node::TITLE) throw string("unexpected underline inside title!"); else if (type == Node::LINK) throw string("unexpected underline inside link!"); else // INLINE throw string("unexpected underline inside inline span!"); break; } case Lexer::TITLE_START: { if (lexer[i].lexeme.size() > 7) throw string("invalid title: \"" + lexer[i].lexeme + "\"!"); if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_title(lexer[i].lexeme.size()-1); } else if (type == Node::SECTION) open_node = open_node->open_title(lexer[i].lexeme.size()-1); else if (type == Node::PARAGRAPH || type == Node::QUOTE || type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_title(lexer[i].lexeme.size()-1); } else if (type == Node::TITLE) throw string("title can't contain another title!"); else if (type == Node::LINK) throw string("link can't contain a title!"); else // INLINE throw string("inline span can't contain a title!"); break; } case Lexer::BOLD_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_bold(); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_bold(); } else if (type == Node::UNORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_bold(); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_bold(); break; } case Lexer::ITALIC_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_italic(); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_italic(); } else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_italic(); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_italic(); break; } case Lexer::UNDERLINED_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_underlined(); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_underlined(); } else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_underlined(); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_underlined(); break; } case Lexer::OVERLINED_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_overlined(); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_overlined(); } else if (type == Node::PARAGRAPH) open_node = open_node->open_overlined(); else if (type == Node::TITLE) open_node = open_node->open_overlined(); else if (type == Node::QUOTE) open_node = open_node->open_overlined(); else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_overlined(); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_overlined(); break; } case Lexer::THROWLINED_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_throwlined(); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_throwlined(); } else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_throwlined(); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_throwlined(); break; } case Lexer::SUBSCRIPT_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_subscript(); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_subscript(); } else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_subscript(); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_subscript(); break; } case Lexer::SUPERSCRIPT_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_superscript(); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_superscript(); } else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_superscript(); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_superscript(); break; } case Lexer::MARKED_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_marked(); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_marked(); } else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_marked(); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_marked(); break; } case Lexer::MONOSPACE_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_monospace(); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_monospace(); } else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_monospace(); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_monospace(); break; } case Lexer::SPAN_OR_IMAGE_FINISH: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->add_text("]"); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->add_text("]"); } else if (type == Node::PARAGRAPH || type == Node::QUOTE || type == Node::LINK) open_node = open_node->add_text("]"); else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->add_text("]"); } else // TITLE, INLINE open_node = open_node->close(); break; } case Lexer::LINK_START: { if (i > len-3 || lexer[++i].type != Lexer::TEXT || lexer[++i].type != Lexer::LINK_FINISH) throw string("unclosed link!"); if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->open_link(lexer[i-1].lexeme); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->open_link(lexer[i-1].lexeme); } else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->open_link(lexer[i-1].lexeme); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->open_link(lexer[i-1].lexeme); break; } case Lexer::LINK_FINISH: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->add_text(">"); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->add_text(">"); } else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->add_text(">"); } else if (type == Node::LINK) open_node = open_node->close(); else // PARAGRAPH, TITLE, QUOTE, INLINE open_node = open_node->add_text(">"); break; } case Lexer::IMAGE_START: { if (i > len-5 || lexer[++i].type != Lexer::TEXT || lexer[++i].type != Lexer::LINK_FINISH || (lexer[++i].type != Lexer::TEXT && lexer[i].type != Lexer::SPAN_OR_IMAGE_FINISH) || (lexer[i].type == Lexer::TEXT && lexer[i+1].type != Lexer::SPAN_OR_IMAGE_FINISH)) throw string("unclosed image defintion!"); if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = open_node->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = open_node->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = open_node->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = open_node->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::PARAGRAPH || type == Node::QUOTE || type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { if (lexer[i].type == Lexer::TEXT) { open_node = open_node->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = open_node->add_image(lexer[i-2].lexeme, ""); } else { // TITLE, LINK, INLINE if (lexer[i].type == Lexer::TEXT) { open_node = open_node->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = open_node->add_image(lexer[i-2].lexeme, ""); } break; } case Lexer::CITE: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::SECTION) open_node = open_node->add_cite(atoi(lexer[i].lexeme.c_str())); else if (type == Node::PARAGRAPH || type == Node::QUOTE || type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::TITLE) throw string("title cant't contain a cite!"); else if (type == Node::LINK) throw string("link can't contain a cite!"); else // INLINE throw string("inline span can't contain a cite!"); break; } case Lexer::QUOTE_START: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_quote(); } else if (type == Node::SECTION) open_node = open_node->open_quote(); else { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_quote(); } break; } case Lexer::NOTIFICATION: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->add_notification(lexer[i].lexeme); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->add_notification(lexer[i].lexeme); } else { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->add_notification(lexer[i].lexeme); } break; } case Lexer::TEXT: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = open_node->open_paragraph(); open_node = open_node->add_text(lexer[i].lexeme); } else if (type == Node::SECTION) { open_node = open_node->open_paragraph(); open_node = open_node->add_text(lexer[i].lexeme); } else if (type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->open_paragraph(); open_node = open_node->add_text(lexer[i].lexeme); } else // PARAGRAPH, TITLE, QUOTE, LINK, INLINE open_node = open_node->add_text(lexer[i].lexeme); break; } case Lexer::UNORDERED_LIST_ITEM_MARKER: { break; } case Lexer::ORDERED_LIST_ITEM_MARKER: { break; } case Lexer::END: { if (type == Node::ROOT) open_node = tree->close(); else if (type == Node::SECTION) { open_node = open_node->close(); open_node = tree->close(); } else if (type == Node::PARAGRAPH || type == Node::QUOTE || type == Node::UNORDERED_LIST || type == Node::ORDERED_LIST) { open_node = open_node->close(); while (open_node->get_type() != Node::SECTION) open_node = open_node->close(); open_node = open_node->close(); open_node = tree->close(); } else // LINK || INLINE throw string("unexpected ending!"); break; } } } concatenate(); return tree; } 

从1357行开始,代码减少到487,几乎是三倍,这还不包括行的长度!

还有一个问题:交货时间如何?为了确定开放节点的类型,我们必须为计算机本身支付多少毫秒?我进行了一个实验-在家用计算机上,同一文档的第一种和第二种情况下,解析器的工作时间以毫秒为单位固定。结果是:

投放-538毫秒。
虚拟功能-1174毫秒。

总计636毫秒-代码紧凑和没有错误的费用。这很多吗?可能吧 但是,如果我们需要一个尽可能快地运行并且需要尽可能少的内存的程序,我们就不会去OOP并用汇编语言来编写它,这要花一个星期的时间,并且冒犯大量错误的风险。所以我的选择是在程序中static_castdynamic_cast相遇的地方,用虚拟函数替换它们。您对此有何看法?

Source: https://habr.com/ru/post/zh-CN458228/


All Articles