Fixed #469 (Preprocessor should read open configurations that are defined within the file)

This commit is contained in:
Daniel Marjamäki 2009-07-22 18:47:50 +02:00
parent 1d514e1afe
commit 6fecd858e3
2 changed files with 92 additions and 3 deletions

View File

@ -31,6 +31,7 @@
#include <cctype>
#include <cstring>
#include <vector>
#include <set>
Preprocessor::Preprocessor(bool debug) : _debug(debug)
{
@ -566,6 +567,9 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata)
std::list<std::string> deflist;
// constants defined through "#define" in the code..
std::set<std::string> 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<std::string> 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<std::string> 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<std::string>::iterator it = ret.begin(); it != ret.end(); ++it)
{
std::string s(*it);
for (std::set<std::string>::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<std::string>::iterator it1 = ret.begin(); it1 != ret.end(); ++it1)
{
std::list<std::string>::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<std::string>::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())
{

View File

@ -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<unsigned int>(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<std::string, std::string> 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)