Skip to content

Commit aa3c4b6

Browse files
authored
Fix #404: simplecpp::TokenList::constFold does not fold '( 0 ) && 10 < X' properly (#405)
1 parent c4b6e37 commit aa3c4b6

3 files changed

Lines changed: 92 additions & 34 deletions

File tree

simplecpp.cpp

Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ void simplecpp::TokenList::constFold()
954954
constFoldQuestionOp(&tok);
955955

956956
// If there is no '(' we are done with the constant folding
957-
if (tok->op != '(')
957+
if (!tok || tok->op != '(')
958958
break;
959959

960960
if (!tok->next || !tok->next->next || tok->next->next->op != ')')
@@ -1164,10 +1164,7 @@ void simplecpp::TokenList::constFoldMulDivRem(Token *tok)
11641164
} else
11651165
continue;
11661166

1167-
tok = tok->previous;
1168-
tok->setstr(toString(result));
1169-
deleteToken(tok->next);
1170-
deleteToken(tok->next);
1167+
simpleSquash(tok, toString(result));
11711168
}
11721169
}
11731170

@@ -1187,10 +1184,7 @@ void simplecpp::TokenList::constFoldAddSub(Token *tok)
11871184
else
11881185
continue;
11891186

1190-
tok = tok->previous;
1191-
tok->setstr(toString(result));
1192-
deleteToken(tok->next);
1193-
deleteToken(tok->next);
1187+
simpleSquash(tok, toString(result));
11941188
}
11951189
}
11961190

@@ -1210,10 +1204,7 @@ void simplecpp::TokenList::constFoldShift(Token *tok)
12101204
else
12111205
continue;
12121206

1213-
tok = tok->previous;
1214-
tok->setstr(toString(result));
1215-
deleteToken(tok->next);
1216-
deleteToken(tok->next);
1207+
simpleSquash(tok, toString(result));
12171208
}
12181209
}
12191210

@@ -1247,10 +1238,7 @@ void simplecpp::TokenList::constFoldComparison(Token *tok)
12471238
else
12481239
continue;
12491240

1250-
tok = tok->previous;
1251-
tok->setstr(toString(result));
1252-
deleteToken(tok->next);
1253-
deleteToken(tok->next);
1241+
simpleSquash(tok, toString(result));
12541242
}
12551243
}
12561244

@@ -1282,12 +1270,51 @@ void simplecpp::TokenList::constFoldBitwise(Token *tok)
12821270
result = (stringToLL(tok->previous->str()) ^ stringToLL(tok->next->str()));
12831271
else /*if (*op == '|')*/
12841272
result = (stringToLL(tok->previous->str()) | stringToLL(tok->next->str()));
1285-
tok = tok->previous;
1286-
tok->setstr(toString(result));
1287-
deleteToken(tok->next);
1288-
deleteToken(tok->next);
1273+
simpleSquash(tok, toString(result));
1274+
}
1275+
}
1276+
}
1277+
1278+
void simplecpp::TokenList::simpleSquash(Token *&tok, const std::string & result)
1279+
{
1280+
tok = tok->previous;
1281+
tok->setstr(result);
1282+
deleteToken(tok->next);
1283+
deleteToken(tok->next);
1284+
}
1285+
1286+
void simplecpp::TokenList::squashTokens(Token *&tok, const std::set<std::string> & breakPoints, bool forwardDirection, const std::string & result)
1287+
{
1288+
const char * const brackets = forwardDirection ? "()" : ")(";
1289+
Token* Token::* const step = forwardDirection ? &Token::next : &Token::previous;
1290+
int skip = 0;
1291+
const Token * const tok1 = tok->*step;
1292+
while (tok1 && tok1->*step) {
1293+
if ((tok1->*step)->op == brackets[1]){
1294+
if (skip) {
1295+
--skip;
1296+
deleteToken(tok1->*step);
1297+
} else
1298+
break;
1299+
} else if ((tok1->*step)->op == brackets[0]) {
1300+
++skip;
1301+
deleteToken(tok1->*step);
1302+
} else if (skip) {
1303+
deleteToken(tok1->*step);
1304+
} else if (breakPoints.count((tok1->*step)->str()) != 0) {
1305+
break;
1306+
} else {
1307+
deleteToken(tok1->*step);
12891308
}
12901309
}
1310+
simpleSquash(tok, result);
1311+
}
1312+
1313+
static simplecpp::Token * constFoldGetOperand(simplecpp::Token * tok, bool forwardDirection)
1314+
{
1315+
simplecpp::Token* simplecpp::Token::* const step = forwardDirection ? &simplecpp::Token::next : &simplecpp::Token::previous;
1316+
const char bracket = forwardDirection ? ')' : '(';
1317+
return tok->*step && (tok->*step)->number && (!((tok->*step)->*step) || (((tok->*step)->*step)->op == bracket)) ? tok->*step : nullptr;
12911318
}
12921319

