📜 ⬆️ ⬇️

Why do we need virtual functions

Hi, Habr. If you know the answer to the question in the title, congratulations, you do not need this article. It is addressed to newcomers to programming, like me, who cannot always independently deal with all the subtleties of C ++ and other typed languages, and if they can, it’s better to still learn from the mistakes of others.

In this article, I will not just answer the question " Why do we need virtual functions in C ++ ", but I will give an example from my practice. For a short answer, you can turn to search engines that give something like the following: " Virtual functions are needed to provide polymorphism — one of the three whales of the OOP. Thanks to them, the machine can determine the type of object itself using a pointer without loading the programmer with this task. " Okay, but the question “why” remains, although now it means a bit more: “ Why rely on a car, waste extra time and memory, if you can podcast the pointer yourself, because the type of object to which it refers is almost always known? ” Indeed, casting at first glance leaves virtual functions out of work, and it is precisely this that causes misconceptions and bad code. In small projects, the loss is not noticeable, but, as you will soon see, with the growth of the caste program, the listing increases in an almost geometric progression.

To begin with, we will recall where in general may be needed castes and virtual functions. A type is lost when an object declared with type A is allocated with a new operation to allocate memory for an object of type B compatible with type A, usually inherited from A. Most often, the object is not one, but the whole array. An array of pointers of the same type, each of which is waiting for the assignment of a memory area with objects of completely different types. Here is an example we consider.

I won’t be too long, the task was as follows: based on the document marked up with Markedit hypertext markup language (you can read about it here ), build a parse tree and create a file containing the same document in HTML markup. My solution consists of three consecutive subroutines: parsing the source text into tokens, building a syntax tree from tokens and building an HTML document based on it. We are interested in the second part.
The point is that the nodes of the target tree have different types (section, paragraph, text node, link, footnote, etc.), but for parent nodes, pointers to child nodes are stored in an array, and therefore have one type - Node.
')
The parser itself in a simplified form works like this: it creates a root of the syntactic tree of the Root type, declares an open_node pointer of the general type Node , which is immediately assigned the address of the tree , and the variable type of the enumerated type of Node_type , and then begins the cycle that searches the tokens from the very first until the last. At each iteration, the open_node type of the open node is first entered into the type variable (types are stored in the node structure as an enumeration), followed by a switch statement that checks the type of the next token (the types of tokens are already carefully provided by the lexer). In each branch of the switch, one more branch is presented that checks the type variable, where, as we remember, there is an open node type. Depending on its value, different actions are performed, for example: add a certain type of node-list to an open node, open another node of a certain type in an open node and send its address to open_node , close an open node, throw an exception. Applies to the topic of the article, we are interested in the second example. Every open node (and generally every node that can be opened) already contains an array of pointers to Node type nodes. Therefore, when we open a new node in an open node (assign the next array pointer to a memory for an object of another type), for the C ++ semantic analyzer it remains an instance of Node type, without acquiring new fields and methods. A pointer to it is now assigned to the variable open_node , without losing the Node type. But how to work with the pointer of the general Node type when you need to call a method, for example, a paragraph? For example, open_bold () , which opens a bold font node in it? After all, open_bold () is declared and defined as a method of the Paragraph class, and Node knows absolutely nothing about it. In addition, open_node is also declared as a pointer to a Node , and methods must accept from all types of opening nodes.

There are two solutions: the obvious and the correct. Obvious for a newbie is static_cast , and the right is virtual functions. Let's first look at one branch of the parser switch, written using the first method:

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

Not bad. And now, I will not drag you for a long time, I will show the same piece of code written using virtual functions:

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

The win is obvious, but do we really need it? After all, then you have to declare all the methods of all derived classes as virtual in the Node class and somehow implement them in each derived class. The answer is yes, indeed. There are not so many methods in this program (29), and their implementation in derived classes that are not related to them, consists of only one line: throw string (“error!”); . You can turn on creative mode and come up with a unique line for each release of the exception. But the most important thing is that due to the reduction of the code, the number of errors in it has decreased. Casting is one of the most important causes of code errors. Because after applying static_cast, the compiler stops swearing if the above class contains the method being called. Meanwhile, different classes may contain different methods with the same name. In my case, the code hid 6 !!! errors, while one of them was duplicated in several branches of the switch. Here she is:

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

Further, under the spoilers, I cite the full listings of the first and second versions of the parser.

Parser with casting
 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; } 

Parser with access to virtual methods
 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; } 

From 1357 lines the code was reduced to 487 - almost three times, not counting the length of the lines!

One question remains: what about the execution time? How many milliseconds should we pay to ensure that the computer itself determines the type of open node? I conducted an experiment - fixed the time of the parser in milliseconds in the first and second cases for the same document on my home computer. Here is the result:

Casting - 538 ms.
Virtual functions - 1174 ms.

Total, 636 ms - a fee for compact code and no errors. A lot of it? Maybe.But if we need a program that works as fast as possible and requires the smallest possible amount of memory, we would not turn to the PLO and generally write it in assembly language, spending a week of time and risking a huge number of errors. So my choice - wherever static_cast and dynamic_cast meet in the program , replace them with virtual functions. What is your opinion?

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


All Articles