ExprEngine: Better handling of conditions

This commit is contained in:
Daniel Marjamäki 2019-09-20 21:27:51 +02:00
parent 38dec6a9ac
commit 6c59957109
2 changed files with 69 additions and 15 deletions

View File

@ -115,27 +115,64 @@ namespace {
const Settings * const settings; const Settings * const settings;
const std::vector<ExprEngine::Callback> &callbacks; const std::vector<ExprEngine::Callback> &callbacks;
Data getData(const Token *cond, bool trueData) { std::vector<Data> getData(const Token *cond, bool trueData) {
Data ret(symbolValueIndex, tokenizer, settings, callbacks, mTrackExecution); std::vector<Data> ret;
ret.push_back(Data(symbolValueIndex, tokenizer, settings, callbacks, mTrackExecution));
for (Memory::const_iterator mem = memory.cbegin(); mem != memory.cend(); ++mem) { for (Memory::const_iterator mem = memory.cbegin(); mem != memory.cend(); ++mem) {
ret.memory[mem->first] = mem->second; for (Data &data : ret)
data.memory[mem->first] = mem->second;
if (cond->isComparisonOp() && cond->astOperand1()->varId() == mem->first && cond->astOperand2()->isNumber()) { if (cond->isComparisonOp() && cond->astOperand1()->varId() == mem->first && cond->astOperand2()->isNumber()) {
const int128_t rhsValue = MathLib::toLongNumber(cond->astOperand2()->str()); const int128_t rhsValue = MathLib::toLongNumber(cond->astOperand2()->str());
if (auto intRange = std::dynamic_pointer_cast<ExprEngine::IntRange>(mem->second)) { if (auto intRange = std::dynamic_pointer_cast<ExprEngine::IntRange>(mem->second)) {
if (cond->str() == ">") { if (cond->str() == ">") {
if (trueData && intRange->minValue <= rhsValue) { if (trueData) {
if (intRange->maxValue <= rhsValue)
return std::vector<Data>();
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), rhsValue + 1, intRange->maxValue); auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), rhsValue + 1, intRange->maxValue);
ret.trackAssignment(cond, val); trackAssignment(cond, val);
ret.memory[mem->first] = val; ret[0].memory[mem->first] = val;
} else if (!trueData && intRange->maxValue > rhsValue) { } else { /* if (!trueData) */
if (intRange->maxValue <= rhsValue)
return std::vector<Data>();
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), intRange->minValue, rhsValue); auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), intRange->minValue, rhsValue);
ret.trackAssignment(cond, val); trackAssignment(cond, val);
ret.memory[mem->first] = val; ret[0].memory[mem->first] = val;
} }
} }
} }
} }
else if (cond->varId() == mem->first) {
if (auto intRange = std::dynamic_pointer_cast<ExprEngine::IntRange>(mem->second)) {
if (trueData) {
if (intRange->minValue == 0 && intRange->maxValue == 0)
return std::vector<Data>();
if (intRange->minValue < 0) {
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), intRange->minValue, -1);
trackAssignment(cond, val);
ret[0].memory[mem->first] = val;
}
if (intRange->maxValue > 0) {
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), 1, intRange->maxValue);
trackAssignment(cond, val);
if (intRange->minValue < 0) {
// create additional intrange..
ret.push_back(Data(symbolValueIndex, tokenizer, settings, callbacks, mTrackExecution));
ret.back().memory = ret[0].memory;
}
ret[0].memory[mem->first] = val;
}
} else { /* if (!trueData) */
if (intRange->maxValue < 0 || intRange->minValue > 0)
return std::vector<Data>();
auto val = std::make_shared<ExprEngine::IntRange>(getNewSymbolName(), 0, 0);
trackAssignment(cond, val);
ret[0].memory[mem->first] = val;
}
}
}
} }
return ret; return ret;
} }
@ -179,7 +216,9 @@ namespace {
for (auto mem : memory) { for (auto mem : memory) {
ExprEngine::ValuePtr value = mem.second; ExprEngine::ValuePtr value = mem.second;
s << " " << symbolDatabase->getVariableFromVarId(mem.first)->name() << "="; s << " " << symbolDatabase->getVariableFromVarId(mem.first)->name() << "=";
if (value->name[0] == '$') if (!value)
s << "(null)";
else if (value->name[0] == '$')
s << "(" << value->name << "," << value->getRange() << ")"; s << "(" << value->name << "," << value->getRange() << ")";
else else
s << value->name; s << value->name;
@ -522,16 +561,19 @@ static void execute(const Token *start, const Token *end, Data &data)
if (Token::simpleMatch(tok, "if (")) { if (Token::simpleMatch(tok, "if (")) {
const Token *cond = tok->next()->astOperand2(); const Token *cond = tok->next()->astOperand2();
/*const ExprEngine::ValuePtr condValue =*/ executeExpression(cond,data); /*const ExprEngine::ValuePtr condValue =*/ executeExpression(cond,data);
Data trueData = data.getData(cond, true); std::vector<Data> trueData = data.getData(cond, true);
Data falseData = data.getData(cond, false); std::vector<Data> falseData = data.getData(cond, false);
const Token *thenStart = tok->linkAt(1)->next(); const Token *thenStart = tok->linkAt(1)->next();
const Token *thenEnd = thenStart->link(); const Token *thenEnd = thenStart->link();
execute(thenStart->next(), end, trueData); for (Data &d : trueData)
execute(thenStart->next(), end, d);
if (Token::simpleMatch(thenEnd, "} else {")) { if (Token::simpleMatch(thenEnd, "} else {")) {
const Token *elseStart = thenEnd->tokAt(2); const Token *elseStart = thenEnd->tokAt(2);
execute(elseStart->next(), end, falseData); for (Data &d : falseData)
execute(elseStart->next(), end, d);
} else { } else {
execute(thenEnd->next(), end, falseData); for (Data &d : falseData)
execute(thenEnd->next(), end, d);
} }
return; return;
} }
@ -553,6 +595,8 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
static ExprEngine::ValuePtr createStructVal(const Scope *structScope, Data &data) static ExprEngine::ValuePtr createStructVal(const Scope *structScope, Data &data)
{ {
if (!structScope)
return ExprEngine::ValuePtr();
std::shared_ptr<ExprEngine::StructValue> structValue = std::make_shared<ExprEngine::StructValue>(data.getNewSymbolName()); std::shared_ptr<ExprEngine::StructValue> structValue = std::make_shared<ExprEngine::StructValue>(data.getNewSymbolName());
for (const Variable &member : structScope->varlist) { for (const Variable &member : structScope->varlist) {
ExprEngine::ValuePtr memberValue = createVariableValue(member, data); ExprEngine::ValuePtr memberValue = createVariableValue(member, data);

View File

@ -43,6 +43,8 @@ private:
TEST_CASE(if1); TEST_CASE(if1);
TEST_CASE(if2); TEST_CASE(if2);
TEST_CASE(if3); TEST_CASE(if3);
TEST_CASE(if4);
TEST_CASE(if5);
TEST_CASE(ifelse1); TEST_CASE(ifelse1);
@ -119,6 +121,14 @@ private:
ASSERT_EQUALS("[1:1][-2147483648:2147483647][-2147483648:2147483647]", getRange("void f() { int x; if (a) { if (b) x=1; } a=x; }", "a=x")); ASSERT_EQUALS("[1:1][-2147483648:2147483647][-2147483648:2147483647]", getRange("void f() { int x; if (a) { if (b) x=1; } a=x; }", "a=x"));
} }
void if4() {
ASSERT_EQUALS("[1:2147483647][-2147483648:-1]", getRange("int x; void f() { if (x) { a=x; }}", "a=x"));
}
void if5() {
ASSERT_EQUALS("[0:0]", getRange("int x; void f() { if (x) {} else { a=x; }}", "a=x"));
}
void ifelse1() { void ifelse1() {
ASSERT_EQUALS("[-32767:6]", getRange("inf f(short x) { if (x > 5) ; else a = x + 1; }", "x+1")); ASSERT_EQUALS("[-32767:6]", getRange("inf f(short x) { if (x > 5) ; else a = x + 1; }", "x+1"));
} }