From 6fecd858e3fa6e89c8d1b4f15e67867380863c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 22 Jul 2009 18:47:50 +0200 Subject: [PATCH] Fixed #469 (Preprocessor should read open configurations that are defined within the file) --- src/preprocessor.cpp | 72 +++++++++++++++++++++++++++++++++++++-- test/testpreprocessor.cpp | 23 +++++++++++++ 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/src/preprocessor.cpp b/src/preprocessor.cpp index 28ef9c675..9f25627ca 100644 --- a/src/preprocessor.cpp +++ b/src/preprocessor.cpp @@ -31,6 +31,7 @@ #include #include #include +#include Preprocessor::Preprocessor(bool debug) : _debug(debug) { @@ -566,6 +567,9 @@ std::list Preprocessor::getcfgs(const std::string &filedata) std::list deflist; + // constants defined through "#define" in the code.. + std::set defines; + // How deep into included files are we currently parsing? // 0=>Source file, 1=>Included by source file, 2=>included by header that was included by source file, etc int filelevel = 0; @@ -587,6 +591,11 @@ std::list Preprocessor::getcfgs(const std::string &filedata) continue; } + else if (line.substr(0, 8) == "#define " && line.find_first_of("( ", 8) == std::string::npos) + { + defines.insert(line.substr(8)); + } + if (filelevel > 0) continue; @@ -612,17 +621,67 @@ std::list Preprocessor::getcfgs(const std::string &filedata) ret.push_back(def); } - if (line.find("#else") == 0 && ! deflist.empty()) + else if (line.find("#else") == 0 && ! deflist.empty()) { std::string def((deflist.back() == "1") ? "0" : "1"); deflist.pop_back(); deflist.push_back(def); } - if (line.find("#endif") == 0 && ! deflist.empty()) + else if (line.find("#endif") == 0 && ! deflist.empty()) deflist.pop_back(); } + // Remove defined constants from ifdef configurations.. + for (std::list::iterator it = ret.begin(); it != ret.end(); ++it) + { + std::string s(*it); + for (std::set::const_iterator it2 = defines.begin(); it2 != defines.end(); ++it2) + { + std::string::size_type pos = 0; + while ((pos = s.find(*it2, pos)) != std::string::npos) + { + std::string::size_type pos1 = pos; + ++pos; + if (pos1 > 0 && s[pos1-1] != ';') + continue; + std::string::size_type pos2 = pos1 + it2->length(); + if (pos2 < s.length() && s[pos2] != ';') + continue; + --pos; + s.erase(pos, it2->length()); + } + } + if (s.length() != it->length()) + { + while (s.length() > 0 && s[0] == ';') + s.erase(0, 1); + + while (s.length() > 0 && s[s.length()-1] == ';') + s.erase(s.length() - 1); + + std::string::size_type pos = 0; + while ((pos = s.find(";;", pos)) != std::string::npos) + s.erase(pos, 1); + + *it = s; + } + } + + // Remove duplicates from the ret list.. + for (std::list::iterator it1 = ret.begin(); it1 != ret.end(); ++it1) + { + std::list::iterator it2 = it1; + ++it2; + while (it2 != ret.end()) + { + if (*it1 == *it2) + ret.erase(it2++); + else + ++it2; + } + } + // convert configurations: "defined(A) && defined(B)" => "A;B" for (std::list::iterator it = ret.begin(); it != ret.end(); ++it) { @@ -757,7 +816,14 @@ std::string Preprocessor::getcode(const std::string &filedata, std::string cfg, std::string def = getdef(line, true); std::string ndef = getdef(line, false); - if (line.find("#elif ") == 0) + if (line.substr(0, 8) == "#define " && line.find_first_of(" (", 8) == std::string::npos) + { + if (!cfg.empty()) + cfg += ";"; + cfg += line.substr(8); + } + + else if (line.find("#elif ") == 0) { if (matched_ifdef.back()) { diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 2fae104c6..f528e4a09 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -141,6 +141,9 @@ private: TEST_CASE(newline_in_macro); TEST_CASE(includes); TEST_CASE(ifdef_ifdefined); + + // define and then ifdef + TEST_CASE(define_ifdef); } @@ -1228,6 +1231,26 @@ private: ASSERT_EQUALS("\nA\n\n\nA\n\n", actual["ABC"]); ASSERT_EQUALS(2, static_cast(actual.size())); } + + void define_ifdef() + { + const char filedata[] = "#define ABC\n" + "#ifndef ABC\n" + "A\n" + "#else\n" + "B\n" + "#endif\n"; + + // Preprocess => actual result.. + std::istringstream istr(filedata); + std::map actual; + Preprocessor preprocessor; + preprocessor.preprocess(istr, actual, "file.c"); + + // Compare results.. + ASSERT_EQUALS("\n\n\n\nB\n\n", actual[""]); + ASSERT_EQUALS(1, actual.size()); + } }; REGISTER_TEST(TestPreprocessor)