diff options
Diffstat (limited to 'flang/lib/Parser/preprocessor.cpp')
-rw-r--r-- | flang/lib/Parser/preprocessor.cpp | 232 |
1 files changed, 133 insertions, 99 deletions
diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp index 88efcf7..8c993e7 100644 --- a/flang/lib/Parser/preprocessor.cpp +++ b/flang/lib/Parser/preprocessor.cpp @@ -259,14 +259,15 @@ void Preprocessor::Define(std::string macro, std::string value) { void Preprocessor::Undefine(std::string macro) { definitions_.erase(macro); } std::optional<TokenSequence> Preprocessor::MacroReplacement( - const TokenSequence &input, Prescanner &prescanner) { + const TokenSequence &input, Prescanner &prescanner, + std::optional<std::size_t> *partialFunctionLikeMacro) { // Do quick scan for any use of a defined name. if (definitions_.empty()) { return std::nullopt; } std::size_t tokens{input.SizeInTokens()}; - std::size_t j; - for (j = 0; j < tokens; ++j) { + std::size_t j{0}; + for (; j < tokens; ++j) { CharBlock token{input.TokenAt(j)}; if (!token.empty() && IsLegalIdentifierStart(token[0]) && IsNameDefined(token)) { @@ -277,6 +278,38 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement( return std::nullopt; // input contains nothing that would be replaced } TokenSequence result{input, 0, j}; + + // After rescanning after macro replacement has failed due to an unclosed + // function-like macro call (no left parenthesis yet, or no closing + // parenthesis), if tokens remain in the input, append them to the + // replacement text and attempt to proceed. Otherwise, return, so that + // the caller may try again with remaining tokens in its input. + auto CompleteFunctionLikeMacro{ + [this, &input, &prescanner, &result, &partialFunctionLikeMacro]( + std::size_t after, const TokenSequence &replacement, + std::size_t pFLMOffset) { + if (after < input.SizeInTokens()) { + result.Put(replacement, 0, pFLMOffset); + TokenSequence suffix; + suffix.Put( + replacement, pFLMOffset, replacement.SizeInTokens() - pFLMOffset); + suffix.Put(input, after, input.SizeInTokens() - after); + auto further{ + ReplaceMacros(suffix, prescanner, partialFunctionLikeMacro)}; + if (partialFunctionLikeMacro && *partialFunctionLikeMacro) { + // still not closed + **partialFunctionLikeMacro += result.SizeInTokens(); + } + result.Put(further); + return true; + } else { + if (partialFunctionLikeMacro) { + *partialFunctionLikeMacro = pFLMOffset + result.SizeInTokens(); + } + return false; + } + }}; + for (; j < tokens; ++j) { CharBlock token{input.TokenAt(j)}; if (token.IsBlank() || !IsLegalIdentifierStart(token[0])) { @@ -294,20 +327,17 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement( continue; } if (!def->isFunctionLike()) { - bool isRenaming{false}; - if (def->isPredefined()) { + if (def->isPredefined() && !def->replacement().empty()) { std::string repl; - if (!def->replacement().empty()) { - std::string name{def->replacement().TokenAt(0).ToString()}; - if (name == "__FILE__") { - repl = "\""s + - allSources_.GetPath(prescanner.GetCurrentProvenance()) + '"'; - } else if (name == "__LINE__") { - std::string buf; - llvm::raw_string_ostream ss{buf}; - ss << allSources_.GetLineNumber(prescanner.GetCurrentProvenance()); - repl = ss.str(); - } + std::string name{def->replacement().TokenAt(0).ToString()}; + if (name == "__FILE__") { + repl = "\""s + + allSources_.GetPath(prescanner.GetCurrentProvenance()) + '"'; + } else if (name == "__LINE__") { + std::string buf; + llvm::raw_string_ostream ss{buf}; + ss << allSources_.GetLineNumber(prescanner.GetCurrentProvenance()); + repl = ss.str(); } if (!repl.empty()) { ProvenanceRange insert{allSources_.AddCompilerInsertion(repl)}; @@ -317,105 +347,109 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement( continue; } } + std::optional<std::size_t> partialFLM; def->set_isDisabled(true); - TokenSequence replaced{ - TokenPasting(ReplaceMacros(def->replacement(), prescanner))}; + TokenSequence replaced{TokenPasting( + ReplaceMacros(def->replacement(), prescanner, &partialFLM))}; def->set_isDisabled(false); - // Allow a keyword-like macro replacement to be the name of - // a function-like macro, possibly surrounded by blanks. - std::size_t k{0}, repTokens{replaced.SizeInTokens()}; - for (; k < repTokens && replaced.TokenAt(k).IsBlank(); ++k) { + if (partialFLM && + CompleteFunctionLikeMacro(j + 1, replaced, *partialFLM)) { + return result; + } + if (!replaced.empty()) { + ProvenanceRange from{def->replacement().GetProvenanceRange()}; + ProvenanceRange use{input.GetTokenProvenanceRange(j)}; + ProvenanceRange newRange{ + allSources_.AddMacroCall(from, use, replaced.ToString())}; + result.Put(replaced, newRange); + } + } else { + // Possible function-like macro call. Skip spaces and newlines to see + // whether '(' is next. + std::size_t k{j}; + bool leftParen{false}; + while (++k < tokens) { + const CharBlock &lookAhead{input.TokenAt(k)}; + if (!lookAhead.IsBlank() && lookAhead[0] != '\n') { + leftParen = lookAhead[0] == '(' && lookAhead.size() == 1; + break; + } } - if (k < repTokens) { - token = replaced.TokenAt(k); - for (++k; k < repTokens && replaced.TokenAt(k).IsBlank(); ++k) { + if (!leftParen) { + if (partialFunctionLikeMacro) { + *partialFunctionLikeMacro = result.SizeInTokens(); + result.Put(input, j, tokens - j); + return result; + } else { + result.Put(input, j); + continue; } - if (k == repTokens && IsLegalIdentifierStart(token[0])) { - auto it{definitions_.find(token)}; - if (it != definitions_.end() && !it->second.isDisabled() && - it->second.isFunctionLike()) { - def = &it->second; - isRenaming = true; + } + std::vector<std::size_t> argStart{++k}; + for (int nesting{0}; k < tokens; ++k) { + CharBlock token{input.TokenAt(k)}; + char ch{token.OnlyNonBlank()}; + if (ch == '(') { + ++nesting; + } else if (ch == ')') { + if (nesting == 0) { + break; } + --nesting; + } else if (ch == ',' && nesting == 0) { + argStart.push_back(k + 1); } } - if (!isRenaming) { - if (!replaced.empty()) { - ProvenanceRange from{def->replacement().GetProvenanceRange()}; - ProvenanceRange use{input.GetTokenProvenanceRange(j)}; - ProvenanceRange newRange{ - allSources_.AddMacroCall(from, use, replaced.ToString())}; - result.Put(replaced, newRange); - } + if (argStart.size() == 1 && k == argStart[0] && + def->argumentCount() == 0) { + // Subtle: () is zero arguments, not one empty argument, + // unless one argument was expected. + argStart.clear(); + } + if (k >= tokens && partialFunctionLikeMacro) { + *partialFunctionLikeMacro = result.SizeInTokens(); + result.Put(input, j, tokens - j); + return result; + } else if (k >= tokens || argStart.size() < def->argumentCount() || + (argStart.size() > def->argumentCount() && !def->isVariadic())) { + result.Put(input, j); continue; } - } - // Possible function-like macro call. Skip spaces and newlines to see - // whether '(' is next. - std::size_t k{j}; - bool leftParen{false}; - while (++k < tokens) { - const CharBlock &lookAhead{input.TokenAt(k)}; - if (!lookAhead.IsBlank() && lookAhead[0] != '\n') { - leftParen = lookAhead[0] == '(' && lookAhead.size() == 1; - break; + std::vector<TokenSequence> args; + for (std::size_t n{0}; n < argStart.size(); ++n) { + std::size_t at{argStart[n]}; + std::size_t count{ + (n + 1 == argStart.size() ? k : argStart[n + 1] - 1) - at}; + args.emplace_back(TokenSequence(input, at, count)); } - } - if (!leftParen) { - result.Put(input, j); - continue; - } - std::vector<std::size_t> argStart{++k}; - for (int nesting{0}; k < tokens; ++k) { - CharBlock token{input.TokenAt(k)}; - char ch{token.OnlyNonBlank()}; - if (ch == '(') { - ++nesting; - } else if (ch == ')') { - if (nesting == 0) { - break; - } - --nesting; - } else if (ch == ',' && nesting == 0) { - argStart.push_back(k + 1); + TokenSequence applied{def->Apply(args, prescanner)}; + std::optional<std::size_t> partialFLM; + def->set_isDisabled(true); + TokenSequence replaced{ + ReplaceMacros(std::move(applied), prescanner, &partialFLM)}; + def->set_isDisabled(false); + if (partialFLM && + CompleteFunctionLikeMacro(k + 1, replaced, *partialFLM)) { + return result; } + if (!replaced.empty()) { + ProvenanceRange from{def->replacement().GetProvenanceRange()}; + ProvenanceRange use{input.GetIntervalProvenanceRange(j, k - j)}; + ProvenanceRange newRange{ + allSources_.AddMacroCall(from, use, replaced.ToString())}; + result.Put(replaced, newRange); + } + j = k; // advance to the terminal ')' } - if (argStart.size() == 1 && k == argStart[0] && def->argumentCount() == 0) { - // Subtle: () is zero arguments, not one empty argument, - // unless one argument was expected. - argStart.clear(); - } - if (k >= tokens || argStart.size() < def->argumentCount() || - (argStart.size() > def->argumentCount() && !def->isVariadic())) { - result.Put(input, j); - continue; - } - std::vector<TokenSequence> args; - for (std::size_t n{0}; n < argStart.size(); ++n) { - std::size_t at{argStart[n]}; - std::size_t count{ - (n + 1 == argStart.size() ? k : argStart[n + 1] - 1) - at}; - args.emplace_back(TokenSequence(input, at, count)); - } - TokenSequence applied{def->Apply(args, prescanner)}; - def->set_isDisabled(true); - TokenSequence replaced{ReplaceMacros(std::move(applied), prescanner)}; - def->set_isDisabled(false); - if (!replaced.empty()) { - ProvenanceRange from{def->replacement().GetProvenanceRange()}; - ProvenanceRange use{input.GetIntervalProvenanceRange(j, k - j)}; - ProvenanceRange newRange{ - allSources_.AddMacroCall(from, use, replaced.ToString())}; - result.Put(replaced, newRange); - } - j = k; // advance to the terminal ')' } return result; } -TokenSequence Preprocessor::ReplaceMacros( - const TokenSequence &tokens, Prescanner &prescanner) { - if (std::optional<TokenSequence> repl{MacroReplacement(tokens, prescanner)}) { +TokenSequence Preprocessor::ReplaceMacros(const TokenSequence &tokens, + Prescanner &prescanner, + std::optional<std::size_t> *partialFunctionLikeMacro) { + if (std::optional<TokenSequence> repl{ + MacroReplacement(tokens, prescanner, partialFunctionLikeMacro)}) { return std::move(*repl); } return tokens; |