diff --git a/externals/simplecpp/simplecpp.cpp b/externals/simplecpp/simplecpp.cpp index b20b1f91e..d06480286 100644 --- a/externals/simplecpp/simplecpp.cpp +++ b/externals/simplecpp/simplecpp.cpp @@ -342,6 +342,16 @@ static std::string escapeString(const std::string &str) { return ostr.str(); } +static void portabilityBackslash(simplecpp::OutputList *outputList, const std::vector &files, const simplecpp::Location &location) { + if (!outputList) + return; + simplecpp::Output err(files); + err.type = simplecpp::Output::PORTABILITY_BACKSLASH; + err.location = location; + err.msg = "Combination 'backslash space newline' is not portable."; + outputList->push_back(err); +} + void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filename, OutputList *outputList) { std::stack loc; @@ -363,6 +373,8 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen if (ch == '\n') { if (cback() && cback()->op == '\\') { + if (location.col > cback()->location.col + 1U) + portabilityBackslash(outputList, files, cback()->location); ++multiline; deleteToken(back()); } else { @@ -415,6 +427,9 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen currentToken += ch; ch = readChar(istr, bom); } + const std::string::size_type pos = currentToken.find_last_not_of(" \t"); + if (pos < currentToken.size() - 1U && currentToken[pos] == '\\') + portabilityBackslash(outputList, files, location); if (currentToken[currentToken.size() - 1U] == '\\') { ++multiline; currentToken.erase(currentToken.size() - 1U); @@ -1464,7 +1479,7 @@ private: Token *A = output->back(); if (!A) throw invalidHashHash(tok->location, name()); - if (!sameline(tok, tok->next)) + if (!sameline(tok, tok->next) || !sameline(tok, tok->next->next)) throw invalidHashHash(tok->location, name()); Token *B = tok->next->next; @@ -1820,6 +1835,31 @@ std::map simplecpp::load(const simplecpp::To return ret; } +static bool preprocessToken(simplecpp::TokenList &output, const simplecpp::Token **tok1, std::map ¯os, std::vector &files, simplecpp::OutputList *outputList) { + const simplecpp::Token *tok = *tok1; + const std::map::const_iterator it = macros.find(tok->str); + if (it != macros.end()) { + simplecpp::TokenList value(files); + try { + *tok1 = it->second.expand(&value, tok, macros, files); + } catch (simplecpp::Macro::Error &err) { + simplecpp::Output out(files); + out.type = simplecpp::Output::SYNTAX_ERROR; + out.location = err.location; + out.msg = "failed to expand \'" + tok->str + "\', " + err.what; + if (outputList) + outputList->push_back(out); + return false; + } + output.takeTokens(value); + } else { + if (!tok->comment) + output.push_back(new simplecpp::Token(*tok)); + *tok1 = tok->next; + } + return true; +} + void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenList &rawtokens, std::vector &files, const std::map &filedata, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, std::list *macroUsage) { std::map sizeOfType(rawtokens.sizeOfType); @@ -1930,8 +1970,37 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL } catch (const std::runtime_error &) { } } else if (ifstates.top() == TRUE && rawtok->str == INCLUDE) { - const bool systemheader = (rawtok->next->str[0] == '<'); - const std::string header(realFilename(rawtok->next->str.substr(1U, rawtok->next->str.size() - 2U))); + TokenList inc1(files); + for (const Token *inctok = rawtok->next; sameline(rawtok,inctok); inctok = inctok->next) { + if (!inctok->comment) + inc1.push_back(new Token(*inctok)); + } + TokenList inc2(files); + if (!inc1.empty() && inc1.cfront()->name) { + const Token *inctok = inc1.cfront(); + if (!preprocessToken(inc2, &inctok, macros, files, outputList)) { + output.clear(); + return; + } + } else { + inc2.takeTokens(inc1); + } + + if (inc2.empty()) { + simplecpp::Output err(files); + err.type = Output::SYNTAX_ERROR; + err.location = rawtok->location; + err.msg = "No header in #include"; + if (outputList) + outputList->push_back(err); + output.clear(); + return; + } + + const Token *inctok = inc2.cfront(); + + const bool systemheader = (inctok->op == '<'); + const std::string header(realFilename(inctok->str.substr(1U, inctok->str.size() - 2U))); const std::string header2 = getFileName(filedata, rawtok->location.file(), header, dui, systemheader); if (header2.empty()) { simplecpp::Output output(files); @@ -1996,24 +2065,10 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL continue; } - const std::map::const_iterator it = macros.find(tok->str); - if (it != macros.end()) { - TokenList value(files); - try { - it->second.expand(&value, tok, macros, files); - } catch (Macro::Error &err) { - Output out(rawtok->location.files); - out.type = Output::SYNTAX_ERROR; - out.location = err.location; - out.msg = "failed to expand \'" + tok->str + "\', " + err.what; - if (outputList) - outputList->push_back(out); - output.clear(); - return; - } - expr.takeTokens(value); - } else { - expr.push_back(new Token(*tok)); + const Token *tmp = tok; + if (!preprocessToken(expr, &tmp, macros, files, outputList)) { + output.clear(); + return; } } try { @@ -2081,28 +2136,9 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL const Location loc(rawtok->location); TokenList tokens(files); - if (macros.find(rawtok->str) != macros.end()) { - std::map::const_iterator macro = macros.find(rawtok->str); - if (macro != macros.end()) { - try { - rawtok = macro->second.expand(&tokens, rawtok, macros, files); - } catch (const simplecpp::Macro::Error &err) { - Output out(err.location.files); - out.type = Output::SYNTAX_ERROR; - out.location = err.location; - out.msg = err.what; - if (outputList) - outputList->push_back(out); - output.clear(); - return; - } - } - } - - else { - if (!rawtok->comment) - tokens.push_back(new Token(*rawtok)); - rawtok = rawtok->next; + if (!preprocessToken(tokens, &rawtok, macros, files, outputList)) { + output.clear(); + return; } if (hash || hashhash) { diff --git a/externals/simplecpp/simplecpp.h b/externals/simplecpp/simplecpp.h index 080b40d21..af9e0d077 100644 --- a/externals/simplecpp/simplecpp.h +++ b/externals/simplecpp/simplecpp.h @@ -158,7 +158,8 @@ struct SIMPLECPP_LIB Output { WARNING, /* #warning */ MISSING_HEADER, INCLUDE_NESTED_TOO_DEEPLY, - SYNTAX_ERROR + SYNTAX_ERROR, + PORTABILITY_BACKSLASH } type; Location location; std::string msg; diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 682a2877e..da4cc5278 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -496,6 +496,7 @@ static bool hasErrors(const simplecpp::OutputList &outputList) return true; case simplecpp::Output::WARNING: case simplecpp::Output::MISSING_HEADER: + case simplecpp::Output::PORTABILITY_BACKSLASH: break; }; } @@ -664,6 +665,7 @@ void Preprocessor::reportOutput(const simplecpp::OutputList &outputList, bool sh error(it->location.file(), it->location.line, it->msg); break; case simplecpp::Output::WARNING: + case simplecpp::Output::PORTABILITY_BACKSLASH: break; case simplecpp::Output::MISSING_HEADER: { const std::string::size_type pos1 = it->msg.find_first_of("<\""); diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 76d6a4938..e2169b2c3 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -1510,7 +1510,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); ASSERT_EQUALS("", actual[""]); - ASSERT_EQUALS("[file.c:6]: (error) Wrong number of parameters for macro 'BC'.\n", errout.str()); + ASSERT_EQUALS("[file.c:6]: (error) failed to expand 'BC', Wrong number of parameters for macro 'BC'.\n", errout.str()); } void newline_in_macro() {