Skip to content

Commit 5231eaa

Browse files
committed
Merge branch 'master' into optimize_paths
2 parents 791d4bb + 0ff0149 commit 5231eaa

3 files changed

Lines changed: 143 additions & 27 deletions

File tree

simplecpp.cpp

Lines changed: 84 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,7 @@ namespace simplecpp {
14621462

14631463
class Macro {
14641464
public:
1465-
explicit Macro(std::vector<std::string> &f) : nameTokDef(nullptr), valueToken(nullptr), endToken(nullptr), files(f), tokenListDefine(f), variadic(false), valueDefinedInCode_(false) {}
1465+
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) {}
14661466

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

1495+
~Macro() {
1496+
delete optExpandValue;
1497+
delete optNoExpandValue;
1498+
}
1499+
14951500
Macro &operator=(const Macro &other) {
14961501
if (this != &other) {
14971502
files = other.files;
@@ -1684,6 +1689,9 @@ namespace simplecpp {
16841689
bool parseDefine(const Token *nametoken) {
16851690
nameTokDef = nametoken;
16861691
variadic = false;
1692+
variadicOpt = false;
1693+
optExpandValue = nullptr;
1694+
optNoExpandValue = nullptr;
16871695
if (!nameTokDef) {
16881696
valueToken = endToken = nullptr;
16891697
args.clear();
@@ -1721,8 +1729,49 @@ namespace simplecpp {
17211729
if (!sameline(valueToken, nameTokDef))
17221730
valueToken = nullptr;
17231731
endToken = valueToken;
1724-
while (sameline(endToken, nameTokDef))
1732+
while (sameline(endToken, nameTokDef)) {
1733+
if (variadic && endToken->str() == "__VA_OPT__")
1734+
variadicOpt = true;
17251735
endToken = endToken->next;
1736+
}
1737+
1738+
if (variadicOpt) {
1739+
TokenList expandValue(files);
1740+
TokenList noExpandValue(files);
1741+
for (const Token *tok = valueToken; tok && tok != endToken;) {
1742+
if (tok->str() == "__VA_OPT__") {
1743+
if (!sameline(tok, tok->next) || tok->next->op != '(')
1744+
throw Error(tok->location, "In definition of '" + nameTokDef->str() + "': Missing opening parenthesis for __VA_OPT__");
1745+
tok = tok->next->next;
1746+
int par = 1;
1747+
while (tok && tok != endToken) {
1748+
if (tok->op == '(')
1749+
par++;
1750+
else if (tok->op == ')')
1751+
par--;
1752+
else if (tok->str() == "__VA_OPT__")
1753+
throw Error(tok->location, "In definition of '" + nameTokDef->str() + "': __VA_OPT__ cannot be nested");
1754+
if (par == 0) {
1755+
tok = tok->next;
1756+
break;
1757+
}
1758+
expandValue.push_back(new Token(*tok));
1759+
tok = tok->next;
1760+
}
1761+
if (par != 0) {
1762+
const Token *const lastTok = expandValue.back() ? expandValue.back() : valueToken->next;
1763+
throw Error(lastTok->location, "In definition of '" + nameTokDef->str() + "': Missing closing parenthesis for __VA_OPT__");
1764+
}
1765+
} else {
1766+
expandValue.push_back(new Token(*tok));
1767+
noExpandValue.push_back(new Token(*tok));
1768+
tok = tok->next;
1769+
}
1770+
}
1771+
optExpandValue = new TokenList(std::move(expandValue));
1772+
optNoExpandValue = new TokenList(std::move(noExpandValue));
1773+
}
1774+
17261775
return true;
17271776
}
17281777

@@ -1877,8 +1926,22 @@ namespace simplecpp {
18771926

18781927
Token * const output_end_1 = output->back();
18791928

1929+
const Token *valueToken2;
1930+
const Token *endToken2;
1931+
1932+
if (variadicOpt) {
1933+
if (parametertokens2.size() > args.size() && parametertokens2[args.size() - 1]->next->op != ')')
1934+
valueToken2 = optExpandValue->cfront();
1935+
else
1936+
valueToken2 = optNoExpandValue->cfront();
1937+
endToken2 = nullptr;
1938+
} else {
1939+
valueToken2 = valueToken;
1940+
endToken2 = endToken;
1941+
}
1942+
18801943
// expand
1881-
for (const Token *tok = valueToken; tok != endToken;) {
1944+
for (const Token *tok = valueToken2; tok != endToken2;) {
18821945
if (tok->op != '#') {
18831946
// A##B => AB
18841947
if (sameline(tok, tok->next) && tok->next && tok->next->op == '#' && tok->next->next && tok->next->next->op == '#') {
@@ -1927,7 +1990,7 @@ namespace simplecpp {
19271990
}
19281991

19291992
tok = tok->next;
1930-
if (tok == endToken) {
1993+
if (tok == endToken2) {
19311994
output->push_back(new Token(*tok->previous));
19321995
break;
19331996
}
@@ -1997,24 +2060,6 @@ namespace simplecpp {
19972060
// Macro parameter..
19982061
{
19992062
TokenList temp(files);
2000-
if (tok->str() == "__VA_OPT__") {
2001-
if (sameline(tok, tok->next) && tok->next->str() == "(") {
2002-
tok = tok->next;
2003-
int paren = 1;
2004-
while (sameline(tok, tok->next)) {
2005-
if (tok->next->str() == "(")
2006-
++paren;
2007-
else if (tok->next->str() == ")")
2008-
--paren;
2009-
if (paren == 0)
2010-
return tok->next->next;
2011-
tok = tok->next;
2012-
if (parametertokens.size() > args.size() && parametertokens.front()->next->str() != ")")
2013-
tok = expandToken(output, loc, tok, macros, expandedmacros, parametertokens)->previous;
2014-
}
2015-
}
2016-
throw Error(tok->location, "Missing parenthesis for __VA_OPT__(content)");
2017-
}
20182063
if (expandArg(&temp, tok, loc, macros, expandedmacros, parametertokens)) {
20192064
if (tok->str() == "__VA_ARGS__" && temp.empty() && output->cback() && output->cback()->str() == "," &&
20202065
tok->nextSkipComments() && tok->nextSkipComments()->str() == ")")
@@ -2315,6 +2360,13 @@ namespace simplecpp {
23152360
/** is macro variadic? */
23162361
bool variadic;
23172362

2363+
/** does the macro expansion have __VA_OPT__? */
2364+
bool variadicOpt;
2365+
2366+
/** Expansion value for varadic macros with __VA_OPT__ expanded and discarded respectively */
2367+
const TokenList *optExpandValue;
2368+
const TokenList *optNoExpandValue;
2369+
23182370
/** was the value of this macro actually defined in the code? */
23192371
bool valueDefinedInCode_;
23202372
};
@@ -3473,6 +3525,16 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
34733525
}
34743526
output.clear();
34753527
return;
3528+
} catch (simplecpp::Macro::Error &err) {
3529+
if (outputList) {
3530+
simplecpp::Output out(files);
3531+
out.type = simplecpp::Output::SYNTAX_ERROR;
3532+
out.location = err.location;
3533+
out.msg = "Failed to parse #define, " + err.what;
3534+
outputList->push_back(out);
3535+
}
3536+
output.clear();
3537+
return;
34763538
}
34773539
} else if (ifstates.top() == True && rawtok->str() == INCLUDE) {
34783540
TokenList inc1(files);

test.cpp

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

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

927927
outputList.clear();
@@ -932,7 +932,7 @@ static void define_va_opt_3()
932932
"err()";
933933

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

@@ -944,7 +944,7 @@ static void define_va_opt_4()
944944

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

950950
outputList.clear();
@@ -954,7 +954,7 @@ static void define_va_opt_4()
954954
"err()";
955955

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

@@ -966,7 +966,46 @@ static void define_va_opt_5()
966966

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

@@ -3074,6 +3113,8 @@ int main(int argc, char **argv)
30743113
TEST_CASE(define_va_opt_3);
30753114
TEST_CASE(define_va_opt_4);
30763115
TEST_CASE(define_va_opt_5);
3116+
TEST_CASE(define_va_opt_6);
3117+
TEST_CASE(define_va_opt_7);
30773118

30783119
TEST_CASE(pragma_backslash); // multiline pragma directive
30793120

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)