From 9820783b60c24f9e1e1692c1f205de98765afdaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 7 Jul 2016 22:58:56 +0200 Subject: [PATCH] Preprocessor: Start replacing our Preprocessor code with simplecpp --- Makefile | 13 +- externals/simplecpp/LICENSE | 166 ++++ externals/simplecpp/simplecpp.cpp | 1172 +++++++++++++++++++++++++++++ externals/simplecpp/simplecpp.h | 219 ++++++ lib/preprocessor.cpp | 144 +++- test/testpreprocessor.cpp | 469 ++++++------ tools/dmake.cpp | 4 +- 7 files changed, 1939 insertions(+), 248 deletions(-) create mode 100644 externals/simplecpp/LICENSE create mode 100644 externals/simplecpp/simplecpp.cpp create mode 100644 externals/simplecpp/simplecpp.h diff --git a/Makefile b/Makefile index c7c654d5a..a79d15283 100644 --- a/Makefile +++ b/Makefile @@ -107,7 +107,7 @@ ifndef PREFIX endif ifndef INCLUDE_FOR_LIB - INCLUDE_FOR_LIB=-Ilib -Iexternals/tinyxml + INCLUDE_FOR_LIB=-Ilib -Iexternals/simplecpp -Iexternals/tinyxml endif ifndef INCLUDE_FOR_CLI @@ -115,7 +115,7 @@ ifndef INCLUDE_FOR_CLI endif ifndef INCLUDE_FOR_TEST - INCLUDE_FOR_TEST=-Ilib -Icli -Iexternals/tinyxml + INCLUDE_FOR_TEST=-Ilib -Icli -Iexternals/simplecpp -Iexternals/tinyxml endif BIN=$(DESTDIR)$(PREFIX)/bin @@ -236,11 +236,17 @@ TESTOBJ = test/options.o \ test/testvalueflow.o \ test/testvarid.o +ifndef SIMPLECPP + SIMPLECPP = externals/simplecpp/simplecpp.o +endif + + ifndef TINYXML TINYXML = externals/tinyxml/tinyxml2.o endif +EXTOBJ += $(SIMPLECPP) EXTOBJ += $(TINYXML) .PHONY: run-dmake @@ -614,6 +620,9 @@ test/testvalueflow.o: test/testvalueflow.cpp lib/cxx11emu.h test/testsuite.h lib test/testvarid.o: test/testvarid.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/token.h lib/valueflow.h lib/mathlib.h lib/settings.h lib/library.h lib/standards.h lib/timer.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testvarid.o test/testvarid.cpp +externals/simplecpp/simplecpp.o: externals/simplecpp/simplecpp.cpp lib/cxx11emu.h externals/simplecpp/simplecpp.h + $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o externals/simplecpp/simplecpp.o externals/simplecpp/simplecpp.cpp + externals/tinyxml/tinyxml2.o: externals/tinyxml/tinyxml2.cpp lib/cxx11emu.h externals/tinyxml/tinyxml2.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o externals/tinyxml/tinyxml2.o externals/tinyxml/tinyxml2.cpp diff --git a/externals/simplecpp/LICENSE b/externals/simplecpp/LICENSE new file mode 100644 index 000000000..341c30bda --- /dev/null +++ b/externals/simplecpp/LICENSE @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/externals/simplecpp/simplecpp.cpp b/externals/simplecpp/simplecpp.cpp new file mode 100644 index 000000000..e7e1d4be0 --- /dev/null +++ b/externals/simplecpp/simplecpp.cpp @@ -0,0 +1,1172 @@ +/* + * simplecpp - A simple and high-fidelity C/C++ preprocessor library + * Copyright (C) 2016 Daniel Marjamäki. + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "simplecpp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +const simplecpp::TokenString DEFINE("define"); +const simplecpp::TokenString ERROR("error"); +const simplecpp::TokenString WARNING("warning"); +const simplecpp::TokenString IF("if"); +const simplecpp::TokenString IFDEF("ifdef"); +const simplecpp::TokenString IFNDEF("ifndef"); +const simplecpp::TokenString DEFINED("defined"); +const simplecpp::TokenString ELSE("else"); +const simplecpp::TokenString ELIF("elif"); +const simplecpp::TokenString ENDIF("endif"); +const simplecpp::TokenString UNDEF("undef"); + +bool sameline(const simplecpp::Token *tok1, const simplecpp::Token *tok2) { + return (tok1 && tok2 && tok1->location.line == tok2->location.line && tok1->location.file == tok2->location.file); +} +} + +void simplecpp::Location::adjust(const std::string &str) { + if (str.find_first_of("\r\n") == std::string::npos) { + col += str.size() - 1U; + return; + } + + for (unsigned int i = 0U; i < str.size(); ++i) { + col++; + if (str[i] == '\n' || str[i] == '\r') { + col = 0; + line++; + if (str[i] == '\r' && (i+1)next) + push_back(new Token(*tok)); +} + +void simplecpp::TokenList::clear() { + while (first) { + Token *next = first->next; + delete first; + first = next; + } + last = nullptr; +} + +void simplecpp::TokenList::push_back(Token *tok) { + if (!first) + first = tok; + else + last->next = tok; + tok->previous = last; + last = tok; +} + +void simplecpp::TokenList::dump() const { + std::cout << stringify(); +} + +std::string simplecpp::TokenList::stringify() const { + std::ostringstream ret; + Location loc; + for (const Token *tok = cbegin(); tok; tok = tok->next) { + while (tok->location.line > loc.line) { + ret << '\n'; + loc.line++; + } + + if (sameline(tok->previous, tok)) + ret << ' '; + + ret << tok->str; + + loc.adjust(tok->str); + } + + return ret.str(); +} + +void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filename, OutputList *outputList) +{ + std::stack loc; + + unsigned int multiline = 0U; + + const Token *oldLastToken = nullptr; + + Location location; + location.file = filename; + location.line = 1U; + location.col = 0U; + while (istr.good()) { + unsigned char ch = (unsigned char)istr.get(); + if (!istr.good()) + break; + location.col++; + + if (ch == '\r' || ch == '\n') { + if (ch == '\r' && istr.peek() == '\n') + istr.get(); + if (cend() && cend()->op == '\\') { + ++multiline; + deleteToken(end()); + } else { + location.line += multiline + 1; + multiline = 0U; + } + location.col = 0; + + if (oldLastToken != cend()) { + oldLastToken = cend(); + const std::string lastline(lastLine()); + + if (lastline == "# file %str%") { + loc.push(location); + location.file = cend()->str.substr(1U, cend()->str.size() - 2U); + location.line = 1U; + } + + // #endfile + else if (lastline == "# endfile" && !loc.empty()) { + location = loc.top(); + loc.pop(); + } + } + + continue; + } + + if (std::isspace(ch)) + continue; + + TokenString currentToken; + + // number or name + if (std::isalnum(ch) || ch == '_') { + while (istr.good() && (std::isalnum(ch) || ch == '_')) { + currentToken += ch; + ch = (unsigned char)istr.get(); + } + istr.unget(); + } + + // comment + else if (ch == '/' && istr.peek() == '/') { + while (istr.good() && ch != '\r' && ch != '\n') { + currentToken += ch; + ch = (unsigned char)istr.get(); + } + istr.unget(); + } + + // comment + else if (ch == '/' && istr.peek() == '*') { + currentToken = "/*"; + (void)istr.get(); + ch = (unsigned char)istr.get(); + while (istr.good()) { + currentToken += ch; + if (currentToken.size() >= 4U && currentToken.substr(currentToken.size() - 2U) == "*/") + break; + ch = (unsigned char)istr.get(); + } + } + + // string / char literal + else if (ch == '\"' || ch == '\'') { + do { + currentToken += ch; + ch = (unsigned char)istr.get(); + if (istr.good() && ch == '\\') { + currentToken += ch; + ch = (unsigned char)istr.get(); + currentToken += ch; + ch = (unsigned char)istr.get(); + } else if (istr.good() && (ch == '\r' || ch == '\n')) { + clear(); + if (outputList) { + Output err; + err.type = Output::ERROR; + err.location = location; + err.msg = std::string("No pair for character (") + currentToken[0] + "). Can't process file. File is either invalid or unicode, which is currently not supported."; + outputList->push_back(err); + } + return; + } + } while (istr.good() && ch != '\"' && ch != '\''); + currentToken += ch; + } + + else { + currentToken += ch; + } + + push_back(new Token(currentToken, location)); + location.adjust(currentToken); + } + + combineOperators(); +} + +void simplecpp::TokenList::constFold() { + while (begin()) { + // goto last '(' + Token *tok = end(); + while (tok && tok->op != '(') + tok = tok->previous; + + // no '(', goto first token + if (!tok) + tok = begin(); + + // Constant fold expression + constFoldUnaryNotPosNeg(tok); + constFoldMulDivRem(tok); + constFoldAddSub(tok); + constFoldComparison(tok); + constFoldBitwise(tok); + constFoldLogicalOp(tok); + constFoldQuestionOp(&tok); + + // If there is no '(' we are done with the constant folding + if (tok->op != '(') + break; + + if (!tok->next || !tok->next->next || tok->next->next->op != ')') + break; + + tok = tok->next; + deleteToken(tok->previous); + deleteToken(tok->next); + } +} + +void simplecpp::TokenList::combineOperators() { + for (Token *tok = begin(); tok; tok = tok->next) { + if (tok->op == '.') { + // float literals.. + if (tok->previous && tok->previous->number) { + tok->setstr(tok->previous->str + '.'); + deleteToken(tok->previous); + if (tok->next && tok->next->startsWithOneOf("Ee")) { + tok->setstr(tok->str + tok->next->str); + deleteToken(tok->next); + } + } + if (tok->next && tok->next->number) { + tok->setstr(tok->str + tok->next->str); + deleteToken(tok->next); + } + } + // match: [0-9.]+E [+-] [0-9]+ + if (tok->number && (tok->str.back() == 'E' || tok->str.back() == 'e') && tok->next && tok->next->isOneOf("+-") && tok->next->next && tok->next->next->number) { + tok->setstr(tok->str + tok->next->op + tok->next->next->str); + deleteToken(tok->next); + deleteToken(tok->next); + } + + if (tok->op == '\0' || !tok->next || tok->next->op == '\0') + continue; + if (tok->next->op == '=' && tok->isOneOf("=!<>+-*/%&|^")) { + tok->setstr(tok->str + "="); + deleteToken(tok->next); + } else if ((tok->op == '|' || tok->op == '&') && tok->op == tok->next->op) { + tok->setstr(tok->str + tok->next->str); + deleteToken(tok->next); + } else if (tok->op == ':' && tok->next->op == ':') { + tok->setstr(tok->str + tok->next->str); + deleteToken(tok->next); + } else if (tok->op == '-' && tok->next->op == '>') { + tok->setstr(tok->str + tok->next->str); + deleteToken(tok->next); + } else if ((tok->op == '<' || tok->op == '>') && tok->op == tok->next->op) { + tok->setstr(tok->str + tok->next->str); + deleteToken(tok->next); + if (tok->next && tok->next->op == '=') { + tok->setstr(tok->str + tok->next->str); + deleteToken(tok->next); + } + } else if ((tok->op == '+' || tok->op == '-') && tok->op == tok->next->op) { + if (tok->location.col + 1U != tok->next->location.col) + continue; + if (tok->previous && tok->previous->number) + continue; + if (tok->next->next && tok->next->next->number) + continue; + tok->setstr(tok->str + tok->next->str); + deleteToken(tok->next); + } + } +} + +void simplecpp::TokenList::constFoldUnaryNotPosNeg(simplecpp::Token *tok) { + for (; tok && tok->op != ')'; tok = tok->next) { + if (tok->op == '!' && tok->next && tok->next->number) { + tok->setstr(tok->next->str == "0" ? "1" : "0"); + deleteToken(tok->next); + } + else { + if (tok->previous && (tok->previous->number || tok->previous->name)) + continue; + if (!tok->next || !tok->next->number) + continue; + switch (tok->op) { + case '+': + tok->setstr(tok->next->str); + deleteToken(tok->next); + break; + case '-': + tok->setstr(tok->op + tok->next->str); + deleteToken(tok->next); + break; + } + } + } +} + +void simplecpp::TokenList::constFoldMulDivRem(Token *tok) { + for (; tok && tok->op != ')'; tok = tok->next) { + if (!tok->previous || !tok->previous->number) + continue; + if (!tok->next || !tok->next->number) + continue; + + long long result; + if (tok->op == '*') + result = (std::stoll(tok->previous->str) * std::stoll(tok->next->str)); + else if (tok->op == '/') + result = (std::stoll(tok->previous->str) / std::stoll(tok->next->str)); + else if (tok->op == '%') + result = (std::stoll(tok->previous->str) % std::stoll(tok->next->str)); + else + continue; + + tok = tok->previous; + tok->setstr(std::to_string(result)); + deleteToken(tok->next); + deleteToken(tok->next); + } +} + +void simplecpp::TokenList::constFoldAddSub(Token *tok) { + for (; tok && tok->op != ')'; tok = tok->next) { + if (!tok->previous || !tok->previous->number) + continue; + if (!tok->next || !tok->next->number) + continue; + + long long result; + if (tok->op == '+') + result = (std::stoll(tok->previous->str) + std::stoll(tok->next->str)); + else if (tok->op == '-') + result = (std::stoll(tok->previous->str) - std::stoll(tok->next->str)); + else + continue; + + tok = tok->previous; + tok->setstr(std::to_string(result)); + deleteToken(tok->next); + deleteToken(tok->next); + } +} + +void simplecpp::TokenList::constFoldComparison(Token *tok) { + for (; tok && tok->op != ')'; tok = tok->next) { + if (!tok->startsWithOneOf("<>=!")) + continue; + if (!tok->previous || !tok->previous->number) + continue; + if (!tok->next || !tok->next->number) + continue; + + int result; + if (tok->str == "==") + result = (std::stoll(tok->previous->str) == std::stoll(tok->next->str)); + else if (tok->str == "!=") + result = (std::stoll(tok->previous->str) != std::stoll(tok->next->str)); + else if (tok->str == ">") + result = (std::stoll(tok->previous->str) > std::stoll(tok->next->str)); + else if (tok->str == ">=") + result = (std::stoll(tok->previous->str) >= std::stoll(tok->next->str)); + else if (tok->str == "<") + result = (std::stoll(tok->previous->str) < std::stoll(tok->next->str)); + else if (tok->str == "<=") + result = (std::stoll(tok->previous->str) <= std::stoll(tok->next->str)); + else + continue; + + tok = tok->previous; + tok->setstr(std::to_string(result)); + deleteToken(tok->next); + deleteToken(tok->next); + } +} + +void simplecpp::TokenList::constFoldBitwise(Token *tok) +{ + Token * const tok1 = tok; + for (const char *op = "&^|"; *op; op++) { + for (tok = tok1; tok && tok->op != ')'; tok = tok->next) { + if (tok->op != *op) + continue; + if (!tok->previous || !tok->previous->number) + continue; + if (!tok->next || !tok->next->number) + continue; + long long result; + if (tok->op == '&') + result = (std::stoll(tok->previous->str) & std::stoll(tok->next->str)); + else if (tok->op == '^') + result = (std::stoll(tok->previous->str) ^ std::stoll(tok->next->str)); + else if (tok->op == '|') + result = (std::stoll(tok->previous->str) | std::stoll(tok->next->str)); + tok = tok->previous; + tok->setstr(std::to_string(result)); + deleteToken(tok->next); + deleteToken(tok->next); + } + } +} + +void simplecpp::TokenList::constFoldLogicalOp(Token *tok) { + for (; tok && tok->op != ')'; tok = tok->next) { + if (tok->str != "&&" && tok->str != "||") + continue; + if (!tok->previous || !tok->previous->number) + continue; + if (!tok->next || !tok->next->number) + continue; + + int result; + if (tok->str == "||") + result = (std::stoll(tok->previous->str) || std::stoll(tok->next->str)); + else if (tok->str == "&&") + result = (std::stoll(tok->previous->str) && std::stoll(tok->next->str)); + else + continue; + + tok = tok->previous; + tok->setstr(std::to_string(result)); + deleteToken(tok->next); + deleteToken(tok->next); + } +} + +void simplecpp::TokenList::constFoldQuestionOp(Token **tok1) { + bool gotoTok1 = false; + for (Token *tok = *tok1; tok && tok->op != ')'; tok = gotoTok1 ? *tok1 : tok->next) { + gotoTok1 = false; + if (tok->str != "?") + continue; + if (!tok->previous || !tok->previous->number) + continue; + if (!tok->next) + continue; + if (!tok->next->next || tok->next->next->op != ':') + continue; + Token * const condTok = tok->previous; + Token * const trueTok = tok->next; + Token * const falseTok = trueTok->next->next; + if (condTok == *tok1) + *tok1 = (condTok->str != "0" ? trueTok : falseTok); + deleteToken(condTok->next); // ? + deleteToken(trueTok->next); // : + deleteToken(condTok->str == "0" ? trueTok : falseTok); + deleteToken(condTok); + gotoTok1 = true; + } +} + +std::string simplecpp::TokenList::lastLine() const { + std::string ret; + for (const Token *tok = cend(); sameline(tok,cend()); tok = tok->previous) { + if (tok->comment) + continue; + if (!ret.empty()) + ret = ' ' + ret; + ret = (tok->str[0] == '\"' ? std::string("%str%") : tok->str) + ret; + } + return ret; +} + +namespace simplecpp { +class Macro { +public: + Macro() : nameToken(nullptr) {} + + explicit Macro(const Token *tok) : nameToken(nullptr) { + if (sameline(tok->previous, tok)) + throw std::runtime_error("bad macro syntax"); + if (tok->op != '#') + throw std::runtime_error("bad macro syntax"); + tok = tok->next; + if (!tok || tok->str != DEFINE) + throw std::runtime_error("bad macro syntax"); + tok = tok->next; + if (!tok || !tok->name) + throw std::runtime_error("bad macro syntax"); + parseDefine(tok); + } + + explicit Macro(const std::string &name, const std::string &value) : nameToken(nullptr) { + const std::string def(name + ' ' + value); + std::istringstream istr(def); + tokenListDefine.readfile(istr); + parseDefine(tokenListDefine.cbegin()); + } + + Macro(const Macro ¯o) { + *this = macro; + } + + void operator=(const Macro ¯o) { + if (this != ¯o) { + if (macro.tokenListDefine.empty()) + parseDefine(macro.nameToken); + else { + tokenListDefine = macro.tokenListDefine; + parseDefine(tokenListDefine.cbegin()); + } + } + } + + const Token * expand(TokenList * const output, const Location &loc, const Token * const nameToken, const std::map ¯os, std::set expandedmacros) const { + const std::set expandedmacros1(expandedmacros); + expandedmacros.insert(nameToken->str); + + usageList.push_back(loc); + + if (!functionLike()) { + Token * const token1 = output->end(); + for (const Token *macro = valueToken; macro != endToken;) { + const std::map::const_iterator it = macros.find(macro->str); + if (it != macros.end() && expandedmacros.find(macro->str) == expandedmacros.end()) { + try { + const Token *macro2 = it->second.expand(output, loc, macro, macros, expandedmacros); + while (macro != macro2 && macro != endToken) + macro = macro->next; + } catch (const wrongNumberOfParameters &) { + if (sameline(macro,macro->next) && macro->next->op == '(') { + unsigned int par = 1U; + for (const Token *tok = macro->next->next; sameline(macro,tok); tok = tok->next) { + if (tok->op == '(') + ++par; + else if (tok->op == ')') { + --par; + if (par == 0U) + break; + } + } + if (par > 0U) { + TokenList tokens; + const Token *tok; + for (tok = macro; sameline(macro,tok); tok = tok->next) + tokens.push_back(new Token(*tok)); + for (tok = nameToken->next; tok; tok = tok->next) { + tokens.push_back(new Token(tok->str, macro->location)); + if (tok->op == '(') + ++par; + else if (tok->op == ')') { + --par; + if (par == 0U) + break; + } + } + if (par == 0U) { + it->second.expand(output, loc, tokens.cbegin(), macros, expandedmacros); + return tok->next; + } + } + } else { + output->push_back(newMacroToken(macro->str, loc, false)); + macro = macro->next; + } + } + } else { + output->push_back(newMacroToken(macro->str, loc, false)); + macro = macro->next; + } + } + setMacroName(output, token1, expandedmacros1); + return nameToken->next; + } + + // Parse macro-call + const std::vector parametertokens(getMacroParameters(nameToken, !expandedmacros1.empty())); + if (parametertokens.size() != args.size() + (args.empty() ? 2U : 1U)) { + throw wrongNumberOfParameters(nameToken->location, name()); + } + + // expand + for (const Token *tok = valueToken; tok != endToken;) { + if (tok->op != '#') { + // A##B => AB + if (tok->next && tok->next->op == '#' && tok->next->next && tok->next->next->op == '#') { + output->push_back(newMacroToken(expandArgStr(tok, parametertokens), loc, !expandedmacros1.empty())); + tok = tok->next; + } else { + tok = expandToken(output, loc, tok, macros, expandedmacros1, expandedmacros, parametertokens); + } + continue; + } + + tok = tok->next; + if (tok->op == '#') { + // A##B => AB + Token *A = output->end(); + if (!A) + throw invalidHashHash(tok->location, name()); + if (!sameline(tok, tok->next)) + throw invalidHashHash(tok->location, name()); + + const std::string strAB = A->str + expandArgStr(tok->next, parametertokens); + tok = tok->next->next; + + output->deleteToken(A); + + TokenList tokens; + tokens.push_back(new Token(strAB, tok->location)); + // TODO: For functionLike macros, push the (...) + + expandToken(output, loc, tokens.cbegin(), macros, expandedmacros1, expandedmacros, parametertokens); + } else { + // #123 => "123" + TokenList tokenListHash; + tok = expandToken(&tokenListHash, loc, tok, macros, expandedmacros1, expandedmacros, parametertokens); + std::string s; + for (const Token *hashtok = tokenListHash.cbegin(); hashtok; hashtok = hashtok->next) + s += hashtok->str; + output->push_back(newMacroToken('\"' + s + '\"', loc, expandedmacros1.empty())); + } + } + + return parametertokens.back()->next; + } + + const TokenString &name() const { + return nameToken->str; + } + + const Location &defineLocation() const { + return nameToken->location; + } + + const std::list &usage() const { + return usageList; + } + + struct Error { + Error(const Location &loc, const std::string &s) : location(loc), what(s) {} + Location location; + std::string what; + }; + + struct wrongNumberOfParameters : public Error { + wrongNumberOfParameters(const Location &loc, const std::string ¯oName) : Error(loc, "Syntax error. Wrong number of parameters for macro \'" + macroName + "\'.") {} + }; + + struct invalidHashHash : public Error { + invalidHashHash(const Location &loc, const std::string ¯oName) : Error(loc, "Syntax error. Invalid ## usage when expanding \'" + macroName + "\'.") {} + }; +private: + Token *newMacroToken(const TokenString &str, const Location &loc, bool rawCode) const { + Token *tok = new Token(str,loc); + if (!rawCode) + tok->macro = nameToken->str; + return tok; + } + + void setMacroName(TokenList *output, Token *token1, const std::set &expandedmacros1) const { + if (!expandedmacros1.empty()) + return; + for (Token *tok = token1 ? token1->next : output->begin(); tok; tok = tok->next) { + if (!tok->macro.empty()) + tok->macro = nameToken->str; + } + } + + void parseDefine(const Token *nametoken) { + nameToken = nametoken; + variadic = false; + if (!nameToken) { + valueToken = endToken = nullptr; + args.clear(); + return; + } + + // function like macro.. + if (functionLike()) { + args.clear(); + const Token *argtok = nameToken->next->next; + while (argtok && argtok->op != ')') { + if (argtok->op == '.' && + argtok->next && argtok->next->op == '.' && + argtok->next->next && argtok->next->next->op == '.' && + argtok->next->next->next && argtok->next->next->next->op == ')') { + variadic = true; + if (!argtok->previous->name) + args.push_back("__VA_ARGS__"); + argtok = argtok->next->next->next; // goto ')' + break; + } + if (argtok->op != ',') + args.push_back(argtok->str); + argtok = argtok->next; + } + valueToken = argtok->next; + } else { + args.clear(); + valueToken = nameToken->next; + } + + if (!sameline(valueToken, nameToken)) + valueToken = nullptr; + endToken = valueToken; + while (sameline(endToken, nameToken)) + endToken = endToken->next; + } + + unsigned int getArgNum(const TokenString &str) const { + unsigned int par = 0; + while (par < args.size()) { + if (str == args[par]) + return par; + par++; + } + return ~0U; + } + + std::vector getMacroParameters(const Token *nameToken, bool def) const { + if (!nameToken->next || nameToken->next->op != '(') + return std::vector(); + + std::vector parametertokens; + parametertokens.push_back(nameToken->next); + unsigned int par = 0U; + for (const Token *tok = nameToken->next->next; def ? sameline(tok,nameToken) : (tok != nullptr); tok = tok->next) { + if (tok->op == '(') + ++par; + else if (tok->op == ')') { + if (par == 0U) { + parametertokens.push_back(tok); + break; + } + --par; + } + else if (par == 0U && tok->op == ',' && (!variadic || parametertokens.size() < args.size())) + parametertokens.push_back(tok); + } + return parametertokens; + } + + const Token *expandToken(TokenList *output, const Location &loc, const Token *tok, const std::map ¯os, std::set expandedmacros1, std::set expandedmacros, const std::vector ¶metertokens) const { + // Not name.. + if (!tok->name) { + output->push_back(newMacroToken(tok->str, loc, false)); + return tok->next; + } + + // Macro parameter.. + if (expandArg(output, tok, loc, macros, expandedmacros1, expandedmacros, parametertokens)) + return tok->next; + + // Macro.. + const std::map::const_iterator it = macros.find(tok->str); + if (it != macros.end() && expandedmacros1.find(tok->str) == expandedmacros1.end()) { + const Macro &calledMacro = it->second; + if (!calledMacro.functionLike()) + return calledMacro.expand(output, loc, tok, macros, expandedmacros); + if (!sameline(tok, tok->next) || tok->next->op != '(') { + // FIXME: handle this + throw wrongNumberOfParameters(tok->location, tok->str); + } + TokenList tokens; + tokens.push_back(new Token(*tok)); + unsigned int par = 0; + const Token *tok2 = tok->next; + while (sameline(tok,tok2)) { + if (!expandArg(&tokens, tok2, tok2->location, macros, expandedmacros1, expandedmacros, parametertokens)) + tokens.push_back(new Token(*tok2)); + if (tok2->op == '(') + ++par; + else if (tok2->op == ')') { + --par; + if (par == 0U) + break; + } + tok2 = tok2->next; + } + calledMacro.expand(output, loc, tokens.cbegin(), macros, expandedmacros); + return tok2->next; + } + + output->push_back(newMacroToken(tok->str, loc, false)); + return tok->next; + } + + bool expandArg(TokenList *output, const Token *tok, const std::vector ¶metertokens) const { + if (!tok->name) + return false; + + const unsigned int argnr = getArgNum(tok->str); + if (argnr >= args.size()) + return false; + + for (const Token *partok = parametertokens[argnr]->next; partok != parametertokens[argnr + 1U]; partok = partok->next) + output->push_back(new Token(*partok)); + + return true; + } + + bool expandArg(TokenList *output, const Token *tok, const Location &loc, const std::map ¯os, std::set expandedmacros1, std::set expandedmacros, const std::vector ¶metertokens) const { + if (!tok->name) + return false; + const unsigned int argnr = getArgNum(tok->str); + if (argnr >= args.size()) + return false; + + for (const Token *partok = parametertokens[argnr]->next; partok != parametertokens[argnr + 1U];) { + const std::map::const_iterator it = macros.find(partok->str); + if (it != macros.end() && expandedmacros1.find(partok->str) == expandedmacros1.end()) + partok = it->second.expand(output, loc, partok, macros, expandedmacros); + else { + output->push_back(newMacroToken(partok->str, loc, expandedmacros1.empty())); + partok = partok->next; + } + } + return true; + } + + std::string expandArgStr(const Token *tok, const std::vector ¶metertokens) const { + TokenList tokens; + if (expandArg(&tokens, tok, parametertokens)) { + std::string s; + for (const Token *tok2 = tokens.cbegin(); tok2; tok2 = tok2->next) + s += tok2->str; + return s; + } + return tok->str; + } + + void setMacro(Token *tok) const { + while (tok) { + if (!tok->macro.empty()) + tok->macro = nameToken->str; + tok = tok->next; + } + } + + bool functionLike() const { + return nameToken->next && + nameToken->next->op == '(' && + sameline(nameToken, nameToken->next) && + nameToken->next->location.col == nameToken->location.col + nameToken->str.size(); + } + + const Token *nameToken; + std::vector args; + bool variadic; + const Token *valueToken; + const Token *endToken; + TokenList tokenListDefine; + mutable std::list usageList; +}; +} + +namespace { +void simplifySizeof(simplecpp::TokenList &expr) { + for (simplecpp::Token *tok = expr.begin(); tok; tok = tok->next) { + if (tok->str != "sizeof") + continue; + simplecpp::Token *tok1 = tok->next; + simplecpp::Token *tok2 = tok1->next; + if (tok1->op == '(') { + while (tok2->op != ')') + tok2 = tok2->next; + tok2 = tok2->next; + } + + unsigned int sz = 0; + for (simplecpp::Token *typeToken = tok1; typeToken != tok2; typeToken = typeToken->next) { + if (typeToken->str == "char") + sz = sizeof(char); + if (typeToken->str == "short") + sz = sizeof(short); + if (typeToken->str == "int") + sz = sizeof(int); + if (typeToken->str == "long") + sz = sizeof(long); + if (typeToken->str == "float") + sz = sizeof(float); + if (typeToken->str == "double") + sz = sizeof(double); + } + + tok->setstr(std::to_string(sz)); + + while (tok->next != tok2) + expr.deleteToken(tok->next); + } +} + +void simplifyName(simplecpp::TokenList &expr) { + for (simplecpp::Token *tok = expr.begin(); tok; tok = tok->next) { + if (tok->name) + tok->setstr("0"); + } +} + +void simplifyNumbers(simplecpp::TokenList &expr) { + for (simplecpp::Token *tok = expr.begin(); tok; tok = tok->next) { + if (tok->str.size() == 1U) + continue; + if (tok->str.compare(0,2,"0x") == 0) + tok->setstr(std::to_string(std::stoll(tok->str.substr(2), nullptr, 16))); + else if (tok->str[0] == '\'') + tok->setstr(std::to_string((unsigned char)tok->str[1])); + } +} + +int evaluate(simplecpp::TokenList expr) { + simplifySizeof(expr); + simplifyName(expr); + simplifyNumbers(expr); + expr.constFold(); + // TODO: handle invalid expressions + return expr.cbegin() && expr.cbegin() == expr.cend() && expr.cbegin()->number ? std::stoi(expr.cbegin()->str) : 0; +} + +const simplecpp::Token *gotoNextLine(const simplecpp::Token *tok) { + const unsigned int line = tok->location.line; + const std::string &file = tok->location.file; + while (tok && tok->location.line == line && tok->location.file == file) + tok = tok->next; + return tok; +} +} + +simplecpp::TokenList simplecpp::preprocess(const simplecpp::TokenList &rawtokens, const Defines &defines, OutputList *outputList, std::list *macroUsage) +{ + std::map macros; + for (std::map::const_iterator it = defines.begin(); it != defines.end(); ++it) { + const Macro macro(it->first, it->second.empty() ? std::string("1") : it->second); + macros[macro.name()] = macro; + } + + // TRUE => code in current #if block should be kept + // ELSE_IS_TRUE => code in current #if block should be dropped. the code in the #else should be kept. + // ALWAYS_FALSE => drop all code in #if and #else + enum IfState { TRUE, ELSE_IS_TRUE, ALWAYS_FALSE }; + std::stack ifstates; + ifstates.push(TRUE); + + TokenList output; + for (const Token *rawtok = rawtokens.cbegin(); rawtok;) { + if (rawtok->op == '#' && !sameline(rawtok->previous, rawtok)) { + rawtok = rawtok->next; + if (!rawtok || !rawtok->name) + continue; + + if (ifstates.top() == TRUE && (rawtok->str == ERROR || rawtok->str == WARNING)) { + if (outputList) { + simplecpp::Output err; + err.type = rawtok->str == ERROR ? Output::ERROR : Output::WARNING; + err.location = rawtok->location; + for (const Token *tok = rawtok->next; tok && sameline(rawtok,tok); tok = tok->next) { + if (!err.msg.empty() && std::isalnum(tok->str[0])) + err.msg += ' '; + err.msg += tok->str; + } + err.msg = '#' + rawtok->str + ' ' + err.msg; + outputList->push_back(err); + } + return TokenList(); + } + + if (rawtok->str == DEFINE) { + if (ifstates.top() != TRUE) + continue; + try { + const Macro ¯o = Macro(rawtok->previous); + macros[macro.name()] = macro; + } catch (const std::runtime_error &) { + } + } else if (rawtok->str == IF || rawtok->str == IFDEF || rawtok->str == IFNDEF || rawtok->str == ELIF) { + bool conditionIsTrue; + if (ifstates.top() == ALWAYS_FALSE) + conditionIsTrue = false; + else if (rawtok->str == IFDEF) + conditionIsTrue = (macros.find(rawtok->next->str) != macros.end()); + else if (rawtok->str == IFNDEF) + conditionIsTrue = (macros.find(rawtok->next->str) == macros.end()); + else if (rawtok->str == IF || rawtok->str == ELIF) { + TokenList expr; + const Token * const endToken = gotoNextLine(rawtok); + for (const Token *tok = rawtok->next; tok != endToken; tok = tok->next) { + if (!tok->name) { + expr.push_back(new Token(*tok)); + continue; + } + + if (tok->str == DEFINED) { + tok = tok->next; + const bool par = (tok && tok->op == '('); + if (par) + tok = tok->next; + if (!tok) + break; + if (macros.find(tok->str) != macros.end()) + expr.push_back(new Token("1", tok->location)); + else + expr.push_back(new Token("0", tok->location)); + if (tok && par) + tok = tok->next; + continue; + } + + const std::map::const_iterator it = macros.find(tok->str); + if (it != macros.end()) { + TokenList value; + std::set expandedmacros; + it->second.expand(&value, tok->location, tok, macros, expandedmacros); + for (const Token *tok2 = value.cbegin(); tok2; tok2 = tok2->next) + expr.push_back(new Token(tok2->str, tok->location)); + } else { + expr.push_back(new Token(*tok)); + } + } + conditionIsTrue = (evaluate(expr) != 0); + } + + if (rawtok->str != ELIF) { + // push a new ifstate.. + if (ifstates.top() != TRUE) + ifstates.push(ALWAYS_FALSE); + else + ifstates.push(conditionIsTrue ? TRUE : ELSE_IS_TRUE); + } else if (ifstates.top() == TRUE) { + ifstates.top() = ALWAYS_FALSE; + } else if (ifstates.top() == ELSE_IS_TRUE && conditionIsTrue) { + ifstates.top() = TRUE; + } + } else if (rawtok->str == ELSE) { + ifstates.top() = (ifstates.top() == ELSE_IS_TRUE) ? TRUE : ALWAYS_FALSE; + } else if (rawtok->str == ENDIF) { + if (ifstates.size() > 1U) + ifstates.pop(); + } else if (rawtok->str == UNDEF) { + if (ifstates.top() == TRUE) { + const Token *tok = rawtok->next; + while (sameline(rawtok,tok) && tok->comment) + tok = tok->next; + if (sameline(rawtok, tok)) + macros.erase(tok->str); + } + } + rawtok = gotoNextLine(rawtok); + if (!rawtok) + break; + continue; + } + + if (ifstates.top() != TRUE) { + // drop code + rawtok = gotoNextLine(rawtok); + continue; + } + + if (macros.find(rawtok->str) != macros.end()) { + std::map::const_iterator macro = macros.find(rawtok->str); + if (macro != macros.end()) { + std::set expandedmacros; + try { + rawtok = macro->second.expand(&output,rawtok->location,rawtok,macros,expandedmacros); + } catch (const simplecpp::Macro::Error &err) { + Output out; + out.type = Output::ERROR; + out.location = err.location; + out.msg = err.what; + if (outputList) + outputList->push_back(out); + return TokenList(); + } + continue; + } + } + + if (!rawtok->comment) + output.push_back(new Token(*rawtok)); + rawtok = rawtok->next; + } + + if (macroUsage) { + for (std::map::const_iterator macroIt = macros.begin(); macroIt != macros.end(); ++macroIt) { + const Macro ¯o = macroIt->second; + const std::list &usage = macro.usage(); + for (std::list::const_iterator usageIt = usage.begin(); usageIt != usage.end(); ++usageIt) { + struct MacroUsage mu; + mu.macroName = macro.name(); + mu.macroLocation = macro.defineLocation(); + mu.useLocation = *usageIt; + macroUsage->push_back(mu); + } + } + } + + return output; +} diff --git a/externals/simplecpp/simplecpp.h b/externals/simplecpp/simplecpp.h new file mode 100644 index 000000000..193e6ed68 --- /dev/null +++ b/externals/simplecpp/simplecpp.h @@ -0,0 +1,219 @@ +/* + * simplecpp - A simple and high-fidelity C/C++ preprocessor library + * Copyright (C) 2016 Daniel Marjamäki. + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef simplecppH +#define simplecppH + +#include +#include +#include +#include +#include + +namespace simplecpp { + +typedef std::string TokenString; + +/** + * Location in source code + */ +class Location { +public: + Location() : line(1U), col(0U) {} + + std::string file; + unsigned int line; + unsigned int col; + + Location &operator=(const Location &other) { + if (this != &other) { + file = other.file; + line = other.line; + col = other.col; + } + return *this; + } + + /** increment this location by string */ + void adjust(const std::string &str); + + bool operator<(const Location &rhs) const { + if (file != rhs.file) + return file < rhs.file; + if (line != rhs.line) + return line < rhs.line; + return col < rhs.col; + } +}; + +/** + * token class. + * @todo don't use std::string representation - for both memory and performance reasons + */ +class Token { +public: + Token(const TokenString &s, const Location &location) : + str(string), location(location), previous(nullptr), next(nullptr), string(s) + { + flags(); + } + + Token(const Token &tok) : + str(string), macro(tok.macro), location(tok.location), previous(nullptr), next(nullptr), string(tok.str) + { + flags(); + } + + void flags() { + name = (str[0] == '_' || std::isalpha(str[0])); + comment = (str.compare(0, 2, "//") == 0 || str.compare(0, 2, "/*") == 0); + number = std::isdigit(str[0]) || (str.size() > 1U && str[0] == '-' && std::isdigit(str[1])); + op = (str.size() == 1U) ? str[0] : '\0'; + } + + void setstr(const std::string &s) { + string = s; + flags(); + } + + bool isOneOf(const char ops[]) const; + bool startsWithOneOf(const char c[]) const; + bool endsWithOneOf(const char c[]) const; + + char op; + const TokenString &str; + TokenString macro; + bool comment; + bool name; + bool number; + Location location; + Token *previous; + Token *next; +private: + TokenString string; +}; + +/** Output from preprocessor */ +struct Output { + enum Type { + ERROR, /* error */ + WARNING /* warning */ + } type; + Location location; + std::string msg; +}; + +typedef std::list OutputList; + +/** List of tokens. */ +class TokenList { +public: + TokenList(); + TokenList(std::istringstream &istr, const std::string &filename=std::string(), OutputList *outputList = 0); + TokenList(const TokenList &other); + ~TokenList(); + void operator=(const TokenList &other); + + void clear(); + bool empty() const { + return !cbegin(); + } + void push_back(Token *token); + + void dump() const; + std::string stringify() const; + + void readfile(std::istream &istr, const std::string &filename=std::string(), OutputList *outputList = 0); + void constFold(); + + Token *begin() { + return first; + } + + const Token *cbegin() const { + return first; + } + + Token *end() { + return last; + } + + const Token *cend() const { + return last; + } + + void deleteToken(Token *tok) { + if (!tok) + return; + Token *prev = tok->previous; + Token *next = tok->next; + if (prev) + prev->next = next; + if (next) + next->previous = prev; + if (first == tok) + first = next; + if (last == tok) + last = prev; + delete tok; + } + +private: + void combineOperators(); + + void constFoldUnaryNotPosNeg(Token *tok); + void constFoldMulDivRem(Token *tok); + void constFoldAddSub(Token *tok); + void constFoldComparison(Token *tok); + void constFoldBitwise(Token *tok); + void constFoldLogicalOp(Token *tok); + void constFoldQuestionOp(Token **tok); + + std::string lastLine() const; + + Token *first; + Token *last; +}; + +/** Tracking how macros are used */ +struct MacroUsage { + std::string macroName; + Location macroLocation; + Location useLocation; +}; + +typedef std::map Defines; + +/** + * Preprocess + * + * Preprocessing is done in two steps currently: + * const simplecpp::TokenList tokens1 = simplecpp::TokenList(f); + * const simplecpp::TokenList tokens2 = simplecpp::preprocess(tokens1, defines); + * + * The "tokens1" will contain tokens for comments and for preprocessor directives. And there is no preprocessing done. + * This "tokens1" can be used if you need to see what comments/directives there are. Or what code is hidden in #if. + * + * The "tokens2" will have normal preprocessor output. No comments nor directives are seen. + * + * @todo simplify interface + */ +TokenList preprocess(const TokenList &rawtokens, const Defines &defines, OutputList *outputList = 0, std::list *macroUsage = 0); +} + +#endif diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index d9082e4d8..77a4412c4 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -23,6 +23,7 @@ #include "path.h" #include "errorlogger.h" #include "settings.h" +#include "simplecpp.h" #include #include @@ -1019,7 +1020,6 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe forcedIncludes += "#file \"" + cur + "\"\n" + - "#line 1\n" + fileData + "\n" + "#endfile\n" ; @@ -1035,7 +1035,6 @@ void Preprocessor::preprocess(std::istream &srcCodeStream, std::string &processe processedFile = forcedIncludes + "#file \"" + filename + "\"\n" + - "#line 1\n" + processedFile + "#endfile\n" ; @@ -1793,6 +1792,145 @@ bool Preprocessor::match_cfg_def(std::map cfg, std::st std::string Preprocessor::getcode(const std::string &filedata, const std::string &cfg, const std::string &filename) { + if (_settings.userUndefs.empty()) { + // Create a map for the cfg for faster access to defines + const std::map defines(getcfgmap(cfg, &_settings, Path::simplifyPath(filename))); + + simplecpp::OutputList outputList; + std::list macroUsage; + + std::istringstream istr(filedata); + const simplecpp::TokenList &tokens1 = simplecpp::TokenList(istr, Path::simplifyPath(filename), &outputList); + const simplecpp::TokenList &tokens2 = simplecpp::preprocess(tokens1, defines, &outputList, ¯oUsage); + + if (!_settings.force) { + for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) { + if (it->type == simplecpp::Output::ERROR) { + error(it->location.file, it->location.line, it->msg); + return ""; + } + } + } + + // directive list.. + directives.clear(); + for (const simplecpp::Token *tok = tokens1.cbegin(); tok; tok = tok ? tok->next : nullptr) { + if ((tok->op != '#') || (tok->previous && tok->previous->location.line == tok->location.line)) + continue; + if (tok->next && tok->next->str == "endfile") + continue; + Directive directive(tok->location.file, tok->location.line, ""); + for (const simplecpp::Token *tok2 = tok; tok2 && tok2->location.line == directive.linenr; tok2 = tok2->next) { + if (tok2->comment) + continue; + if (!directive.str.empty() && (tok2->location.col > tok2->previous->location.col + tok2->previous->str.size())) + directive.str += ' '; + if (directive.str == "#" && tok2->str == "file") + directive.str += "include"; + else + directive.str += tok2->str; + } + directives.push_back(directive); + } + + // ensure that define macros are not used in the code + for (std::map::const_iterator defineIt = defines.begin(); defineIt != defines.end(); ++defineIt) { + const std::string macroName = defineIt->first; + if (macroName.find("(") != std::string::npos) + continue; + const std::string macroValue = defineIt->second; + if (!defineIt->second.empty()) + continue; + for (std::list::const_iterator usageIt = macroUsage.begin(); usageIt != macroUsage.end(); ++usageIt) { + const simplecpp::MacroUsage &mu = *usageIt; + if (mu.macroName != macroName) + continue; + bool directiveLocation = false; + for (std::list::const_iterator dirIt = directives.begin(); dirIt != directives.end(); ++dirIt) { + if (mu.useLocation.file == dirIt->file && mu.useLocation.line == dirIt->linenr) { + directiveLocation = true; + break; + } + } + if (!directiveLocation) { + if (_settings.isEnabled("information")) + validateCfgError(cfg, macroName); + return ""; + } + } + } + + // assembler code locations.. + std::set assemblerLocations; + for (std::list::const_iterator dirIt = directives.begin(); dirIt != directives.end(); ++dirIt) { + const Directive &d1 = *dirIt; + if (d1.str.compare(0, 11, "#pragma asm") != 0) + continue; + std::list::const_iterator dirIt2 = dirIt; + ++dirIt2; + if (dirIt2 == directives.end()) + continue; + + const Directive &d2 = *dirIt2; + if (d2.str.compare(0,14,"#pragma endasm") != 0 || d1.file != d2.file) + continue; + + simplecpp::Location loc; + loc.file = d1.file; + loc.col = 0U; + + for (unsigned int linenr = d1.linenr + 1U; linenr < d2.linenr; linenr++) { + loc.line = linenr; + assemblerLocations.insert(loc); + } + } + + const bool writeLocations = (filedata.find("\n#file \"") != std::string::npos); + + std::string prevfile; + unsigned int line = 1; + std::ostringstream ret; + for (const simplecpp::Token *tok = tokens2.cbegin(); tok; tok = tok->next) { + if (writeLocations && tok->location.file != prevfile) { + ret << "\n#line " << tok->location.line << " \"" << tok->location.file << "\"\n"; + prevfile = tok->location.file; + line = tok->location.line; + } + + if (tok->previous && line == tok->location.line) + ret << ' '; + bool newline = false; + while (tok->location.line > line) { + ret << '\n'; + line++; + newline = true; + } + if (newline) { + simplecpp::Location loc = tok->location; + loc.col = 0U; + if (assemblerLocations.find(loc) != assemblerLocations.end()) { + ret << "asm();"; + while (assemblerLocations.find(loc) != assemblerLocations.end()) { + loc.line++; + } + while (tok && tok->location.line < loc.line) + tok = tok->next; + if (!tok) + break; + while (line < tok->location.line) { + ret << '\n'; + ++line; + } + } + } + if (!tok->macro.empty()) + ret << Preprocessor::macroChar; + ret << tok->str; + } + + return ret.str(); + } + // For the error report and preprocessor dump: // line number relative to current (included) file // (may decrease when popping back from an included file) @@ -1808,7 +1946,7 @@ std::string Preprocessor::getcode(const std::string &filedata, const std::string std::map cfgmap(getcfgmap(cfg, &_settings, filename)); std::stack filenames; - filenames.push(filename); + filenames.push(Path::simplifyPath(filename)); std::stack lineNumbers; std::istringstream istr(filedata); std::string line; diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 9a74bde1d..1e4c94466 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -26,6 +26,7 @@ #include "tokenize.h" #include "token.h" #include "settings.h" +#include "simplecpp.h" #include #include @@ -49,7 +50,29 @@ public: } static std::string expandMacros(const char code[], ErrorLogger *errorLogger = 0) { - return Preprocessor::expandMacros(code, "file.cpp", "", errorLogger); + std::istringstream istr(code); + simplecpp::OutputList outputList; + const simplecpp::TokenList tokens1 = simplecpp::TokenList(istr, "file.cpp", &outputList); + const simplecpp::TokenList tokens2 = simplecpp::preprocess(tokens1, simplecpp::Defines(), &outputList); + + if (errorLogger) { + for (simplecpp::OutputList::const_iterator it = outputList.begin(); it != outputList.end(); ++it) { + const simplecpp::Output &output = *it; + if (output.type == simplecpp::Output::ERROR) { + + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc(output.location.file, output.location.line); + locationList.push_back(loc); + errorLogger->reportErr(ErrorLogger::ErrorMessage(locationList, + Severity::error, + output.msg, + "preprocessorError", + false)); + } + } + } + + return tokens2.stringify(); } static int getHeaderFileName(std::string &str) { @@ -181,7 +204,6 @@ private: TEST_CASE(macro_simple18); // (1e-7) TEST_CASE(macroInMacro1); TEST_CASE(macroInMacro2); - TEST_CASE(macro_mismatch); TEST_CASE(macro_linenumbers); TEST_CASE(macro_nopar); TEST_CASE(macro_incdec); // separate ++ and -- with space when expanding such macro: '#define M(X) A-X' @@ -292,8 +314,6 @@ private: TEST_CASE(handleUndef); - TEST_CASE(macroChar); - TEST_CASE(validateCfg); TEST_CASE(if_sizeof); @@ -448,7 +468,7 @@ private: // Compare results.. ASSERT_EQUALS(1U, actual.size()); - ASSERT_EQUALS("\ncpp\n\n\n\n", actual[""]); + ASSERT_EQUALS("\ncpp", actual[""]); } { @@ -459,7 +479,7 @@ private: // Compare results.. ASSERT_EQUALS(1U, actual.size()); - ASSERT_EQUALS("\n\n\nc\n\n", actual[""]); + ASSERT_EQUALS("\n\n\nc", actual[""]); } } @@ -477,8 +497,8 @@ private: // Compare results.. ASSERT_EQUALS(2, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\nqwerty\n\n", actual[""]); - ASSERT_EQUALS("\nabcdef\n\n\n\n", actual["WIN32"]); + ASSERT_EQUALS("\n\n\nqwerty", actual[""]); + ASSERT_EQUALS("\nabcdef", actual["WIN32"]); } void test2() { @@ -494,8 +514,8 @@ private: // Compare results.. ASSERT_EQUALS(2, static_cast(actual.size())); - ASSERT_EQUALS("\n\" # ifdef WIN32\"\n\n\n\n", actual[""]); - ASSERT_EQUALS("\n\n\nqwerty\n\n", actual["WIN32"]); + ASSERT_EQUALS("\n\" # ifdef WIN32\"", actual[""]); + ASSERT_EQUALS("\n\n\nqwerty", actual["WIN32"]); } void test3() { @@ -513,9 +533,9 @@ private: // Compare results.. ASSERT_EQUALS(3, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\na\n\n\n\nc\n\n", actual["ABC"]); - ASSERT_EQUALS("\na\n\nb\n\nc\n\n", actual["ABC;DEF"]); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("\na\n\n\n\nc", actual["ABC"]); + ASSERT_EQUALS("\na\n\nb\n\nc", actual["ABC;DEF"]); } void test4() { @@ -532,8 +552,8 @@ private: // Compare results.. ASSERT_EQUALS(2, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\nA\n\n\nA\n\n", actual["ABC"]); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("\nA\n\n\nA", actual["ABC"]); } void test5() { @@ -552,9 +572,9 @@ private: // Compare results.. ASSERT_EQUALS(3, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\nB\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\nA\n\n\n\n\n\n\n", actual["ABC"]); - ASSERT_EQUALS("\n\n\nB\n\nC\n\n\n", actual["DEF"]); + ASSERT_EQUALS("\n\n\nB", actual[""]); + ASSERT_EQUALS("\nA", actual["ABC"]); + ASSERT_EQUALS("\n\n\nB\n\nC", actual["DEF"]); } void test6() { @@ -587,8 +607,8 @@ private: // Compare results.. ASSERT_EQUALS(2, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\nA\n\nB\n\n\n", actual["ABC"]); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("\nA\n\nB", actual["ABC"]); test7a(); test7b(); @@ -714,8 +734,8 @@ private: // Compare results.. ASSERT_EQUALS(2U, actual.size()); - ASSERT_EQUALS("\n\n\n", actual[""]); - ASSERT_EQUALS("\n1\n\n", actual["A=1"]); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("\n1", actual["A=1"]); } void test9() { @@ -759,7 +779,7 @@ private: // Compare results.. ASSERT_EQUALS(2, static_cast(actual.size())); ASSERT_EQUALS("", actual[""]); - ASSERT_EQUALS("\n;\n\n\n\n", actual["A"]); + ASSERT_EQUALS("\n;", actual["A"]); } @@ -942,8 +962,8 @@ private: // Expected configurations: "" and "ABC" ASSERT_EQUALS(2, static_cast(actual.size())); - ASSERT_EQUALS("\n#file \"abc.h\"\n\n\n\n\n\n\n\n\n#endfile\n\nint main() {}\n", actual[""]); - ASSERT_EQUALS("\n#file \"abc.h\"\nclass A{};\n\n\n\n\n\n\n\n#endfile\n\nint main() {}\n", actual["ABC"]); + ASSERT_EQUALS("\n#line 4 \"file.c\"\nint main ( ) { }", actual[""]); + ASSERT_EQUALS("\n#line 1 \"abc.h\"\nclass A { } ;\n#line 4 \"file.c\"\n int main ( ) { }", actual["ABC"]); } void newlines() { @@ -966,7 +986,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n", actual[""]); + ASSERT_EQUALS("", actual[""]); } { @@ -981,7 +1001,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n", actual[""]); + ASSERT_EQUALS("", actual[""]); } { @@ -996,7 +1016,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("void f()\n{\n*p = a / *b / *c;\n}\n", actual[""]); + ASSERT_EQUALS("void f ( )\n{\n* p = a / * b / * c ;\n}", actual[""]); } } @@ -1014,7 +1034,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n", actual[""]); + ASSERT_EQUALS("", actual[""]); } void if1() { @@ -1028,7 +1048,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\nABC\n\n", actual[""]); + ASSERT_EQUALS("\nABC", actual[""]); } @@ -1046,9 +1066,9 @@ private: // Compare results.. ASSERT_EQUALS(3, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\nABC\n\n\n\n", actual["DEF1"]); - ASSERT_EQUALS("\n\n\nDEF\n\n", actual["DEF2"]); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("\nABC", actual["DEF1"]); + ASSERT_EQUALS("\n\n\nDEF", actual["DEF2"]); } { @@ -1066,9 +1086,9 @@ private: // Compare results.. ASSERT_EQUALS(3, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n\nGHI\n\n", actual[""]); - ASSERT_EQUALS("\nABC\n\n\n\n\n\n", actual["DEF1"]); - ASSERT_EQUALS("\n\n\nDEF\n\n\n\n", actual["DEF2"]); + ASSERT_EQUALS("\n\n\n\n\nGHI", actual[""]); + ASSERT_EQUALS("\nABC", actual["DEF1"]); + ASSERT_EQUALS("\n\n\nDEF", actual["DEF2"]); } } @@ -1126,9 +1146,11 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\nB\n\n", actual[""]); - TODO_ASSERT_EQUALS("\nA\n\n\n\n", - "", actual["LIBVER=101"]); + ASSERT_EQUALS("\n" + "\n" + "\n" + "B", actual[""]); + TODO_ASSERT_EQUALS("A", "", actual["LIBVER=101"]); } void if_cond2() { @@ -1145,9 +1167,9 @@ private: // Compare results.. ASSERT_EQUALS(3, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\na\n\n\n\n\n", actual["A"]); - ASSERT_EQUALS("\na\n\n\nab\n\n", actual["A;B"]); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("\na", actual["A"]); + ASSERT_EQUALS("\na\n\n\nab", actual["A;B"]); if_cond2b(); if_cond2c(); if_cond2d(); @@ -1170,9 +1192,9 @@ private: // Compare results.. ASSERT_EQUALS(3, static_cast(actual.size())); - ASSERT_EQUALS("\n!a\n\n\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\n\n\n\n\n\na\n\n", actual["A"]); - ASSERT_EQUALS("\n!a\n\nb\n\n\n\n\n", actual["B"]); + ASSERT_EQUALS("\n! a", actual[""]); + ASSERT_EQUALS("\n\n\n\n\n\na", actual["A"]); + ASSERT_EQUALS("\n! a\n\nb", actual["B"]); } void if_cond2c() { @@ -1193,9 +1215,9 @@ private: // Compare results.. ASSERT_EQUALS(3, static_cast(actual.size())); - ASSERT_EQUALS("\n!a\n\n\n\n!b\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\n\n\n\n\n\n\n\na\n\n", actual["A"]); - ASSERT_EQUALS("\n!a\n\nb\n\n\n\n\n\n\n", actual["B"]); + ASSERT_EQUALS("\n! a\n\n\n\n! b", actual[""]); + ASSERT_EQUALS("\n\n\n\n\n\n\n\na", actual["A"]); + ASSERT_EQUALS("\n! a\n\nb", actual["B"]); } void if_cond2d() { @@ -1221,10 +1243,10 @@ private: // Compare results.. ASSERT_EQUALS(4, static_cast(actual.size())); - ASSERT_EQUALS("\n!a\n\n\n\n!b\n\n\n\n\n\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\n\n\n\n\n\n\n\na\n\n\n\n!b\n\n\n", actual["A"]); - ASSERT_EQUALS("\n\n\n\n\n\n\n\na\n\nb\n\n\n\n\n", actual["A;B"]); - ASSERT_EQUALS("\n!a\n\nb\n\n\n\n\n\n\n\n\n\n\n\n", actual["B"]); + ASSERT_EQUALS("\n! a\n\n\n\n! b", actual[""]); + ASSERT_EQUALS("\n\n\n\n\n\n\n\na\n\n\n\n! b", actual["A"]); + ASSERT_EQUALS("\n\n\n\n\n\n\n\na\n\nb", actual["A;B"]); + ASSERT_EQUALS("\n! a\n\nb", actual["B"]); } void if_cond2e() { @@ -1245,9 +1267,9 @@ private: // Compare results.. ASSERT_EQUALS(3, static_cast(actual.size())); - ASSERT_EQUALS("\n!a\n\n\n\n", actual[""]); - ASSERT_EQUALS("\n\n\n!b\n\n", actual["A"]); - TODO_ASSERT_EQUALS("\n\n\n\n\n", "", actual["A;B"]); + ASSERT_EQUALS("\n! a", actual[""]); + ASSERT_EQUALS("\n\n\n! b", actual["A"]); + ASSERT_EQUALS("", actual["A;B"]); ASSERT_EQUALS("", errout.str()); } @@ -1265,9 +1287,9 @@ private: // Compare results.. ASSERT_EQUALS(3, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\na\n\n\n\n\n", actual["A"]); - ASSERT_EQUALS("\na\n\nabc\n\n\n", actual["A;B;C"]); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("\na", actual["A"]); + ASSERT_EQUALS("\na\n\nabc", actual["A;B;C"]); } void if_cond4() { @@ -1284,7 +1306,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\nab\n\n", actual[""]); + ASSERT_EQUALS("\n\n\nab", actual[""]); } { @@ -1302,9 +1324,9 @@ private: // Compare results.. ASSERT_EQUALS(3, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\n{\n\n\n\n}\n\n", actual["A"]); - ASSERT_EQUALS("\n{\n\nfoo();\n\n}\n\n", actual["A;B"]); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("\n{\n\n\n\n}", actual["A"]); + ASSERT_EQUALS("\n{\n\nfoo ( ) ;\n\n}", actual["A;B"]); } { @@ -1320,7 +1342,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\nab\n\n", actual[""]); + ASSERT_EQUALS("\n\n\nab", actual[""]); } { @@ -1334,8 +1356,8 @@ private: // Compare results.. ASSERT_EQUALS(2, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n", actual[""]); - ASSERT_EQUALS("\nfoo();\n\n", actual["A"]); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("\nfoo ( ) ;", actual["A"]); } { @@ -1349,7 +1371,7 @@ private: // Compare results.. TODO_ASSERT_EQUALS(2, 1, static_cast(actual.size())); - ASSERT_EQUALS("\nfoo();\n\n", actual[""]); + ASSERT_EQUALS("\nfoo ( ) ;", actual[""]); } } @@ -1368,8 +1390,8 @@ private: // Compare results.. ASSERT_EQUALS(2, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\ncd\n\n\n\n", actual[""]); - ASSERT_EQUALS("\nab\n\ncd\n\nef\n\n", actual["A;B"]); + ASSERT_EQUALS("\n\n\ncd", actual[""]); + ASSERT_EQUALS("\nab\n\ncd\n\nef", actual["A;B"]); } void if_cond6() { @@ -1395,7 +1417,7 @@ private: // Compare results.. ASSERT_EQUALS(1, (int)actual.size()); - ASSERT_EQUALS("\n\n", actual[""]); + ASSERT_EQUALS("", actual[""]); } @@ -1410,7 +1432,7 @@ private: // Compare results.. ASSERT_EQUALS(1, (int)actual.size()); - ASSERT_EQUALS("\nabc\n\n", actual[""]); + ASSERT_EQUALS("\nabc", actual[""]); } void if_cond10() { @@ -1440,21 +1462,21 @@ private: "#if A == 1\n" ";\n" "#endif\n"; - ASSERT_EQUALS("\n\n;\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("\n\n;", preprocessor0.getcode(filedata,"","")); } void if_cond13() { const char filedata[] = "#if ('A' == 0x41)\n" "123\n" "#endif\n"; - ASSERT_EQUALS("\n123\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("\n123", preprocessor0.getcode(filedata,"","")); } void if_cond14() { const char filedata[] = "#if !(A)\n" "123\n" "#endif\n"; - ASSERT_EQUALS("\n123\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("\n123", preprocessor0.getcode(filedata,"","")); } void if_cond15() { // #4456 - segmentation fault @@ -1489,7 +1511,7 @@ private: // Compare results.. ASSERT_EQUALS(1, (int)actual.size()); - ASSERT_EQUALS("\n\n\n", actual[""]); + ASSERT_EQUALS("", actual[""]); // the "defined(DEF_10) || defined(DEF_11)" are not handled correctly.. ASSERT_EQUALS("(debug) unhandled configuration: defined(DEF_10)||defined(DEF_11)\n", errout.str()); @@ -1503,8 +1525,8 @@ private: const std::string code("#if X || Y\n" "a1;\n" "#endif\n"); - ASSERT_EQUALS("\na1;\n\n", preprocessor0.getcode(code, "X", "test.c")); - ASSERT_EQUALS("\na1;\n\n", preprocessor0.getcode(code, "Y", "test.c")); + ASSERT_EQUALS("\na1 ;", preprocessor0.getcode(code, "X", "test.c")); + ASSERT_EQUALS("\na1 ;", preprocessor0.getcode(code, "Y", "test.c")); } void if_macro_eq_macro() { @@ -1519,7 +1541,7 @@ private: std::map actual; preprocess(code, actual); - ASSERT_EQUALS("\n\n\n\nWilma\n\n\n\n", actual[""]); + ASSERT_EQUALS("\n\n\n\nWilma", actual[""]); } void ticket_3675() { @@ -1547,7 +1569,7 @@ private: preprocess(code, actual); // First, it must not hang. Second, inline must becomes inline, and __forceinline must become __forceinline. - ASSERT_EQUALS("\n\n\n\n\n$$$__forceinline $$inline $$__forceinline\n", actual[""]); + ASSERT_EQUALS("\n\n\n\n\n$__forceinline $inline $__forceinline", actual[""]); } void ticket_4922() { // #4922 @@ -1581,8 +1603,8 @@ private: void multiline4() { errout.str(""); - const char filedata[] = "#define A int a = 4;\\ \n" - " int b = 5;\n" + const char filedata[] = "#define A 1 \\ \n" + "2\n" "A\n"; // Preprocess => actual result.. @@ -1592,9 +1614,9 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); #ifdef __GNUC__ - ASSERT_EQUALS("\n\n$int $a = $4; $int $b = $5;\n", actual[""]); + ASSERT_EQUALS("\n\n$1 $2", actual[""]); #else - ASSERT_EQUALS("\nint b = 5;\n$int $a = $4;\\\n", actual[""]); + ASSERT_EQUALS("\n2\n$1 \\", actual[""]); #endif ASSERT_EQUALS("", errout.str()); } @@ -1613,7 +1635,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\nint main(){\n$int $a = $4;\n}\n", actual[""]); + ASSERT_EQUALS("\n\nint main ( ) {\n$int $a $= $4 $;\n}", actual[""]); ASSERT_EQUALS("", errout.str()); } @@ -1650,32 +1672,32 @@ private: { const char filedata[] = "#define AAA(aa) f(aa)\n" "AAA(5);\n"; - ASSERT_EQUALS("\n$f($5);\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nf ( 5 ) ;", OurPreprocessor::expandMacros(filedata)); } { const char filedata[] = "#define AAA(aa) f(aa)\n" "AAA (5);\n"; - ASSERT_EQUALS("\n$f($5);\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nf ( 5 ) ;", OurPreprocessor::expandMacros(filedata)); } } void macro_simple2() const { const char filedata[] = "#define min(x,y) x $0 ) $return $1;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nif ( temp > 0 ) return 1 ;", OurPreprocessor::expandMacros(filedata)); } void macro_simple5() const { @@ -1686,75 +1708,75 @@ private: " int temp = 0;\n" " ABC\n" "}\n"; - ASSERT_EQUALS("\n\nvoid foo()\n{\n int temp = 0;\n $if( $temp > $0 ) $return $1;\n}\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\nvoid foo ( )\n{\nint temp = 0 ;\nif ( temp > 0 ) return 1 ;\n}", OurPreprocessor::expandMacros(filedata)); } void macro_simple6() const { const char filedata[] = "#define ABC (a+b+c)\n" "ABC\n"; - ASSERT_EQUALS("\n$($a+$b+$c)\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n( a + b + c )", OurPreprocessor::expandMacros(filedata)); } void macro_simple7() const { const char filedata[] = "#define ABC(str) str\n" "ABC(\"(\")\n"; - ASSERT_EQUALS("\n$\"(\"\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\"(\"", OurPreprocessor::expandMacros(filedata)); } void macro_simple8() const { const char filedata[] = "#define ABC 123\n" "#define ABCD 1234\n" "ABC ABCD\n"; - ASSERT_EQUALS("\n\n$123 $1234\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\n123 1234", OurPreprocessor::expandMacros(filedata)); } void macro_simple9() const { const char filedata[] = "#define ABC(a) f(a)\n" "ABC( \"\\\"\" );\n" "ABC( \"g\" );\n"; - ASSERT_EQUALS("\n$f(\"\\\"\");\n$f(\"g\");\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nf ( \"\\\"\" ) ;\nf ( \"g\" ) ;", OurPreprocessor::expandMacros(filedata)); } void macro_simple10() const { const char filedata[] = "#define ABC(t) t x\n" "ABC(unsigned long);\n"; - ASSERT_EQUALS("\n$unsigned $long $x;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nunsigned long x ;", OurPreprocessor::expandMacros(filedata)); } void macro_simple11() const { const char filedata[] = "#define ABC(x) delete x\n" "ABC(a);\n"; - ASSERT_EQUALS("\n$delete $a;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\ndelete a ;", OurPreprocessor::expandMacros(filedata)); } void macro_simple12() const { const char filedata[] = "#define AB ab.AB\n" "AB.CD\n"; - ASSERT_EQUALS("\n$ab.$AB.CD\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nab . AB . CD", OurPreprocessor::expandMacros(filedata)); } void macro_simple13() const { const char filedata[] = "#define TRACE(x)\n" "TRACE(;if(a))\n"; - ASSERT_EQUALS("\n$\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("", OurPreprocessor::expandMacros(filedata)); } void macro_simple14() const { const char filedata[] = "#define A \" a \"\n" "printf(A);\n"; - ASSERT_EQUALS("\nprintf($\" a \");\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nprintf ( \" a \" ) ;", OurPreprocessor::expandMacros(filedata)); } void macro_simple15() const { const char filedata[] = "#define FOO\"foo\"\n" "FOO\n"; - ASSERT_EQUALS("\n$\"foo\"\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\"foo\"", OurPreprocessor::expandMacros(filedata)); } void macro_simple16() const { // # 4703 const char filedata[] = "#define MACRO( A, B, C ) class A##B##C##Creator {};\n" "MACRO( B\t, U , G )"; - ASSERT_EQUALS("\n$class $BUGCreator{};", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nclass BUGCreator { } ;", OurPreprocessor::expandMacros(filedata)); } void macro_simple17() const { // # 5074 - the Token::isExpandedMacro() doesn't always indicate properly if token comes from macro @@ -1762,41 +1784,41 @@ private: // "\n123+$123" since the first 123 comes from the source code const char filedata[] = "#define MACRO(A) A+123\n" "MACRO(123)"; - ASSERT_EQUALS("\n$123+$123", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n123 + 123", OurPreprocessor::expandMacros(filedata)); } void macro_simple18() const { // (1e-7) const char filedata1[] = "#define A (1e-7)\n" "a=A;"; - ASSERT_EQUALS("\na=$($1e-7);", OurPreprocessor::expandMacros(filedata1)); + ASSERT_EQUALS("\na = ( 1e-7 ) ;", OurPreprocessor::expandMacros(filedata1)); const char filedata2[] = "#define A (1E-7)\n" "a=A;"; - ASSERT_EQUALS("\na=$($1E-7);", OurPreprocessor::expandMacros(filedata2)); + ASSERT_EQUALS("\na = ( 1E-7 ) ;", OurPreprocessor::expandMacros(filedata2)); const char filedata3[] = "#define A (1e+7)\n" "a=A;"; - ASSERT_EQUALS("\na=$($1e+7);", OurPreprocessor::expandMacros(filedata3)); + ASSERT_EQUALS("\na = ( 1e+7 ) ;", OurPreprocessor::expandMacros(filedata3)); const char filedata4[] = "#define A (1.e+7)\n" "a=A;"; - ASSERT_EQUALS("\na=$($1.e+7);", OurPreprocessor::expandMacros(filedata4)); + ASSERT_EQUALS("\na = ( 1.e+7 ) ;", OurPreprocessor::expandMacros(filedata4)); const char filedata5[] = "#define A (1.7f)\n" "a=A;"; - ASSERT_EQUALS("\na=$($1.7f);", OurPreprocessor::expandMacros(filedata5)); + ASSERT_EQUALS("\na = ( 1.7f ) ;", OurPreprocessor::expandMacros(filedata5)); const char filedata6[] = "#define A (.1)\n" "a=A;"; - ASSERT_EQUALS("\na=$($.1);", OurPreprocessor::expandMacros(filedata6)); + ASSERT_EQUALS("\na = ( .1 ) ;", OurPreprocessor::expandMacros(filedata6)); const char filedata7[] = "#define A (1.)\n" "a=A;"; - ASSERT_EQUALS("\na=$($1.);", OurPreprocessor::expandMacros(filedata7)); + ASSERT_EQUALS("\na = ( 1. ) ;", OurPreprocessor::expandMacros(filedata7)); const char filedata8[] = "#define A (8.0E+007)\n" "a=A;"; - ASSERT_EQUALS("\na=$($8.0E+007);", OurPreprocessor::expandMacros(filedata8)); + ASSERT_EQUALS("\na = ( 8.0E+007 ) ;", OurPreprocessor::expandMacros(filedata8)); } void macroInMacro1() const { @@ -1804,66 +1826,52 @@ private: const char filedata[] = "#define A(m) long n = m; n++;\n" "#define B(n) A(n)\n" "B(0)\n"; - ASSERT_EQUALS("\n\n$$long $n=$0;$n++;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\nlong n = 0 ; n ++ ;", OurPreprocessor::expandMacros(filedata)); } { const char filedata[] = "#define A B\n" "#define B 3\n" "A\n"; - ASSERT_EQUALS("\n\n$$3\n", OurPreprocessor::expandMacros(filedata)); - } - - { - const char filedata[] = "#define DBG(fmt, args...) printf(fmt, ## args)\n" - "#define D(fmt, args...) DBG(fmt, ## args)\n" - "DBG(\"hello\");\n"; - ASSERT_EQUALS("\n\n$printf(\"hello\");\n", OurPreprocessor::expandMacros(filedata)); - } - - { - const char filedata[] = "#define DBG(fmt, args...) printf(fmt, ## args)\n" - "#define D(fmt, args...) DBG(fmt, ## args)\n" - "DBG(\"hello: %d\",3);\n"; - ASSERT_EQUALS("\n\n$printf(\"hello: %d\",$3);\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\n3", OurPreprocessor::expandMacros(filedata)); } { const char filedata[] = "#define BC(b, c...) 0##b * 0##c\n" "#define ABC(a, b...) a + BC(b)\n" "\n" - "ABC(1);\n" + "ABC(1);\n" // <- too few parameters "ABC(2,3);\n" "ABC(4,5,6);\n"; - ASSERT_EQUALS("\n\n\n$1+$$0*$0;\n$2+$$03*$0;\n$4+$$05*$06;\n", OurPreprocessor::expandMacros(filedata)); + //ASSERT_EQUALS("\n\n\n1 + 0 * 0;\n2 + 03 * 0;\n4 + 05 * 06;", OurPreprocessor::expandMacros(filedata)); } { const char filedata[] = "#define A 4\n" "#define B(a) a,A\n" "B(2);\n"; - ASSERT_EQUALS("\n\n$2, $4;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\n2 , 4 ;", OurPreprocessor::expandMacros(filedata)); } { const char filedata[] = "#define A(x) (x)\n" "#define B )A(\n" "#define C )A(\n"; - ASSERT_EQUALS("\n\n\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("", OurPreprocessor::expandMacros(filedata)); } { const char filedata[] = "#define A(x) (x*2)\n" "#define B A(\n" "foo B(i));\n"; - ASSERT_EQUALS("\n\nfoo $$(($i)*$2);\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\nfoo ( ( i ) * 2 ) ;", OurPreprocessor::expandMacros(filedata)); } { const char filedata[] = "#define foo foo\n" "foo\n"; - ASSERT_EQUALS("\n$foo\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nfoo", OurPreprocessor::expandMacros(filedata)); } { @@ -1872,7 +1880,7 @@ private: "#define A(name) void foo##name() { do { B(1, 2); }\n" "A(0)\n" "A(1)\n"; - ASSERT_EQUALS("\n\n$void $foo0(){$do{$$}$while($0);}\n$void $foo1(){$do{$$}$while($0);}\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\nvoid foo0 ( ) { do { } while ( 0 ) ; }\nvoid foo1 ( ) { do { } while ( 0 ) ; }", OurPreprocessor::expandMacros(filedata)); } { @@ -1880,7 +1888,7 @@ private: "#define B(x) (\n" "#define A() B(xx)\n" "B(1) A() ) )\n"; - ASSERT_EQUALS("\n\n$( $$( ) )\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\n( ( ) )", OurPreprocessor::expandMacros(filedata)); } { @@ -1888,14 +1896,14 @@ private: "#define PTR1 (\n" "#define PTR2 PTR1 PTR1\n" "int PTR2 PTR2 foo )))) = 0;\n"; - ASSERT_EQUALS("\n\nint $$( $$( $$( $$( foo )))) = 0;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\nint ( ( ( ( foo ) ) ) ) = 0 ;", OurPreprocessor::expandMacros(filedata)); } { const char filedata[] = "#define PTR1 (\n" "PTR1 PTR1\n"; - ASSERT_EQUALS("\n$( $(\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n( (", OurPreprocessor::expandMacros(filedata)); } } @@ -1903,13 +1911,7 @@ private: const char filedata[] = "#define A(x) a##x\n" "#define B 0\n" "A(B)\n"; - ASSERT_EQUALS("\n\n$aB\n", OurPreprocessor::expandMacros(filedata)); - } - - void macro_mismatch() const { - const char filedata[] = "#define AAA(aa,bb) f(aa)\n" - "AAA(5);\n"; - ASSERT_EQUALS("\nAAA(5);\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\naB", OurPreprocessor::expandMacros(filedata)); } void macro_linenumbers() const { @@ -1918,25 +1920,25 @@ private: "\n" ")\n" "int a;\n"; - ASSERT_EQUALS("\n$" + ASSERT_EQUALS("\n" "\n" "\n" "\n" - "int a;\n", + "int a ;", OurPreprocessor::expandMacros(filedata)); } void macro_nopar() const { const char filedata[] = "#define AAA( ) { NULL }\n" "AAA()\n"; - ASSERT_EQUALS("\n${ $NULL }\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n{ NULL }", OurPreprocessor::expandMacros(filedata)); } void macro_incdec() const { const char filedata[] = "#define M1(X) 1+X\n" "#define M2(X) 2-X\n" "M1(+1) M2(-1)\n"; - ASSERT_EQUALS("\n\n$1+ +$1 $2- -$1\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\n1 + + 1 2 - - 1", OurPreprocessor::expandMacros(filedata)); } void macro_switchCase() const { @@ -1948,14 +1950,14 @@ private: " break; " "}\n" "A( 5 );\n"; - ASSERT_EQUALS("\n$switch($a){$case $2:$break;};\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nswitch ( a ) { case 2 : break ; } ;", OurPreprocessor::expandMacros(filedata)); } { // Make sure "2 BB" doesn't become "2BB" const char filedata[] = "#define A() AA : 2 BB\n" "A();\n"; - ASSERT_EQUALS("\n$AA : $2 $BB;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nAA : 2 BB ;", OurPreprocessor::expandMacros(filedata)); } { @@ -1963,7 +1965,7 @@ private: "#define B() A\n" "#define C( a ) B() break;\n" "{C( 2 );\n"; - ASSERT_EQUALS("\n\n\n{$$$}$break;;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\n\n{ } break ; ;", OurPreprocessor::expandMacros(filedata)); } @@ -1972,7 +1974,7 @@ private: "#define B() A\n" "#define C( a ) B() _break;\n" "{C( 2 );\n"; - ASSERT_EQUALS("\n\n\n{$$$}$_break;;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\n\n{ } _break ; ;", OurPreprocessor::expandMacros(filedata)); } @@ -1981,21 +1983,21 @@ private: "#define B() A\n" "#define C( a ) B() 5;\n" "{C( 2 );\n"; - ASSERT_EQUALS("\n\n\n{$$$}$5;;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\n\n{ } 5 ; ;", OurPreprocessor::expandMacros(filedata)); } } void macro_NULL() const { // Let the tokenizer handle NULL. // See ticket #4482 - UB when passing NULL to variadic function - ASSERT_EQUALS("\n$0", OurPreprocessor::expandMacros("#define null 0\nnull")); - ASSERT_EQUALS("\nNULL", OurPreprocessor::expandMacros("#define NULL 0\nNULL")); + ASSERT_EQUALS("\n0", OurPreprocessor::expandMacros("#define null 0\nnull")); + // TODO ASSERT_EQUALS("\nNULL", OurPreprocessor::expandMacros("#define NULL 0\nNULL")); } void string1() { const char filedata[] = "int main()" "{" - " const char *a = \"#define A\n\";" + " const char *a = \"#define A\";" "}\n"; // Preprocess => actual result.. @@ -2004,7 +2006,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("int main(){ const char *a = \"#define A\n\";}\n", actual[""]); + ASSERT_EQUALS("int main ( ) { const char * a = \"#define A\" ; }", actual[""]); } void string2() const { @@ -2012,14 +2014,14 @@ private: "str = \"AAA\"\n"; // Compare results.. - ASSERT_EQUALS("\nstr = \"AAA\"\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nstr = \"AAA\"", OurPreprocessor::expandMacros(filedata)); } void string3() const { const char filedata[] = "str(\";\");\n"; // Compare results.. - ASSERT_EQUALS("str(\";\");\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("str ( \";\" ) ;", OurPreprocessor::expandMacros(filedata)); } @@ -2031,7 +2033,7 @@ private: "AAA\n"; // Compare results.. - ASSERT_EQUALS("\n\n\n$char $b=$0;\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\n\nchar b = 0 ;", OurPreprocessor::expandMacros(filedata)); } { @@ -2040,7 +2042,7 @@ private: "#undef z\n" "int z;\n" "z = 0;\n"; - ASSERT_EQUALS("\n\nint z;\nz = 0;\n", preprocessor0.getcode(filedata, "", "")); + ASSERT_EQUALS("\n\nint z ;\nz = 0 ;", preprocessor0.getcode(filedata, "", "")); } } @@ -2051,37 +2053,37 @@ private: "AAA\n"; // Compare results.. - ASSERT_EQUALS("\n\n\n$789\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n\n\n789", OurPreprocessor::expandMacros(filedata)); } void preprocessor_doublesharp() const { // simple testcase without ## const char filedata1[] = "#define TEST(var,val) var = val\n" "TEST(foo,20);\n"; - ASSERT_EQUALS("\n$foo=$20;\n", OurPreprocessor::expandMacros(filedata1)); + ASSERT_EQUALS("\nfoo = 20 ;", OurPreprocessor::expandMacros(filedata1)); // simple testcase with ## const char filedata2[] = "#define TEST(var,val) var##_##val = val\n" "TEST(foo,20);\n"; - ASSERT_EQUALS("\n$foo_20=$20;\n", OurPreprocessor::expandMacros(filedata2)); + ASSERT_EQUALS("\nfoo_20 = 20 ;", OurPreprocessor::expandMacros(filedata2)); // concat macroname const char filedata3[] = "#define ABCD 123\n" "#define A(B) A##B\n" "A(BCD)\n"; - ASSERT_EQUALS("\n\n$$123\n", OurPreprocessor::expandMacros(filedata3)); + ASSERT_EQUALS("\n\n123", OurPreprocessor::expandMacros(filedata3)); // Ticket #1802 - inner ## must be expanded before outer macro const char filedata4[] = "#define A(B) A##B\n" "#define a(B) A(B)\n" "a(A(B))\n"; - ASSERT_EQUALS("\n\n$$AAB\n", OurPreprocessor::expandMacros(filedata4)); + ASSERT_EQUALS("\n\nAAB", OurPreprocessor::expandMacros(filedata4)); // Ticket #1802 - inner ## must be expanded before outer macro const char filedata5[] = "#define AB(A,B) A##B\n" "#define ab(A,B) AB(A,B)\n" "ab(a,AB(b,c))\n"; - ASSERT_EQUALS("\n\n$$abc\n", OurPreprocessor::expandMacros(filedata5)); + ASSERT_EQUALS("\n\nabc", OurPreprocessor::expandMacros(filedata5)); // Ticket #1802 const char filedata6[] = "#define AB_(A,B) A ## B\n" @@ -2089,7 +2091,7 @@ private: "#define ab(suf) AB(X, AB_(_, suf))\n" "#define X x\n" "ab(y)\n"; - ASSERT_EQUALS("\n\n\n\n$$$x_y\n", OurPreprocessor::expandMacros(filedata6)); + ASSERT_EQUALS("\n\n\n\nx_y", OurPreprocessor::expandMacros(filedata6)); } @@ -2097,7 +2099,7 @@ private: void preprocessor_include_in_str() { const char filedata[] = "int main()\n" "{\n" - "const char *a = \"#include \n\";\n" + "const char *a = \"#include \";\n" "return 0;\n" "}\n"; @@ -2107,7 +2109,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("int main()\n{\nconst char *a = \"#include \n\";\nreturn 0;\n}\n", actual[""]); + ASSERT_EQUALS("int main ( )\n{\nconst char * a = \"#include \" ;\nreturn 0 ;\n}", actual[""]); } @@ -2120,7 +2122,7 @@ private: // Preprocess.. std::string actual = OurPreprocessor::expandMacros(filedata); - ASSERT_EQUALS("\n$printf(\"[0x%lx-0x%lx)\",$pstart,$pend);\n", actual); + ASSERT_EQUALS("\nprintf ( \"[0x%lx-0x%lx)\" , pstart , pend ) ;", actual); } void va_args_2() const { @@ -2130,29 +2132,29 @@ private: // Preprocess.. std::string actual = OurPreprocessor::expandMacros(filedata); - ASSERT_EQUALS("\n$printf(\"hello\");\n", actual); + // invalid code ASSERT_EQUALS("\nprintf ( \"hello\" ) ;", actual); } void va_args_3() const { const char filedata[] = "#define FRED(...) { fred(__VA_ARGS__); }\n" "FRED(123)\n"; - ASSERT_EQUALS("\n${ $fred($123); }\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\n{ fred ( 123 ) ; }", OurPreprocessor::expandMacros(filedata)); } void va_args_4() const { const char filedata[] = "#define FRED(name, ...) name (__VA_ARGS__)\n" "FRED(abc, 123)\n"; - ASSERT_EQUALS("\n$abc($123)\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\nabc ( 123 )", OurPreprocessor::expandMacros(filedata)); } void va_args_5() { const char filedata1[] = "#define A(...) #__VA_ARGS__\n" "A(123)\n"; - ASSERT_EQUALS("\n$\"123\"\n", OurPreprocessor::expandMacros(filedata1)); + ASSERT_EQUALS("\n\"123\"", OurPreprocessor::expandMacros(filedata1)); const char filedata2[] = "#define A(X,...) X(#__VA_ARGS__)\n" "A(f,123)\n"; - ASSERT_EQUALS("\n$f(\"123\")\n", OurPreprocessor::expandMacros(filedata2)); + ASSERT_EQUALS("\nf ( \"123\" )", OurPreprocessor::expandMacros(filedata2)); } @@ -2171,7 +2173,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\nint main()\n{\nif( $'ABCD' == 0 );\nreturn 0;\n}\n", actual[""]); + ASSERT_EQUALS("\nint main ( )\n{\nif ( $'ABCD' == 0 ) ;\nreturn 0 ;\n}", actual[""]); } @@ -2182,7 +2184,7 @@ private: // expand macros.. std::string actual = OurPreprocessor::expandMacros(filedata); - ASSERT_EQUALS("\n$\"abc\"\n", actual); + ASSERT_EQUALS("\n\"abc\"", actual); } void stringify2() const { @@ -2192,7 +2194,7 @@ private: // expand macros.. std::string actual = OurPreprocessor::expandMacros(filedata); - ASSERT_EQUALS("\n$g(\"abc\");\n", actual); + ASSERT_EQUALS("\ng ( \"abc\" ) ;", actual); } void stringify3() const { @@ -2202,7 +2204,7 @@ private: // expand macros.. std::string actual = OurPreprocessor::expandMacros(filedata); - ASSERT_EQUALS("\n$g(\"abc\");\n", actual); + ASSERT_EQUALS("\ng ( \"abc\" ) ;", actual); } void stringify4() const { @@ -2214,13 +2216,13 @@ private: // expand macros.. std::string actual = OurPreprocessor::expandMacros(filedata); - ASSERT_EQUALS("\n1 $\n\n\"abc\" 2\n", actual); + ASSERT_EQUALS("\n1 \"abc\"\n\n2", actual); } void stringify5() const { const char filedata[] = "#define A(x) a(#x,x)\n" "A(foo(\"\\\"\"))\n"; - ASSERT_EQUALS("\n$a(\"foo(\\\"\\\\\\\"\\\")\",$foo(\"\\\"\"))\n", OurPreprocessor::expandMacros(filedata)); + ASSERT_EQUALS("\na ( \"foo(\"\\\"\")\" , foo ( \"\\\"\" ) )", OurPreprocessor::expandMacros(filedata)); } void pragma() { @@ -2235,7 +2237,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\nvoid f()\n{\n}\n", actual[""]); + ASSERT_EQUALS("\nvoid f ( )\n{\n}", actual[""]); } void pragma_asm_1() { @@ -2254,7 +2256,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\naaa\n\n\n\nbbb\n", actual[""]); + ASSERT_EQUALS("\nasm();\n\naaa\n\nasm();\n\nbbb", actual[""]); } void pragma_asm_2() { @@ -2269,7 +2271,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\nasm(temp);\nbbb\n", actual[""]); + ASSERT_EQUALS("\nasm();\n\nbbb", actual[""]); } void pragma_once() { @@ -2295,7 +2297,7 @@ private: // Compare results.. ASSERT_EQUALS(2, static_cast(actual.size())); - const std::string expected("void f() {\n\n\n}\n"); + const std::string expected("void f ( ) {\n\n\n}"); ASSERT_EQUALS(expected, actual[""]); ASSERT_EQUALS(expected, actual["A"]); } @@ -2309,20 +2311,13 @@ private: "{\n" " char a = 'a'; // '\n" "}\n"; - const char expected[] = "\n" - "\n" - "\n" - "void f()\n" - "{\n" - "char a = 'a';\n" - "}\n"; // Preprocess => actual result.. std::map actual; preprocess(filedata, actual); - ASSERT_EQUALS(expected, actual[""]); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("[file.c:2]: (error) No pair for character ('). Can't process file. File is either invalid or unicode, which is currently not supported.\n", errout.str()); } } @@ -2378,8 +2373,8 @@ private: errout.str(""); const std::string actual(OurPreprocessor::expandMacros(filedata, this)); - ASSERT_EQUALS("\n\nint a = $1;\n", actual); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("", actual); + ASSERT_EQUALS("[file.cpp:2]: (error) No pair for character (\"). Can't process file. File is either invalid or unicode, which is currently not supported.\n", errout.str()); } { @@ -2429,7 +2424,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\nvoid f() {\n$g( );\n}\n", actual[""]); + ASSERT_EQUALS("\nvoid f ( ) {\n$g $( ) ;\n}", actual[""]); ASSERT_EQUALS("", errout.str()); } @@ -2447,8 +2442,8 @@ private: // Compare results.. ASSERT_EQUALS(2, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n\n$20\n", actual[""]); - ASSERT_EQUALS("\n\n\n\n\n$10\n", actual["A"]); + ASSERT_EQUALS("\n\n\n\n\n$20", actual[""]); + ASSERT_EQUALS("\n\n\n\n\n$10", actual["A"]); ASSERT_EQUALS("", errout.str()); } @@ -2464,7 +2459,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\n\nvoid f() ${ }\n", actual[""]); + ASSERT_EQUALS("\n\nvoid f ( ) ${ }", actual[""]); ASSERT_EQUALS("", errout.str()); } @@ -2485,7 +2480,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); ASSERT_EQUALS("", actual[""]); - ASSERT_EQUALS("[file.c:6]: (error) Syntax error. Not enough parameters for macro 'BC'.\n", errout.str()); + ASSERT_EQUALS("[file.c:6]: (error) Syntax error. Wrong number of parameters for macro 'BC'.\n", errout.str()); } void newline_in_macro() { @@ -2501,7 +2496,7 @@ private: // Compare results.. ASSERT_EQUALS(1, static_cast(actual.size())); - ASSERT_EQUALS("\nvoid f()\n{\n$printf(\"\\n\");\n}\n", actual[""]); + ASSERT_EQUALS("\nvoid f ( )\n{\n$printf $( \"\\n\" $) ;\n}", actual[""]); ASSERT_EQUALS("", errout.str()); } @@ -2550,8 +2545,8 @@ private: preprocess(filedata, actual); // Compare results.. - ASSERT_EQUALS("\n\n\n\n\n\n", actual[""]); - ASSERT_EQUALS("\nA\n\n\nA\n\n", actual["ABC"]); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("\nA\n\n\nA", actual["ABC"]); ASSERT_EQUALS(2, static_cast(actual.size())); } @@ -2561,14 +2556,14 @@ private: "#if A\n" "FOO\n" "#endif"; - ASSERT_EQUALS("\n\n\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("", preprocessor0.getcode(filedata,"","")); } { const char filedata[] = "#define A 1\n" "#if A==1\n" "FOO\n" "#endif"; - ASSERT_EQUALS("\n\nFOO\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("\n\nFOO", preprocessor0.getcode(filedata,"","")); } } @@ -2578,7 +2573,7 @@ private: "#if (B==A) || (B==C)\n" "FOO\n" "#endif"; - ASSERT_EQUALS("\n\n\nFOO\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("\n\n\nFOO", preprocessor0.getcode(filedata,"","")); } void define_if3() { @@ -2586,7 +2581,7 @@ private: "#if (A==0)\n" "FOO\n" "#endif"; - ASSERT_EQUALS("\n\nFOO\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("\n\nFOO", preprocessor0.getcode(filedata,"","")); } void define_if4() { @@ -2594,7 +2589,7 @@ private: "#if X==123\n" "FOO\n" "#endif"; - ASSERT_EQUALS("\n\nFOO\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("\n\nFOO", preprocessor0.getcode(filedata,"","")); } void define_if5() { // #4516 - #define B (A & 0x00f0) @@ -2604,7 +2599,7 @@ private: "#if B==0x0010\n" "FOO\n" "#endif"; - ASSERT_EQUALS("\n\n\nFOO\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("\n\n\nFOO", preprocessor0.getcode(filedata,"","")); } { const char filedata[] = "#define A 0x00f0\n" @@ -2613,14 +2608,14 @@ private: "#if C==0x0010\n" "FOO\n" "#endif"; - ASSERT_EQUALS("\n\n\n\nFOO\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("\n\n\n\nFOO", preprocessor0.getcode(filedata,"","")); } { const char filedata[] = "#define A (1+A)\n" // don't hang for recursive macros "#if A==1\n" "FOO\n" "#endif"; - ASSERT_EQUALS("\n\n\n\n", preprocessor0.getcode(filedata,"","")); + ASSERT_EQUALS("\n\nFOO", preprocessor0.getcode(filedata,"","")); } } @@ -2659,7 +2654,7 @@ private: // Compare results.. ASSERT_EQUALS(1, (int)actual.size()); - ASSERT_EQUALS("\n\n\n\nB\n\n", actual[""]); + ASSERT_EQUALS("\n\n\n\nB", actual[""]); } { @@ -2674,7 +2669,7 @@ private: // Compare results.. ASSERT_EQUALS(1, (int)actual.size()); - ASSERT_EQUALS("\n\n$1\n\n", actual[""]); + ASSERT_EQUALS("\n\n$1", actual[""]); } { @@ -2689,7 +2684,7 @@ private: // Compare results.. ASSERT_EQUALS(1, (int)actual.size()); - ASSERT_EQUALS("\n\n$1\n\n", actual[""]); + ASSERT_EQUALS("\n\n$1", actual[""]); } { @@ -2704,7 +2699,7 @@ private: // Compare results.. ASSERT_EQUALS(1, (int)actual.size()); - ASSERT_EQUALS("\n\n$1\n\n", actual[""]); + ASSERT_EQUALS("\n\n$1", actual[""]); } { @@ -2720,7 +2715,7 @@ private: // Compare results.. ASSERT_EQUALS(1, (int)actual.size()); - ASSERT_EQUALS("\n\n\n\n$1\n", actual[""]); + ASSERT_EQUALS("\n\n\n\n$1", actual[""]); } } @@ -2736,7 +2731,7 @@ private: // Compare results.. ASSERT_EQUALS(1U, actual.size()); - ASSERT_EQUALS("\n\n\n\n", actual[""]); + ASSERT_EQUALS("", actual[""]); } void define_ifndef2() { @@ -2749,8 +2744,8 @@ private: "B me;\n"; // Preprocess => actual result.. - ASSERT_EQUALS("\n\n\n\n\n\n$int me;\n", preprocessor0.getcode(filedata, "", "a.cpp")); - ASSERT_EQUALS("\n\n\n\n\n\n$char me;\n", preprocessor0.getcode(filedata, "A", "a.cpp")); + ASSERT_EQUALS("\n\n\n\n\n\n$int me ;", preprocessor0.getcode(filedata, "", "a.cpp")); + ASSERT_EQUALS("\n\n\n\n\n\n$char me ;", preprocessor0.getcode(filedata, "A", "a.cpp")); } void ifndef_define() { @@ -2764,7 +2759,7 @@ private: preprocess(filedata, actual); ASSERT_EQUALS(1U, actual.size()); - ASSERT_EQUALS("\n\n\n$123;\n", actual[""]); + ASSERT_EQUALS("\n\n\n123 ;", actual[""]); } void undef_ifdef() { @@ -2774,8 +2769,8 @@ private: "#endif\n"; // Preprocess => actual result.. - ASSERT_EQUALS("\n\n\n\n", preprocessor0.getcode(filedata, "", "a.cpp")); - ASSERT_EQUALS("\n\n\n\n", preprocessor0.getcode(filedata, "A", "a.cpp")); + ASSERT_EQUALS("", preprocessor0.getcode(filedata, "", "a.cpp")); + ASSERT_EQUALS("", preprocessor0.getcode(filedata, "A", "a.cpp")); } void redundant_config() { @@ -2817,7 +2812,7 @@ private: preprocess(filedata, actual); // Compare results.. - ASSERT_EQUALS("char a[] = \"#endfile\";\nchar b[] = \"#endfile\";\n\n", actual[""]); + ASSERT_EQUALS("char a [ ] = \"#endfile\" ;\nchar b [ ] = \"#endfile\" ;", actual[""]); ASSERT_EQUALS(1, (int)actual.size()); } @@ -2937,7 +2932,7 @@ private: "#endif\n"); std::string actual = preprocessor0.getcode(src, "X=1", "test.c"); - ASSERT_EQUALS("\nFred & Wilma\n\n", actual); + ASSERT_EQUALS("\nFred & Wilma", actual); } void predefine2() { @@ -2946,12 +2941,12 @@ private: "#endif\n"); { std::string actual = preprocessor0.getcode(src, "X=1", "test.c"); - ASSERT_EQUALS("\n\n\n", actual); + ASSERT_EQUALS("", actual); } { std::string actual = preprocessor0.getcode(src, "X=1;Y=2", "test.c"); - ASSERT_EQUALS("\nFred & Wilma\n\n", actual); + ASSERT_EQUALS("\nFred & Wilma", actual); } } @@ -2963,22 +2958,22 @@ private: "Fred & Wilma\n" "#endif\n"; const std::string actual = preprocessor0.getcode(code, "TEST", "test.c"); - ASSERT_EQUALS("\n\n\nFred & Wilma\n\n", actual); + ASSERT_EQUALS("\n\n\nFred & Wilma", actual); } void predefine4() { // #3577 const char code[] = "char buf[X];\n"; const std::string actual = preprocessor0.getcode(code, "X=123", "test.c"); - ASSERT_EQUALS("char buf[$123];\n", actual); + ASSERT_EQUALS("char buf [ $123 ] ;", actual); } void predefine5() { // #3737, #5119 - automatically define __cplusplus // #3737... const char code[] = "#ifdef __cplusplus\n123\n#endif"; Settings settings; - ASSERT_EQUALS("\n\n\n", preprocessor0.getcode(code, "X=123", "test.c")); - ASSERT_EQUALS("\n123\n\n", preprocessor0.getcode(code, "X=123", "test.cpp")); + ASSERT_EQUALS("", preprocessor0.getcode(code, "X=123", "test.c")); + ASSERT_EQUALS("\n123", preprocessor0.getcode(code, "X=123", "test.cpp")); // #5119... ASSERT_EQUALS(false, Preprocessor::cplusplus(nullptr,"test.c")); @@ -3026,7 +3021,7 @@ private: // #2942 - segfault const char code[] = "#elif (){\n"; const std::string actual = preprocessor0.getcode(code, "TEST", "test.c"); - ASSERT_EQUALS("\n", actual); + ASSERT_EQUALS("", actual); } void def_handleIncludes() { @@ -3517,7 +3512,7 @@ private: // Compare results.. ASSERT_EQUALS(1U, actual.size()); - TODO_ASSERT_EQUALS("\n;\n","\n$XDefined;\n", actual[""]); + TODO_ASSERT_EQUALS("\n;","\n$XDefined;\n", actual[""]); } void undef8() { @@ -3619,14 +3614,6 @@ private: ASSERT_EQUALS(0U, configurations.size()); } - void macroChar() const { - const char filedata[] = "#define X 1\nX\n"; - ASSERT_EQUALS("\n$1\n", OurPreprocessor::expandMacros(filedata,nullptr)); - Preprocessor::macroChar = char(1); - ASSERT_EQUALS("\n" + std::string(char(1),1U) + "1\n", OurPreprocessor::expandMacros(filedata,nullptr)); - Preprocessor::macroChar = '$'; - } - void validateCfg() { Settings settings; Preprocessor preprocessor(settings, this); @@ -3674,7 +3661,7 @@ private: std::map actual; preprocess(code, actual); - ASSERT_EQUALS("\nFred & Wilma\n\n\n\n\n", actual[""]); + ASSERT_EQUALS("\nFred & Wilma", actual[""]); } void double_include() { diff --git a/tools/dmake.cpp b/tools/dmake.cpp index 9b44086e1..efe6fceff 100644 --- a/tools/dmake.cpp +++ b/tools/dmake.cpp @@ -375,9 +375,9 @@ int main(int argc, char **argv) << "endif\n\n"; makeConditionalVariable(fout, "PREFIX", "/usr"); - makeConditionalVariable(fout, "INCLUDE_FOR_LIB", "-Ilib -Iexternals/tinyxml"); + makeConditionalVariable(fout, "INCLUDE_FOR_LIB", "-Ilib -Iexternals/simplecpp -Iexternals/tinyxml"); makeConditionalVariable(fout, "INCLUDE_FOR_CLI", "-Ilib -Iexternals/tinyxml"); - makeConditionalVariable(fout, "INCLUDE_FOR_TEST", "-Ilib -Icli -Iexternals/tinyxml"); + makeConditionalVariable(fout, "INCLUDE_FOR_TEST", "-Ilib -Icli -Iexternals/simplecpp -Iexternals/tinyxml"); fout << "BIN=$(DESTDIR)$(PREFIX)/bin\n\n"; fout << "# For 'make man': sudo apt-get install xsltproc docbook-xsl docbook-xml on Linux\n";