@@ -301,8 +301,82 @@ void Preprocessor::DefineStandardMacros() {
301
301
Define (" __TIMESTAMP__" s, " __TIMESTAMP__" s);
302
302
}
303
303
304
+ static const std::string idChars{
305
+ " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789" s};
306
+
307
+ static std::optional<std::vector<std::string>> TokenizeMacroNameAndArgs (
308
+ const std::string &str) {
309
+ // TODO: variadic macros on the command line (?)
310
+ std::vector<std::string> names;
311
+ for (std::string::size_type at{0 };;) {
312
+ auto nameStart{str.find_first_not_of (" " s, at)};
313
+ if (nameStart == str.npos ) {
314
+ return std::nullopt;
315
+ }
316
+ auto nameEnd{str.find_first_not_of (idChars, nameStart)};
317
+ if (nameEnd == str.npos ) {
318
+ return std::nullopt;
319
+ }
320
+ auto punc{str.find_first_not_of (" " s, nameEnd)};
321
+ if (punc == str.npos ) {
322
+ return std::nullopt;
323
+ }
324
+ if ((at == 0 && str[punc] != ' (' ) ||
325
+ (at > 0 && str[punc] != ' ,' && str[punc] != ' )' )) {
326
+ return std::nullopt;
327
+ }
328
+ names.push_back (str.substr (nameStart, nameEnd - nameStart));
329
+ at = punc + 1 ;
330
+ if (str[punc] == ' )' ) {
331
+ if (str.find_first_not_of (" " s, at) != str.npos ) {
332
+ return std::nullopt;
333
+ } else {
334
+ return names;
335
+ }
336
+ }
337
+ }
338
+ }
339
+
340
+ TokenSequence Preprocessor::TokenizeMacroBody (const std::string &str) {
341
+ TokenSequence tokens;
342
+ Provenance provenance{allSources_.AddCompilerInsertion (str).start ()};
343
+ auto end{str.size ()};
344
+ for (std::string::size_type at{0 }; at < end;) {
345
+ // Alternate between tokens that are identifiers (and therefore subject
346
+ // to argument replacement) and those that are not.
347
+ auto start{str.find_first_of (idChars, at)};
348
+ if (start == str.npos ) {
349
+ tokens.Put (str.substr (at), provenance + at);
350
+ break ;
351
+ } else if (start > at) {
352
+ tokens.Put (str.substr (at, start - at), provenance + at);
353
+ }
354
+ at = str.find_first_not_of (idChars, start + 1 );
355
+ if (at == str.npos ) {
356
+ tokens.Put (str.substr (start), provenance + start);
357
+ break ;
358
+ } else {
359
+ tokens.Put (str.substr (start, at - start), provenance + start);
360
+ }
361
+ }
362
+ return tokens;
363
+ }
364
+
304
365
void Preprocessor::Define (const std::string ¯o, const std::string &value) {
305
- definitions_.emplace (SaveTokenAsName (macro), Definition{value, allSources_});
366
+ if (auto lhs{TokenizeMacroNameAndArgs (macro)}) {
367
+ // function-like macro
368
+ CharBlock macroName{SaveTokenAsName (lhs->front ())};
369
+ auto iter{lhs->begin ()};
370
+ ++iter;
371
+ std::vector<std::string> argNames{iter, lhs->end ()};
372
+ auto rhs{TokenizeMacroBody (value)};
373
+ definitions_.emplace (std::make_pair (macroName,
374
+ Definition{
375
+ argNames, rhs, 0 , rhs.SizeInTokens (), /* isVariadic=*/ false }));
376
+ } else { // keyword macro
377
+ definitions_.emplace (
378
+ SaveTokenAsName (macro), Definition{value, allSources_});
379
+ }
306
380
}
307
381
308
382
void Preprocessor::Undefine (std::string macro) { definitions_.erase (macro); }
0 commit comments