Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ option(DISABLE_CPP03_SYNTAX_CHECK "Disable the C++03 syntax check." OFF)

include(CheckCXXCompilerFlag)

if (WIN32)
# prevent simplifyPath_cppcheck() from wasting time on looking for a hypothetical network host
add_definitions(-DUNCHOST=$ENV{COMPUTERNAME})
endif()

function(add_compile_options_safe FLAG)
string(MAKE_C_IDENTIFIER "HAS_CXX_FLAG${FLAG}" mangled_flag)
check_cxx_compiler_flag(${FLAG} ${mangled_flag})
Expand Down
1 change: 0 additions & 1 deletion run-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ def cleanup(out):
'c99-6_10_3_4_p6.c',
'expr_usual_conversions.c', # condition is true: 4U - 30 >= 0
'stdint.c',
'stringize_misc.c',

# GCC..
'diagnostic-pragma-1.c',
Expand Down
82 changes: 35 additions & 47 deletions simplecpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ static const simplecpp::TokenString ONCE("once");

static const simplecpp::TokenString HAS_INCLUDE("__has_include");

static const simplecpp::TokenString INNER_COMMA(",,");

template<class T> static std::string toString(T t)
{
// NOLINTNEXTLINE(misc-const-correctness) - false positive
Expand Down Expand Up @@ -888,7 +886,7 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename,
}

if (prefix.empty())
push_back(new Token(s, location)); // push string without newlines
push_back(new Token(s, location, isspace(stream.peekChar()))); // push string without newlines
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is not guaranteed to be portable. we include the <cctype> so we should call std::isspace.

else
back()->setstr(prefix + s);

Expand Down Expand Up @@ -918,7 +916,7 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename,
}
}

push_back(new Token(currentToken, location));
push_back(new Token(currentToken, location, isspace(stream.peekChar())));

if (multiline)
location.col += currentToken.size();
Expand Down Expand Up @@ -1548,9 +1546,9 @@ namespace simplecpp {
// Copy macro call to a new tokenlist with no linebreaks
const Token * const rawtok1 = rawtok;
TokenList rawtokens2(inputFiles);
rawtokens2.push_back(new Token(rawtok->str(), rawtok1->location));
rawtokens2.push_back(new Token(rawtok->str(), rawtok1->location, rawtok->whitespaceahead));
rawtok = rawtok->next;
rawtokens2.push_back(new Token(rawtok->str(), rawtok1->location));
rawtokens2.push_back(new Token(rawtok->str(), rawtok1->location, rawtok->whitespaceahead));
rawtok = rawtok->next;
int par = 1;
while (rawtok && par > 0) {
Expand All @@ -1560,13 +1558,10 @@ namespace simplecpp {
--par;
else if (rawtok->op == '#' && !sameline(rawtok->previous, rawtok))
throw Error(rawtok->location, "it is invalid to use a preprocessor directive as macro parameter");
rawtokens2.push_back(new Token(rawtok->str(), rawtok1->location));
rawtokens2.push_back(new Token(rawtok->str(), rawtok1->location, rawtok->whitespaceahead));
rawtok = rawtok->next;
}
bool first = true;
if (valueToken && valueToken->str() == rawtok1->str())
first = false;
if (expand(&output2, rawtok1->location, rawtokens2.cfront(), macros, expandedmacros, first))
if (expand(&output2, rawtok1->location, rawtokens2.cfront(), macros, expandedmacros))
rawtok = rawtok1->next;
} else {
rawtok = expand(&output2, rawtok->location, rawtok, macros, expandedmacros);
Expand Down Expand Up @@ -1622,10 +1617,6 @@ namespace simplecpp {
rawtok = rawtok2->next;
}
output->takeTokens(output2);
for (Token* tok = output->front(); tok; tok = tok->next) {
if (tok->str() == INNER_COMMA)
tok->setstr(",");
}
return rawtok;
}

Expand Down Expand Up @@ -1792,28 +1783,12 @@ namespace simplecpp {
// A##B => AB
tok = expandHashHash(tokens, rawloc, tok, macros, expandedmacros, parametertokens);
} else if (tok->op == '#' && sameline(tok, tok->next) && tok->next->op != '#') {
tok = expandHash(tokens, rawloc, tok, macros, expandedmacros, parametertokens);
tok = expandHash(tokens, rawloc, tok, expandedmacros, parametertokens);
} else {
if (!expandArg(tokens, tok, rawloc, macros, expandedmacros, parametertokens)) {
bool expanded = false;
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()) {
Token* mtok = tokens->back();
m.expand(tokens, rawloc, tok, macros, expandedmacros);
for (mtok = mtok->next; mtok; mtok = mtok->next) {
if (mtok->op == ',')
mtok->setstr(INNER_COMMA);
}
expanded = true;
}
}
if (!expanded) {
tokens->push_back(new Token(*tok));
if (tok->macro.empty() && (par > 0 || tok->str() != "("))
tokens->back()->macro = name();
}
tokens->push_back(new Token(*tok));
if (tok->macro.empty() && (par > 0 || tok->str() != "("))
tokens->back()->macro = name();
}

