diff --git a/simplecpp.cpp b/simplecpp.cpp index 20ae2528..576b0da7 100755 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -954,7 +954,7 @@ void simplecpp::TokenList::constFold() constFoldQuestionOp(&tok); // If there is no '(' we are done with the constant folding - if (tok->op != '(') + if (!tok || tok->op != '(') break; if (!tok->next || !tok->next->next || tok->next->next->op != ')') @@ -1164,10 +1164,7 @@ void simplecpp::TokenList::constFoldMulDivRem(Token *tok) } else continue; - tok = tok->previous; - tok->setstr(toString(result)); - deleteToken(tok->next); - deleteToken(tok->next); + simpleSquash(tok, toString(result)); } } @@ -1187,10 +1184,7 @@ void simplecpp::TokenList::constFoldAddSub(Token *tok) else continue; - tok = tok->previous; - tok->setstr(toString(result)); - deleteToken(tok->next); - deleteToken(tok->next); + simpleSquash(tok, toString(result)); } } @@ -1210,10 +1204,7 @@ void simplecpp::TokenList::constFoldShift(Token *tok) else continue; - tok = tok->previous; - tok->setstr(toString(result)); - deleteToken(tok->next); - deleteToken(tok->next); + simpleSquash(tok, toString(result)); } } @@ -1247,10 +1238,7 @@ void simplecpp::TokenList::constFoldComparison(Token *tok) else continue; - tok = tok->previous; - tok->setstr(toString(result)); - deleteToken(tok->next); - deleteToken(tok->next); + simpleSquash(tok, toString(result)); } } @@ -1282,12 +1270,51 @@ void simplecpp::TokenList::constFoldBitwise(Token *tok) result = (stringToLL(tok->previous->str()) ^ stringToLL(tok->next->str())); else /*if (*op == '|')*/ result = (stringToLL(tok->previous->str()) | stringToLL(tok->next->str())); - tok = tok->previous; - tok->setstr(toString(result)); - deleteToken(tok->next); - deleteToken(tok->next); + simpleSquash(tok, toString(result)); + } + } +} + +void simplecpp::TokenList::simpleSquash(Token *&tok, const std::string & result) +{ + tok = tok->previous; + tok->setstr(result); + deleteToken(tok->next); + deleteToken(tok->next); +} + +void simplecpp::TokenList::squashTokens(Token *&tok, const std::set & breakPoints, bool forwardDirection, const std::string & result) +{ + const char * const brackets = forwardDirection ? "()" : ")("; + Token* Token::* const step = forwardDirection ? &Token::next : &Token::previous; + int skip = 0; + const Token * const tok1 = tok->*step; + while (tok1 && tok1->*step) { + if ((tok1->*step)->op == brackets[1]){ + if (skip) { + --skip; + deleteToken(tok1->*step); + } else + break; + } else if ((tok1->*step)->op == brackets[0]) { + ++skip; + deleteToken(tok1->*step); + } else if (skip) { + deleteToken(tok1->*step); + } else if (breakPoints.count((tok1->*step)->str()) != 0) { + break; + } else { + deleteToken(tok1->*step); } } + simpleSquash(tok, result); +} + +static simplecpp::Token * constFoldGetOperand(simplecpp::Token * tok, bool forwardDirection) +{ + simplecpp::Token* simplecpp::Token::* const step = forwardDirection ? &simplecpp::Token::next : &simplecpp::Token::previous; + const char bracket = forwardDirection ? ')' : '('; + return tok->*step && (tok->*step)->number && (!((tok->*step)->*step) || (((tok->*step)->*step)->op == bracket)) ? tok->*step : nullptr; } static const std::string AND("and"); @@ -1303,21 +1330,24 @@ void simplecpp::TokenList::constFoldLogicalOp(Token *tok) } if (tok->str() != "&&" && tok->str() != "||") continue; - if (!tok->previous || !tok->previous->number) - continue; - if (!tok->next || !tok->next->number) + const Token* const lhs = constFoldGetOperand(tok, false); + const Token* const rhs = constFoldGetOperand(tok, true); + if (!lhs) // if lhs is not a single number we don't need to fold continue; - int result; - if (tok->str() == "||") - result = (stringToLL(tok->previous->str()) || stringToLL(tok->next->str())); - else /*if (tok->str() == "&&")*/ - result = (stringToLL(tok->previous->str()) && stringToLL(tok->next->str())); - - tok = tok->previous; - tok->setstr(toString(result)); - deleteToken(tok->next); - deleteToken(tok->next); + std::set breakPoints; + breakPoints.insert(":"); + breakPoints.insert("?"); + if (tok->str() == "||"){ + if (stringToLL(lhs->str()) != 0LL || (rhs && stringToLL(rhs->str()) != 0LL)) + squashTokens(tok, breakPoints, stringToLL(lhs->str()) != 0LL, toString(1)); + } else /*if (tok->str() == "&&")*/ { + breakPoints.insert("||"); + if (stringToLL(lhs->str()) == 0LL || (rhs && stringToLL(rhs->str()) == 0LL)) + squashTokens(tok, breakPoints, stringToLL(lhs->str()) == 0LL, toString(0)); + else if (rhs && stringToLL(lhs->str()) && stringToLL(rhs->str())) + simpleSquash(tok, "1"); + } } } diff --git a/simplecpp.h b/simplecpp.h index f5c69593..0be48306 100755 --- a/simplecpp.h +++ b/simplecpp.h @@ -301,6 +301,8 @@ namespace simplecpp { void constFoldLogicalOp(Token *tok); void constFoldQuestionOp(Token **tok1); + void simpleSquash(Token *&tok, const std::string & result); + void squashTokens(Token *&tok, const std::set & breakPoints, bool forwardDirection, const std::string & result); std::string readUntil(Stream &stream, const Location &location, char start, char end, OutputList *outputList); void lineDirective(unsigned int fileIndex, unsigned int line, Location *location); diff --git a/test.cpp b/test.cpp index 3ff00b33..622c9b90 100644 --- a/test.cpp +++ b/test.cpp @@ -452,6 +452,15 @@ static void constFold() ASSERT_EQUALS("1", testConstFold("010==8")); ASSERT_EQUALS("exception", testConstFold("!1 ? 2 :")); ASSERT_EQUALS("exception", testConstFold("?2:3")); + ASSERT_EQUALS("0", testConstFold("( 0 ) && 10 < X")); + ASSERT_EQUALS("0", testConstFold("1+2*(3+4) && 7 - 7")); + ASSERT_EQUALS("1", testConstFold("( 1 ) || 10 < X")); + ASSERT_EQUALS("1", testConstFold("1+2*(3+4) || 8 - 7")); + ASSERT_EQUALS("X && 0", testConstFold("X && 0")); + ASSERT_EQUALS("X >= 0 || 0 < Y", testConstFold("X >= 0 || 0 < Y")); + ASSERT_EQUALS("X && 1 && Z", testConstFold("X && (1 || Y) && Z")); + ASSERT_EQUALS("0 || Y", testConstFold("0 && X || Y")); + ASSERT_EQUALS("X > 0 && Y", testConstFold("X > 0 && Y")); } #ifdef __CYGWIN__ @@ -1598,6 +1607,22 @@ static void ifA() ASSERT_EQUALS("\nX", preprocess(code, dui)); } +static void ifXorY() +{ + const char code[] = "#if Z > 0 || 0 < Y\n" + "X\n" + "#endif"; + ASSERT_EQUALS("", preprocess(code)); + + simplecpp::DUI dui; + dui.defines.push_back("Z=1"); + ASSERT_EQUALS("\nX", preprocess(code, dui)); + + dui.defines.clear(); + dui.defines.push_back("Y=15"); + ASSERT_EQUALS("\nX", preprocess(code, dui)); +} + static void ifCharLiteral() { const char code[] = "#if ('A'==0x41)\n" @@ -3104,6 +3129,7 @@ int main(int argc, char **argv) TEST_CASE(ifdef2); TEST_CASE(ifndef); TEST_CASE(ifA); + TEST_CASE(ifXorY); TEST_CASE(ifCharLiteral); TEST_CASE(ifDefined); TEST_CASE(ifDefinedNoPar);