Por que precisamos de funções virtuais

Oi Habr. Se você souber a resposta para a pergunta no título, parabéns, não precisa deste artigo. É dirigido a iniciantes em programação, como eu, que nem sempre conseguem entender de maneira independente todos os meandros do C ++ e de outras linguagens digitadas; se puderem, é melhor aprender com os erros de outras pessoas.

Neste artigo, não responderei apenas à pergunta " Por que precisamos de funções virtuais em C ++ ", mas darei um exemplo da minha prática. Para uma breve resposta, você pode recorrer aos mecanismos de pesquisa que produzem algo como o seguinte: " As funções virtuais são necessárias para fornecer polimorfismo - uma das três baleias OOP. Graças a elas, a própria máquina pode determinar o tipo de objeto por ponteiro, sem carregar o programador com esta tarefa " . Ok, mas a pergunta "por que" permanece, embora agora signifique um pouco diferente: " Por que confiar na máquina, gaste tempo e memória extras, se você pode fazer o podcast do ponteiro, porque o tipo de objeto ao qual se refere é quase sempre conhecido? " De fato, a transmissão à primeira vista deixa as funções virtuais sem trabalho, e é isso que causa conceitos errados e código incorreto. Em pequenos projetos, a perda é invisível, mas, como você verá em breve, com o crescimento do programa, as castas aumentam a listagem em uma progressão quase geométrica.

Primeiro, vamos lembrar onde castas e funções virtuais podem ser necessárias. Um tipo é perdido quando um objeto declarado com o tipo A recebe uma nova operação para alocar memória para um objeto do tipo B compatível com o tipo A, geralmente herdado de A. Na maioria das vezes, o objeto não é um, mas uma matriz inteira. Uma matriz de ponteiros do mesmo tipo, cada um deles aguardando a atribuição de uma área de memória com objetos de tipos completamente diferentes. Aqui está um exemplo que consideraremos.

Não vou arrastar por muito tempo, a tarefa era a seguinte: com base em um documento marcado com a linguagem de marcação de hipertexto Markedit (você pode ler sobre isso aqui ), construa uma árvore de análise e crie um arquivo contendo o mesmo documento na marcação HTML. Minha solução consiste em três rotinas seqüenciais: analisar o texto de origem em tokens, criar uma árvore de sintaxe a partir de tokens e criar um documento HTML em sua base. Estamos interessados ​​na segunda parte.
O fato é que os nós da árvore de destino têm tipos diferentes (seção, parágrafo, nó de texto, link, nota de rodapé etc.), mas para nós pai, ponteiros para nós filhos são armazenados na matriz e, portanto, têm um tipo - Nó.

O analisador em si, de forma simplificada, funciona assim: cria a “raiz” da árvore de sintaxe da árvore com o tipo Raiz , declara um ponteiro open_node do tipo geral Node , que é imediatamente atribuído ao endereço da árvore e a variável de tipo do tipo enumerado Node_type e, em seguida, o loop inicia, repetindo os tokens desde o primeiro até o último. A cada iteração, o tipo do nó aberto open_node é inserido primeiro na variável de tipo (os tipos na forma de uma enumeração são armazenados na estrutura do nó), seguidos pela instrução switch , que verifica o tipo do próximo token (os tipos de tokens já são fornecidos com cuidado pelo lexer). Em cada ramificação do comutador, é apresentada outra ramificação que verifica a variável de tipo , onde, como lembramos, o tipo de nó aberto está contido. Dependendo do seu valor, diferentes ações são executadas, por exemplo: adicione uma lista de nós de um determinado tipo a um nó aberto, abra outro nó de um determinado tipo em um nó aberto e passe seu endereço para open_node , feche o nó aberto e gere uma exceção. Aplicável ao tópico do artigo, estamos interessados ​​no segundo exemplo. Cada nó aberto (e geralmente todos os nós que podem ser abertos) já contém uma matriz de ponteiros para nós do tipo Node . Portanto, quando abrimos um novo nó em um nó aberto (atribuímos a área de memória para um objeto de outro tipo ao próximo ponteiro da matriz), para um analisador semântico C ++, ele permanece uma instância do tipo Node sem adquirir novos campos e métodos. Um ponteiro para ele agora é atribuído à variável open_node , sem perder o tipo de Node . Mas como trabalhar com um ponteiro de um tipo de geral quando você precisa chamar um método, por exemplo, um parágrafo? Por exemplo, open_bold () , que abre um nó de fonte em negrito? Afinal, open_bold () é declarado e definido como um método da classe Paragraph , e Node não o conhece completamente. Além disso, open_node também é declarado como um ponteiro para e deve aceitar métodos de todos os tipos de nós de abertura.

Existem duas soluções aqui: a óbvia e a correta. O óbvio para um iniciante é o static_cast , e as funções virtuais estão corretas. Vamos primeiro examinar uma ramificação do analisador de comutador escrita usando o primeiro método:

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

Nada mal. E agora, não vou arrastá-lo por muito tempo, mostrarei a mesma seção de código escrita usando funções virtuais:

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

O ganho é óbvio, mas realmente precisamos dele? Afinal, você deve declarar na classe Node todos os métodos de todas as classes derivadas como virtuais e, de alguma forma, implementá-los em cada classe derivada. A resposta é sim, de fato. Não existem muitos métodos especificamente neste programa (29), e sua implementação em classes derivadas que não estão relacionadas a elas consiste em apenas uma linha: throw string ("error!"); . Você pode ativar o modo criativo e criar uma linha exclusiva para cada lançamento de exceção. Mas o mais importante - devido à redução de código, o número de erros diminuiu. A transmissão é uma das causas mais importantes de erros no código. Porque, após aplicar static_cast, o compilador para de xingar se a classe chamada estiver contida na classe especificada. Enquanto isso, classes diferentes podem conter métodos diferentes com o mesmo nome. No meu caso, 6 estava oculto no código !!! erros, enquanto um deles foi duplicado em várias ramificações do comutador. Aqui está:

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

Em seguida, nos spoilers, trago listagens completas da primeira e da segunda versões do analisador.

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

Analisador com acesso a métodos virtuais
 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; } 

De 1357 linhas, o código foi reduzido para 487 - quase três vezes, sem contar o comprimento das linhas!

Uma pergunta permanece: e quanto ao prazo de entrega? Quantos milissegundos temos que pagar pelo próprio computador para determinar o tipo de nó aberto? Realizei um experimento - corrigi o tempo de trabalho do analisador em milissegundos no primeiro e no segundo casos para o mesmo documento no meu computador doméstico. Aqui está o resultado:

Fundição - 538 ms.
Funções virtuais - 1174 ms.

Total, 636 ms - uma taxa pela compactação do código e pela ausência de erros. Isso é muito? Possivelmente. Mas se precisarmos de um programa que funcione o mais rápido possível e exija a menor quantidade possível de memória, não iremos ao OOP e o escreveremos na linguagem assembly, gastando uma semana e arriscando-se a cometer um grande número de erros. Portanto, minha escolha é onde quer que static_cast e dynamic_cast se encontrem no programa , substitua-os por funções virtuais. Qual a sua opinião?

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


All Articles