@@ -32,10 +32,11 @@ Prescanner::Prescanner(Messages &messages, CookedSource &cooked,
32
32
backslashFreeFormContinuation_{preprocessor.AnyDefinitions ()},
33
33
encoding_{allSources_.encoding ()} {}
34
34
35
- Prescanner::Prescanner (const Prescanner &that)
35
+ Prescanner::Prescanner (const Prescanner &that, bool isNestedInIncludeDirective )
36
36
: messages_{that.messages_ }, cooked_{that.cooked_ },
37
37
preprocessor_{that.preprocessor_ }, allSources_{that.allSources_ },
38
38
features_{that.features_ },
39
+ isNestedInIncludeDirective_{isNestedInIncludeDirective},
39
40
backslashFreeFormContinuation_{that.backslashFreeFormContinuation_ },
40
41
inFixedForm_{that.inFixedForm_ },
41
42
fixedFormColumnLimit_{that.fixedFormColumnLimit_ },
@@ -104,11 +105,14 @@ void Prescanner::Statement() {
104
105
NextLine ();
105
106
return ;
106
107
case LineClassification::Kind::ConditionalCompilationDirective:
107
- case LineClassification::Kind::IncludeDirective:
108
108
case LineClassification::Kind::DefinitionDirective:
109
109
case LineClassification::Kind::PreprocessorDirective:
110
110
preprocessor_.Directive (TokenizePreprocessorDirective (), *this );
111
111
return ;
112
+ case LineClassification::Kind::IncludeDirective:
113
+ preprocessor_.Directive (TokenizePreprocessorDirective (), *this );
114
+ afterIncludeDirective_ = true ;
115
+ return ;
112
116
case LineClassification::Kind::CompilerDirective: {
113
117
directiveSentinel_ = line.sentinel ;
114
118
CHECK (InCompilerDirective ());
@@ -213,10 +217,7 @@ void Prescanner::Statement() {
213
217
Say (preprocessed->GetProvenanceRange (),
214
218
" Preprocessed line resembles a preprocessor directive" _warn_en_US);
215
219
}
216
- preprocessed->ToLowerCase ()
217
- .CheckBadFortranCharacters (messages_, *this )
218
- .CheckBadParentheses (messages_)
219
- .Emit (cooked_);
220
+ CheckAndEmitLine (preprocessed->ToLowerCase (), newlineProvenance);
220
221
break ;
221
222
case LineClassification::Kind::CompilerDirective:
222
223
if (preprocessed->HasRedundantBlanks ()) {
@@ -228,10 +229,9 @@ void Prescanner::Statement() {
228
229
NormalizeCompilerDirectiveCommentMarker (*preprocessed);
229
230
preprocessed->ToLowerCase ();
230
231
SourceFormChange (preprocessed->ToString ());
231
- preprocessed->ClipComment (*this , true /* skip first ! */ )
232
- .CheckBadFortranCharacters (messages_, *this )
233
- .CheckBadParentheses (messages_)
234
- .Emit (cooked_);
232
+ CheckAndEmitLine (preprocessed->ToLowerCase ().ClipComment (
233
+ *this , true /* skip first ! */ ),
234
+ newlineProvenance);
235
235
break ;
236
236
case LineClassification::Kind::Source:
237
237
if (inFixedForm_) {
@@ -246,14 +246,11 @@ void Prescanner::Statement() {
246
246
preprocessed->RemoveRedundantBlanks ();
247
247
}
248
248
}
249
- preprocessed->ToLowerCase ()
250
- .ClipComment (*this )
251
- .CheckBadFortranCharacters (messages_, *this )
252
- .CheckBadParentheses (messages_)
253
- .Emit (cooked_);
249
+ CheckAndEmitLine (
250
+ preprocessed->ToLowerCase ().ClipComment (*this ), newlineProvenance);
254
251
break ;
255
252
}
256
- } else {
253
+ } else { // no macro replacement
257
254
if (line.kind == LineClassification::Kind::CompilerDirective) {
258
255
while (CompilerDirectiveContinuation (tokens, line.sentinel )) {
259
256
newlineProvenance = GetCurrentProvenance ();
@@ -266,16 +263,29 @@ void Prescanner::Statement() {
266
263
EnforceStupidEndStatementRules (tokens);
267
264
}
268
265
}
269
- tokens.CheckBadFortranCharacters (messages_, *this )
270
- .CheckBadParentheses (messages_)
271
- .Emit (cooked_);
266
+ CheckAndEmitLine (tokens, newlineProvenance);
272
267
}
268
+ directiveSentinel_ = nullptr ;
269
+ }
270
+
271
+ void Prescanner::CheckAndEmitLine (
272
+ TokenSequence &tokens, Provenance newlineProvenance) {
273
+ tokens.CheckBadFortranCharacters (messages_, *this );
274
+ // Parenthesis nesting check does not apply while any #include is
275
+ // active, nor on the lines before and after a top-level #include.
276
+ // Applications play shenanigans with line continuation before and
277
+ // after #include'd subprogram argument lists.
278
+ if (!isNestedInIncludeDirective_ && !omitNewline_ &&
279
+ !afterIncludeDirective_) {
280
+ tokens.CheckBadParentheses (messages_);
281
+ }
282
+ tokens.Emit (cooked_);
273
283
if (omitNewline_) {
274
284
omitNewline_ = false ;
275
285
} else {
276
286
cooked_.Put (' \n ' , newlineProvenance);
287
+ afterIncludeDirective_ = false ;
277
288
}
278
- directiveSentinel_ = nullptr ;
279
289
}
280
290
281
291
TokenSequence Prescanner::TokenizePreprocessorDirective () {
@@ -985,7 +995,9 @@ void Prescanner::FortranInclude(const char *firstQuote) {
985
995
provenance, static_cast <std::size_t >(p - nextLine_)};
986
996
ProvenanceRange fileRange{
987
997
allSources_.AddIncludedFile (*included, includeLineRange)};
988
- Prescanner{*this }.set_encoding (included->encoding ()).Prescan (fileRange);
998
+ Prescanner{*this , /* isNestedInIncludeDirective=*/ false }
999
+ .set_encoding (included->encoding ())
1000
+ .Prescan (fileRange);
989
1001
}
990
1002
}
991
1003
0 commit comments