Fixed #1060 (Preprocessor: wrong define handling)

This commit is contained in:
Daniel Marjamäki 2009-12-11 19:28:37 +01:00
parent 91114c50d2
commit e52fb36c5c
3 changed files with 100 additions and 84 deletions

View File

@ -593,8 +593,16 @@ std::string Preprocessor::getdef(std::string line, bool def)
line.erase(0, line.find(" ")); line.erase(0, line.find(" "));
// Remove all spaces. // Remove all spaces.
while (line.find(" ") != std::string::npos) std::string::size_type pos = 0;
line.erase(line.find(" "), 1); while ((pos = line.find(" ", pos)) != std::string::npos)
{
const char chprev = (pos > 0) ? line[pos-1] : 0;
const char chnext = (pos + 1 < line.length()) ? line[pos+1] : 0;
if (std::isalnum(chprev) && std::isalnum(chnext))
++pos;
else
line.erase(pos, 1);
}
// The remaining string is our result. // The remaining string is our result.
return line; return line;
@ -870,12 +878,37 @@ std::list<std::string> Preprocessor::getcfgs(const std::string &filedata, const
void Preprocessor::simplifyCondition(const std::map<std::string, std::string> &variables, std::string &condition) void Preprocessor::simplifyCondition(const std::map<std::string, std::string> &variables, std::string &condition)
{ {
Tokenizer tokenizer; Tokenizer tokenizer;
std::istringstream istr(condition.c_str()); std::istringstream istr(("(" + condition + ")").c_str());
tokenizer.tokenize(istr, ""); tokenizer.tokenize(istr, "");
// replace variable names with values.. // replace variable names with values..
for (Token *tok = const_cast<Token *>(tokenizer.tokens()); tok; tok = tok->next()) for (Token *tok = const_cast<Token *>(tokenizer.tokens()); tok; tok = tok->next())
{ {
if (!tok->isName())
continue;
if (Token::Match(tok, "defined ( %var% )"))
{
if (variables.find(tok->strAt(2)) == variables.end())
tok->str("0");
else
tok->str("1");
tok->deleteNext();
tok->deleteNext();
tok->deleteNext();
continue;
}
if (Token::Match(tok, "defined %var%"))
{
if (variables.find(tok->strAt(1)) == variables.end())
tok->str("0");
else
tok->str("1");
tok->deleteNext();
continue;
}
const std::map<std::string, std::string>::const_iterator it = variables.find(tok->str()); const std::map<std::string, std::string>::const_iterator it = variables.find(tok->str());
if (it != variables.end()) if (it != variables.end())
{ {
@ -889,28 +922,13 @@ void Preprocessor::simplifyCondition(const std::map<std::string, std::string> &v
// simplify calculations.. // simplify calculations..
tokenizer.simplifyCalculations(); tokenizer.simplifyCalculations();
if (!tokenizer.tokens()->tokAt(3) && Token::Match(tokenizer.tokens(), "%num% ==|!=|<=|>=|<|> %num%")) if (Token::simpleMatch(tokenizer.tokens(), "( 1 )") ||
{ Token::simpleMatch(tokenizer.tokens(), "( 1 ||"))
const std::string &op1(tokenizer.tokens()->str()); condition = "1";
const std::string &cmp(tokenizer.tokens()->tokAt(1)->str()); else if (Token::simpleMatch(tokenizer.tokens(), "( 0 )"))
const std::string &op2(tokenizer.tokens()->tokAt(2)->str()); condition = "0";
if (cmp == "==")
condition = (op1 == op2) ? "1" : "0";
else if (cmp == "!=")
condition = (op1 != op2) ? "1" : "0";
else if (cmp == "<=")
condition = (op1 <= op2) ? "1" : "0";
else if (cmp == ">=")
condition = (op1 >= op2) ? "1" : "0";
else if (cmp == "<")
condition = (op1 < op2) ? "1" : "0";
else if (cmp == ">")
condition = (op1 > op2) ? "1" : "0";
}
} }
bool Preprocessor::match_cfg_def(const std::map<std::string, std::string> &cfg, std::string def) bool Preprocessor::match_cfg_def(const std::map<std::string, std::string> &cfg, std::string def)
{ {
//std::cout << "cfg: \"" << cfg << "\" "; //std::cout << "cfg: \"" << cfg << "\" ";
@ -921,68 +939,12 @@ bool Preprocessor::match_cfg_def(const std::map<std::string, std::string> &cfg,
if (cfg.find(def) != cfg.end()) if (cfg.find(def) != cfg.end())
return true; return true;
for (std::string::size_type pos = def.find("defined("); pos != std::string::npos; pos = def.find("defined(", pos + 1))
{
// The character before "defined" must not be '_' or alphanumeric
unsigned char chPrev = (pos > 0) ? def[pos-1] : ' ';
if (chPrev == '_' || std::isalnum(chPrev))
continue;
// Extract the parameter..
std::string::size_type pos2 = def.find(")", pos);
if (pos2 == std::string::npos)
continue;
std::string::size_type pos1 = pos + 8;
const std::string par(def.substr(pos1, pos2 - pos1));
const bool isdefined(cfg.find(par) != cfg.end());
def.erase(pos, pos2 + 1 - pos);
def.insert(pos, isdefined ? "1" : "0");
}
if (def.find("1||") != std::string::npos || def.find("||1") != std::string::npos)
return true;
while (def.find("1&&") != std::string::npos)
{
def.erase(def.find("1&&"), 3);
}
//std::cout << " => \"" << def << "\"" << std::endl;
if (def == "0") if (def == "0")
return false; return false;
if (def == "1") if (def == "1")
return true; return true;
/*
if (cfg.empty())
return false;
// remove the define values
while (cfg.find("=") != std::string::npos)
{
std::string::size_type pos1 = cfg.find("=");
std::string::size_type pos2 = cfg.find(";", pos1);
if (pos2 == std::string::npos)
cfg.erase(pos1);
else
cfg.erase(pos1, pos2 - pos1);
}
while (! cfg.empty())
{
if (cfg.find(";") == std::string::npos)
return bool(cfg == def);
std::string _cfg = cfg.substr(0, cfg.find(";"));
if (_cfg == def)
return true;
cfg.erase(0, cfg.find(";") + 1);
}
*/
return false; return false;
} }
@ -1116,15 +1078,15 @@ std::string Preprocessor::getcode(const std::string &filedata, std::string cfg,
if (match && line.compare(0, 6, "#error") == 0) if (match && line.compare(0, 6, "#error") == 0)
return ""; return "";
if (!match && line.find("#define") == 0) if (!match && line.compare(0, 8, "#define ") == 0)
{ {
// Remove define that is not part of this configuration // Remove define that is not part of this configuration
line = ""; line = "";
} }
else if (line.find("#file \"") == 0 || else if (line.compare(0, 7, "#file \"") == 0 ||
line.find("#endfile") == 0 || line.compare(0, 8, "#endfile") == 0 ||
line.find("#define") == 0 || line.compare(0, 8, "#define ") == 0 ||
line.find("#undef") == 0) line.compare(0, 6, "#undef") == 0)
{ {
// We must not remove #file tags or line numbers // We must not remove #file tags or line numbers
// are corrupted. File tags are removed by the tokenizer. // are corrupted. File tags are removed by the tokenizer.

View File

@ -3900,6 +3900,48 @@ bool Tokenizer::simplifyCalculations()
tok->deleteNext(); tok->deleteNext();
ret = true; ret = true;
} }
if (Token::simpleMatch(tok->previous(), "( 0 ||") ||
Token::simpleMatch(tok, "|| 0 )") ||
Token::simpleMatch(tok->previous(), "( 1 &&") ||
Token::simpleMatch(tok, "&& 1 )"))
{
tok->deleteThis();
tok->deleteThis();
}
if (Token::Match(tok, "%num% ==|!=|<=|>=|<|> %num%") &&
MathLib::isInt(tok->str()) &&
MathLib::isInt(tok->tokAt(2)->str()))
{
const std::string prev(tok->previous() ? tok->strAt(-1) : "");
const std::string after(tok->tokAt(3) ? tok->strAt(3) : "");
if ((prev == "(" || prev == "&&" || prev == "||") && (after == ")" || after == "&&" || after == "||"))
{
const int op1(MathLib::toLongNumber(tok->str()));
const std::string &cmp(tok->next()->str());
const int op2(MathLib::toLongNumber(tok->tokAt(2)->str()));
std::string result;
if (cmp == "==")
result = (op1 == op2) ? "1" : "0";
else if (cmp == "!=")
result = (op1 != op2) ? "1" : "0";
else if (cmp == "<=")
result = (op1 <= op2) ? "1" : "0";
else if (cmp == ">=")
result = (op1 >= op2) ? "1" : "0";
else if (cmp == "<")
result = (op1 < op2) ? "1" : "0";
else if (cmp == ">")
result = (op1 > op2) ? "1" : "0";
tok->str(result);
tok->deleteNext();
tok->deleteNext();
}
}
} }
return ret; return ret;
} }

View File

@ -594,6 +594,18 @@ private:
void match_cfg_def() void match_cfg_def()
{ {
{
std::map<std::string, std::string> cfg;
ASSERT_EQUALS(false, Preprocessor::match_cfg_def(cfg, "A>1||defined(B)"));
}
{
std::map<std::string, std::string> cfg;
cfg["A"] = "";
cfg["B"] = "";
ASSERT_EQUALS(true, Preprocessor::match_cfg_def(cfg, "defined(A)&&defined(B)"));
}
{ {
std::map<std::string, std::string> cfg; std::map<std::string, std::string> cfg;
cfg["ABC"] = ""; cfg["ABC"] = "";