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 beginners in programming, like me, who can’t always independently understand all the intricacies of C ++ and other typed languages, and if they can, it is better to learn from other people's mistakes anyway.

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 brief answer, you can turn to search engines that display something like the following: " Virtual functions are needed to provide polymorphism - one of the three OOP whales. Thanks to them, the machine itself can determine the type of object by pointer, without loading the programmer with this task"Okay, but the question" why "remains, although now it means a little different:" Why rely on the machine, spend 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 without work, and it is it that causes errors and bad code. In small projects, the loss is invisible, but, as you will soon see, with the growth of the program, castes increase the listing in almost geometric progression.

First, let's recall where castes and virtual functions may be needed at all. A type is lost when an object declared with type A is allocated 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 an entire 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 will consider.

I won’t drag out for a long time, the task was this: based on a document marked up with Markedit hypertext markup language (you can read about it here), build a parsing tree and create a file containing the same document in the HTML markup. My solution consists of three sequential routines: parsing the source text into tokens, building a syntax tree from tokens and building an HTML document on its basis. We are interested in the second part.
The fact is that the nodes of the destination tree have different types (section, paragraph, text node, link, footnote, etc.), but for parent nodes, pointers to child nodes are stored in the array, and therefore have one type - Node.

In a simplified form itself parser works: creating a "root" trie tree with type Root , declared pointer open_node general type of the Node , which is then assigned an addresstree , and the type variable of the enumerated type Node_type , and then a cycle begins, iterating through the tokens from the very first to the last. At each iteration, the type of the open_node open node is entered into the type variable first (types in the form of an enumeration are stored in the node structure), followed by the switch statement , which checks the type of the next token (the types of tokens are already carefully provided by the lexer). In each branch of the switch, another branch is presented that checks the type variable, where, as we recall, contains the type of open node. Depending on its value, different actions are performed, for example: add a node-list of a certain type to an open node, open another node of a certain type in an open node and pass its address to open_node , close the open node, throw an exception. Applicable to the topic of the article, we are interested in the second example. Each open node (and generally every node that can be opened) already contains an array of pointers to nodes of type Node . Therefore, when we open a new node in an open node (we assign a memory region for an object of another type to the next array pointer), for a C ++ semantic analyzer it remains an instance of Node typewithout acquiring new fields and methods. A pointer to it is now assigned to the variable open_node , without losing the type of Node . But how to work with a pointer of a 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 is completely unaware of it. In addition, open_node is also declared as a pointer to Node , and it must accept methods from all types of opening nodes.

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

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

Not bad. And now, I won’t drag it on for a long time, I will show the same section 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 gain is obvious, but do we really need it? After all, then you have to declare in the Node class all methods of all derived classes as virtual and somehow implement them in each derived class. The answer is yes, indeed. There are not so many methods specifically 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 enable creative mode and come up with a unique line for each exception throw. But most importantly - due to code reduction, the number of errors in it has decreased. Casting is one of the most important causes of errors in code. Because after applying static_castthe compiler stops swearing if the class contains the called method. Meanwhile, different classes may contain different methods with the same name. In my case, 6 was hidden in the code !!! errors, while one of them was duplicated in several switch branches. Here she is:

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

