@@ -301,8 +301,82 @@ void Preprocessor::DefineStandardMacros() {
301301 Define (" __TIMESTAMP__" s, " __TIMESTAMP__" s);
302302}
303303
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+
304365void 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+ }
306380}
307381
308382void Preprocessor::Undefine (std::string macro) { definitions_.erase (macro); }
0 commit comments