Mengapa kita membutuhkan fungsi virtual

Hai, Habr. Jika Anda tahu jawaban pertanyaan dalam judul, selamat, Anda tidak perlu artikel ini. Ini ditujukan kepada pemula dalam pemrograman, seperti saya, yang tidak selalu dapat memahami semua seluk beluk C ++ dan bahasa lainnya yang diketik secara mandiri, dan jika mereka bisa, lebih baik untuk belajar dari kesalahan orang lain.

Pada artikel ini, saya tidak hanya akan menjawab pertanyaan " Mengapa kita membutuhkan fungsi virtual di C ++ ", tetapi saya akan memberikan contoh dari praktik saya. Untuk jawaban singkat, Anda dapat beralih ke mesin pencari yang menghasilkan sesuatu seperti berikut: " Fungsi virtual diperlukan untuk memberikan polimorfisme - salah satu dari tiga paus OOP. Berkat mereka, mesin itu sendiri dapat menentukan jenis objek dengan pointer tanpa memuat tugas kepada programmer. " Oke, tetapi pertanyaan "mengapa" tetap ada, meskipun sekarang artinya sedikit berbeda: " Mengapa mengandalkan mesin, menghabiskan waktu dan memori ekstra, jika Anda dapat podcast pointer sendiri, karena jenis objek yang dirujuk hampir selalu dikenal? " Memang, casting sekilas meninggalkan fungsi virtual tanpa kerja, dan inilah yang menyebabkan kesalahpahaman dan kode buruk. Dalam proyek-proyek kecil, kerugiannya tidak terlihat, tetapi, seperti yang akan segera Anda lihat, dengan pertumbuhan program, kasta meningkatkan daftar dalam perkembangan yang hampir geometris.

Pertama, mari kita ingat di mana kasta dan fungsi virtual mungkin diperlukan sama sekali. Tipe hilang ketika suatu objek yang dideklarasikan dengan tipe A dialokasikan operasi baru untuk mengalokasikan memori untuk objek tipe B yang kompatibel dengan tipe A, biasanya diwarisi dari A. Paling sering objek bukan satu, tetapi seluruh array. Array pointer dari tipe yang sama, masing-masing menunggu penugasan area memori dengan objek dari tipe yang sama sekali berbeda. Berikut adalah contoh yang akan kami pertimbangkan.

Saya tidak akan berlama-lama, tugasnya adalah ini: berdasarkan pada dokumen yang ditandai dengan bahasa markup Markedit hypertext (Anda dapat membacanya di sini ), membangun parsing tree dan membuat file yang berisi dokumen yang sama dalam markup HTML. Solusi saya terdiri dari tiga rutinitas berurutan: mem-parsing teks sumber menjadi token, membangun pohon sintaks dari token dan membangun dokumen HTML berdasarkan itu. Kami tertarik pada bagian kedua.
Faktanya adalah bahwa node dari pohon tujuan memiliki jenis yang berbeda (bagian, paragraf, simpul teks, tautan, catatan kaki, dll.), Tetapi untuk simpul induk, pointer ke simpul anak disimpan dalam larik, dan karenanya memiliki satu jenis - Node.

