@@ -180,6 +180,28 @@ void Prescanner::Statement() {
180
180
}
181
181
} else {
182
182
SkipSpaces ();
183
+ // Check for a leading identifier that might be a keyword macro
184
+ // that will expand to anything indicating a non-source line, like
185
+ // a comment marker or directive sentinel. If so, disable line
186
+ // continuation, so that NextToken() won't consume anything from
187
+ // following lines.
188
+ if (IsLegalIdentifierStart (*at_)) {
189
+ CHECK (NextToken (tokens));
190
+ CHECK (tokens.SizeInTokens () == 1 );
191
+ CharBlock id{tokens.TokenAt (0 )};
192
+ if (preprocessor_.IsNameDefined (id) &&
193
+ !preprocessor_.IsFunctionLikeDefinition (id)) {
194
+ if (auto replaced{preprocessor_.MacroReplacement (tokens, *this )}) {
195
+ auto newLineClass{ClassifyLine (*replaced, GetCurrentProvenance ())};
196
+ disableSourceContinuation_ =
197
+ newLineClass.kind != LineClassification::Kind::Source;
198
+ if (newLineClass.kind ==
199
+ LineClassification::Kind::CompilerDirective) {
200
+ directiveSentinel_ = newLineClass.sentinel ;
201
+ }
202
+ }
203
+ }
204
+ }
183
205
}
184
206
break ;
185
207
}
@@ -197,17 +219,13 @@ void Prescanner::Statement() {
197
219
Provenance newlineProvenance{GetCurrentProvenance ()};
198
220
if (std::optional<TokenSequence> preprocessed{
199
221
preprocessor_.MacroReplacement (tokens, *this )}) {
200
- // Reprocess the preprocessed line. Append a newline temporarily.
201
- preprocessed->PutNextTokenChar (' \n ' , newlineProvenance);
202
- preprocessed->CloseToken ();
203
- const char *ppd{preprocessed->ToCharBlock ().begin ()};
204
- LineClassification ppl{ClassifyLine (ppd)};
205
- preprocessed->pop_back (); // remove the newline
222
+ // Reprocess the preprocessed line.
223
+ LineClassification ppl{ClassifyLine (*preprocessed, newlineProvenance)};
206
224
switch (ppl.kind ) {
207
225
case LineClassification::Kind::Comment:
208
226
break ;
209
227
case LineClassification::Kind::IncludeLine:
210
- FortranInclude (ppd + ppl.payloadOffset );
228
+ FortranInclude (preprocessed-> TokenAt ( 0 ). begin () + ppl.payloadOffset );
211
229
break ;
212
230
case LineClassification::Kind::ConditionalCompilationDirective:
213
231
case LineClassification::Kind::IncludeDirective:
@@ -270,7 +288,8 @@ void Prescanner::Statement() {
270
288
271
289
void Prescanner::CheckAndEmitLine (
272
290
TokenSequence &tokens, Provenance newlineProvenance) {
273
- tokens.CheckBadFortranCharacters (messages_, *this );
291
+ tokens.CheckBadFortranCharacters (
292
+ messages_, *this , disableSourceContinuation_);
274
293
// Parenthesis nesting check does not apply while any #include is
275
294
// active, nor on the lines before and after a top-level #include.
276
295
// Applications play shenanigans with line continuation before and
@@ -1243,7 +1262,9 @@ bool Prescanner::IsImplicitContinuation() const {
1243
1262
}
1244
1263
1245
1264
bool Prescanner::Continuation (bool mightNeedFixedFormSpace) {
1246
- if (*at_ == ' \n ' || *at_ == ' &' ) {
1265
+ if (disableSourceContinuation_) {
1266
+ return false ;
1267
+ } else if (*at_ == ' \n ' || *at_ == ' &' ) {
1247
1268
if (inFixedForm_) {
1248
1269
return FixedFormContinuation (mightNeedFixedFormSpace);
1249
1270
} else {
@@ -1255,8 +1276,9 @@ bool Prescanner::Continuation(bool mightNeedFixedFormSpace) {
1255
1276
BeginSourceLine (nextLine_);
1256
1277
NextLine ();
1257
1278
return true ;
1279
+ } else {
1280
+ return false ;
1258
1281
}
1259
- return false ;
1260
1282
}
1261
1283
1262
1284
std::optional<Prescanner::LineClassification>
@@ -1418,6 +1440,17 @@ Prescanner::LineClassification Prescanner::ClassifyLine(
1418
1440
return {LineClassification::Kind::Source};
1419
1441
}
1420
1442
1443
+ Prescanner::LineClassification Prescanner::ClassifyLine (
1444
+ TokenSequence &tokens, Provenance newlineProvenance) const {
1445
+ // Append a newline temporarily.
1446
+ tokens.PutNextTokenChar (' \n ' , newlineProvenance);
1447
+ tokens.CloseToken ();
1448
+ const char *ppd{tokens.ToCharBlock ().begin ()};
1449
+ LineClassification classification{ClassifyLine (ppd)};
1450
+ tokens.pop_back (); // remove the newline
1451
+ return classification;
1452
+ }
1453
+
1421
1454
void Prescanner::SourceFormChange (std::string &&dir) {
1422
1455
if (dir == " !dir$ free" ) {
1423
1456
inFixedForm_ = false ;
@@ -1445,7 +1478,7 @@ bool Prescanner::CompilerDirectiveContinuation(
1445
1478
return true ;
1446
1479
}
1447
1480
CHECK (origSentinel != nullptr );
1448
- directiveSentinel_ = origSentinel; // so IsDirective () is true
1481
+ directiveSentinel_ = origSentinel; // so InCompilerDirective () is true
1449
1482
const char *nextContinuation{
1450
1483
followingLine.kind == LineClassification::Kind::CompilerDirective
1451
1484
? FreeFormContinuationLine (true )
@@ -1457,7 +1490,6 @@ bool Prescanner::CompilerDirectiveContinuation(
1457
1490
auto origNextLine{nextLine_};
1458
1491
BeginSourceLine (nextLine_);
1459
1492
NextLine ();
1460
- TokenSequence followingTokens;
1461
1493
if (nextContinuation) {
1462
1494
// What follows is !DIR$ & xxx; skip over the & so that it
1463
1495
// doesn't cause a spurious continuation.
@@ -1467,6 +1499,7 @@ bool Prescanner::CompilerDirectiveContinuation(
1467
1499
// but might become a directive continuation afterwards.
1468
1500
SkipSpaces ();
1469
1501
}
1502
+ TokenSequence followingTokens;
1470
1503
while (NextToken (followingTokens)) {
1471
1504
}
1472
1505
if (auto followingPrepro{
@@ -1475,25 +1508,31 @@ bool Prescanner::CompilerDirectiveContinuation(
1475
1508
}
1476
1509
followingTokens.RemoveRedundantBlanks ();
1477
1510
std::size_t startAt{0 };
1478
- std::size_t keep {followingTokens.SizeInTokens ()};
1511
+ std::size_t following {followingTokens.SizeInTokens ()};
1479
1512
bool ok{false };
1480
1513
if (nextContinuation) {
1481
1514
ok = true ;
1482
1515
} else {
1483
- if (keep >= 3 && followingTokens. TokenAt ( 0 ) == " ! " &&
1484
- followingTokens.TokenAt (2 ) == " & " ) {
1516
+ startAt = 2 ;
1517
+ if (startAt < following && followingTokens.TokenAt (0 ) == " ! " ) {
1485
1518
CharBlock sentinel{followingTokens.TokenAt (1 )};
1486
1519
if (!sentinel.empty () &&
1487
1520
std::memcmp (sentinel.begin (), origSentinel, sentinel.size ()) == 0 ) {
1488
- startAt = 3 ;
1489
- keep -= 3 ;
1490
1521
ok = true ;
1522
+ while (
1523
+ startAt < following && followingTokens.TokenAt (startAt).IsBlank ()) {
1524
+ ++startAt;
1525
+ }
1526
+ if (startAt < following && followingTokens.TokenAt (startAt) == " &" ) {
1527
+ ++startAt;
1528
+ }
1491
1529
}
1492
1530
}
1493
1531
}
1494
1532
if (ok) {
1495
1533
tokens.pop_back (); // delete original '&'
1496
- tokens.Put (followingTokens, startAt, keep);
1534
+ tokens.Put (followingTokens, startAt, following - startAt);
1535
+ tokens.RemoveRedundantBlanks ();
1497
1536
} else {
1498
1537
nextLine_ = origNextLine;
1499
1538
}
0 commit comments