From f69b1f426e2c1c10cc76115596fc09bbdd8c9348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=E4ki?= Date: Sat, 26 Jan 2013 16:21:33 +0100 Subject: [PATCH] Preprocessor: Improved handling of expressions in simplifyVarMap. Ticket: #4516 --- lib/preprocessor.cpp | 60 ++++++++++++++++++++++++++------------- test/testpreprocessor.cpp | 26 ++++++++++++----- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 3fccc9d62..632f0f811 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -992,6 +992,40 @@ std::string Preprocessor::getdef(std::string line, bool def) return line; } +/** Simplify variable in variable map. */ +static void simplifyVarMapExpandValue(Token *tok, const std::map &variables, std::set seenVariables) +{ + // TODO: handle function-macros too. + + // Prevent infinite recursion.. + if (seenVariables.find(tok->str()) != seenVariables.end()) + return; + seenVariables.insert(tok->str()); + + const std::map::const_iterator it = variables.find(tok->str()); + if (it != variables.end()) { + TokenList tokenList(NULL); + std::istringstream istr(it->second); + if (tokenList.createTokens(istr)) { + // expand token list + for (Token *tok2 = tokenList.front(); tok2; tok2 = tok2->next()) { + if (tok->isName()) { + simplifyVarMapExpandValue(tok2, variables, seenVariables); + } + } + + // insert token list into "parent" token list + for (const Token *tok2 = tokenList.front(); tok2; tok2 = tok2->next()) { + if (tok2->previous()) { + tok->insertToken(tok2->str()); + tok = tok->next(); + } else + tok->str(tok2->str()); + } + } + } +} + /** * Simplifies the variable map. For example if the map contains A=>B, B=>1, then A=>B is simplified to A=>1. * @param [in,out] variables - a map of variable name to variable value. This map will be modified. @@ -999,32 +1033,20 @@ std::string Preprocessor::getdef(std::string line, bool def) static void simplifyVarMap(std::map &variables) { for (std::map::iterator i = variables.begin(); i != variables.end(); ++i) { - std::string& varValue = i->second; - - // TODO: handle function-macros too. - - // Bailout if variable A depends on variable B which depends on A.. - std::set seenVariables; - TokenList tokenList(NULL); std::istringstream istr(i->second); if (tokenList.createTokens(istr)) { for (Token *tok = tokenList.front(); tok; tok = tok->next()) { if (tok->isName()) { - std::map::iterator it = variables.find(tok->str()); - while (it != variables.end() && it->first != it->second) { - if (seenVariables.find(it->first) != seenVariables.end()) { - // We have already seen this variable. there is a cycle of #define that we can't process at - // this time. Stop trying to simplify the current variable and leave it as is. - break; - } else { - seenVariables.insert(it->first); - varValue = it->second; - it = variables.find(varValue); - } - } + std::set seenVariables; + simplifyVarMapExpandValue(tok, variables, seenVariables); } } + + std::string str; + for (const Token *tok = tokenList.front(); tok; tok = tok->next()) + str.append((tok->previous() ? " " : "") + tok->str()); + i->second = str; } } } diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 9f4f33b72..b28fe1a0c 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -2740,13 +2740,25 @@ private: } void define_if5() { // #4516 - #define B (A & 0x00f0) - const char filedata[] = "#define A 0x0010\n" - "#define B (A & 0x00f0)\n" - "#if B==0x0010\n" - "FOO\n" - "#endif"; - Preprocessor preprocessor(NULL, this); - ASSERT_EQUALS("\n\n\nFOO\n\n", preprocessor.getcode(filedata,"","")); + { + const char filedata[] = "#define A 0x0010\n" + "#define B (A & 0x00f0)\n" + "#if B==0x0010\n" + "FOO\n" + "#endif"; + Preprocessor preprocessor(NULL, this); + ASSERT_EQUALS("\n\n\nFOO\n\n", preprocessor.getcode(filedata,"","")); + } + { + const char filedata[] = "#define A 0x00f0\n" + "#define B (16)\n" + "#define C (B & A)\n" + "#if C==0x0010\n" + "FOO\n" + "#endif"; + Preprocessor preprocessor(NULL, this); + ASSERT_EQUALS("\n\n\n\nFOO\n\n", preprocessor.getcode(filedata,"","")); + } } void define_ifdef() {