Advertisement
kutuzzzov

Урок 8 свой препроцессор

May 29th, 2023
1,599
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.83 KB | None | 0 0
  1. #include <cassert>
  2. #include <filesystem>
  3. #include <fstream>
  4. #include <iostream>
  5. #include <regex>
  6. #include <sstream>
  7. #include <string>
  8. #include <string_view>
  9. #include <vector>
  10.  
  11. using namespace std;
  12. using filesystem::path;
  13.  
  14. path operator""_p(const char* data, std::size_t sz) {
  15.     return path(data, data + sz);
  16. }
  17.  
  18. void PrintError(const string& dest, const string& src, int string_number) {
  19.     cout << "unknown include file "s << dest
  20.         << " at file " << src << " at line "s << string_number << endl;
  21. }
  22.  
  23. // напишите эту функцию
  24. bool Preprocess(istream& input, ostream& output, const path& file_name, const vector<path>& include_directories) {
  25.     static regex local_reg (R"/(\s*#\s*include\s*"([^"]*)"\s*)/");
  26.    static regex remote_reg (R"/(\s*#\s*include\s*<([^>]*)>\s*)/");
  27.     smatch matched;
  28.     int string_counter = 0;
  29.     for (string str; getline(input, str); ) {
  30.         ++string_counter;
  31.         bool outside_find = false;
  32.         path next_path;
  33.         if (regex_match(str, matched, local_reg)) {
  34.             next_path = file_name.parent_path() / string(matched[1]);
  35.             if (filesystem::exists(next_path)) {
  36.                 ifstream in(next_path.string(), ios::in);
  37.                 if (in.is_open()) {
  38.                     if (!Preprocess(in, output, next_path.string(), include_directories)) {
  39.                         return false;
  40.                     }
  41.                     continue;
  42.                 }
  43.                 else {
  44.                     PrintError(next_path.filename().string(), file_name.string(), string_counter);
  45.                     return false;
  46.                 }
  47.             }
  48.             else {
  49.                 outside_find = true;
  50.             }
  51.         }
  52.         if (outside_find || regex_match(str, matched, remote_reg)) {
  53.             bool finded = false;
  54.             for (const auto& dir : include_directories) {
  55.                 next_path = dir / string(matched[1]);
  56.                 if (filesystem::exists(next_path)) {
  57.                     ifstream in(next_path.string(), ios::in);
  58.                     if (in.is_open()) {
  59.                         if (!Preprocess(in, output, next_path.string(), include_directories)) {
  60.                             return false;
  61.                         }
  62.                         finded = true;
  63.                         break;
  64.                     }
  65.                     else {
  66.                         PrintError(next_path.filename().string(), file_name.string(), string_counter);
  67.                         return false;
  68.                     }
  69.                 }
  70.             }
  71.             if (!finded) {
  72.                 PrintError(next_path.filename().string(), file_name.string(), string_counter);
  73.                 return false;
  74.             }
  75.             continue;
  76.         }
  77.         output << str << endl;
  78.     }
  79.     return true;
  80. }
  81.  
  82. bool Preprocess(const path& in_file, const path& out_file, const vector<path>& include_directories) {
  83.     if (!filesystem::exists(in_file)) {
  84.         return false;
  85.     }
  86.     ifstream in(in_file.string(), ios::in);
  87.     if (!in) {
  88.         return false;
  89.     }
  90.     ofstream out(out_file, ios::out);
  91.     return Preprocess(in, out, in_file, include_directories);
  92. }
  93.  
  94. string GetFileContents(string file) {
  95.     ifstream stream(file);
  96.  
  97.     // конструируем string по двум итераторам
  98.     return {(istreambuf_iterator<char>(stream)), istreambuf_iterator<char>()};
  99. }
  100.  
  101. void Test() {
  102.     error_code err;
  103.     filesystem::remove_all("sources"_p, err);
  104.     filesystem::create_directories("sources"_p / "include2"_p / "lib"_p, err);
  105.     filesystem::create_directories("sources"_p / "include1"_p, err);
  106.     filesystem::create_directories("sources"_p / "dir1"_p / "subdir"_p, err);
  107.  
  108.     {
  109.         ofstream file("sources/a.cpp");
  110.         file << "// this comment before include\n"
  111.                 "#include \"dir1/b.h\"\n"
  112.                 "// text between b.h and c.h\n"
  113.                 "#include \"dir1/d.h\"\n"
  114.                 "\n"
  115.                 "int SayHello() {\n"
  116.                 "    cout << \"hello, world!\" << endl;\n"
  117.                 "#   include<dummy.txt>\n"
  118.                 "}\n"sv;
  119.     }
  120.     {
  121.         ofstream file("sources/dir1/b.h");
  122.         file << "// text from b.h before include\n"
  123.                 "#include \"subdir/c.h\"\n"
  124.                 "// text from b.h after include"sv;
  125.     }
  126.     {
  127.         ofstream file("sources/dir1/subdir/c.h");
  128.         file << "// text from c.h before include\n"
  129.                 "#include <std1.h>\n"
  130.                 "// text from c.h after include\n"sv;
  131.     }
  132.     {
  133.         ofstream file("sources/dir1/d.h");
  134.         file << "// text from d.h before include\n"
  135.                 "#include \"lib/std2.h\"\n"
  136.                 "// text from d.h after include\n"sv;
  137.     }
  138.     {
  139.         ofstream file("sources/include1/std1.h");
  140.         file << "// std1\n"sv;
  141.     }
  142.     {
  143.         ofstream file("sources/include2/lib/std2.h");
  144.         file << "// std2\n"sv;
  145.     }
  146.  
  147.     assert((!Preprocess("sources"_p / "a.cpp"_p, "sources"_p / "a.in"_p,
  148.                                   {"sources"_p / "include1"_p,"sources"_p / "include2"_p})));
  149.  
  150.     ostringstream test_out;
  151.     test_out << "// this comment before include\n"
  152.                 "// text from b.h before include\n"
  153.                 "// text from c.h before include\n"
  154.                 "// std1\n"
  155.                 "// text from c.h after include\n"
  156.                 "// text from b.h after include\n"
  157.                 "// text between b.h and c.h\n"
  158.                 "// text from d.h before include\n"
  159.                 "// std2\n"
  160.                 "// text from d.h after include\n"
  161.                 "\n"
  162.                 "int SayHello() {\n"
  163.                 "    cout << \"hello, world!\" << endl;\n"sv;
  164.  
  165.     assert(GetFileContents("sources/a.in"s) == test_out.str());
  166. }
  167.  
  168. int main() {
  169.     Test();
  170. }
  171.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement