diff --git a/externals/simplecpp/simplecpp.cpp b/externals/simplecpp/simplecpp.cpp index 68ff803da..c8c47bbb6 100644 --- a/externals/simplecpp/simplecpp.cpp +++ b/externals/simplecpp/simplecpp.cpp @@ -1,6 +1,6 @@ /* * simplecpp - A simple and high-fidelity C/C++ preprocessor library - * Copyright (C) 2016 Daniel Marjamäki. + * Copyright (C) 2016-2022 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 @@ -24,16 +24,18 @@ #include #include -#include #include +#include #include -#include // IWYU pragma: keep +#include #include #include -#include // IWYU pragma: keep +#include #include #include -#include +#if __cplusplus >= 201103L +#include +#endif #include #ifdef SIMPLECPP_WINDOWS @@ -42,6 +44,10 @@ #undef TRUE #endif +#if (__cplusplus < 201103L) && !defined(__APPLE__) +#define nullptr NULL +#endif + static bool isHex(const std::string &s) { return s.size()>2 && (s.compare(0,2,"0x")==0 || s.compare(0,2,"0X")==0); @@ -52,6 +58,17 @@ static bool isOct(const std::string &s) return s.size()>1 && (s[0]=='0') && (s[1] >= '0') && (s[1] < '8'); } +static bool isStringLiteral(const std::string &s) +{ + return s.size() > 1 && (s[0]=='\"') && (*s.rbegin()=='\"'); +} + +static bool isCharLiteral(const std::string &s) +{ + // char literal patterns can include 'a', '\t', '\000', '\xff', 'abcd', and maybe '' + // This only checks for the surrounding '' but doesn't parse the content. + return s.size() > 1 && (s[0]=='\'') && (*s.rbegin()=='\''); +} static const simplecpp::TokenString DEFINE("define"); static const simplecpp::TokenString UNDEF("undef"); @@ -152,7 +169,7 @@ const std::string simplecpp::Location::emptyFileName; void simplecpp::Location::adjust(const std::string &str) { - if (str.find_first_of("\r\n") == std::string::npos) { + if (strpbrk(str.c_str(), "\r\n") == nullptr) { col += str.size(); return; } @@ -170,17 +187,17 @@ void simplecpp::Location::adjust(const std::string &str) bool simplecpp::Token::isOneOf(const char ops[]) const { - return (op != '\0') && (std::strchr(ops, op) != NULL); + return (op != '\0') && (std::strchr(ops, op) != nullptr); } bool simplecpp::Token::startsWithOneOf(const char c[]) const { - return std::strchr(c, string[0]) != NULL; + return std::strchr(c, string[0]) != nullptr; } bool simplecpp::Token::endsWithOneOf(const char c[]) const { - return std::strchr(c, string[string.size() - 1U]) != NULL; + return std::strchr(c, string[string.size() - 1U]) != nullptr; } void simplecpp::Token::printAll() const @@ -208,21 +225,21 @@ void simplecpp::Token::printOut() const std::cout << std::endl; } -simplecpp::TokenList::TokenList(std::vector &filenames) : frontToken(NULL), backToken(NULL), files(filenames) {} +simplecpp::TokenList::TokenList(std::vector &filenames) : frontToken(nullptr), backToken(nullptr), files(filenames) {} simplecpp::TokenList::TokenList(std::istream &istr, std::vector &filenames, const std::string &filename, OutputList *outputList) - : frontToken(NULL), backToken(NULL), files(filenames) + : frontToken(nullptr), backToken(nullptr), files(filenames) { readfile(istr,filename,outputList); } -simplecpp::TokenList::TokenList(const TokenList &other) : frontToken(NULL), backToken(NULL), files(other.files) +simplecpp::TokenList::TokenList(const TokenList &other) : frontToken(nullptr), backToken(nullptr), files(other.files) { *this = other; } #if __cplusplus >= 201103L -simplecpp::TokenList::TokenList(TokenList &&other) : frontToken(NULL), backToken(NULL), files(other.files) +simplecpp::TokenList::TokenList(TokenList &&other) : TokenList(other) { *this = std::move(other); } @@ -237,6 +254,7 @@ simplecpp::TokenList &simplecpp::TokenList::operator=(const TokenList &other) { if (this != &other) { clear(); + files = other.files; for (const Token *tok = other.cfront(); tok; tok = tok->next) push_back(new Token(*tok)); sizeOfType = other.sizeOfType; @@ -249,10 +267,11 @@ simplecpp::TokenList &simplecpp::TokenList::operator=(TokenList &&other) { if (this != &other) { clear(); - backToken = other.backToken; - other.backToken = NULL; frontToken = other.frontToken; - other.frontToken = NULL; + other.frontToken = nullptr; + backToken = other.backToken; + other.backToken = nullptr; + files = other.files; sizeOfType = std::move(other.sizeOfType); } return *this; @@ -261,7 +280,7 @@ simplecpp::TokenList &simplecpp::TokenList::operator=(TokenList &&other) void simplecpp::TokenList::clear() { - backToken = NULL; + backToken = nullptr; while (frontToken) { Token *next = frontToken->next; delete frontToken; @@ -313,20 +332,20 @@ std::string simplecpp::TokenList::stringify() const static unsigned char readChar(std::istream &istr, unsigned int bom) { - unsigned char ch = (unsigned char)istr.get(); + unsigned char ch = static_cast(istr.get()); // For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the // character is non-ASCII character then replace it with 0xff if (bom == 0xfeff || bom == 0xfffe) { - const unsigned char ch2 = (unsigned char)istr.get(); + const unsigned char ch2 = static_cast(istr.get()); const int ch16 = (bom == 0xfeff) ? (ch<<8 | ch2) : (ch2<<8 | ch); - ch = (unsigned char)((ch16 >= 0x80) ? 0xff : ch16); + ch = static_cast(((ch16 >= 0x80) ? 0xff : ch16)); } // Handling of newlines.. if (ch == '\r') { ch = '\n'; - if (bom == 0 && (char)istr.peek() == '\n') + if (bom == 0 && static_cast(istr.peek()) == '\n') (void)istr.get(); else if (bom == 0xfeff || bom == 0xfffe) { int c1 = istr.get(); @@ -344,16 +363,16 @@ static unsigned char readChar(std::istream &istr, unsigned int bom) static unsigned char peekChar(std::istream &istr, unsigned int bom) { - unsigned char ch = (unsigned char)istr.peek(); + unsigned char ch = static_cast(istr.peek()); // For UTF-16 encoded files the BOM is 0xfeff/0xfffe. If the // character is non-ASCII character then replace it with 0xff if (bom == 0xfeff || bom == 0xfffe) { (void)istr.get(); - const unsigned char ch2 = (unsigned char)istr.peek(); + const unsigned char ch2 = static_cast(istr.peek()); istr.unget(); const int ch16 = (bom == 0xfeff) ? (ch<<8 | ch2) : (ch2<<8 | ch); - ch = (unsigned char)((ch16 >= 0x80) ? 0xff : ch16); + ch = static_cast(((ch16 >= 0x80) ? 0xff : ch16)); } // Handling of newlines.. @@ -376,9 +395,9 @@ static unsigned short getAndSkipBOM(std::istream &istr) // The UTF-16 BOM is 0xfffe or 0xfeff. if (ch1 >= 0xfe) { - unsigned short bom = ((unsigned char)istr.get() << 8); + unsigned short bom = (static_cast(istr.get()) << 8); if (istr.peek() >= 0xfe) - return bom | (unsigned char)istr.get(); + return bom | static_cast(istr.get()); istr.unget(); return 0; } @@ -450,13 +469,15 @@ void simplecpp::TokenList::lineDirective(unsigned int fileIndex, unsigned int li } } +static const std::string COMMENT_END("*/"); + void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filename, OutputList *outputList) { std::stack loc; unsigned int multiline = 0U; - const Token *oldLastToken = NULL; + const Token *oldLastToken = nullptr; const unsigned short bom = getAndSkipBOM(istr); @@ -477,7 +498,7 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen err.type = simplecpp::Output::UNHANDLED_CHAR_ERROR; err.location = location; std::ostringstream s; - s << (int)ch; + s << static_cast(ch); err.msg = "The code contains unhandled character(s) (character code=" + s.str() + "). Neither unicode nor extended ascii is supported."; outputList->push_back(err); } @@ -500,6 +521,8 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen if (oldLastToken != cback()) { oldLastToken = cback(); + if (!isLastLinePreprocessor()) + continue; const std::string lastline(lastLine()); if (lastline == "# file %str%") { const Token *strtok = cback(); @@ -590,7 +613,7 @@ void simplecpp::TokenList::readfile(std::istream &istr, const std::string &filen ch = readChar(istr,bom); while (istr.good()) { currentToken += ch; - if (currentToken.size() >= 4U && endsWith(currentToken, "*/")) + if (currentToken.size() >= 4U && endsWith(currentToken, COMMENT_END)) break; ch = readChar(istr,bom); } @@ -1194,19 +1217,42 @@ std::string simplecpp::TokenList::lastLine(int maxsize) const { std::string ret; int count = 0; - for (const Token *tok = cback(); sameline(tok,cback()); tok = tok->previous) { + for (const Token *tok = cback(); ; tok = tok->previous) { + if (!sameline(tok, cback())) { + break; + } if (tok->comment) continue; - if (!ret.empty()) - ret.insert(0, 1, ' '); - ret.insert(0, tok->str()[0] == '\"' ? std::string("%str%") - : tok->number ? std::string("%num%") : tok->str()); if (++count > maxsize) return ""; + if (!ret.empty()) + ret.insert(0, 1, ' '); + if (tok->str()[0] == '\"') + ret.insert(0, "%str%"); + else if (tok->number) + ret.insert(0, "%num%"); + else + ret.insert(0, tok->str()); } return ret; } +bool simplecpp::TokenList::isLastLinePreprocessor(int maxsize) const +{ + const Token* prevTok = nullptr; + int count = 0; + for (const Token *tok = cback(); ; tok = tok->previous) { + if (!sameline(tok, cback())) + break; + if (tok->comment) + continue; + if (++count > maxsize) + return false; + prevTok = tok; + } + return prevTok && prevTok->str()[0] == '#'; +} + unsigned int simplecpp::TokenList::fileIndex(const std::string &filename) { for (unsigned int i = 0; i < files.size(); ++i) { @@ -1219,11 +1265,18 @@ unsigned int simplecpp::TokenList::fileIndex(const std::string &filename) namespace simplecpp { + class Macro; +#if __cplusplus >= 201103L + using MacroMap = std::unordered_map; +#else + typedef std::map MacroMap; +#endif + class Macro { public: - explicit Macro(std::vector &f) : nameTokDef(NULL), variadic(false), valueToken(NULL), endToken(NULL), files(f), tokenListDefine(f), valueDefinedInCode_(false) {} + explicit Macro(std::vector &f) : nameTokDef(nullptr), variadic(false), valueToken(nullptr), endToken(nullptr), files(f), tokenListDefine(f), valueDefinedInCode_(false) {} - Macro(const Token *tok, std::vector &f) : nameTokDef(NULL), files(f), tokenListDefine(f), valueDefinedInCode_(true) { + Macro(const Token *tok, std::vector &f) : nameTokDef(nullptr), files(f), tokenListDefine(f), valueDefinedInCode_(true) { if (sameline(tok->previous, tok)) throw std::runtime_error("bad macro syntax"); if (tok->op != '#') @@ -1239,7 +1292,7 @@ namespace simplecpp { throw std::runtime_error("bad macro syntax"); } - Macro(const std::string &name, const std::string &value, std::vector &f) : nameTokDef(NULL), files(f), tokenListDefine(f), valueDefinedInCode_(false) { + Macro(const std::string &name, const std::string &value, std::vector &f) : nameTokDef(nullptr), files(f), tokenListDefine(f), valueDefinedInCode_(false) { const std::string def(name + ' ' + value); std::istringstream istr(def); tokenListDefine.readfile(istr); @@ -1247,20 +1300,22 @@ namespace simplecpp { throw std::runtime_error("bad macro syntax. macroname=" + name + " value=" + value); } - Macro(const Macro ¯o) : nameTokDef(NULL), files(macro.files), tokenListDefine(macro.files), valueDefinedInCode_(macro.valueDefinedInCode_) { - *this = macro; + Macro(const Macro &other) : nameTokDef(nullptr), files(other.files), tokenListDefine(other.files), valueDefinedInCode_(other.valueDefinedInCode_) { + *this = other; } - void operator=(const Macro ¯o) { - if (this != ¯o) { - valueDefinedInCode_ = macro.valueDefinedInCode_; - if (macro.tokenListDefine.empty()) - parseDefine(macro.nameTokDef); + Macro &operator=(const Macro &other) { + if (this != &other) { + files = other.files; + valueDefinedInCode_ = other.valueDefinedInCode_; + if (other.tokenListDefine.empty()) + parseDefine(other.nameTokDef); else { - tokenListDefine = macro.tokenListDefine; + tokenListDefine = other.tokenListDefine; parseDefine(tokenListDefine.cfront()); } } + return *this; } bool valueDefinedInCode() const { @@ -1278,7 +1333,7 @@ namespace simplecpp { */ const Token * expand(TokenList * const output, const Token * rawtok, - const std::map ¯os, + const MacroMap ¯os, std::vector &inputFiles) const { std::set expandedmacros; @@ -1332,7 +1387,7 @@ namespace simplecpp { break; if (output2.cfront() != output2.cback() && macro2tok->str() == this->name()) break; - const std::map::const_iterator macro = macros.find(macro2tok->str()); + const MacroMap::const_iterator macro = macros.find(macro2tok->str()); if (macro == macros.end() || !macro->second.functionLike()) break; TokenList rawtokens2(inputFiles); @@ -1357,7 +1412,7 @@ namespace simplecpp { } if (!rawtok2 || par != 1U) break; - if (macro->second.expand(&output2, rawtok->location, rawtokens2.cfront(), macros, expandedmacros) != NULL) + if (macro->second.expand(&output2, rawtok->location, rawtokens2.cfront(), macros, expandedmacros) != nullptr) break; rawtok = rawtok2->next; } @@ -1391,8 +1446,8 @@ namespace simplecpp { /** base class for errors */ struct Error { Error(const Location &loc, const std::string &s) : location(loc), what(s) {} - Location location; - std::string what; + const Location location; + const std::string what; }; /** Struct that is thrown when macro is expanded with wrong number of parameters */ @@ -1402,11 +1457,28 @@ namespace simplecpp { /** Struct that is thrown when there is invalid ## usage */ struct invalidHashHash : public Error { - invalidHashHash(const Location &loc, const std::string ¯oName) : Error(loc, "Invalid ## usage when expanding \'" + macroName + "\'.") {} + static inline std::string format(const std::string ¯oName, const std::string &message) { + return "Invalid ## usage when expanding \'" + macroName + "\': " + message; + } + + invalidHashHash(const Location &loc, const std::string ¯oName, const std::string &message) + : Error(loc, format(macroName, message)) { } + + static inline invalidHashHash unexpectedToken(const Location &loc, const std::string ¯oName, const Token *tokenA) { + return invalidHashHash(loc, macroName, "Unexpected token '"+ tokenA->str()+"'"); + } + + static inline invalidHashHash cannotCombine(const Location &loc, const std::string ¯oName, const Token *tokenA, const Token *tokenB) { + return invalidHashHash(loc, macroName, "Pasting '"+ tokenA->str()+ "' and '"+ tokenB->str() + "' yields an invalid token."); + } + + static inline invalidHashHash unexpectedNewline(const Location &loc, const std::string ¯oName) { + return invalidHashHash(loc, macroName, "Unexpected newline"); + } }; private: /** Create new token where Token::macro is set for replaced tokens */ - Token *newMacroToken(const TokenString &str, const Location &loc, bool replaced, const Token *expandedFromToken=NULL) const { + Token *newMacroToken(const TokenString &str, const Location &loc, bool replaced, const Token *expandedFromToken=nullptr) const { Token *tok = new Token(str,loc); if (replaced) tok->macro = nameTokDef->str(); @@ -1419,7 +1491,7 @@ namespace simplecpp { nameTokDef = nametoken; variadic = false; if (!nameTokDef) { - valueToken = endToken = NULL; + valueToken = endToken = nullptr; args.clear(); return false; } @@ -1443,17 +1515,17 @@ namespace simplecpp { } if (!sameline(nametoken, argtok)) { endToken = argtok ? argtok->previous : argtok; - valueToken = NULL; + valueToken = nullptr; return false; } - valueToken = argtok ? argtok->next : NULL; + valueToken = argtok ? argtok->next : nullptr; } else { args.clear(); valueToken = nameTokDef->next; } if (!sameline(valueToken, nameTokDef)) - valueToken = NULL; + valueToken = nullptr; endToken = valueToken; while (sameline(endToken, nameTokDef)) endToken = endToken->next; @@ -1477,7 +1549,7 @@ namespace simplecpp { std::vector parametertokens; parametertokens.push_back(nameTokInst->next); unsigned int par = 0U; - for (const Token *tok = nameTokInst->next->next; calledInDefine ? sameline(tok, nameTokInst) : (tok != NULL); tok = tok->next) { + for (const Token *tok = nameTokInst->next->next; calledInDefine ? sameline(tok, nameTokInst) : (tok != nullptr); tok = tok->next) { if (tok->op == '(') ++par; else if (tok->op == ')') { @@ -1495,11 +1567,11 @@ namespace simplecpp { const Token *appendTokens(TokenList *tokens, const Location &rawloc, const Token * const lpar, - const std::map ¯os, + const MacroMap ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { if (!lpar || lpar->op != '(') - return NULL; + return nullptr; unsigned int par = 0; const Token *tok = lpar; while (sameline(lpar, tok)) { @@ -1511,7 +1583,7 @@ namespace simplecpp { } else { if (!expandArg(tokens, tok, rawloc, macros, expandedmacros, parametertokens)) { bool expanded = false; - const std::map::const_iterator it = macros.find(tok->str()); + const MacroMap::const_iterator it = macros.find(tok->str()); if (it != macros.end() && expandedmacros.find(tok->str()) == expandedmacros.end()) { const Macro &m = it->second; if (!m.functionLike()) { @@ -1538,10 +1610,10 @@ namespace simplecpp { } for (Token *tok2 = tokens->front(); tok2; tok2 = tok2->next) tok2->location = lpar->location; - return sameline(lpar,tok) ? tok : NULL; + return sameline(lpar,tok) ? tok : nullptr; } - const Token * expand(TokenList * const output, const Location &loc, const Token * const nameTokInst, const std::map ¯os, std::set expandedmacros, bool first=false) const { + const Token * expand(TokenList * const output, const Location &loc, const Token * const nameTokInst, const MacroMap ¯os, std::set expandedmacros, bool first=false) const { if (!first) expandedmacros.insert(nameTokInst->str()); @@ -1596,7 +1668,7 @@ namespace simplecpp { } } - const std::map::const_iterator m = macros.find("__COUNTER__"); + const MacroMap::const_iterator m = macros.find("__COUNTER__"); if (!counter || m == macros.end()) parametertokens2.swap(parametertokens1); @@ -1626,7 +1698,7 @@ namespace simplecpp { // A##B => AB if (sameline(tok, tok->next) && tok->next && tok->next->op == '#' && tok->next->next && tok->next->next->op == '#') { if (!sameline(tok, tok->next->next->next)) - throw invalidHashHash(tok->location, name()); + throw invalidHashHash::unexpectedNewline(tok->location, name()); TokenList new_output(files); if (!expandArg(&new_output, tok, parametertokens2)) output->push_back(newMacroToken(tok->str(), loc, isReplaced(expandedmacros), tok)); @@ -1687,7 +1759,7 @@ namespace simplecpp { return functionLike() ? parametertokens2.back()->next : nameTokInst->next; } - const Token *recursiveExpandToken(TokenList *output, TokenList &temp, const Location &loc, const Token *tok, const std::map ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { + const Token *recursiveExpandToken(TokenList *output, TokenList &temp, const Location &loc, const Token *tok, const MacroMap ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { if (!(temp.cback() && temp.cback()->name && tok->next && tok->next->op == '(')) { output->takeTokens(temp); return tok->next; @@ -1698,7 +1770,7 @@ namespace simplecpp { return tok->next; } - const std::map::const_iterator it = macros.find(temp.cback()->str()); + const MacroMap::const_iterator it = macros.find(temp.cback()->str()); if (it == macros.end() || expandedmacros.find(temp.cback()->str()) != expandedmacros.end()) { output->takeTokens(temp); return tok->next; @@ -1722,7 +1794,7 @@ namespace simplecpp { return tok2->next; } - const Token *expandToken(TokenList *output, const Location &loc, const Token *tok, const std::map ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { + const Token *expandToken(TokenList *output, const Location &loc, const Token *tok, const MacroMap ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { // Not name.. if (!tok->name) { output->push_back(newMacroToken(tok->str(), loc, true, tok)); @@ -1737,7 +1809,7 @@ namespace simplecpp { } // Macro.. - const std::map::const_iterator it = macros.find(tok->str()); + const MacroMap::const_iterator it = macros.find(tok->str()); if (it != macros.end() && expandedmacros.find(tok->str()) == expandedmacros.end()) { std::set expandedmacros2(expandedmacros); expandedmacros2.insert(tok->str()); @@ -1766,10 +1838,10 @@ namespace simplecpp { else if (tok->str() == DEFINED) { const Token *tok2 = tok->next; - const Token *tok3 = tok2 ? tok2->next : NULL; - const Token *tok4 = tok3 ? tok3->next : NULL; - const Token *defToken = NULL; - const Token *lastToken = NULL; + const Token *tok3 = tok2 ? tok2->next : nullptr; + const Token *tok4 = tok3 ? tok3->next : nullptr; + const Token *defToken = nullptr; + const Token *lastToken = nullptr; if (sameline(tok, tok4) && tok2->op == '(' && tok3->name && tok4->op == ')') { defToken = tok3; lastToken = tok4; @@ -1816,7 +1888,7 @@ namespace simplecpp { return true; } - bool expandArg(TokenList *output, const Token *tok, const Location &loc, const std::map ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { + bool expandArg(TokenList *output, const Token *tok, const Location &loc, const MacroMap ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { if (!tok->name) return false; const unsigned int argnr = getArgNum(tok->str()); @@ -1825,7 +1897,7 @@ namespace simplecpp { if (variadic && argnr + 1U >= parametertokens.size()) // empty variadic parameter return true; for (const Token *partok = parametertokens[argnr]->next; partok != parametertokens[argnr + 1U];) { - const std::map::const_iterator it = macros.find(partok->str()); + const MacroMap::const_iterator it = macros.find(partok->str()); if (it != macros.end() && !partok->isExpandedFrom(&it->second) && (partok->str() == name() || expandedmacros.find(partok->str()) == expandedmacros.end())) partok = it->second.expand(output, loc, partok, macros, expandedmacros); else { @@ -1847,7 +1919,7 @@ namespace simplecpp { * @param parametertokens parameters given when expanding this macro * @return token after the X */ - const Token *expandHash(TokenList *output, const Location &loc, const Token *tok, const std::map ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { + const Token *expandHash(TokenList *output, const Location &loc, const Token *tok, const MacroMap ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { TokenList tokenListHash(files); tok = expandToken(&tokenListHash, loc, tok->next, macros, expandedmacros, parametertokens); std::ostringstream ostr; @@ -1870,74 +1942,93 @@ namespace simplecpp { * @param parametertokens parameters given when expanding this macro * @return token after B */ - const Token *expandHashHash(TokenList *output, const Location &loc, const Token *tok, const std::map ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { + const Token *expandHashHash(TokenList *output, const Location &loc, const Token *tok, const MacroMap ¯os, const std::set &expandedmacros, const std::vector ¶metertokens) const { Token *A = output->back(); if (!A) - throw invalidHashHash(tok->location, name()); + throw invalidHashHash(tok->location, name(), "Missing first argument"); if (!sameline(tok, tok->next) || !sameline(tok, tok->next->next)) - throw invalidHashHash(tok->location, name()); + throw invalidHashHash::unexpectedNewline(tok->location, name()); bool canBeConcatenatedWithEqual = A->isOneOf("+-*/%&|^") || A->str() == "<<" || A->str() == ">>"; - if (!A->name && !A->number && A->op != ',' && !A->str().empty() && !canBeConcatenatedWithEqual) - throw invalidHashHash(tok->location, name()); + bool canBeConcatenatedStringOrChar = isStringLiteral(A->str()) || isCharLiteral(A->str()); + if (!A->name && !A->number && A->op != ',' && !A->str().empty() && !canBeConcatenatedWithEqual && !canBeConcatenatedStringOrChar) + throw invalidHashHash::unexpectedToken(tok->location, name(), A); Token *B = tok->next->next; if (!B->name && !B->number && B->op && !B->isOneOf("#=")) - throw invalidHashHash(tok->location, name()); + throw invalidHashHash::unexpectedToken(tok->location, name(), B); if ((canBeConcatenatedWithEqual && B->op != '=') || (!canBeConcatenatedWithEqual && B->op == '=')) - throw invalidHashHash(tok->location, name()); + throw invalidHashHash::cannotCombine(tok->location, name(), A, B); - std::string strAB; - - const bool varargs = variadic && args.size() >= 1U && B->str() == args[args.size()-1U]; + // Superficial check; more in-depth would in theory be possible _after_ expandArg + if (canBeConcatenatedStringOrChar && (B->number || !B->name)) + throw invalidHashHash::cannotCombine(tok->location, name(), A, B); TokenList tokensB(files); - if (expandArg(&tokensB, B, parametertokens)) { - if (tokensB.empty()) - strAB = A->str(); - else if (varargs && A->op == ',') { - strAB = ","; - } else { - strAB = A->str() + tokensB.cfront()->str(); - tokensB.deleteToken(tokensB.front()); - } - } else { - strAB = A->str() + B->str(); - } - const Token *nextTok = B->next; - if (varargs && tokensB.empty() && tok->previous->str() == ",") - output->deleteToken(A); - else if (strAB != "," && macros.find(strAB) == macros.end()) { - A->setstr(strAB); - for (Token *b = tokensB.front(); b; b = b->next) - b->location = loc; - output->takeTokens(tokensB); - } else if (nextTok->op == '#' && nextTok->next->op == '#') { - TokenList output2(files); - output2.push_back(new Token(strAB, tok->location)); - nextTok = expandHashHash(&output2, loc, nextTok, macros, expandedmacros, parametertokens); - output->deleteToken(A); - output->takeTokens(output2); - } else { - output->deleteToken(A); - TokenList tokens(files); - tokens.push_back(new Token(strAB, tok->location)); - // for function like macros, push the (...) - if (tokensB.empty() && sameline(B,B->next) && B->next->op=='(') { - const std::map::const_iterator it = macros.find(strAB); - if (it != macros.end() && expandedmacros.find(strAB) == expandedmacros.end() && it->second.functionLike()) { - const Token *tok2 = appendTokens(&tokens, loc, B->next, macros, expandedmacros, parametertokens); - if (tok2) - nextTok = tok2->next; - } + + if (canBeConcatenatedStringOrChar) { + // It seems clearer to handle this case separately even though the code is similar-ish, but we don't want to merge here. + // TODO The question is whether the ## or varargs may still apply, and how to provoke? + if (expandArg(&tokensB, B, parametertokens)) { + for (Token *b = tokensB.front(); b; b = b->next) + b->location = loc; + } else { + tokensB.push_back(new Token(*B)); + tokensB.back()->location = loc; } - expandToken(output, loc, tokens.cfront(), macros, expandedmacros, parametertokens); - for (Token *b = tokensB.front(); b; b = b->next) - b->location = loc; output->takeTokens(tokensB); + } else { + std::string strAB; + + const bool varargs = variadic && args.size() >= 1U && B->str() == args[args.size()-1U]; + + if (expandArg(&tokensB, B, parametertokens)) { + if (tokensB.empty()) + strAB = A->str(); + else if (varargs && A->op == ',') { + strAB = ","; + } else { + strAB = A->str() + tokensB.cfront()->str(); + tokensB.deleteToken(tokensB.front()); + } + } else { + strAB = A->str() + B->str(); + } + + if (varargs && tokensB.empty() && tok->previous->str() == ",") + output->deleteToken(A); + else if (strAB != "," && macros.find(strAB) == macros.end()) { + A->setstr(strAB); + for (Token *b = tokensB.front(); b; b = b->next) + b->location = loc; + output->takeTokens(tokensB); + } else if (nextTok->op == '#' && nextTok->next->op == '#') { + TokenList output2(files); + output2.push_back(new Token(strAB, tok->location)); + nextTok = expandHashHash(&output2, loc, nextTok, macros, expandedmacros, parametertokens); + output->deleteToken(A); + output->takeTokens(output2); + } else { + output->deleteToken(A); + TokenList tokens(files); + tokens.push_back(new Token(strAB, tok->location)); + // for function like macros, push the (...) + if (tokensB.empty() && sameline(B,B->next) && B->next->op=='(') { + const MacroMap::const_iterator it = macros.find(strAB); + if (it != macros.end() && expandedmacros.find(strAB) == expandedmacros.end() && it->second.functionLike()) { + const Token *tok2 = appendTokens(&tokens, loc, B->next, macros, expandedmacros, parametertokens); + if (tok2) + nextTok = tok2->next; + } + } + expandToken(output, loc, tokens.cfront(), macros, expandedmacros, parametertokens); + for (Token *b = tokensB.front(); b; b = b->next) + b->location = loc; + output->takeTokens(tokensB); + } } return nextTok; @@ -2220,14 +2311,19 @@ namespace simplecpp { continue; } // get previous subpath - const std::string::size_type pos1 = path.rfind('/', pos - 1U) + 1U; - const std::string previousSubPath = path.substr(pos1, pos-pos1); + std::string::size_type pos1 = path.rfind('/', pos - 1U); + if (pos1 == std::string::npos) { + pos1 = 0; + } else { + pos1 += 1U; + } + const std::string previousSubPath = path.substr(pos1, pos - pos1); if (previousSubPath == "..") { // don't simplify ++pos; } else { // remove previous subpath and ".." - path.erase(pos1,pos-pos1+4); + path.erase(pos1, pos - pos1 + 4); if (path.empty()) path = "."; // update pos @@ -2623,7 +2719,7 @@ static NonExistingFilesCache nonExistingFilesCache; #endif -static std::string _openHeader(std::ifstream &f, const std::string &path) +static std::string openHeader(std::ifstream &f, const std::string &path) { #ifdef SIMPLECPP_WINDOWS std::string simplePath = simplecpp::simplifyPath(path); @@ -2652,7 +2748,7 @@ static std::string getRelativeFileName(const std::string &sourcefile, const std: static std::string openHeaderRelative(std::ifstream &f, const std::string &sourcefile, const std::string &header) { - return _openHeader(f, getRelativeFileName(sourcefile, header)); + return openHeader(f, getRelativeFileName(sourcefile, header)); } static std::string getIncludePathFileName(const std::string &includePath, const std::string &header) @@ -2666,7 +2762,7 @@ static std::string getIncludePathFileName(const std::string &includePath, const static std::string openHeaderIncludePath(std::ifstream &f, const simplecpp::DUI &dui, const std::string &header) { for (std::list::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) { - std::string simplePath = _openHeader(f, getIncludePathFileName(*it, header)); + std::string simplePath = openHeader(f, getIncludePathFileName(*it, header)); if (!simplePath.empty()) return simplePath; } @@ -2676,7 +2772,7 @@ static std::string openHeaderIncludePath(std::ifstream &f, const simplecpp::DUI static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const std::string &sourcefile, const std::string &header, bool systemheader) { if (isAbsolutePath(header)) - return _openHeader(f, header); + return openHeader(f, header); std::string ret; @@ -2754,8 +2850,8 @@ std::map simplecpp::load(const simplecpp::To filelist.push_back(tokenlist->front()); } - for (const Token *rawtok = rawtokens.cfront(); rawtok || !filelist.empty(); rawtok = rawtok ? rawtok->next : NULL) { - if (rawtok == NULL) { + for (const Token *rawtok = rawtokens.cfront(); rawtok || !filelist.empty(); rawtok = rawtok ? rawtok->next : nullptr) { + if (rawtok == nullptr) { rawtok = filelist.back(); filelist.pop_back(); } @@ -2792,10 +2888,10 @@ std::map simplecpp::load(const simplecpp::To return ret; } -static bool preprocessToken(simplecpp::TokenList &output, const simplecpp::Token **tok1, std::map ¯os, std::vector &files, simplecpp::OutputList *outputList) +static bool preprocessToken(simplecpp::TokenList &output, const simplecpp::Token **tok1, simplecpp::MacroMap ¯os, std::vector &files, simplecpp::OutputList *outputList) { const simplecpp::Token *tok = *tok1; - const std::map::const_iterator it = macros.find(tok->str()); + const simplecpp::MacroMap::const_iterator it = macros.find(tok->str()); if (it != macros.end()) { simplecpp::TokenList value(files); try { @@ -2819,6 +2915,28 @@ static bool preprocessToken(simplecpp::TokenList &output, const simplecpp::Token return true; } +static void getLocaltime(struct tm <ime) { + time_t t; + time(&t); +#ifndef _WIN32 + localtime_r(&t, <ime); +#else + localtime_s(<ime, &t); +#endif +} + +static std::string getDateDefine(struct tm *timep) { + char buf[] = "??? ?? ????"; + strftime(buf, sizeof(buf), "%b %d %Y", timep); + return std::string("\"").append(buf).append("\""); +} + +static std::string getTimeDefine(struct tm *timep) { + char buf[] = "??:??:??"; + strftime(buf, sizeof(buf), "%T", timep); + return std::string("\"").append(buf).append("\""); +} + void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenList &rawtokens, std::vector &files, std::map &filedata, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, std::list *macroUsage, std::list *ifCond) { std::map sizeOfType(rawtokens.sizeOfType); @@ -2844,7 +2962,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL sizeOfType.insert(std::make_pair("long double *", sizeof(long double *))); const bool hasInclude = (dui.std.size() == 5 && dui.std.compare(0,3,"c++") == 0 && dui.std >= "c++17"); - std::map macros; + MacroMap macros; for (std::list::const_iterator it = dui.defines.begin(); it != dui.defines.end(); ++it) { const std::string ¯ostr = *it; const std::string::size_type eq = macrostr.find('='); @@ -2861,15 +2979,21 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL macros.insert(std::make_pair("__FILE__", Macro("__FILE__", "__FILE__", files))); macros.insert(std::make_pair("__LINE__", Macro("__LINE__", "__LINE__", files))); macros.insert(std::make_pair("__COUNTER__", Macro("__COUNTER__", "__COUNTER__", files))); + struct tm ltime = {}; + getLocaltime(ltime); + macros.insert(std::make_pair("__DATE__", Macro("__DATE__", getDateDefine(<ime), files))); + macros.insert(std::make_pair("__TIME__", Macro("__TIME__", getTimeDefine(<ime), files))); - if (dui.std == "c++11") - macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", "201103L", files))); - else if (dui.std == "c++14") - macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", "201402L", files))); - else if (dui.std == "c++17") - macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", "201703L", files))); - else if (dui.std == "c++20") - macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", "202002L", files))); + if (!dui.std.empty()) { + std::string std_def = simplecpp::getCStdString(dui.std); + if (!std_def.empty()) { + macros.insert(std::make_pair("__STDC_VERSION__", Macro("__STDC_VERSION__", std_def, files))); + } else { + std_def = simplecpp::getCppStdString(dui.std); + if (!std_def.empty()) + macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", std_def, files))); + } + } // 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. @@ -2889,8 +3013,10 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL includetokenstack.push(f->second->cfront()); } - for (const Token *rawtok = NULL; rawtok || !includetokenstack.empty();) { - if (rawtok == NULL) { + std::map > maybeUsedMacros; + + for (const Token *rawtok = nullptr; rawtok || !includetokenstack.empty();) { + if (rawtok == nullptr) { rawtok = includetokenstack.top(); includetokenstack.pop(); continue; @@ -2944,7 +3070,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL try { const Macro ¯o = Macro(rawtok->previous, files); if (dui.undefined.find(macro.name()) == dui.undefined.end()) { - std::map::iterator it = macros.find(macro.name()); + MacroMap::iterator it = macros.find(macro.name()); if (it == macros.end()) macros.insert(std::pair(macro.name(), macro)); else @@ -3035,7 +3161,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL } else if (pragmaOnce.find(header2) == pragmaOnce.end()) { includetokenstack.push(gotoNextLine(rawtok)); const TokenList *includetokens = filedata.find(header2)->second; - rawtok = includetokens ? includetokens->cfront() : NULL; + rawtok = includetokens ? includetokens->cfront() : nullptr; continue; } } else if (rawtok->str() == IF || rawtok->str() == IFDEF || rawtok->str() == IFNDEF || rawtok->str() == ELIF) { @@ -3054,11 +3180,13 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL bool conditionIsTrue; if (ifstates.top() == ALWAYS_FALSE || (ifstates.top() == ELSE_IS_TRUE && rawtok->str() != ELIF)) conditionIsTrue = false; - else if (rawtok->str() == IFDEF) + else if (rawtok->str() == IFDEF) { conditionIsTrue = (macros.find(rawtok->next->str()) != macros.end() || (hasInclude && rawtok->next->str() == HAS_INCLUDE)); - else if (rawtok->str() == IFNDEF) + maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location); + } else if (rawtok->str() == IFNDEF) { conditionIsTrue = (macros.find(rawtok->next->str()) == macros.end() && !(hasInclude && rawtok->next->str() == HAS_INCLUDE)); - else { /*if (rawtok->str() == IF || rawtok->str() == ELIF)*/ + maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location); + } else { /*if (rawtok->str() == IF || rawtok->str() == ELIF)*/ TokenList expr(files); for (const Token *tok = rawtok->next; tok && tok->location.sameline(rawtok->location); tok = tok->next) { if (!tok->name) { @@ -3071,6 +3199,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL const bool par = (tok && tok->op == '('); if (par) tok = tok->next; + maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location); if (tok) { if (macros.find(tok->str()) != macros.end()) expr.push_back(new Token("1", tok->location)); @@ -3080,7 +3209,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL expr.push_back(new Token("0", tok->location)); } if (par) - tok = tok ? tok->next : NULL; + tok = tok ? tok->next : nullptr; if (!tok || !sameline(rawtok,tok) || (par && tok->op != ')')) { if (outputList) { Output out(rawtok->location.files); @@ -3109,7 +3238,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL expr.push_back(new Token(header2.empty() ? "0" : "1", tok->location)); } if (par) - tok = tok ? tok->next : NULL; + tok = tok ? tok->next : nullptr; if (!tok || !sameline(rawtok,tok) || (par && tok->op != ')')) { if (outputList) { Output out(rawtok->location.files); @@ -3124,6 +3253,8 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL continue; } + maybeUsedMacros[rawtok->next->str()].push_back(rawtok->next->location); + const Token *tmp = tok; if (!preprocessToken(expr, &tmp, macros, files, outputList)) { output.clear(); @@ -3231,9 +3362,11 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL } if (macroUsage) { - for (std::map::const_iterator macroIt = macros.begin(); macroIt != macros.end(); ++macroIt) { + for (simplecpp::MacroMap::const_iterator macroIt = macros.begin(); macroIt != macros.end(); ++macroIt) { const Macro ¯o = macroIt->second; - const std::list &usage = macro.usage(); + std::list usage = macro.usage(); + const std::list& temp = maybeUsedMacros[macro.name()]; + usage.insert(usage.end(), temp.begin(), temp.end()); for (std::list::const_iterator usageIt = usage.begin(); usageIt != usage.end(); ++usageIt) { MacroUsage mu(usageIt->files, macro.valueDefinedInCode()); mu.macroName = macro.name(); @@ -3251,3 +3384,48 @@ void simplecpp::cleanup(std::map &filedata) delete it->second; filedata.clear(); } + +std::string simplecpp::getCStdString(const std::string &std) +{ + if (std == "c90" || std == "c89" || std == "iso9899:1990" || std == "iso9899:199409" || std == "gnu90" || std == "gnu89") { + // __STDC_VERSION__ is not set for C90 although the macro was added in the 1994 amendments + return ""; + } + if (std == "c99" || std == "c9x" || std == "iso9899:1999" || std == "iso9899:199x" || std == "gnu99"|| std == "gnu9x") + return "199901L"; + if (std == "c11" || std == "c1x" || std == "iso9899:2011" || std == "gnu11" || std == "gnu1x") + return "201112L"; + if (std == "c17" || std == "c18" || std == "iso9899:2017" || std == "iso9899:2018" || std == "gnu17"|| std == "gnu18") + return "201710L"; + if (std == "c2x" || std == "gnu2x") { + // Clang 11 returns "201710L" + return "202000L"; + } + return ""; +} + +std::string simplecpp::getCppStdString(const std::string &std) +{ + if (std == "c++98" || std == "c++03" || std == "gnu++98" || std == "gnu++03") + return "199711L"; + if (std == "c++11" || std == "gnu++11" || std == "c++0x" || std == "gnu++0x") + return "201103L"; + if (std == "c++14" || std == "c++1y" || std == "gnu++14" || std == "gnu++1y") + return "201402L"; + if (std == "c++17" || std == "c++1z" || std == "gnu++17" || std == "gnu++1z") + return "201703L"; + if (std == "c++20" || std == "c++2a" || std == "gnu++20" || std == "gnu++2a") { + // GCC 10 returns "201703L" + return "202002L"; + } + /* + if (std == "c++23" || std == "c++2b" || std == "gnu++23" || std == "gnu++2b") { + // supported by GCC 11+ + return ""; + } */ + return ""; +} + +#if (__cplusplus < 201103L) && !defined(__APPLE__) +#undef nullptr +#endif diff --git a/externals/simplecpp/simplecpp.h b/externals/simplecpp/simplecpp.h index faeb20076..4b97aa350 100644 --- a/externals/simplecpp/simplecpp.h +++ b/externals/simplecpp/simplecpp.h @@ -1,6 +1,6 @@ /* * simplecpp - A simple and high-fidelity C/C++ preprocessor library - * Copyright (C) 2016 Daniel Marjamäki. + * Copyright (C) 2016-2022 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 @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -40,10 +41,14 @@ # define SIMPLECPP_LIB #endif +#if (__cplusplus < 201103L) && !defined(__APPLE__) +#define nullptr NULL +#endif namespace simplecpp { typedef std::string TokenString; + class Macro; /** * Location in source code @@ -97,20 +102,19 @@ namespace simplecpp { class SIMPLECPP_LIB Token { public: Token(const TokenString &s, const Location &loc) : - location(loc), previous(NULL), next(NULL), string(s) { + location(loc), previous(nullptr), next(nullptr), string(s) { flags(); } Token(const Token &tok) : - macro(tok.macro), location(tok.location), previous(NULL), next(NULL), string(tok.string) { - flags(); + macro(tok.macro), op(tok.op), comment(tok.comment), name(tok.name), number(tok.number), location(tok.location), previous(nullptr), next(nullptr), string(tok.string), mExpandedFrom(tok.mExpandedFrom) { } void flags() { - name = (std::isalpha((unsigned char)string[0]) || string[0] == '_' || string[0] == '$') - && (string.find('\'') == string.npos); + name = (std::isalpha(static_cast(string[0])) || string[0] == '_' || string[0] == '$') + && (std::memchr(string.c_str(), '\'', string.size()) == nullptr); comment = string.size() > 1U && string[0] == '/' && (string[1] == '/' || string[1] == '*'); - number = std::isdigit((unsigned char)string[0]) || (string.size() > 1U && string[0] == '-' && std::isdigit((unsigned char)string[1])); + number = std::isdigit(static_cast(string[0])) || (string.size() > 1U && string[0] == '-' && std::isdigit(static_cast(string[1]))); op = (string.size() == 1U) ? string[0] : '\0'; } @@ -149,11 +153,11 @@ namespace simplecpp { return tok; } - void setExpandedFrom(const Token *tok, const void* m) { + void setExpandedFrom(const Token *tok, const Macro* m) { mExpandedFrom = tok->mExpandedFrom; mExpandedFrom.insert(m); } - bool isExpandedFrom(const void* m) const { + bool isExpandedFrom(const Macro* m) const { return mExpandedFrom.find(m) != mExpandedFrom.end(); } @@ -162,7 +166,7 @@ namespace simplecpp { private: TokenString string; - std::set mExpandedFrom; + std::set mExpandedFrom; // Not implemented - prevent assignment Token &operator=(const Token &tok); @@ -191,7 +195,7 @@ namespace simplecpp { class SIMPLECPP_LIB TokenList { public: explicit TokenList(std::vector &filenames); - TokenList(std::istream &istr, std::vector &filenames, const std::string &filename=std::string(), OutputList *outputList = NULL); + TokenList(std::istream &istr, std::vector &filenames, const std::string &filename=std::string(), OutputList *outputList = nullptr); TokenList(const TokenList &other); #if __cplusplus >= 201103L TokenList(TokenList &&other); @@ -211,7 +215,7 @@ namespace simplecpp { void dump() const; std::string stringify() const; - void readfile(std::istream &istr, const std::string &filename=std::string(), OutputList *outputList = NULL); + void readfile(std::istream &istr, const std::string &filename=std::string(), OutputList *outputList = nullptr); void constFold(); void removeComments(); @@ -258,7 +262,7 @@ namespace simplecpp { other.frontToken->previous = backToken; } backToken = other.backToken; - other.frontToken = other.backToken = NULL; + other.frontToken = other.backToken = nullptr; } /** sizeof(T) */ @@ -280,6 +284,7 @@ namespace simplecpp { void lineDirective(unsigned int fileIndex, unsigned int line, Location *location); std::string lastLine(int maxsize=100000) const; + bool isLastLinePreprocessor(int maxsize=100000) const; unsigned int fileIndex(const std::string &filename); @@ -320,7 +325,7 @@ namespace simplecpp { SIMPLECPP_LIB long long characterLiteralToLL(const std::string& str); - SIMPLECPP_LIB std::map load(const TokenList &rawtokens, std::vector &filenames, const DUI &dui, OutputList *outputList = NULL); + SIMPLECPP_LIB std::map load(const TokenList &rawtokens, std::vector &filenames, const DUI &dui, OutputList *outputList = nullptr); /** * Preprocess @@ -334,7 +339,7 @@ namespace simplecpp { * @param macroUsage output: macro usage * @param ifCond output: #if/#elif expressions */ - SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector &files, std::map &filedata, const DUI &dui, OutputList *outputList = NULL, std::list *macroUsage = NULL, std::list *ifCond = NULL); + SIMPLECPP_LIB void preprocess(TokenList &output, const TokenList &rawtokens, std::vector &files, std::map &filedata, const DUI &dui, OutputList *outputList = nullptr, std::list *macroUsage = nullptr, std::list *ifCond = nullptr); /** * Deallocate data @@ -346,6 +351,16 @@ namespace simplecpp { /** Convert Cygwin path to Windows path */ SIMPLECPP_LIB std::string convertCygwinToWindowsPath(const std::string &cygwinPath); + + /** Returns the __STDC_VERSION__ value for a given standard */ + SIMPLECPP_LIB static std::string getCStdString(const std::string &std); + + /** Returns the __cplusplus value for a given standard */ + SIMPLECPP_LIB static std::string getCppStdString(const std::string &std); } +#if (__cplusplus < 201103L) && !defined(__APPLE__) +#undef nullptr +#endif + #endif