if (tok->op == '(')
Expand All @@ -1831,10 +1806,8 @@ namespace simplecpp {
return sameline(lpar,tok) ? tok : nullptr;
}

const Token * expand(TokenList * const output, const Location &loc, const Token * const nameTokInst, const MacroMap &macros, std::set<TokenString> expandedmacros, bool first=false) const {

if (!first)
expandedmacros.insert(nameTokInst->str());
const Token * expand(TokenList * const output, const Location &loc, const Token * const nameTokInst, const MacroMap &macros, std::set<TokenString> expandedmacros) const {
expandedmacros.insert(nameTokInst->str());

usageList.push_back(loc);

Expand Down Expand Up @@ -1917,6 +1890,14 @@ namespace simplecpp {
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::unexpectedNewline(tok->location, name());
if (variadic && tok->op == ',' && tok->next->next->next->str() == args.back()) {
Token *const comma = newMacroToken(tok->str(), loc, isReplaced(expandedmacros), tok);
output->push_back(comma);
tok = expandToken(output, loc, tok->next->next->next, macros, expandedmacros, parametertokens2);
if (output->back() == comma)
output->deleteToken(comma);
continue;
}
TokenList new_output(files);
if (!expandArg(&new_output, tok, parametertokens2))
output->push_back(newMacroToken(tok->str(), loc, isReplaced(expandedmacros), tok));
Expand Down Expand Up @@ -1961,7 +1942,7 @@ namespace simplecpp {
tok = expandHashHash(output, loc, tok->previous, macros, expandedmacros, parametertokens2);
} else {
// #123 => "123"
tok = expandHash(output, loc, tok->previous, macros, expandedmacros, parametertokens2);
tok = expandHash(output, loc, tok->previous, expandedmacros, parametertokens2);
}
}

Expand Down Expand Up @@ -2138,14 +2119,17 @@ namespace simplecpp {
return true;
for (const Token *partok = parametertokens[argnr]->next; partok != parametertokens[argnr + 1U];) {
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 {
if (it != macros.end() && !partok->isExpandedFrom(&it->second) && (partok->str() == name() || expandedmacros.find(partok->str()) == expandedmacros.end())) {
const std::set<TokenString> expandedmacros2; // temporary amnesia to allow reexpansion of currently expanding macros during argument evaluation
partok = it->second.expand(output, loc, partok, macros, expandedmacros2);
} else {
output->push_back(newMacroToken(partok->str(), loc, isReplaced(expandedmacros), partok));
output->back()->macro = partok->macro;
partok = partok->next;
}
}
if (tok->whitespaceahead && output->back())
output->back()->whitespaceahead = true;
return true;
}

Expand All @@ -2154,18 +2138,22 @@ namespace simplecpp {
* @param output destination tokenlist
* @param loc location for expanded token
* @param tok The # token
* @param macros all macros
* @param expandedmacros set with expanded macros, with this macro
* @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 MacroMap &macros, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> &parametertokens) const {
const Token *expandHash(TokenList *output, const Location &loc, const Token *tok, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> &parametertokens) const {
TokenList tokenListHash(files);
tok = expandToken(&tokenListHash, loc, tok->next, macros, expandedmacros, parametertokens);
const MacroMap macros2; // temporarily bypass macro expansion
tok = expandToken(&tokenListHash, loc, tok->next, macros2, expandedmacros, parametertokens);
std::ostringstream ostr;
ostr << '\"';
for (const Token *hashtok = tokenListHash.cfront(); hashtok; hashtok = hashtok->next)
for (const Token *hashtok = tokenListHash.cfront(), *next; hashtok; hashtok = next) {
next = hashtok->next;
ostr << hashtok->str();
if (next && hashtok->whitespaceahead)
ostr << ' ';
}
ostr << '\"';
output->push_back(newMacroToken(escapeString(ostr.str()), loc, isReplaced(expandedmacros)));
return tok;
Expand Down
9 changes: 6 additions & 3 deletions simplecpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ namespace simplecpp {
*/
class SIMPLECPP_LIB Token {
public:
Token(const TokenString &s, const Location &loc) :
location(loc), previous(nullptr), next(nullptr), string(s) {
Token(const TokenString &s, const Location &loc, bool wsahead = false) :
whitespaceahead(wsahead), location(loc), previous(nullptr), next(nullptr), string(s) {
flags();
}

Token(const Token &tok) :
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) {
macro(tok.macro), op(tok.op), comment(tok.comment), name(tok.name), number(tok.number), whitespaceahead(tok.whitespaceahead), location(tok.location), previous(nullptr), next(nullptr), string(tok.string), mExpandedFrom(tok.mExpandedFrom) {
}

void flags() {
Expand Down Expand Up @@ -132,6 +132,7 @@ namespace simplecpp {
bool comment;
bool name;
bool number;
bool whitespaceahead;
Location location;
Token *previous;
Token *next;
Expand All @@ -153,6 +154,8 @@ namespace simplecpp {
void setExpandedFrom(const Token *tok, const Macro* m) {
mExpandedFrom = tok->mExpandedFrom;
mExpandedFrom.insert(m);
if (tok->whitespaceahead)
whitespaceahead = true;
}
bool isExpandedFrom(const Macro* m) const {
return mExpandedFrom.find(m) != mExpandedFrom.end();
Expand Down
43 changes: 40 additions & 3 deletions test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include <string>
#include <vector>

#define STRINGIZE_(x) #x
#define STRINGIZE(x) STRINGIZE_(x)

static int numberOfFailedAssertions = 0;

#define ASSERT_EQUALS(expected, actual) (assertEquals((expected), (actual), __LINE__))
Expand Down Expand Up @@ -44,7 +47,7 @@ static int assertEquals(const std::string &expected, const std::string &actual,
return (expected == actual);
}

static int assertEquals(const unsigned int &expected, const unsigned int &actual, int line)
static int assertEquals(const long long &expected, const long long &actual, int line)
{
return assertEquals(std::to_string(expected), std::to_string(actual), line);
}
Expand Down Expand Up @@ -717,6 +720,17 @@ static void define_define_11()
ASSERT_EQUALS("\n\n\n\nP2DIR ;", preprocess(code));
}

static void define_define_11a()
{
const char code[] = "#define A_B_C 0x1\n"
"#define A_ADDRESS 0x00001000U\n"
"#define A ((uint32_t ) A_ADDRESS)\n"
"#define CONCAT(x, y, z) x ## _ ## y ## _ ## z\n"
"#define TEST_MACRO CONCAT(A, B, C)\n"
"TEST_MACRO\n";
ASSERT_EQUALS("\n\n\n\n\n0x1", preprocess(code));
}

static void define_define_12()
{
const char code[] = "#define XY(Z) Z\n"
Expand Down Expand Up @@ -1019,6 +1033,17 @@ static void hash()
preprocess("#define A(x) (x)\n"
"#define B(x) A(#x)\n"
"B(123)"));

ASSERT_EQUALS("\n\nprintf ( \"bar(3)\" \"\\n\" ) ;",
preprocess("#define bar(x) x % 2\n"
"#define foo(x) printf(#x \"\\n\")\n"
"foo(bar(3));"));

ASSERT_EQUALS("\n\n\n\"Y Y\"",
preprocess("#define X(x,y) x y\n"
"#define STR_(x) #x\n"
"#define STR(x) STR_(x)\n"
"STR(X(Y,Y))"));
}

static void hashhash1() // #4703
Expand Down Expand Up @@ -1058,6 +1083,16 @@ static void hashhash4() // nonstandard gcc/clang extension for empty varargs
ASSERT_EQUALS("\n\na ( 1 ) ;", preprocess(code));
}

static void hashhash4a()
{
const char code[] = "#define GETMYID(a) ((a))+1\n"
"#define FIGHT_FOO(c, ...) foo(c, ##__VA_ARGS__)\n"
"#define FIGHT_BAR(c, args...) bar(c, ##args)\n"
"FIGHT_FOO(1, GETMYID(a));\n"
"FIGHT_BAR(1, GETMYID(b));";
ASSERT_EQUALS("\n\n\nfoo ( 1 , ( ( a ) ) + 1 ) ;\nbar ( 1 , ( ( b ) ) + 1 ) ;", preprocess(code));
}

static void hashhash5()
{
ASSERT_EQUALS("x1", preprocess("x##__LINE__"));
Expand Down Expand Up @@ -2567,8 +2602,8 @@ static void simplifyPath_cppcheck()
ASSERT_EQUALS("src/", simplecpp::simplifyPath("src/abc/../"));

// Handling of UNC paths on Windows
ASSERT_EQUALS("//src/test.cpp", simplecpp::simplifyPath("//src/test.cpp"));
ASSERT_EQUALS("//src/test.cpp", simplecpp::simplifyPath("///src/test.cpp"));
ASSERT_EQUALS("//" STRINGIZE(UNCHOST) "/test.cpp", simplecpp::simplifyPath("//" STRINGIZE(UNCHOST) "/test.cpp"));
ASSERT_EQUALS("//" STRINGIZE(UNCHOST) "/test.cpp", simplecpp::simplifyPath("///" STRINGIZE(UNCHOST) "/test.cpp"));
}

static void simplifyPath_New()
Expand Down Expand Up @@ -2855,6 +2890,7 @@ int main(int argc, char **argv)
TEST_CASE(define_define_9); // line break in nested macro call
TEST_CASE(define_define_10);
TEST_CASE(define_define_11);
TEST_CASE(define_define_11a);
TEST_CASE(define_define_12); // expand result of ##
TEST_CASE(define_define_13);
TEST_CASE(define_define_14);
Expand Down Expand Up @@ -2892,6 +2928,7 @@ int main(int argc, char **argv)
TEST_CASE(hashhash2);
TEST_CASE(hashhash3);
TEST_CASE(hashhash4);
TEST_CASE(hashhash4a); // #66, #130
TEST_CASE(hashhash5);
TEST_CASE(hashhash6);
TEST_CASE(hashhash7); // # ## # (C standard; 6.10.3.3.p4)
Expand Down