Parser itu sendiri, dalam bentuk yang disederhanakan, berfungsi seperti ini: ia menciptakan "root" dari pohon sintaksis pohon dengan tipe Root , menyatakan pointer open_node dari tipe umum Node , yang segera menetapkan alamat tree , dan variabel tipe dari tipe yang disebutkan , Node_type , dan kemudian loop dimulai, mengulangi token dari awal. sampai yang terakhir. Pada setiap iterasi, jenis open_node open node dimasukkan ke dalam variabel tipe pertama (tipe dalam bentuk enumerasi disimpan dalam struktur node), diikuti oleh pernyataan switch , yang memeriksa jenis token berikutnya (jenis token sudah dengan hati-hati disediakan oleh lexer). Di setiap cabang switch, cabang lain disajikan yang memeriksa variabel tipe , di mana, seperti yang kita ingat, jenis node terbuka terkandung. Bergantung pada nilainya, tindakan yang berbeda dilakukan, misalnya: menambahkan simpul-daftar dari jenis tertentu ke simpul terbuka, membuka simpul lain dari jenis tertentu dalam simpul terbuka dan meneruskan alamatnya ke open_node , menutup simpul terbuka, melempar pengecualian. Berlaku untuk topik artikel, kami tertarik pada contoh kedua. Setiap node terbuka (dan umumnya setiap node yang dapat dibuka) sudah berisi array pointer ke node tipe Node . Oleh karena itu, ketika kita membuka simpul baru di simpul terbuka (kita menetapkan area memori untuk objek tipe lain ke pointer array berikutnya), untuk penganalisis semantik C ++, ia tetap merupakan instance dari tipe Node tanpa memperoleh bidang dan metode baru. Pointer ke sana sekarang ditugaskan ke variabel open_node , tanpa kehilangan jenis Node . Tetapi bagaimana cara bekerja dengan pointer dari tipe Node umum ketika Anda perlu memanggil metode, misalnya, paragraf? Misalnya, open_bold () , yang membuka simpul font tebal di dalamnya? Bagaimanapun, open_bold () dideklarasikan dan didefinisikan sebagai metode kelas Paragraph , dan Node sama sekali tidak menyadarinya. Selain itu, open_node juga dideklarasikan sebagai pointer ke Node , dan harus menerima metode dari semua jenis node pembuka.

Ada dua solusi di sini: yang jelas dan yang tepat. Jelas untuk pemula adalah static_cast , dan fungsi virtual benar. Pertama mari kita lihat satu cabang parser switch yang ditulis menggunakan metode pertama:

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

Tidak buruk. Dan sekarang, saya tidak akan menyeretnya untuk waktu yang lama, saya akan menunjukkan bagian kode yang sama yang ditulis menggunakan fungsi virtual:

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

Keuntungannya jelas, tetapi apakah kita benar-benar membutuhkannya? Setelah semua, maka Anda harus mendeklarasikan dalam kelas Node semua metode dari semua kelas turunan sebagai virtual dan entah bagaimana mengimplementasikannya di setiap kelas turunan. Jawabannya adalah ya. Tidak ada banyak metode khusus dalam program ini (29), dan implementasinya dalam kelas turunan yang tidak terkait dengannya hanya terdiri dari satu baris: throw string ("error!"); . Anda dapat mengaktifkan mode kreatif dan menghasilkan garis unik untuk setiap lemparan pengecualian. Tetapi yang paling penting - karena pengurangan kode, jumlah kesalahan di dalamnya telah menurun. Casting adalah salah satu penyebab kesalahan kode yang paling penting. Karena setelah menerapkan static_cast, kompiler berhenti bersumpah jika kelas yang dipanggil terkandung dalam kelas yang diberikan. Sementara itu, kelas yang berbeda mungkin berisi metode yang berbeda dengan nama yang sama. Dalam kasus saya, 6 disembunyikan dalam kode !!! kesalahan, sementara salah satu dari mereka diduplikasi di beberapa cabang switch. Ini dia:

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

Selanjutnya, di bawah spoiler, saya membawa daftar lengkap parser versi pertama dan kedua.

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

Parser dengan akses ke metode virtual
 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; } 

Dari 1357 baris, kode dikurangi menjadi 487 - hampir tiga kali, tidak termasuk panjang garis!

Masih ada satu pertanyaan: bagaimana dengan lead time? Berapa milidetik yang harus kita bayarkan untuk komputer itu sendiri untuk menentukan jenis simpul terbuka? Saya melakukan percobaan - saya memperbaiki waktu kerja parser dalam milidetik dalam kasus pertama dan kedua untuk dokumen yang sama di komputer rumah saya. Inilah hasilnya:

Casting - 538 ms.
Fungsi virtual - 1174 ms.

Total, 636 ms - biaya untuk kekompakan kode dan tidak adanya kesalahan. Apakah ini banyak? Mungkin Tetapi jika kita membutuhkan program yang bekerja secepat mungkin dan membutuhkan memori sesedikit mungkin, kita tidak akan pergi ke OOP dan menulisnya dalam bahasa assembly bersama, menghabiskan waktu seminggu dan mengambil risiko membuat sejumlah besar kesalahan. Jadi pilihan saya adalah di mana static_cast dan dynamic_cast bertemu di program , ganti dengan fungsi virtual. Apa pendapat anda

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


All Articles