Skip to content

Commit 56509a8

Browse files
committed
Merge branch 'master' into cxx11
2 parents 208cc65 + 8f8bfe3 commit 56509a8

3 files changed

Lines changed: 148 additions & 27 deletions

File tree

simplecpp.cpp

Lines changed: 89 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,7 @@ namespace simplecpp {
14631463

14641464
class Macro {
14651465
public:
1466-
explicit Macro(std::vector<std::string> &f) : nameTokDef(nullptr), valueToken(nullptr), endToken(nullptr), files(f), tokenListDefine(f), variadic(false), valueDefinedInCode_(false) {}
1466+
explicit Macro(std::vector<std::string> &f) : nameTokDef(nullptr), valueToken(nullptr), endToken(nullptr), files(f), tokenListDefine(f), variadic(false), variadicOpt(false), optExpandValue(nullptr), optNoExpandValue(nullptr), valueDefinedInCode_(false) {}
14671467

14681468
Macro(const Token *tok, std::vector<std::string> &f) : nameTokDef(nullptr), files(f), tokenListDefine(f), valueDefinedInCode_(true) {
14691469
if (sameline(tok->previousSkipComments(), tok))
@@ -1493,6 +1493,11 @@ namespace simplecpp {
14931493
*this = other;
14941494
}
14951495

1496+
~Macro() {
1497+
delete optExpandValue;
1498+
delete optNoExpandValue;
1499+
}
1500+
14961501
Macro &operator=(const Macro &other) {
14971502
if (this != &other) {
14981503
files = other.files;
@@ -1685,6 +1690,9 @@ namespace simplecpp {
16851690
bool parseDefine(const Token *nametoken) {
16861691
nameTokDef = nametoken;
16871692
variadic = false;
1693+
variadicOpt = false;
1694+
optExpandValue = nullptr;
1695+
optNoExpandValue = nullptr;
16881696
if (!nameTokDef) {
16891697
valueToken = endToken = nullptr;
16901698
args.clear();
@@ -1722,8 +1730,54 @@ namespace simplecpp {
17221730
if (!sameline(valueToken, nameTokDef))
17231731
valueToken = nullptr;
17241732
endToken = valueToken;
1725-
while (sameline(endToken, nameTokDef))
1733+
while (sameline(endToken, nameTokDef)) {
1734+
if (variadic && endToken->str() == "__VA_OPT__")
1735+
variadicOpt = true;
17261736
endToken = endToken->next;
1737+
}
1738+
1739+
if (variadicOpt) {
1740+
TokenList expandValue(files);
1741+
TokenList noExpandValue(files);
1742+
for (const Token *tok = valueToken; tok && tok != endToken;) {
1743+
if (tok->str() == "__VA_OPT__") {
1744+
if (!sameline(tok, tok->next) || tok->next->op != '(')
1745+
throw Error(tok->location, "In definition of '" + nameTokDef->str() + "': Missing opening parenthesis for __VA_OPT__");
1746+
tok = tok->next->next;
1747+
int par = 1;
1748+
while (tok && tok != endToken) {
1749+
if (tok->op == '(')
1750+
par++;
1751+
else if (tok->op == ')')
1752+
par--;
1753+
else if (tok->str() == "__VA_OPT__")
1754+
throw Error(tok->location, "In definition of '" + nameTokDef->str() + "': __VA_OPT__ cannot be nested");
1755+
if (par == 0) {
1756+
tok = tok->next;
1757+
break;
1758+
}
1759+
expandValue.push_back(new Token(*tok));
1760+
tok = tok->next;
1761+
}
1762+
if (par != 0) {
1763+
const Token *const lastTok = expandValue.back() ? expandValue.back() : valueToken->next;
1764+
throw Error(lastTok->location, "In definition of '" + nameTokDef->str() + "': Missing closing parenthesis for __VA_OPT__");
1765+
}
1766+
} else {
1767+
expandValue.push_back(new Token(*tok));
1768+
noExpandValue.push_back(new Token(*tok));
1769+
tok = tok->next;
1770+
}
1771+
}
1772+
#if __cplusplus >= 201103L
1773+
optExpandValue = new TokenList(std::move(expandValue));
1774+
optNoExpandValue = new TokenList(std::move(noExpandValue));
1775+
#else
1776+
optExpandValue = new TokenList(expandValue);
1777+
optNoExpandValue = new TokenList(noExpandValue);
1778+
#endif
1779+
}
1780+
17271781
return true;
17281782
}
17291783

@@ -1878,8 +1932,22 @@ namespace simplecpp {
18781932

18791933
Token * const output_end_1 = output->back();
18801934

1935+
const Token *valueToken2;
1936+
const Token *endToken2;
1937+
1938+
if (variadicOpt) {
1939+
if (parametertokens2.size() > args.size() && parametertokens2[args.size() - 1]->next->op != ')')
1940+
valueToken2 = optExpandValue->cfront();
1941+
else
1942+
valueToken2 = optNoExpandValue->cfront();
1943+
endToken2 = nullptr;
1944+
} else {
1945+
valueToken2 = valueToken;
1946+
endToken2 = endToken;
1947+
}
1948+
18811949
// expand
1882-
for (const Token *tok = valueToken; tok != endToken;) {
1950+
for (const Token *tok = valueToken2; tok != endToken2;) {
18831951
if (tok->op != '#') {
18841952
// A##B => AB
18851953
if (sameline(tok, tok->next) && tok->next && tok->next->op == '#' && tok->next->next && tok->next->next->op == '#') {
@@ -1928,7 +1996,7 @@ namespace simplecpp {
19281996
}
19291997

19301998
tok = tok->next;
1931-
if (tok == endToken) {
1999+
if (tok == endToken2) {
19322000
output->push_back(new Token(*tok->previous));
19332001
break;
19342002
}
@@ -1998,24 +2066,6 @@ namespace simplecpp {
19982066
// Macro parameter..
19992067
{
20002068
TokenList temp(files);
2001-
if (tok->str() == "__VA_OPT__") {
2002-
if (sameline(tok, tok->next) && tok->next->str() == "(") {
2003-
tok = tok->next;
2004-
int paren = 1;
2005-
while (sameline(tok, tok->next)) {
2006-
if (tok->next->str() == "(")
2007-
++paren;
2008-
else if (tok->next->str() == ")")
2009-
--paren;
2010-
if (paren == 0)
2011-
return tok->next->next;
2012-
tok = tok->next;
2013-
if (parametertokens.size() > args.size() && parametertokens.front()->next->str() != ")")
2014-
tok = expandToken(output, loc, tok, macros, expandedmacros, parametertokens)->previous;
2015-
}
2016-
}
2017-
throw Error(tok->location, "Missing parenthesis for __VA_OPT__(content)");
2018-
}
20192069
if (expandArg(&temp, tok, loc, macros, expandedmacros, parametertokens)) {
20202070
if (tok->str() == "__VA_ARGS__" && temp.empty() && output->cback() && output->cback()->str() == "," &&
20212071
tok->nextSkipComments() && tok->nextSkipComments()->str() == ")")
@@ -2316,6 +2366,13 @@ namespace simplecpp {
23162366
/** is macro variadic? */
23172367
bool variadic;
23182368

2369+
/** does the macro expansion have __VA_OPT__? */
2370+
bool variadicOpt;
2371+
2372+
/** Expansion value for varadic macros with __VA_OPT__ expanded and discarded respectively */
2373+
const TokenList *optExpandValue;
2374+
const TokenList *optNoExpandValue;
2375+
23192376
/** was the value of this macro actually defined in the code? */
23202377
bool valueDefinedInCode_;
23212378
};
@@ -3561,6 +3618,16 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
35613618
}
35623619
output.clear();
35633620
return;
3621+
} catch (simplecpp::Macro::Error &err) {
3622+
if (outputList) {
3623+
simplecpp::Output out(files);
3624+
out.type = simplecpp::Output::SYNTAX_ERROR;
3625+
out.location = err.location;
3626+
out.msg = "Failed to parse #define, " + err.what;
3627+
outputList->push_back(out);
3628+
}
3629+
output.clear();
3630+
return;
35643631
}
35653632
} else if (ifstates.top() == True && rawtok->str() == INCLUDE) {
35663633
TokenList inc1(files);

test.cpp

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,7 @@ static void define_va_opt_3()
923923

924924
simplecpp::OutputList outputList;
925925
ASSERT_EQUALS("", preprocess(code1, &outputList));
926-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'err', Missing parenthesis for __VA_OPT__(content)\n",
926+
ASSERT_EQUALS("file0,1,syntax_error,Failed to parse #define, In definition of 'err': Missing closing parenthesis for __VA_OPT__\n",
927927
toString(outputList));
928928

929929
outputList.clear();
@@ -934,7 +934,7 @@ static void define_va_opt_3()
934934
"err()";
935935

936936
ASSERT_EQUALS("", preprocess(code2, &outputList));
937-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'err', Missing parenthesis for __VA_OPT__(content)\n",
937+
ASSERT_EQUALS("file0,1,syntax_error,Failed to parse #define, In definition of 'err': Missing opening parenthesis for __VA_OPT__\n",
938938
toString(outputList));
939939
}
940940

@@ -946,7 +946,7 @@ static void define_va_opt_4()
946946

947947
simplecpp::OutputList outputList;
948948
ASSERT_EQUALS("", preprocess(code1, &outputList));
949-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'err', Missing parenthesis for __VA_OPT__(content)\n",
949+
ASSERT_EQUALS("file0,1,syntax_error,Failed to parse #define, In definition of 'err': Missing opening parenthesis for __VA_OPT__\n",
950950
toString(outputList));
951951

952952
outputList.clear();
@@ -956,7 +956,7 @@ static void define_va_opt_4()
956956
"err()";
957957

958958
ASSERT_EQUALS("", preprocess(code2, &outputList));
959-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'err', Missing parenthesis for __VA_OPT__(content)\n",
959+
ASSERT_EQUALS("file0,1,syntax_error,Failed to parse #define, In definition of 'err': Missing opening parenthesis for __VA_OPT__\n",
960960
toString(outputList));
961961
}
962962

@@ -968,7 +968,46 @@ static void define_va_opt_5()
968968

969969
simplecpp::OutputList outputList;
970970
ASSERT_EQUALS("", preprocess(code, &outputList));
971-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'err', Missing parenthesis for __VA_OPT__(content)\n",
971+
ASSERT_EQUALS("file0,1,syntax_error,Failed to parse #define, In definition of 'err': Missing opening parenthesis for __VA_OPT__\n",
972+
toString(outputList));
973+
}
974+
975+
static void define_va_opt_6()
976+
{
977+
// nested __VA_OPT__
978+
const char code[] = "#define err(...) __VA_OPT__(__VA_OPT__(something))\n"
979+
"err()";
980+
981+
simplecpp::OutputList outputList;
982+
ASSERT_EQUALS("", preprocess(code, &outputList));
983+
ASSERT_EQUALS("file0,1,syntax_error,Failed to parse #define, In definition of 'err': __VA_OPT__ cannot be nested\n",
984+
toString(outputList));
985+
}
986+
987+
static void define_va_opt_7()
988+
{
989+
// eof in __VA_OPT__
990+
const char code1[] = "#define err(...) __VA_OPT__";
991+
992+
simplecpp::OutputList outputList;
993+
ASSERT_EQUALS("", preprocess(code1, &outputList));
994+
ASSERT_EQUALS("file0,1,syntax_error,Failed to parse #define, In definition of 'err': Missing opening parenthesis for __VA_OPT__\n",
995+
toString(outputList));
996+
997+
outputList.clear();
998+
999+
const char code2[] = "#define err(...) __VA_OPT__(";
1000+
1001+
ASSERT_EQUALS("", preprocess(code2, &outputList));
1002+
ASSERT_EQUALS("file0,1,syntax_error,Failed to parse #define, In definition of 'err': Missing closing parenthesis for __VA_OPT__\n",
1003+
toString(outputList));
1004+
1005+
outputList.clear();
1006+
1007+
const char code3[] = "#define err(...) __VA_OPT__(x";
1008+
1009+
ASSERT_EQUALS("", preprocess(code3, &outputList));
1010+
ASSERT_EQUALS("file0,1,syntax_error,Failed to parse #define, In definition of 'err': Missing closing parenthesis for __VA_OPT__\n",
9721011
toString(outputList));
9731012
}
9741013

@@ -3063,6 +3102,8 @@ int main(int argc, char **argv)
30633102
TEST_CASE(define_va_opt_3);
30643103
TEST_CASE(define_va_opt_4);
30653104
TEST_CASE(define_va_opt_5);
3105+
TEST_CASE(define_va_opt_6);
3106+
TEST_CASE(define_va_opt_7);
30663107

30673108
TEST_CASE(pragma_backslash); // multiline pragma directive
30683109

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -E %s | grep '^ printf( "%%s" , "Hello" );$'
2+
3+
#define P( x, ...) printf( x __VA_OPT__(,) __VA_ARGS__ )
4+
#define PF( x, ...) P( x __VA_OPT__(,) __VA_ARGS__ )
5+
6+
int main()
7+
{
8+
PF( "%s", "Hello" );
9+
PF( "Hello", );
10+
PF( "Hello" );
11+
PF( , );
12+
PF( );
13+
}

0 commit comments

Comments
 (0)