Next, under the spoilers, I bring complete 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(open_node)->add_text("\n");
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->add_text("\n");
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->add_text("\n");
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
            } else if (type == Node::LINK) {
                open_node = static_cast(open_node)->add_text(lexer[i].lexeme);
            } else // INLINE
                open_node = static_cast(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(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
            } else if (type == Node::QUOTE) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
            } else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(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(open_node)->close();
                open_node = tree->add_line();
            } else if (type == Node::PARAGRAPH) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(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(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->close();
                open_node = tree->add_line();
            } else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->close();
                open_node = tree->add_line();
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(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(open_node)->open_title(lexer[i].lexeme.size()-1);
            } else if (type == Node::SECTION)
                open_node = static_cast(open_node)->open_title(lexer[i].lexeme.size()-1);
            else if (type == Node::PARAGRAPH) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(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(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_title(lexer[i].lexeme.size()-1);
            } else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_title(lexer[i].lexeme.size()-1);
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(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(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_bold();
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_bold();
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->open_bold();
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->open_bold();
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->open_bold();
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_bold();
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_bold();
            } else if (type == Node::LINK)
                open_node = static_cast(open_node)->open_bold();
            else // INLINE
                open_node = static_cast(open_node)->open_bold();
        break; }
        case Lexer::ITALIC_START: {
            if (type == Node::ROOT) {
                open_node = tree->open_section();
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_italic();
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_italic();
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->open_italic();
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->open_italic();
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->open_italic();
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_italic();
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_italic();
            } else if (type == Node::LINK)
                open_node = static_cast(open_node)->open_italic();
            else // INLINE
                open_node = static_cast(open_node)->open_italic();
        break; }
        case Lexer::UNDERLINED_START: {
            if (type == Node::ROOT) {
                open_node = tree->open_section();
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_underlined();
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_underlined();
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->open_underlined();
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->open_underlined();
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->open_underlined();
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_underlined();
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_underlined();
            } else if (type == Node::LINK)
                open_node = static_cast(open_node)->open_underlined();
            else // INLINE
                open_node = static_cast(open_node)->open_underlined();
        break; }
        case Lexer::OVERLINED_START: {
            if (type == Node::ROOT) {
                open_node = tree->open_section();
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_overlined();
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_overlined();
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->open_overlined();
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->open_overlined();
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->open_overlined();
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_overlined();
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_overlined();
            } else if (type == Node::LINK)
                open_node = static_cast(open_node)->open_overlined();
            else // INLINE
                open_node = static_cast(open_node)->open_overlined();
        break; }
        case Lexer::THROWLINED_START: {
            if (type == Node::ROOT) {
                open_node = tree->open_section();
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_throwlined();
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_throwlined();
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->open_throwlined();
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->open_throwlined();
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->open_throwlined();
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_throwlined();
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_throwlined();
            } else if (type == Node::LINK)
                open_node = static_cast(open_node)->open_throwlined();
            else // INLINE
                open_node = static_cast(open_node)->open_throwlined();
        break; }
        case Lexer::SUBSCRIPT_START: {
            if (type == Node::ROOT) {
                open_node = tree->open_section();
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_subscript();
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_subscript();
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->open_subscript();
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->open_subscript();
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->open_subscript();
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_subscript();
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_subscript();
            } else if (type == Node::LINK)
                open_node = static_cast(open_node)->open_subscript();
            else // INLINE
                open_node = static_cast(open_node)->open_subscript();
        break; }
        case Lexer::SUPERSCRIPT_START: {
            if (type == Node::ROOT) {
                open_node = tree->open_section();
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_superscript();
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_superscript();
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->open_superscript();
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->open_superscript();
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->open_superscript();
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_superscript();
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_superscript();
            } else if (type == Node::LINK)
                open_node = static_cast(open_node)->open_superscript();
            else // INLINE
                open_node = static_cast(open_node)->open_superscript();
        break; }
        case Lexer::MARKED_START: {
            if (type == Node::ROOT) {
                open_node = tree->open_section();
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_marked();
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_marked();
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->open_marked();
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->open_marked();
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->open_marked();
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_marked();
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_marked();
            } else if (type == Node::LINK)
                open_node = static_cast(open_node)->open_marked();
            else // INLINE
                open_node = static_cast(open_node)->open_marked();
        break; }
        case Lexer::MONOSPACE_START: {
            if (type == Node::ROOT) {
                open_node = tree->open_section();
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_monospace();
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_monospace();
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->open_monospace();
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->open_monospace();
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->open_monospace();
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_monospace();
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_monospace();
            } else if (type == Node::LINK)
                open_node = static_cast(open_node)->open_monospace();
            else // INLINE
                open_node = static_cast(open_node)->open_monospace();
        break; }
        case Lexer::SPAN_OR_IMAGE_FINISH: {
            if (type == Node::TITLE)
                open_node = static_cast(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(open_node)->close();
            else if (type == Node::ROOT) {
                open_node = tree->open_section();
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->add_text("]");
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->add_text("]");
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->add_text("]");
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->add_text("]");
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->add_text("]");
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->add_text("]");
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->add_text("]");
            } else // INLINE
                open_node = static_cast(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(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_link(lexer[i-1].lexeme);
            } else if (type == Node::SECTION) {
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_link(lexer[i-1].lexeme);
            } else if (type == Node::PARAGRAPH)
                open_node = static_cast(open_node)->open_link(lexer[i-1].lexeme);
            else if (type == Node::TITLE)
                open_node = static_cast(open_node)->open_link(lexer[i-1].lexeme);
            else if (type == Node::QUOTE)
                open_node = static_cast(open_node)->open_link(lexer[i-1].lexeme);
            else if (type == Node::UNORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_link(lexer[i-1].lexeme);
            } else if (type == Node::ORDERED_LIST) {
                open_node = static_cast(open_node)->close();
                while (open_node->get_type() != Node::SECTION) {
                    if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::UNORDERED_LIST)
                        open_node = static_cast(open_node)->close();
                    else if (open_node->get_type() == Node::PARAGRAPH)
                        open_node = static_cast(open_node)->close();
                }
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->open_link(lexer[i-1].lexeme);
            } else if (type == Node::LINK)
                open_node = static_cast(open_node)->open_link(lexer[i-1].lexeme);
            else // INLINE
                open_node = static_cast(open_node)->open_link(lexer[i-1].lexeme);
        break; }
        case Lexer::LINK_FINISH: {
            if (type == Node::LINK)
                open_node = static_cast(open_node)->close();
            else if (type == Node::ROOT) {
                open_node = tree->open_section();
                open_node = static_cast(open_node)->open_paragraph();
                open_node = static_cast(open_node)->add_text(">");
            } else if (type == Node::SECTION) {
                open_node = static_cast
(open_node).open_paragraph(); open_node = static_cast(open_node)->add_text(">"); } else if (type == Node::PARAGRAPH) open_node = static_cast(open_node)->add_text(">"); else if (type == Node::TITLE) open_node = static_cast(open_node)->add_text(">"); else if (type == Node::QUOTE) open_node = static_cast(open_node)->add_text(">"); else if (type == Node::UNORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_text(">"); } else if (type == Node::ORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_text(">"); } else // INLINE open_node = static_cast(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(open_node)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::SECTION) { open_node = static_cast(open_node)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::PARAGRAPH) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::TITLE) { if (lexer[i].type == Lexer::TEXT) { open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::QUOTE) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::ORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); if (lexer[i].type == Lexer::TEXT) { open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, ""); } else if (type == Node::LINK) { if (lexer[i].type == Lexer::TEXT) { open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, ""); } else { // INLINE if (lexer[i].type == Lexer::TEXT) { open_node = static_cast(open_node)->add_image(lexer[i-2].lexeme, lexer[i].lexeme); i++; } else open_node = static_cast(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(open_node)->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::SECTION) open_node = static_cast(open_node)->add_cite(atoi(lexer[i].lexeme.c_str())); else if (type == Node::PARAGRAPH) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::TITLE) open_node = static_cast(open_node)->add_image(lexer[i-3].lexeme, lexer[i-1].lexeme); else if (type == Node::QUOTE) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->add_cite(atoi(lexer[i].lexeme.c_str())); } else if (type == Node::ORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(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(open_node)->open_quote(); } else if (type == Node::SECTION) open_node = static_cast(open_node)->open_quote(); else if (type == Node::PARAGRAPH) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_quote(); } else if (type == Node::TITLE) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_quote(); } else if (type == Node::QUOTE) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_quote(); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_quote(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_quote(); } else if (type == Node::LINK) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_quote(); } else { // INLINE open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_quote(); } break; } case Lexer::NOTIFICATION: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::SECTION) { open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::PARAGRAPH) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::TITLE) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::QUOTE) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::ORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_notification(lexer[i].lexeme); } else if (type == Node::LINK) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_notification(lexer[i].lexeme); } else { // INLINE open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_notification(lexer[i].lexeme); } break; } case Lexer::TEXT: { if (type == Node::ROOT) { open_node = tree->open_section(); open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_text(lexer[i].lexeme); } else if (type == Node::SECTION) { open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_text(lexer[i].lexeme); } else if (type == Node::PARAGRAPH) open_node = static_cast(open_node)->add_text(lexer[i].lexeme); else if (type == Node::TITLE) open_node = static_cast(open_node)->add_text(lexer[i].lexeme); else if (type == Node::QUOTE) open_node = static_cast(open_node)->add_text(lexer[i].lexeme); else if (type == Node::UNORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_text(lexer[i].lexeme); } else if (type == Node::ORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->open_paragraph(); open_node = static_cast(open_node)->add_text(lexer[i].lexeme); } else if (type == Node::LINK) { open_node = static_cast(open_node)->add_text(lexer[i].lexeme); } else // INLINE open_node = static_cast(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(open_node)->close(); open_node = tree->close(); } else if (type == Node::PARAGRAPH) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->close(); open_node = tree->close(); } else if (type == Node::QUOTE) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->close(); open_node = tree->close(); } else if (type == Node::UNORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(open_node)->close(); open_node = tree->close(); } else if (type == Node::ORDERED_LIST) { open_node = static_cast(open_node)->close(); while (open_node->get_type() != Node::SECTION) { if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::UNORDERED_LIST) open_node = static_cast(open_node)->close(); else if (open_node->get_type() == Node::PARAGRAPH) open_node = static_cast(open_node)->close(); } open_node = static_cast(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 lead time? How many milliseconds do we have to pay for the computer itself to determine the type of open node? I conducted an experiment - I fixed the parser working time 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 the compactness of the code and the absence of errors. Is this a lot? Maybe. But if we need a program that works as fast as possible and requires as little memory as possible, we would not go to OOP and write it in assembly language altogether, spending a week and risking making a huge number of errors. So my choice is wherever static_cast and dynamic_cast meet in the program , replace them with virtual functions. What is your opinion?

Only registered users can participate in the survey. Please come in.

Casting or virtual functions?

  • 30% Casting 15
  • 86% Virtual Features 43

Also popular now: