@@ -150,10 +150,7 @@ void Prescanner::Statement() {
150
150
CHECK (*at_ == ' !' );
151
151
}
152
152
std::optional<int > condOffset;
153
- bool isOpenMPCondCompilation{
154
- directiveSentinel_[0 ] == ' $' && directiveSentinel_[1 ] == ' \0 ' };
155
- if (isOpenMPCondCompilation) {
156
- // OpenMP conditional compilation line.
153
+ if (InOpenMPConditionalLine ()) {
157
154
condOffset = 2 ;
158
155
} else if (directiveSentinel_[0 ] == ' @' && directiveSentinel_[1 ] == ' c' &&
159
156
directiveSentinel_[2 ] == ' u' && directiveSentinel_[3 ] == ' f' &&
@@ -167,19 +164,10 @@ void Prescanner::Statement() {
167
164
FortranInclude (at_ + *payload);
168
165
return ;
169
166
}
170
- while (true ) {
171
- if (auto n{IsSpace (at_)}) {
172
- at_ += n, ++column_;
173
- } else if (*at_ == ' \t ' ) {
174
- ++at_, ++column_;
175
- tabInCurrentLine_ = true ;
176
- } else if (inFixedForm_ && column_ == 6 && !tabInCurrentLine_ &&
177
- *at_ == ' 0' ) {
178
- ++at_, ++column_;
179
- } else {
180
- break ;
181
- }
167
+ if (inFixedForm_) {
168
+ LabelField (tokens);
182
169
}
170
+ SkipSpaces ();
183
171
} else {
184
172
// Compiler directive. Emit normalized sentinel, squash following spaces.
185
173
// Conditional compilation lines (!$) take this path in -E mode too
@@ -190,35 +178,47 @@ void Prescanner::Statement() {
190
178
++sp, ++at_, ++column_) {
191
179
EmitChar (tokens, *sp);
192
180
}
193
- if (IsSpaceOrTab (at_)) {
194
- while (int n{IsSpaceOrTab (at_)}) {
195
- if (isOpenMPCondCompilation && inFixedForm_) {
181
+ if (inFixedForm_) {
182
+ while (column_ < 6 ) {
183
+ if (*at_ == ' \t ' ) {
184
+ tabInCurrentLine_ = true ;
185
+ ++at_;
186
+ for (; column_ < 7 ; ++column_) {
187
+ EmitChar (tokens, ' ' );
188
+ }
189
+ } else if (int spaceBytes{IsSpace (at_)}) {
196
190
EmitChar (tokens, ' ' );
197
- }
198
- tabInCurrentLine_ |= *at_ == ' \t ' ;
199
- at_ += n, ++column_;
200
- if (inFixedForm_ && column_ > fixedFormColumnLimit_) {
191
+ at_ += spaceBytes;
192
+ ++column_;
193
+ } else {
194
+ if (InOpenMPConditionalLine () && column_ == 3 &&
195
+ IsDecimalDigit (*at_)) {
196
+ // subtle: !$ in -E mode can't be immediately followed by a digit
197
+ EmitChar (tokens, ' ' );
198
+ }
201
199
break ;
202
200
}
203
201
}
204
- if (isOpenMPCondCompilation && inFixedForm_ && column_ == 6 ) {
205
- if (*at_ == ' 0' ) {
206
- EmitChar (tokens, ' ' );
207
- } else {
208
- tokens.CloseToken ();
209
- EmitChar (tokens, ' &' );
210
- }
211
- ++at_, ++column_;
202
+ } else if (int spaceBytes{IsSpaceOrTab (at_)}) {
203
+ EmitChar (tokens, ' ' );
204
+ at_ += spaceBytes, ++column_;
205
+ }
206
+ tokens.CloseToken ();
207
+ SkipSpaces ();
208
+ if (InOpenMPConditionalLine () && inFixedForm_ && !tabInCurrentLine_ &&
209
+ column_ == 6 && *at_ != ' \n ' ) {
210
+ // !$ 0 - turn '0' into a space
211
+ // !$ 1 - turn '1' into '&'
212
+ if (int n{IsSpace (at_)}; n || *at_ == ' 0' ) {
213
+ at_ += n ? n : 1 ;
212
214
} else {
213
- EmitChar (tokens, ' ' );
215
+ ++at_;
216
+ EmitChar (tokens, ' &' );
217
+ tokens.CloseToken ();
214
218
}
219
+ ++column_;
220
+ SkipSpaces ();
215
221
}
216
- tokens.CloseToken ();
217
- }
218
- if (*at_ == ' !' || *at_ == ' \n ' ||
219
- (inFixedForm_ && column_ > fixedFormColumnLimit_ &&
220
- !tabInCurrentLine_)) {
221
- return ; // Directive without payload
222
222
}
223
223
break ;
224
224
}
@@ -323,8 +323,8 @@ void Prescanner::Statement() {
323
323
NormalizeCompilerDirectiveCommentMarker (*preprocessed);
324
324
preprocessed->ToLowerCase ();
325
325
SourceFormChange (preprocessed->ToString ());
326
- CheckAndEmitLine (preprocessed-> ToLowerCase (). ClipComment (
327
- *this , true /* skip first ! */ ),
326
+ CheckAndEmitLine (
327
+ preprocessed-> ClipComment ( *this , true /* skip first ! */ ),
328
328
newlineProvenance);
329
329
break ;
330
330
case LineClassification::Kind::Source:
@@ -349,6 +349,24 @@ void Prescanner::Statement() {
349
349
while (CompilerDirectiveContinuation (tokens, line.sentinel )) {
350
350
newlineProvenance = GetCurrentProvenance ();
351
351
}
352
+ if (preprocessingOnly_ && inFixedForm_ && InOpenMPConditionalLine () &&
353
+ nextLine_ < limit_) {
354
+ // In -E mode, when the line after !$ conditional compilation is a
355
+ // regular fixed form continuation line, append a '&' to the line.
356
+ const char *p{nextLine_};
357
+ int col{1 };
358
+ while (int n{IsSpace (p)}) {
359
+ if (*p == ' \t ' ) {
360
+ break ;
361
+ }
362
+ p += n;
363
+ ++col;
364
+ }
365
+ if (col == 6 && *p != ' 0' && *p != ' \t ' && *p != ' \n ' ) {
366
+ EmitChar (tokens, ' &' );
367
+ tokens.CloseToken ();
368
+ }
369
+ }
352
370
tokens.ToLowerCase ();
353
371
SourceFormChange (tokens.ToString ());
354
372
} else { // Kind::Source
@@ -544,7 +562,8 @@ void Prescanner::SkipToEndOfLine() {
544
562
bool Prescanner::MustSkipToEndOfLine () const {
545
563
if (inFixedForm_ && column_ > fixedFormColumnLimit_ && !tabInCurrentLine_) {
546
564
return true ; // skip over ignored columns in right margin (73:80)
547
- } else if (*at_ == ' !' && !inCharLiteral_) {
565
+ } else if (*at_ == ' !' && !inCharLiteral_ &&
566
+ (!inFixedForm_ || tabInCurrentLine_ || column_ != 6 )) {
548
567
return !IsCompilerDirectiveSentinel (at_);
549
568
} else {
550
569
return false ;
@@ -569,10 +588,11 @@ void Prescanner::NextChar() {
569
588
// directives, Fortran ! comments, stuff after the right margin in
570
589
// fixed form, and all forms of line continuation.
571
590
bool Prescanner::SkipToNextSignificantCharacter () {
572
- auto anyContinuationLine{false };
573
591
if (inPreprocessorDirective_) {
574
592
SkipCComments ();
593
+ return false ;
575
594
} else {
595
+ auto anyContinuationLine{false };
576
596
bool mightNeedSpace{false };
577
597
if (MustSkipToEndOfLine ()) {
578
598
SkipToEndOfLine ();
@@ -589,8 +609,8 @@ bool Prescanner::SkipToNextSignificantCharacter() {
589
609
if (*at_ == ' \t ' ) {
590
610
tabInCurrentLine_ = true ;
591
611
}
612
+ return anyContinuationLine;
592
613
}
593
- return anyContinuationLine;
594
614
}
595
615
596
616
void Prescanner::SkipCComments () {
@@ -1119,12 +1139,10 @@ static bool IsAtProcess(const char *p) {
1119
1139
1120
1140
bool Prescanner::IsFixedFormCommentLine (const char *start) const {
1121
1141
const char *p{start};
1122
-
1123
1142
// The @process directive must start in column 1.
1124
1143
if (*p == ' @' && IsAtProcess (p)) {
1125
1144
return true ;
1126
1145
}
1127
-
1128
1146
if (IsFixedFormCommentChar (*p) || *p == ' %' || // VAX %list, %eject, &c.
1129
1147
((*p == ' D' || *p == ' d' ) &&
1130
1148
!features_.IsEnabled (LanguageFeature::OldDebugLines))) {
@@ -1324,24 +1342,11 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
1324
1342
features_.IsEnabled (LanguageFeature::OldDebugLines))) &&
1325
1343
nextLine_[1 ] == ' ' && nextLine_[2 ] == ' ' && nextLine_[3 ] == ' ' &&
1326
1344
nextLine_[4 ] == ' ' };
1327
- if (InCompilerDirective ()) {
1328
- if (directiveSentinel_[0 ] == ' $' && directiveSentinel_[1 ] == ' \0 ' ) {
1329
- if (IsFixedFormCommentChar (col1)) {
1330
- if (nextLine_[1 ] == ' $' &&
1331
- (nextLine_[2 ] == ' &' || IsSpaceOrTab (&nextLine_[2 ]))) {
1332
- // Next line is also !$ conditional compilation, might be continuation
1333
- if (preprocessingOnly_) {
1334
- return nullptr ;
1335
- }
1336
- } else {
1337
- return nullptr ; // comment, or distinct directive
1338
- }
1339
- } else if (!canBeNonDirectiveContinuation) {
1340
- return nullptr ;
1341
- }
1342
- } else if (!IsFixedFormCommentChar (col1)) {
1343
- return nullptr ; // in directive other than !$, but next line is not
1344
- } else { // in directive other than !$, next line might be continuation
1345
+ if (InCompilerDirective () &&
1346
+ !(InOpenMPConditionalLine () && !preprocessingOnly_)) {
1347
+ // !$ under -E is not continued, but deferred to later compilation
1348
+ if (IsFixedFormCommentChar (col1) &&
1349
+ !(InOpenMPConditionalLine () && preprocessingOnly_)) {
1345
1350
int j{1 };
1346
1351
for (; j < 5 ; ++j) {
1347
1352
char ch{directiveSentinel_[j - 1 ]};
@@ -1356,31 +1361,27 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
1356
1361
return nullptr ;
1357
1362
}
1358
1363
}
1359
- }
1360
- const char *col6{nextLine_ + 5 };
1361
- if (*col6 != ' \n ' && *col6 != ' 0' && !IsSpaceOrTab (col6)) {
1362
- if (mightNeedSpace && !IsSpace (nextLine_ + 6 )) {
1363
- insertASpace_ = true ;
1364
+ const char *col6{nextLine_ + 5 };
1365
+ if (*col6 != ' \n ' && *col6 != ' 0' && !IsSpaceOrTab (col6)) {
1366
+ if (mightNeedSpace && !IsSpace (nextLine_ + 6 )) {
1367
+ insertASpace_ = true ;
1368
+ }
1369
+ return nextLine_ + 6 ;
1364
1370
}
1365
- return nextLine_ + 6 ;
1366
1371
}
1367
- } else {
1368
- // Normal case: not in a compiler directive.
1369
- if (IsFixedFormCommentChar (col1)) {
1370
- if (nextLine_[1 ] == ' $' && nextLine_[2 ] == ' ' && nextLine_[3 ] == ' ' &&
1371
- nextLine_[4 ] == ' ' &&
1372
- IsCompilerDirectiveSentinel (&nextLine_[1 ], 1 ) &&
1373
- !preprocessingOnly_) {
1374
- // !$ conditional compilation line as a continuation
1375
- const char *col6{nextLine_ + 5 };
1376
- if (*col6 != ' \n ' && *col6 != ' 0' && !IsSpaceOrTab (col6)) {
1377
- if (mightNeedSpace && !IsSpace (nextLine_ + 6 )) {
1378
- insertASpace_ = true ;
1379
- }
1380
- return nextLine_ + 6 ;
1381
- }
1372
+ } else { // Normal case: not in a compiler directive.
1373
+ // !$ conditional compilation lines may be continuations when not
1374
+ // just preprocessing.
1375
+ if (!preprocessingOnly_ && IsFixedFormCommentChar (col1) &&
1376
+ nextLine_[1 ] == ' $' && nextLine_[2 ] == ' ' && nextLine_[3 ] == ' ' &&
1377
+ nextLine_[4 ] == ' ' && IsCompilerDirectiveSentinel (&nextLine_[1 ], 1 )) {
1378
+ if (const char *col6{nextLine_ + 5 };
1379
+ *col6 != ' \n ' && *col6 != ' 0' && !IsSpaceOrTab (col6)) {
1380
+ insertASpace_ |= mightNeedSpace && !IsSpace (nextLine_ + 6 );
1381
+ return nextLine_ + 6 ;
1382
+ } else {
1383
+ return nullptr ;
1382
1384
}
1383
- return nullptr ;
1384
1385
}
1385
1386
if (col1 == ' &' &&
1386
1387
features_.IsEnabled (
@@ -1422,13 +1423,13 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
1422
1423
}
1423
1424
p = SkipWhiteSpaceIncludingEmptyMacros (p);
1424
1425
if (InCompilerDirective ()) {
1425
- if (directiveSentinel_[ 0 ] == ' $ ' && directiveSentinel_[ 1 ] == ' \0 ' ) {
1426
+ if (InOpenMPConditionalLine () ) {
1426
1427
if (preprocessingOnly_) {
1427
1428
// in -E mode, don't treat !$ as a continuation
1428
1429
return nullptr ;
1429
1430
} else if (p[0 ] == ' !' && p[1 ] == ' $' ) {
1430
1431
// accept but do not require a matching sentinel
1431
- if (!( p[2 ] == ' &' || IsSpaceOrTab (&p[2 ]) )) {
1432
+ if (p[2 ] != ' &' && ! IsSpaceOrTab (&p[2 ])) {
1432
1433
return nullptr ; // not !$
1433
1434
}
1434
1435
p += 2 ;
@@ -1566,15 +1567,11 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
1566
1567
}
1567
1568
char sentinel[5 ], *sp{sentinel};
1568
1569
int column{2 };
1569
- for (; column < 6 ; ++column, ++p) {
1570
- if (*p == ' \n ' || IsSpaceOrTab (p)) {
1571
- break ;
1572
- }
1573
- if (sp == sentinel + 1 && sentinel[0 ] == ' $' && IsDecimalDigit (*p)) {
1574
- // OpenMP conditional compilation line: leave the label alone
1570
+ for (; column < 6 ; ++column) {
1571
+ if (*p == ' \n ' || IsSpaceOrTab (p) || IsDecimalDigit (*p)) {
1575
1572
break ;
1576
1573
}
1577
- *sp++ = ToLowerCaseLetter (*p);
1574
+ *sp++ = ToLowerCaseLetter (*p++ );
1578
1575
}
1579
1576
if (sp == sentinel) {
1580
1577
return std::nullopt;
@@ -1600,7 +1597,8 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
1600
1597
++p;
1601
1598
} else if (int n{IsSpaceOrTab (p)}) {
1602
1599
p += n;
1603
- } else if (isOpenMPConditional && preprocessingOnly_ && !hadDigit) {
1600
+ } else if (isOpenMPConditional && preprocessingOnly_ && !hadDigit &&
1601
+ *p != ' \n ' ) {
1604
1602
// In -E mode, "!$ &" is treated as a directive
1605
1603
} else {
1606
1604
// This is a Continuation line, not an initial directive line.
@@ -1671,14 +1669,14 @@ const char *Prescanner::IsCompilerDirectiveSentinel(CharBlock token) const {
1671
1669
std::optional<std::pair<const char *, const char *>>
1672
1670
Prescanner::IsCompilerDirectiveSentinel (const char *p) const {
1673
1671
char sentinel[8 ];
1674
- for (std::size_t j{0 }; j + 1 < sizeof sentinel && *p != ' \n ' ; ++p, ++j) {
1672
+ for (std::size_t j{0 }; j + 1 < sizeof sentinel; ++p, ++j) {
1675
1673
if (int n{IsSpaceOrTab (p)};
1676
1674
n || !(IsLetter (*p) || *p == ' $' || *p == ' @' )) {
1677
1675
if (j > 0 ) {
1678
- if (j == 1 && sentinel[0 ] == ' $' && n == 0 && *p != ' &' ) {
1679
- // OpenMP conditional compilation line sentinels have to
1676
+ if (j == 1 && sentinel[0 ] == ' $' && n == 0 && *p != ' &' && *p != ' \n ' ) {
1677
+ // Free form OpenMP conditional compilation line sentinels have to
1680
1678
// be immediately followed by a space or &, not a digit
1681
- // or anything else.
1679
+ // or anything else. A newline also works for an initial line.
1682
1680
break ;
1683
1681
}
1684
1682
sentinel[j] = ' \0 ' ;
0 commit comments