Skip to content

Commit 2fb6739

Browse files
committed
Expand function macros that have arguments at the end
1 parent 74a5a63 commit 2fb6739

3 files changed

Lines changed: 50 additions & 3 deletions

File tree

run-tests.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ def cleanup(out: str) -> str:
8080
'macro_rescan_varargs.c',
8181

8282
# todo, high priority
83-
'c99-6_10_3_4_p5.c',
8483
'c99-6_10_3_4_p6.c',
8584
'expr_usual_conversions.c', # condition is true: 4U - 30 >= 0
8685
'stdint.c',

simplecpp.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2310,12 +2310,43 @@ namespace simplecpp {
23102310
return false;
23112311
if (variadic && argnr + 1U >= parametertokens.size()) // empty variadic parameter
23122312
return true;
2313-
for (const Token *partok = parametertokens[argnr]->next; partok != parametertokens[argnr + 1U];) {
2313+
const Token * const argEnd = parametertokens[argnr + 1U];
2314+
for (const Token *partok = parametertokens[argnr]->next; partok != argEnd;) {
23142315
const MacroMap::const_iterator it = macros.find(partok->str());
23152316
if (it != macros.end() && !partok->isExpandedFrom(&it->second) && (partok->str() == name() || expandedmacros.find(partok->str()) == expandedmacros.end())) {
23162317
std::set<TokenString> expandedmacros2(expandedmacros); // temporary amnesia to allow reexpansion of currently expanding macros during argument evaluation
23172318
expandedmacros2.erase(name());
2318-
partok = it->second.expand(output, loc, partok, macros, std::move(expandedmacros2));
2319+
TokenList temp(files);
2320+
partok = it->second.expand(temp, loc, partok, macros, expandedmacros2);
2321+
// Expand while the expansion result ends with the name of a
2322+
// function-like macro whose arguments are supplied by the
2323+
// remaining argument tokens
2324+
while (partok && partok->previous) {
2325+
const Macro * const calledMacro = rescanMacro(temp, partok->previous, macros, expandedmacros2);
2326+
if (!calledMacro)
2327+
break;
2328+
TokenList temp2(files);
2329+
temp2.push_back(new Token(temp.cback()->str(), partok->location));
2330+
unsigned int par = 0;
2331+
const Token *tok2 = partok;
2332+
for (; tok2 && tok2 != argEnd; tok2 = tok2->next) {
2333+
temp2.push_back(new Token(*tok2));
2334+
if (tok2->op == '(')
2335+
++par;
2336+
else if (tok2->op == ')') {
2337+
--par;
2338+
if (par == 0U)
2339+
break;
2340+
}
2341+
}
2342+
if (!tok2 || tok2 == argEnd)
2343+
break;
2344+
output.takeTokens(temp);
2345+
output.deleteToken(output.back());
2346+
calledMacro->expand(temp, loc, temp2.cfront(), macros, expandedmacros2);
2347+
partok = tok2->next;
2348+
}
2349+
output.takeTokens(temp);
23192350
} else {
23202351
output.push_back(newMacroToken(partok->str(), loc, isReplaced(expandedmacros), partok));
23212352
output.back()->macro = partok->macro;

test.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,22 @@ static void define26()
989989
"f ( ) ( )", preprocess(code2));
990990
}
991991

992+
static void define27()
993+
{
994+
// an expansion result inside a macro argument that is a function-like macro
995+
// name must be rescanned against the remaining argument tokens
996+
const char code[] = "#define o1(a) a()\n"
997+
"#define b(c, d) c##d\n"
998+
"#define l(c, d) b(c, 1)\n"
999+
"#define m(e, f)\n"
1000+
"#define g(h, i) m(h, )\n"
1001+
"#define j(h, i) g(h, )\n"
1002+
"#define k() l(j(, ), )\n"
1003+
"#define n(a) j(l(o, )(a), )\n"
1004+
"n(k)\n";
1005+
ASSERT_EQUALS("", preprocess(code));
1006+
}
1007+
9921008

9931009
static void define_invalid_1()
9941010
{
@@ -4563,6 +4579,7 @@ static void runTests(int argc, char **argv, Input input)
45634579
TEST_CASE(define24);
45644580
TEST_CASE(define25);
45654581
TEST_CASE(define26);
4582+
TEST_CASE(define27);
45664583
TEST_CASE(define_invalid_1);
45674584
TEST_CASE(define_invalid_2);
45684585
TEST_CASE(define_invalid_3);

0 commit comments

Comments
 (0)