@@ -150,10 +150,7 @@ void Prescanner::Statement() {
150150 CHECK (*at_ == ' !' );
151151 }
152152 std::optional<int > condOffset;
153- bool isOpenMPCondCompilation{
154- directiveSentinel_[0 ] == ' $' && directiveSentinel_[1 ] == ' \0 ' };
155- if (isOpenMPCondCompilation) {
156- // OpenMP conditional compilation line.
153+ if (InOpenMPConditionalLine ()) {
157154 condOffset = 2 ;
158155 } else if (directiveSentinel_[0 ] == ' @' && directiveSentinel_[1 ] == ' c' &&
159156 directiveSentinel_[2 ] == ' u' && directiveSentinel_[3 ] == ' f' &&
@@ -167,19 +164,10 @@ void Prescanner::Statement() {
167164 FortranInclude (at_ + *payload);
168165 return ;
169166 }
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);
182169 }
170+ SkipSpaces ();
183171 } else {
184172 // Compiler directive. Emit normalized sentinel, squash following spaces.
185173 // Conditional compilation lines (!$) take this path in -E mode too
@@ -190,35 +178,47 @@ void Prescanner::Statement() {
190178 ++sp, ++at_, ++column_) {
191179 EmitChar (tokens, *sp);
192180 }
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_)}) {
196190 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+ }
201199 break ;
202200 }
203201 }
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 ;
212214 } else {
213- EmitChar (tokens, ' ' );
215+ ++at_;
216+ EmitChar (tokens, ' &' );
217+ tokens.CloseToken ();
214218 }
219+ ++column_;
220+ SkipSpaces ();
215221 }
216- tokens.CloseToken ();
217- }
218- if (*at_ == ' !' || *at_ == ' \n ' ||
219- (inFixedForm_ && column_ > fixedFormColumnLimit_ &&
220- !tabInCurrentLine_)) {
221- return ; // Directive without payload
222222 }
223223 break ;
224224 }
@@ -323,8 +323,8 @@ void Prescanner::Statement() {
323323 NormalizeCompilerDirectiveCommentMarker (*preprocessed);
324324 preprocessed->ToLowerCase ();
325325 SourceFormChange (preprocessed->ToString ());
326- CheckAndEmitLine (preprocessed-> ToLowerCase (). ClipComment (
327- *this , true /* skip first ! */ ),
326+ CheckAndEmitLine (
327+ preprocessed-> ClipComment ( *this , true /* skip first ! */ ),
328328 newlineProvenance);
329329 break ;
330330 case LineClassification::Kind::Source:
@@ -349,6 +349,24 @@ void Prescanner::Statement() {
349349 while (CompilerDirectiveContinuation (tokens, line.sentinel )) {
350350 newlineProvenance = GetCurrentProvenance ();
351351 }
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+ }
352370 tokens.ToLowerCase ();
353371 SourceFormChange (tokens.ToString ());
354372 } else { // Kind::Source
@@ -544,7 +562,8 @@ void Prescanner::SkipToEndOfLine() {
544562bool Prescanner::MustSkipToEndOfLine () const {
545563 if (inFixedForm_ && column_ > fixedFormColumnLimit_ && !tabInCurrentLine_) {
546564 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 )) {
548567 return !IsCompilerDirectiveSentinel (at_);
549568 } else {
550569 return false ;
@@ -569,10 +588,11 @@ void Prescanner::NextChar() {
569588// directives, Fortran ! comments, stuff after the right margin in
570589// fixed form, and all forms of line continuation.
571590bool Prescanner::SkipToNextSignificantCharacter () {
572- auto anyContinuationLine{false };
573591 if (inPreprocessorDirective_) {
574592 SkipCComments ();
593+ return false ;
575594 } else {
595+ auto anyContinuationLine{false };
576596 bool mightNeedSpace{false };
577597 if (MustSkipToEndOfLine ()) {
578598 SkipToEndOfLine ();
@@ -589,8 +609,8 @@ bool Prescanner::SkipToNextSignificantCharacter() {
589609 if (*at_ == ' \t ' ) {
590610 tabInCurrentLine_ = true ;
591611 }
612+ return anyContinuationLine;
592613 }
593- return anyContinuationLine;
594614}
595615
596616void Prescanner::SkipCComments () {
@@ -1119,12 +1139,10 @@ static bool IsAtProcess(const char *p) {
11191139
11201140bool Prescanner::IsFixedFormCommentLine (const char *start) const {
11211141 const char *p{start};
1122-
11231142 // The @process directive must start in column 1.
11241143 if (*p == ' @' && IsAtProcess (p)) {
11251144 return true ;
11261145 }
1127-
11281146 if (IsFixedFormCommentChar (*p) || *p == ' %' || // VAX %list, %eject, &c.
11291147 ((*p == ' D' || *p == ' d' ) &&
11301148 !features_.IsEnabled (LanguageFeature::OldDebugLines))) {
@@ -1324,24 +1342,11 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
13241342 features_.IsEnabled (LanguageFeature::OldDebugLines))) &&
13251343 nextLine_[1 ] == ' ' && nextLine_[2 ] == ' ' && nextLine_[3 ] == ' ' &&
13261344 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_)) {
13451350 int j{1 };
13461351 for (; j < 5 ; ++j) {
13471352 char ch{directiveSentinel_[j - 1 ]};
@@ -1356,31 +1361,27 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
13561361 return nullptr ;
13571362 }
13581363 }
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 ;
13641370 }
1365- return nextLine_ + 6 ;
13661371 }
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 ;
13821384 }
1383- return nullptr ;
13841385 }
13851386 if (col1 == ' &' &&
13861387 features_.IsEnabled (
@@ -1422,13 +1423,13 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
14221423 }
14231424 p = SkipWhiteSpaceIncludingEmptyMacros (p);
14241425 if (InCompilerDirective ()) {
1425- if (directiveSentinel_[ 0 ] == ' $ ' && directiveSentinel_[ 1 ] == ' \0 ' ) {
1426+ if (InOpenMPConditionalLine () ) {
14261427 if (preprocessingOnly_) {
14271428 // in -E mode, don't treat !$ as a continuation
14281429 return nullptr ;
14291430 } else if (p[0 ] == ' !' && p[1 ] == ' $' ) {
14301431 // accept but do not require a matching sentinel
1431- if (!( p[2 ] == ' &' || IsSpaceOrTab (&p[2 ]) )) {
1432+ if (p[2 ] != ' &' && ! IsSpaceOrTab (&p[2 ])) {
14321433 return nullptr ; // not !$
14331434 }
14341435 p += 2 ;
@@ -1566,15 +1567,11 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
15661567 }
15671568 char sentinel[5 ], *sp{sentinel};
15681569 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)) {
15751572 break ;
15761573 }
1577- *sp++ = ToLowerCaseLetter (*p);
1574+ *sp++ = ToLowerCaseLetter (*p++ );
15781575 }
15791576 if (sp == sentinel) {
15801577 return std::nullopt ;
@@ -1600,7 +1597,8 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
16001597 ++p;
16011598 } else if (int n{IsSpaceOrTab (p)}) {
16021599 p += n;
1603- } else if (isOpenMPConditional && preprocessingOnly_ && !hadDigit) {
1600+ } else if (isOpenMPConditional && preprocessingOnly_ && !hadDigit &&
1601+ *p != ' \n ' ) {
16041602 // In -E mode, "!$ &" is treated as a directive
16051603 } else {
16061604 // This is a Continuation line, not an initial directive line.
@@ -1671,14 +1669,14 @@ const char *Prescanner::IsCompilerDirectiveSentinel(CharBlock token) const {
16711669std::optional<std::pair<const char *, const char *>>
16721670Prescanner::IsCompilerDirectiveSentinel (const char *p) const {
16731671 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) {
16751673 if (int n{IsSpaceOrTab (p)};
16761674 n || !(IsLetter (*p) || *p == ' $' || *p == ' @' )) {
16771675 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
16801678 // 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.
16821680 break ;
16831681 }
16841682 sentinel[j] = ' \0 ' ;
0 commit comments