diff options
Diffstat (limited to 'flang/lib/Parser')
-rw-r--r-- | flang/lib/Parser/preprocessor.cpp | 88 | ||||
-rw-r--r-- | flang/lib/Parser/preprocessor.h | 7 | ||||
-rw-r--r-- | flang/lib/Parser/prescan.cpp | 17 | ||||
-rw-r--r-- | flang/lib/Parser/prescan.h | 6 | ||||
-rw-r--r-- | flang/lib/Parser/token-sequence.cpp | 8 |
5 files changed, 83 insertions, 43 deletions
diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp index 9197906..d755605 100644 --- a/flang/lib/Parser/preprocessor.cpp +++ b/flang/lib/Parser/preprocessor.cpp @@ -147,12 +147,14 @@ TokenSequence Definition::Apply( CharBlock token{replacement_.TokenAt(j)}; std::size_t bytes{token.size()}; if (skipping) { - if (bytes == 1) { - if (token[0] == '(') { - ++parenthesesNesting; - } else if (token[0] == ')') { - skipping = --parenthesesNesting > 0; + char ch{token.OnlyNonBlank()}; + if (ch == '(') { + ++parenthesesNesting; + } else if (ch == ')') { + if (parenthesesNesting > 0) { + --parenthesesNesting; } + skipping = parenthesesNesting > 0; } continue; } @@ -207,18 +209,21 @@ TokenSequence Definition::Apply( result.Put(args[k]); } } else if (bytes == 10 && isVariadic_ && token.ToString() == "__VA_OPT__" && - j + 2 < tokens && replacement_.TokenAt(j + 1).ToString() == "(" && + j + 2 < tokens && replacement_.TokenAt(j + 1).OnlyNonBlank() == '(' && parenthesesNesting == 0) { parenthesesNesting = 1; skipping = args.size() == argumentCount_; ++j; } else { - if (bytes == 1 && parenthesesNesting > 0 && token[0] == '(') { - ++parenthesesNesting; - } else if (bytes == 1 && parenthesesNesting > 0 && token[0] == ')') { - if (--parenthesesNesting == 0) { - skipping = false; - continue; + if (parenthesesNesting > 0) { + char ch{token.OnlyNonBlank()}; + if (ch == '(') { + ++parenthesesNesting; + } else if (ch == ')') { + if (--parenthesesNesting == 0) { + skipping = false; + continue; + } } } result.Put(replacement_, j); @@ -361,18 +366,16 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement( std::vector<std::size_t> argStart{++k}; for (int nesting{0}; k < tokens; ++k) { CharBlock token{input.TokenAt(k)}; - if (token.size() == 1) { - char ch{token[0]}; - if (ch == '(') { - ++nesting; - } else if (ch == ')') { - if (nesting == 0) { - break; - } - --nesting; - } else if (ch == ',' && nesting == 0) { - argStart.push_back(k + 1); + 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 (argStart.size() == 1 && k == argStart[0] && def->argumentCount() == 0) { @@ -454,12 +457,11 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) { } nameToken = SaveTokenAsName(nameToken); definitions_.erase(nameToken); - if (++j < tokens && dir.TokenAt(j).size() == 1 && - dir.TokenAt(j)[0] == '(') { + if (++j < tokens && dir.TokenAt(j).OnlyNonBlank() == '(') { j = dir.SkipBlanks(j + 1); std::vector<std::string> argName; bool isVariadic{false}; - if (dir.TokenAt(j).ToString() != ")") { + if (dir.TokenAt(j).OnlyNonBlank() != ')') { while (true) { std::string an{dir.TokenAt(j).ToString()}; if (an == "...") { @@ -478,11 +480,11 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) { "#define: malformed argument list"_err_en_US); return; } - std::string punc{dir.TokenAt(j).ToString()}; - if (punc == ")") { + char punc{dir.TokenAt(j).OnlyNonBlank()}; + if (punc == ')') { break; } - if (isVariadic || punc != ",") { + if (isVariadic || punc != ',') { prescanner.Say(dir.GetTokenProvenanceRange(j), "#define: malformed argument list"_err_en_US); return; @@ -502,10 +504,12 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) { } } j = dir.SkipBlanks(j + 1); + CheckForUnbalancedParentheses(dir, j, tokens - j); definitions_.emplace(std::make_pair( nameToken, Definition{argName, dir, j, tokens - j, isVariadic})); } else { j = dir.SkipBlanks(j + 1); + CheckForUnbalancedParentheses(dir, j, tokens - j); definitions_.emplace( std::make_pair(nameToken, Definition{dir, j, tokens - j})); } @@ -883,7 +887,7 @@ static std::int64_t ExpressionValue(const TokenSequence &token, } switch (op) { case PARENS: - if (*atToken < tokens && token.TokenAt(*atToken).ToString() == ")") { + if (*atToken < tokens && token.TokenAt(*atToken).OnlyNonBlank() == ')') { ++*atToken; break; } @@ -1085,8 +1089,8 @@ bool Preprocessor::IsIfPredicateTrue(const TokenSequence &expr, if (ToLowerCaseLetters(expr1.TokenAt(j).ToString()) == "defined") { CharBlock name; if (j + 3 < expr1.SizeInTokens() && - expr1.TokenAt(j + 1).ToString() == "(" && - expr1.TokenAt(j + 3).ToString() == ")") { + expr1.TokenAt(j + 1).OnlyNonBlank() == '(' && + expr1.TokenAt(j + 3).OnlyNonBlank() == ')') { name = expr1.TokenAt(j + 2); j += 3; } else if (j + 1 < expr1.SizeInTokens() && @@ -1176,4 +1180,24 @@ void Preprocessor::LineDirective( sourceFile->LineDirective(pos->trueLineNumber + 1, *linePath, *lineNumber); } } + +void Preprocessor::CheckForUnbalancedParentheses( + const TokenSequence &tokens, std::size_t j, std::size_t n) { + if (!anyMacroWithUnbalancedParentheses_) { + int nesting{0}; + for (; n-- > 0; ++j) { + char ch{tokens.TokenAt(j).OnlyNonBlank()}; + if (ch == '(') { + ++nesting; + } else if (ch == ')') { + if (nesting-- == 0) { + break; + } + } + } + if (nesting != 0) { + anyMacroWithUnbalancedParentheses_ = true; + } + } +} } // namespace Fortran::parser diff --git a/flang/lib/Parser/preprocessor.h b/flang/lib/Parser/preprocessor.h index 5d866ae..cea8483 100644 --- a/flang/lib/Parser/preprocessor.h +++ b/flang/lib/Parser/preprocessor.h @@ -80,6 +80,10 @@ public: // Implements a preprocessor directive. void Directive(const TokenSequence &, Prescanner &); + bool anyMacroWithUnbalancedParentheses() const { + return anyMacroWithUnbalancedParentheses_; + } + private: enum class IsElseActive { No, Yes }; enum class CanDeadElseAppear { No, Yes }; @@ -91,11 +95,14 @@ private: bool IsIfPredicateTrue(const TokenSequence &expr, std::size_t first, std::size_t exprTokens, Prescanner &); void LineDirective(const TokenSequence &, std::size_t, Prescanner &); + void CheckForUnbalancedParentheses( + const TokenSequence &, std::size_t first, std::size_t tokens); AllSources &allSources_; std::list<std::string> names_; std::unordered_map<CharBlock, Definition> definitions_; std::stack<CanDeadElseAppear> ifStack_; + bool anyMacroWithUnbalancedParentheses_{false}; }; } // namespace Fortran::parser #endif // FORTRAN_PARSER_PREPROCESSOR_H_ diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp index d84b62cb..f9f94bb 100644 --- a/flang/lib/Parser/prescan.cpp +++ b/flang/lib/Parser/prescan.cpp @@ -630,10 +630,14 @@ bool Prescanner::NextToken(TokenSequence &tokens) { } } else { char ch{*at_}; - if (ch == '(' || ch == '[') { - ++delimiterNesting_; - } else if ((ch == ')' || ch == ']') && delimiterNesting_ > 0) { - --delimiterNesting_; + if (ch == '(') { + if (parenthesisNesting_++ == 0) { + isPossibleMacroCall_ = tokens.SizeInTokens() > 0 && + preprocessor_.IsNameDefined( + tokens.TokenAt(tokens.SizeInTokens() - 1)); + } + } else if (ch == ')' && parenthesisNesting_ > 0) { + --parenthesisNesting_; } char nch{EmitCharAndAdvance(tokens, ch)}; preventHollerith_ = false; @@ -1142,8 +1146,9 @@ bool Prescanner::FreeFormContinuation() { // Implicit line continuation allows a preprocessor macro call with // arguments to span multiple lines. bool Prescanner::IsImplicitContinuation() const { - return !inPreprocessorDirective_ && !inCharLiteral_ && - delimiterNesting_ > 0 && !IsAtEnd() && + return !inPreprocessorDirective_ && !inCharLiteral_ && isPossibleMacroCall_ && + parenthesisNesting_ > 0 && + !preprocessor_.anyMacroWithUnbalancedParentheses() && !IsAtEnd() && ClassifyLine(nextLine_).kind == LineClassification::Kind::Source; } diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h index 86fa06f..0216326 100644 --- a/flang/lib/Parser/prescan.h +++ b/flang/lib/Parser/prescan.h @@ -109,8 +109,9 @@ private: BeginSourceLineAndAdvance(); slashInCurrentStatement_ = false; preventHollerith_ = false; - delimiterNesting_ = 0; + parenthesisNesting_ = 0; continuationLines_ = 0; + isPossibleMacroCall_ = false; } Provenance GetProvenance(const char *sourceChar) const { @@ -194,9 +195,10 @@ private: bool inFixedForm_{false}; int fixedFormColumnLimit_{72}; Encoding encoding_{Encoding::UTF_8}; - int delimiterNesting_{0}; + int parenthesisNesting_{0}; int prescannerNesting_{0}; int continuationLines_{0}; + bool isPossibleMacroCall_{false}; Provenance startProvenance_; const char *start_{nullptr}; // beginning of current source file content diff --git a/flang/lib/Parser/token-sequence.cpp b/flang/lib/Parser/token-sequence.cpp index f94c8142..139d2e1 100644 --- a/flang/lib/Parser/token-sequence.cpp +++ b/flang/lib/Parser/token-sequence.cpp @@ -376,11 +376,13 @@ const TokenSequence &TokenSequence::CheckBadParentheses( std::size_t tokens{SizeInTokens()}; for (std::size_t j{0}; j < tokens; ++j) { CharBlock token{TokenAt(j)}; - char ch{token.FirstNonBlank()}; + char ch{token.OnlyNonBlank()}; if (ch == '(') { ++nesting; } else if (ch == ')') { - --nesting; + if (nesting-- == 0) { + break; + } } } if (nesting != 0) { @@ -388,7 +390,7 @@ const TokenSequence &TokenSequence::CheckBadParentheses( std::vector<std::size_t> stack; for (std::size_t j{0}; j < tokens; ++j) { CharBlock token{TokenAt(j)}; - char ch{token.FirstNonBlank()}; + char ch{token.OnlyNonBlank()}; if (ch == '(') { stack.push_back(j); } else if (ch == ')') { |