@@ -212,14 +212,6 @@ void Prescanner::Statement() {
212212 }
213213 break ;
214214 }
215- case LineClassification::Kind::CompilerDirectiveAfterMacroExpansion:
216- BeginStatementAndAdvance ();
217- SkipSpaces ();
218- if (*at_ == ' !' ) {
219- tokens.Put (at_++, 1 , GetCurrentProvenance ());
220- ++column_;
221- }
222- break ;
223215 case LineClassification::Kind::Source: {
224216 BeginStatementAndAdvance ();
225217 bool checkLabelField{false };
@@ -246,17 +238,30 @@ void Prescanner::Statement() {
246238 // a comment marker or directive sentinel. If so, disable line
247239 // continuation, so that NextToken() won't consume anything from
248240 // following lines.
249- if (auto kwName{GetKeywordMacroName (at_)}) {
250- checkLabelField = false ;
251- Provenance here{GetCurrentProvenance ()};
252- TokenSequence replacement{ExpandKeywordMacro (*kwName, here)};
253- auto newLineClass{ClassifyLine (replacement, here)};
254- if (newLineClass.kind == LineClassification::Kind::CompilerDirective) {
255- directiveSentinel_ = newLineClass.sentinel ;
256- disableSourceContinuation_ = false ;
257- } else {
258- disableSourceContinuation_ = !replacement.empty () &&
259- newLineClass.kind != LineClassification::Kind::Source;
241+ if (IsLegalIdentifierStart (*at_)) {
242+ // TODO: Only bother with these cases when any keyword macro has
243+ // been defined with replacement text that could begin a comment
244+ // or directive sentinel.
245+ const char *p{at_};
246+ while (IsLegalInIdentifier (*++p)) {
247+ }
248+ CharBlock id{at_, static_cast <std::size_t >(p - at_)};
249+ if (preprocessor_.IsNameDefined (id) &&
250+ !preprocessor_.IsFunctionLikeDefinition (id)) {
251+ checkLabelField = false ;
252+ TokenSequence toks;
253+ toks.Put (id, GetProvenance (at_));
254+ if (auto replaced{preprocessor_.MacroReplacement (toks, *this )}) {
255+ auto newLineClass{ClassifyLine (*replaced, GetCurrentProvenance ())};
256+ if (newLineClass.kind ==
257+ LineClassification::Kind::CompilerDirective) {
258+ directiveSentinel_ = newLineClass.sentinel ;
259+ disableSourceContinuation_ = false ;
260+ } else {
261+ disableSourceContinuation_ = !replaced->empty () &&
262+ newLineClass.kind != LineClassification::Kind::Source;
263+ }
264+ }
260265 }
261266 }
262267 if (checkLabelField) {
@@ -299,7 +304,6 @@ void Prescanner::Statement() {
299304 CheckAndEmitLine (preprocessed->ToLowerCase (), newlineProvenance);
300305 break ;
301306 case LineClassification::Kind::CompilerDirective:
302- case LineClassification::Kind::CompilerDirectiveAfterMacroExpansion:
303307 if (preprocessed->HasRedundantBlanks ()) {
304308 preprocessed->RemoveRedundantBlanks ();
305309 }
@@ -331,39 +335,40 @@ void Prescanner::Statement() {
331335 preprocessed->ToLowerCase ().ClipComment (*this ), newlineProvenance);
332336 break ;
333337 }
334- } else if (line.kind == LineClassification::Kind::CompilerDirective) {
335- while (CompilerDirectiveContinuation (tokens, line.sentinel )) {
336- newlineProvenance = GetCurrentProvenance ();
337- }
338- if (preprocessingOnly_ && inFixedForm_ && InConditionalLine () &&
339- nextLine_ < limit_) {
340- // In -E mode, when the line after !$ conditional compilation is a
341- // regular fixed form continuation line, append a '&' to the line.
342- const char *p{nextLine_};
343- int col{1 };
344- while (int n{IsSpace (p)}) {
345- if (*p == ' \t ' ) {
346- break ;
338+ } else { // no macro replacement
339+ if (line.kind == LineClassification::Kind::CompilerDirective) {
340+ while (CompilerDirectiveContinuation (tokens, line.sentinel )) {
341+ newlineProvenance = GetCurrentProvenance ();
342+ }
343+ if (preprocessingOnly_ && inFixedForm_ && InConditionalLine () &&
344+ nextLine_ < limit_) {
345+ // In -E mode, when the line after !$ conditional compilation is a
346+ // regular fixed form continuation line, append a '&' to the line.
347+ const char *p{nextLine_};
348+ int col{1 };
349+ while (int n{IsSpace (p)}) {
350+ if (*p == ' \t ' ) {
351+ break ;
352+ }
353+ p += n;
354+ ++col;
355+ }
356+ if (col == 6 && *p != ' 0' && *p != ' \t ' && *p != ' \n ' ) {
357+ EmitChar (tokens, ' &' );
358+ tokens.CloseToken ();
347359 }
348- p += n;
349- ++col;
350360 }
351- if (col == 6 && *p != ' 0' && *p != ' \t ' && *p != ' \n ' ) {
352- EmitChar (tokens, ' &' );
353- tokens.CloseToken ();
361+ tokens.ToLowerCase ();
362+ if (!SourceFormChange (tokens.ToString ())) {
363+ CheckAndEmitLine (tokens, newlineProvenance);
364+ }
365+ } else { // Kind::Source
366+ tokens.ToLowerCase ();
367+ if (inFixedForm_) {
368+ EnforceStupidEndStatementRules (tokens);
354369 }
355- }
356- tokens.ToLowerCase ();
357- if (!SourceFormChange (tokens.ToString ())) {
358370 CheckAndEmitLine (tokens, newlineProvenance);
359371 }
360- } else {
361- CHECK (line.kind == LineClassification::Kind::Source);
362- tokens.ToLowerCase ();
363- if (inFixedForm_) {
364- EnforceStupidEndStatementRules (tokens);
365- }
366- CheckAndEmitLine (tokens, newlineProvenance);
367372 }
368373 directiveSentinel_ = nullptr ;
369374}
@@ -562,8 +567,7 @@ bool Prescanner::MustSkipToEndOfLine() const {
562567 return true ; // skip over ignored columns in right margin (73:80)
563568 } else if (*at_ == ' !' && !inCharLiteral_ &&
564569 (!inFixedForm_ || tabInCurrentLine_ || column_ != 6 )) {
565- return InCompilerDirective () ||
566- !IsCompilerDirectiveSentinelAfterKeywordMacro (at_ + 1 );
570+ return InCompilerDirective () || !IsCompilerDirectiveSentinel (at_ + 1 );
567571 } else {
568572 return false ;
569573 }
@@ -1612,9 +1616,6 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
16121616 if (!IsFixedFormCommentChar (col1)) {
16131617 return std::nullopt ;
16141618 }
1615- // TODO: Handle keyword macros that expand to directives in fixed form.
1616- // The comment character can't be 'c' or 'C'. Need to figure out whether
1617- // fixed form continuation should apply to the expansions.
16181619 char sentinel[5 ], *sp{sentinel};
16191620 int column{2 };
16201621 for (; column < 6 ; ++column) {
@@ -1677,28 +1678,20 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const {
16771678std::optional<Prescanner::LineClassification>
16781679Prescanner::IsFreeFormCompilerDirectiveLine (const char *start) const {
16791680 if (const char *p{SkipWhiteSpaceIncludingEmptyMacros (start)};
1680- p && *p == ' !' ) {
1681- if (auto lnClass{IsCompilerDirectiveSentinelAfterKeywordMacro (p + 1 )}) {
1682- if (lnClass->kind == LineClassification::Kind::CompilerDirective) {
1683- const char *sentinel{lnClass->sentinel };
1684- CHECK (sentinel != nullptr );
1685- const char *payload{nullptr };
1686- if (sentinel[0 ] == ' $' && sentinel[1 ] == ' \0 ' ) {
1687- payload = p + 2 ; // !$
1688- } else if (sentinel[1 ] == ' @' ) {
1689- payload = p + 5 ; // !@acc or !@cuf
1690- }
1691- if (payload) {
1692- if (const char *comment{IsFreeFormComment (payload)}) {
1693- if (*comment == ' !' ) { // !$ !blah or !@acc !blah
1694- // Conditional line comment - treat as comment
1695- return std::nullopt ;
1696- }
1681+ p && *p++ == ' !' ) {
1682+ if (auto maybePair{IsCompilerDirectiveSentinel (p)}) {
1683+ auto offset{static_cast <std::size_t >(p - start - 1 )};
1684+ const char *sentinel{maybePair->first };
1685+ if ((sentinel[0 ] == ' $' && sentinel[1 ] == ' \0 ' ) || sentinel[1 ] == ' @' ) {
1686+ if (const char *comment{IsFreeFormComment (maybePair->second )}) {
1687+ if (*comment == ' !' ) {
1688+ // Conditional line comment - treat as comment
1689+ return std::nullopt ;
16971690 }
16981691 }
1699- lnClass->payloadOffset = static_cast <std::size_t >(p - start);
17001692 }
1701- return lnClass;
1693+ return {LineClassification{
1694+ LineClassification::Kind::CompilerDirective, offset, sentinel}};
17021695 }
17031696 }
17041697 return std::nullopt ;
@@ -1715,31 +1708,6 @@ Prescanner &Prescanner::AddCompilerDirectiveSentinel(const std::string &dir) {
17151708 return *this ;
17161709}
17171710
1718- std::optional<CharBlock> Prescanner::GetKeywordMacroName (
1719- const char *start) const {
1720- if (IsLegalIdentifierStart (*start)) {
1721- // TODO: Only bother with these cases when any keyword macro has
1722- // been defined with replacement text that could begin a comment
1723- // or directive sentinel.
1724- const char *p{start};
1725- while (IsLegalInIdentifier (*++p)) {
1726- }
1727- CharBlock name{start, static_cast <std::size_t >(p - start)};
1728- if (preprocessor_.IsNameDefined (name) &&
1729- !preprocessor_.IsFunctionLikeDefinition (name)) {
1730- return name;
1731- }
1732- }
1733- return std::nullopt ;
1734- }
1735-
1736- TokenSequence Prescanner::ExpandKeywordMacro (
1737- CharBlock name, Provenance provenance) const {
1738- TokenSequence toks;
1739- toks.Put (name, provenance);
1740- return preprocessor_.MacroReplacement (toks, *this ).value ();
1741- }
1742-
17431711const char *Prescanner::IsCompilerDirectiveSentinel (
17441712 const char *sentinel, std::size_t len) const {
17451713 std::uint64_t packed{0 };
@@ -1797,26 +1765,8 @@ Prescanner::IsCompilerDirectiveSentinel(const char *p) const {
17971765 return std::nullopt ;
17981766}
17991767
1800- auto Prescanner::IsCompilerDirectiveSentinelAfterKeywordMacro (
1801- const char *p) const -> std::optional<LineClassification> {
1802- if (auto name{GetKeywordMacroName (p)}) {
1803- Provenance provenance{GetProvenance (p)};
1804- TokenSequence expansion{ExpandKeywordMacro (*name, provenance)};
1805- expansion.Put (" \n " , 1 , provenance); // termination
1806- CharBlock block{expansion.ToLowerCase ().ToCharBlock ()};
1807- if (auto maybePair{IsCompilerDirectiveSentinel (block.begin ())}) {
1808- return LineClassification{
1809- LineClassification::Kind::CompilerDirectiveAfterMacroExpansion,
1810- name->size (), maybePair->first };
1811- }
1812- } else if (auto maybePair{IsCompilerDirectiveSentinel (p)}) {
1813- return LineClassification{LineClassification::Kind::CompilerDirective,
1814- static_cast <std::size_t >(maybePair->second - p), maybePair->first };
1815- }
1816- return std::nullopt ;
1817- }
1818-
1819- auto Prescanner::ClassifyLine (const char *start) const -> LineClassification {
1768+ Prescanner::LineClassification Prescanner::ClassifyLine (
1769+ const char *start) const {
18201770 if (inFixedForm_) {
18211771 if (std::optional<LineClassification> lc{
18221772 IsFixedFormCompilerDirectiveLine (start)}) {
0 commit comments