@@ -179,14 +179,31 @@ static bool isValidPunctuatorPaste(const std::string &s)
179179 return isPunctuator (s) || (s.size () >= 2 && s[0 ] == ' .' && std::isdigit (static_cast <unsigned char >(s[1 ])));
180180}
181181
182+ /*
183+ * When an operation can't be evaluated (division by zero), its result is an
184+ * error value. The error is only reported if the error value is used, so an
185+ * operand that is not evaluated, as in "0 && (1/0)", does not cause an error.
186+ */
187+ static const std::string ERROR_VALUE (" #error:" );
188+
189+ static bool isErrorValue (const simplecpp::Token *tok)
190+ {
191+ return tok && tok->str ().compare (0 , ERROR_VALUE .size (), ERROR_VALUE ) == 0 ;
192+ }
193+
194+ static bool isValue (const simplecpp::Token *tok)
195+ {
196+ return tok && (tok->number || isErrorValue (tok));
197+ }
198+
182199static bool isAlternativeBinaryOp (const simplecpp::Token *tok, const std::string &alt)
183200{
184201 return (tok->name &&
185202 tok->str () == alt &&
186203 tok->previous &&
187204 tok->next &&
188- (tok->previous -> number || tok->previous ->name || tok->previous ->op == ' )' ) &&
189- (tok->next -> number || tok->next ->name || tok->next ->op == ' (' ));
205+ (isValue ( tok->previous ) || tok->previous ->name || tok->previous ->op == ' )' ) &&
206+ (isValue ( tok->next ) || tok->next ->name || tok->next ->op == ' (' ));
190207}
191208
192209static bool isAlternativeUnaryOp (const simplecpp::Token *tok, const std::string &alt)
@@ -1072,6 +1089,23 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename,
10721089 combineOperators ();
10731090}
10741091
1092+ /* *
1093+ * If one operand of the binary operator tok is an error value then
1094+ * "lhs op rhs" is replaced by that error value.
1095+ * @return the error value token, or nullptr
1096+ */
1097+ static simplecpp::Token *foldErrorValue (simplecpp::TokenList &tokens, simplecpp::Token *tok)
1098+ {
1099+ simplecpp::Token * const lhs = tok->previous ;
1100+ if (!isErrorValue (lhs) && !isErrorValue (tok->next ))
1101+ return nullptr ;
1102+ if (!isErrorValue (lhs))
1103+ lhs->setstr (tok->next ->str ());
1104+ tokens.deleteToken (tok->next );
1105+ tokens.deleteToken (tok);
1106+ return lhs;
1107+ }
1108+
10751109void simplecpp::TokenList::constFold ()
10761110{
10771111 while (cfront ()) {
@@ -1105,6 +1139,11 @@ void simplecpp::TokenList::constFold()
11051139 deleteToken (tok->previous );
11061140 deleteToken (tok->next );
11071141 }
1142+
1143+ for (const Token *tok = cfront (); tok; tok = tok->next ) {
1144+ if (isErrorValue (tok))
1145+ throw std::overflow_error (tok->str ().substr (ERROR_VALUE .size ()));
1146+ }
11081147}
11091148
11101149static bool isFloatSuffix (const simplecpp::Token *tok)
@@ -1262,17 +1301,27 @@ void simplecpp::TokenList::constFoldUnaryNotPosNeg(simplecpp::Token *tok)
12621301 else if (isAlternativeUnaryOp (tok, COMPL ))
12631302 tok->op = ' ~' ;
12641303
1265- if (tok->op == ' !' && tok->next && tok->next ->number ) {
1304+ if (tok->isOneOf (" !~" ) && isErrorValue (tok->next )) {
1305+ tok->setstr (tok->next ->str ());
1306+ deleteToken (tok->next );
1307+ } else if (tok->op == ' !' && tok->next && tok->next ->number ) {
12661308 tok->setstr (tok->next ->str () == " 0" ? " 1" : " 0" );
12671309 deleteToken (tok->next );
12681310 } else if (tok->op == ' ~' && tok->next && tok->next ->number ) {
12691311 tok->setstr (toString (~stringToLL (tok->next->str ())));
12701312 deleteToken (tok->next);
12711313 } else {
1272- if (tok->previous && (tok->previous -> number || tok->previous ->name ))
1314+ if (tok->previous && (isValue ( tok->previous ) || tok->previous ->name ))
12731315 continue ;
1274- if (!tok->next || !tok-> next -> number )
1316+ if (!isValue ( tok->next ) )
12751317 continue ;
1318+ if (isErrorValue (tok->next )) {
1319+ if (tok->isOneOf (" +-" )) {
1320+ tok->setstr (tok->next ->str ());
1321+ deleteToken (tok->next );
1322+ }
1323+ continue ;
1324+ }
12761325 switch (tok->op ) {
12771326 case ' +' :
12781327 tok->setstr (tok->next ->str ());
@@ -1290,32 +1339,33 @@ void simplecpp::TokenList::constFoldUnaryNotPosNeg(simplecpp::Token *tok)
12901339void simplecpp::TokenList::constFoldMulDivRem (Token *tok)
12911340{
12921341 for (; tok && tok->op != ' )' ; tok = tok->next ) {
1293- if (!tok->previous || !tok->previous ->number )
1342+ if (!isValue (tok->previous ) || !isValue (tok->next ))
1343+ continue ;
1344+ if (!tok->isOneOf (" */%" ))
12941345 continue ;
1295- if (!tok->next || !tok->next ->number )
1346+ if (Token * const errorValue = foldErrorValue (*this , tok)) {
1347+ tok = errorValue;
12961348 continue ;
1349+ }
12971350
1298- long long result;
1351+ std::string result;
12991352 if (tok->op == ' *' ) {
1300- result = (stringToLL (tok->previous ->str ()) * stringToLL (tok->next ->str ()));
1301- }
1302- else if (tok->op == ' /' || tok->op == ' %' ) {
1353+ result = toString (stringToLL (tok->previous ->str ()) * stringToLL (tok->next ->str ()));
1354+ } else {
13031355 const long long rhs = stringToLL (tok->next ->str ());
1304- if (rhs == 0 )
1305- throw std::overflow_error (" division/modulo by zero" );
13061356 const long long lhs = stringToLL (tok->previous ->str ());
1307- if (rhs == -1 && lhs == std::numeric_limits<long long >::min ())
1308- throw std::overflow_error (" division overflow" );
1309- if (tok->op == ' /' )
1310- result = (lhs / rhs);
1357+ if (rhs == 0 )
1358+ result = ERROR_VALUE + " division/modulo by zero" ;
1359+ else if (rhs == -1 && lhs == std::numeric_limits<long long >::min ())
1360+ result = ERROR_VALUE + " division overflow" ;
1361+ else if (tok->op == ' /' )
1362+ result = toString (lhs / rhs);
13111363 else
1312- result = (lhs % rhs);
1313- } else {
1314- continue ;
1364+ result = toString (lhs % rhs);
13151365 }
13161366
13171367 tok = tok->previous ;
1318- tok->setstr (toString ( result) );
1368+ tok->setstr (result);
13191369 deleteToken (tok->next );
13201370 deleteToken (tok->next );
13211371 }
@@ -1324,10 +1374,14 @@ void simplecpp::TokenList::constFoldMulDivRem(Token *tok)
13241374void simplecpp::TokenList::constFoldAddSub (Token *tok)
13251375{
13261376 for (; tok && tok->op != ' )' ; tok = tok->next ) {
1327- if (!tok->previous || !tok->previous ->number )
1377+ if (!isValue (tok->previous ) || !isValue (tok->next ))
1378+ continue ;
1379+ if (!tok->isOneOf (" +-" ))
13281380 continue ;
1329- if (!tok->next || !tok->next ->number )
1381+ if (Token * const errorValue = foldErrorValue (*this , tok)) {
1382+ tok = errorValue;
13301383 continue ;
1384+ }
13311385
13321386 long long result;
13331387 if (tok->op == ' +' )
@@ -1347,10 +1401,14 @@ void simplecpp::TokenList::constFoldAddSub(Token *tok)
13471401void simplecpp::TokenList::constFoldShift (Token *tok)
13481402{
13491403 for (; tok && tok->op != ' )' ; tok = tok->next ) {
1350- if (!tok->previous || !tok->previous ->number )
1404+ if (!isValue (tok->previous ) || !isValue (tok->next ))
1405+ continue ;
1406+ if (tok->str () != " <<" && tok->str () != " >>" )
13511407 continue ;
1352- if (!tok->next || !tok->next ->number )
1408+ if (Token * const errorValue = foldErrorValue (*this , tok)) {
1409+ tok = errorValue;
13531410 continue ;
1411+ }
13541412
13551413 long long result;
13561414 if (tok->str () == " <<" )
@@ -1374,12 +1432,14 @@ void simplecpp::TokenList::constFoldComparison(Token *tok)
13741432 if (isAlternativeBinaryOp (tok,NOTEQ ))
13751433 tok->setstr (" !=" );
13761434
1377- if (!tok->startsWithOneOf (" <>=! " ) )
1435+ if (!tok->isOneOf (" <>" ) && tok-> str () != " <= " && tok-> str () != " >= " && tok-> str () != " == " && tok-> str () != " != " )
13781436 continue ;
1379- if (!tok->previous || !tok->previous -> number )
1437+ if (!isValue ( tok->previous ) || !isValue ( tok->next ) )
13801438 continue ;
1381- if (!tok->next || !tok->next ->number )
1439+ if (Token * const errorValue = foldErrorValue (*this , tok)) {
1440+ tok = errorValue;
13821441 continue ;
1442+ }
13831443
13841444 int result;
13851445 if (tok->str () == " ==" )
@@ -1419,10 +1479,12 @@ void simplecpp::TokenList::constFoldBitwise(Token *tok)
14191479 for (tok = tok1; tok && tok->op != ' )' ; tok = tok->next ) {
14201480 if (tok->op != *op && !isAlternativeBinaryOp (tok, *alternativeOp))
14211481 continue ;
1422- if (!tok->previous || !tok->previous -> number )
1482+ if (!isValue ( tok->previous ) || !isValue ( tok->next ) )
14231483 continue ;
1424- if (!tok->next || !tok->next ->number )
1484+ if (Token * const errorValue = foldErrorValue (*this , tok)) {
1485+ tok = errorValue;
14251486 continue ;
1487+ }
14261488 long long result;
14271489 if (*op == ' &' )
14281490 result = (stringToLL (tok->previous ->str ()) & stringToLL (tok->next ->str ()));
@@ -1455,19 +1517,24 @@ void simplecpp::TokenList::constFoldLogicalOp(Token *tok)
14551517 for (Token *t = tok; t && t->op != ' )' ; t = t->next ) {
14561518 if (t->str () != op)
14571519 continue ;
1458- if (!t->previous || !t->previous ->number )
1459- continue ;
1460- if (!t->next || !t->next ->number )
1520+ if (!isValue (t->previous ) || !isValue (t->next ))
14611521 continue ;
14621522
1463- int result;
1464- if (t->str () == " ||" )
1465- result = (stringToLL (t->previous ->str ()) || stringToLL (t->next ->str ()));
1466- else /* if (t->str() == "&&")*/
1467- result = (stringToLL (t->previous ->str ()) && stringToLL (t->next ->str ()));
1523+ // the right operand is not evaluated if the left operand decides the result
1524+ std::string result;
1525+ if (isErrorValue (t->previous ))
1526+ result = t->previous ->str ();
1527+ else if (t->str () == " ||" && stringToLL (t->previous ->str ()) != 0 )
1528+ result = " 1" ;
1529+ else if (t->str () == " &&" && stringToLL (t->previous ->str ()) == 0 )
1530+ result = " 0" ;
1531+ else if (isErrorValue (t->next ))
1532+ result = t->next ->str ();
1533+ else
1534+ result = (stringToLL (t->next ->str ()) != 0 ) ? " 1" : " 0" ;
14681535
14691536 t = t->previous ;
1470- t->setstr (toString ( result) );
1537+ t->setstr (result);
14711538 deleteToken (t->next );
14721539 deleteToken (t->next );
14731540 }
@@ -1476,30 +1543,42 @@ void simplecpp::TokenList::constFoldLogicalOp(Token *tok)
14761543
14771544void simplecpp::TokenList::constFoldQuestionOp (Token *&tok1)
14781545{
1479- bool gotoTok1 = false ;
1480- // NOLINTNEXTLINE(misc-const-correctness) - technically correct but used to access non-const data
1481- for (Token *tok = tok1; tok && tok->op != ' )' ; tok = gotoTok1 ? tok1 : tok->next ) {
1482- gotoTok1 = false ;
1483- if (tok->str () != " ?" )
1484- continue ;
1546+ // ?: is right-associative, "a ? b : c ? d : e" means "a ? b : (c ? d : e)",
1547+ // so the last ? is folded first
1548+ std::vector<const Token *> questionTokens;
1549+ for (const Token *t = tok1; t && t->op != ' )' ; t = t->next ) {
1550+ if (t->str () == " ?" )
1551+ questionTokens.push_back (t);
1552+ }
1553+ while (!questionTokens.empty ()) {
1554+ const Token * const tok = questionTokens.back ();
1555+ questionTokens.pop_back ();
14851556 if (!tok->previous || !tok->next || !tok->next ->next )
14861557 throw std::runtime_error (" invalid expression" );
1487- if (!tok->previous ->number )
1488- continue ;
1489- if (tok->next ->next ->op != ' :' )
1490- continue ;
14911558 Token * const condTok = tok->previous ;
14921559 Token * const trueTok = tok->next ;
14931560 Token * const falseTok = trueTok->next ->next ;
14941561 if (!falseTok)
14951562 throw std::runtime_error (" invalid expression" );
1496- if (condTok == tok1)
1497- tok1 = (condTok->str () != " 0" ? trueTok : falseTok);
1498- deleteToken (condTok->next ); // ?
1499- deleteToken (trueTok->next ); // :
1500- deleteToken (condTok->str () == " 0" ? trueTok : falseTok);
1501- deleteToken (condTok);
1502- gotoTok1 = true ;
1563+ if (trueTok->next ->op != ' :' )
1564+ return ;
1565+ if (!isValue (condTok) || !isValue (trueTok) || !isValue (falseTok))
1566+ return ;
1567+ if (isErrorValue (condTok)) {
1568+ // "error ? x : y" => error
1569+ deleteToken (condTok->next ); // ?
1570+ deleteToken (trueTok->next ); // :
1571+ deleteToken (trueTok);
1572+ deleteToken (falseTok);
1573+ } else {
1574+ Token * const result = (condTok->str () != " 0" ? trueTok : falseTok);
1575+ if (condTok == tok1)
1576+ tok1 = result;
1577+ deleteToken (condTok->next ); // ?
1578+ deleteToken (trueTok->next ); // :
1579+ deleteToken (result == falseTok ? trueTok : falseTok); // the operand that is not evaluated
1580+ deleteToken (condTok);
1581+ }
15031582 }
15041583}
15051584
0 commit comments