12931320
static const std::string AND("and");
@@ -1303,21 +1330,24 @@ void simplecpp::TokenList::constFoldLogicalOp(Token *tok)
13031330
}
13041331
if (tok->str() != "&&" && tok->str() != "||")
13051332
continue;
1306-
if (!tok->previous || !tok->previous->number)
1307-
continue;
1308-
if (!tok->next || !tok->next->number)
1333+
const Token* const lhs = constFoldGetOperand(tok, false);
1334+
const Token* const rhs = constFoldGetOperand(tok, true);
1335+
if (!lhs) // if lhs is not a single number we don't need to fold
13091336
continue;
13101337

1311-
int result;
1312-
if (tok->str() == "||")
1313-
result = (stringToLL(tok->previous->str()) || stringToLL(tok->next->str()));
1314-
else /*if (tok->str() == "&&")*/
1315-
result = (stringToLL(tok->previous->str()) && stringToLL(tok->next->str()));
1316-
1317-
tok = tok->previous;
1318-
tok->setstr(toString(result));
1319-
deleteToken(tok->next);
1320-
deleteToken(tok->next);
1338+
std::set<std::string> breakPoints;
1339+
breakPoints.insert(":");
1340+
breakPoints.insert("?");
1341+
if (tok->str() == "||"){
1342+
if (stringToLL(lhs->str()) != 0LL || (rhs && stringToLL(rhs->str()) != 0LL))
1343+
squashTokens(tok, breakPoints, stringToLL(lhs->str()) != 0LL, toString(1));
1344+
} else /*if (tok->str() == "&&")*/ {
1345+
breakPoints.insert("||");
1346+
if (stringToLL(lhs->str()) == 0LL || (rhs && stringToLL(rhs->str()) == 0LL))
1347+
squashTokens(tok, breakPoints, stringToLL(lhs->str()) == 0LL, toString(0));
1348+
else if (rhs && stringToLL(lhs->str()) && stringToLL(rhs->str()))
1349+
simpleSquash(tok, "1");
1350+
}
13211351
}
13221352
}
13231353

simplecpp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ namespace simplecpp {
301301
void constFoldLogicalOp(Token *tok);
302302
void constFoldQuestionOp(Token **tok1);
303303

304+
void simpleSquash(Token *&tok, const std::string & result);
305+
void squashTokens(Token *&tok, const std::set<std::string> & breakPoints, bool forwardDirection, const std::string & result);
304306
std::string readUntil(Stream &stream, const Location &location, char start, char end, OutputList *outputList);
305307
void lineDirective(unsigned int fileIndex, unsigned int line, Location *location);
306308

test.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,15 @@ static void constFold()
452452
ASSERT_EQUALS("1", testConstFold("010==8"));
453453
ASSERT_EQUALS("exception", testConstFold("!1 ? 2 :"));
454454
ASSERT_EQUALS("exception", testConstFold("?2:3"));
455+
ASSERT_EQUALS("0", testConstFold("( 0 ) && 10 < X"));
456+
ASSERT_EQUALS("0", testConstFold("1+2*(3+4) && 7 - 7"));
457+
ASSERT_EQUALS("1", testConstFold("( 1 ) || 10 < X"));
458+
ASSERT_EQUALS("1", testConstFold("1+2*(3+4) || 8 - 7"));
459+
ASSERT_EQUALS("X && 0", testConstFold("X && 0"));
460+
ASSERT_EQUALS("X >= 0 || 0 < Y", testConstFold("X >= 0 || 0 < Y"));
461+
ASSERT_EQUALS("X && 1 && Z", testConstFold("X && (1 || Y) && Z"));
462+
ASSERT_EQUALS("0 || Y", testConstFold("0 && X || Y"));
463+
ASSERT_EQUALS("X > 0 && Y", testConstFold("X > 0 && Y"));
455464
}
456465

457466
#ifdef __CYGWIN__
@@ -1598,6 +1607,22 @@ static void ifA()
15981607
ASSERT_EQUALS("\nX", preprocess(code, dui));
15991608
}
16001609

1610+
static void ifXorY()
1611+
{
1612+
const char code[] = "#if Z > 0 || 0 < Y\n"
1613+
"X\n"
1614+
"#endif";
1615+
ASSERT_EQUALS("", preprocess(code));
1616+
1617+
simplecpp::DUI dui;
1618+
dui.defines.push_back("Z=1");
1619+
ASSERT_EQUALS("\nX", preprocess(code, dui));
1620+
1621+
dui.defines.clear();
1622+
dui.defines.push_back("Y=15");
1623+
ASSERT_EQUALS("\nX", preprocess(code, dui));
1624+
}
1625+
16011626
static void ifCharLiteral()
16021627
{
16031628
const char code[] = "#if ('A'==0x41)\n"
@@ -3104,6 +3129,7 @@ int main(int argc, char **argv)
31043129
TEST_CASE(ifdef2);
31053130
TEST_CASE(ifndef);
31063131
TEST_CASE(ifA);
3132+
TEST_CASE(ifXorY);
31073133
TEST_CASE(ifCharLiteral);
31083134
TEST_CASE(ifDefined);
31093135
TEST_CASE(ifDefinedNoPar);

0 commit comments

Comments
 (0)