aboutsummaryrefslogtreecommitdiff
path: root/flang/lib/Parser
diff options
context:
space:
mode:
Diffstat (limited to 'flang/lib/Parser')
-rw-r--r--flang/lib/Parser/preprocessor.cpp88
-rw-r--r--flang/lib/Parser/preprocessor.h7
-rw-r--r--flang/lib/Parser/prescan.cpp17
-rw-r--r--flang/lib/Parser/prescan.h6
-rw-r--r--flang/lib/Parser/token-sequence.cpp8
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 == ')') {