From 827407a86aa07f35ca31239c4f28cc2486170204 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Fri, 15 Mar 2019 13:57:41 -0700 Subject: [PATCH] [flang] more spec work, handle classic C comments Original-commit: flang-compiler/f18@d901ee7f500df48c81d786a2f9fcef4c65049d2f Reviewed-on: https://github.com/flang-compiler/f18/pull/335 Tree-same-pre-rewrite: false --- flang/lib/parser/features.h | 2 +- flang/lib/parser/preprocessor.cc | 4 +- flang/lib/parser/prescan.cc | 116 ++++++++++++++++++++++++++++---------- flang/lib/parser/prescan.h | 12 +++- flang/tools/f18/f18-parse-demo.cc | 3 +- 5 files changed, 102 insertions(+), 35 deletions(-) diff --git a/flang/lib/parser/features.h b/flang/lib/parser/features.h index d971fdb..953f2cf 100644 --- a/flang/lib/parser/features.h +++ b/flang/lib/parser/features.h @@ -30,7 +30,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines, Convert, Dispose, IOListLeadingComma, AbbreviatedEditDescriptor, ProgramParentheses, PercentRefAndVal, OmitFunctionDummies, CrayPointer, Hollerith, ArithmeticIF, Assign, AssignedGOTO, Pause, OpenMP, - CruftAfterAmpersand) + CruftAfterAmpersand, ClassicCComments) using LanguageFeatures = common::EnumSet; diff --git a/flang/lib/parser/preprocessor.cc b/flang/lib/parser/preprocessor.cc index 149d72a..d1c253d 100644 --- a/flang/lib/parser/preprocessor.cc +++ b/flang/lib/parser/preprocessor.cc @@ -461,11 +461,9 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) { } else if (dirName == "ifdef" || dirName == "ifndef") { bool doThen{false}; if (nameToken.empty()) { - // Warning, not error, in PGI. - // This misusage appears in WRF & other SPEC codes (might be a local mod). prescanner->Say( dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset), - "#%s: missing name"_en_US, dirName.data()); + "#%s: missing name"_err_en_US, dirName.data()); } else { j = dir.SkipBlanks(j + 1); if (j != tokens) { diff --git a/flang/lib/parser/prescan.cc b/flang/lib/parser/prescan.cc index 2e1c69e..8edf7e1 100644 --- a/flang/lib/parser/prescan.cc +++ b/flang/lib/parser/prescan.cc @@ -96,7 +96,10 @@ void Prescanner::Statement() { TokenSequence tokens; LineClassification line{ClassifyLine(lineStart_)}; switch (line.kind) { - case LineClassification::Kind::Comment: NextLine(); return; + case LineClassification::Kind::Comment: + lineStart_ += line.payloadOffset; // advance to '!' or newline + NextLine(); + return; case LineClassification::Kind::IncludeLine: FortranInclude(lineStart_ + line.payloadOffset); NextLine(); @@ -283,19 +286,7 @@ void Prescanner::NextChar() { CHECK(*at_ != '\n'); ++at_, ++column_; if (inPreprocessorDirective_) { - while (*at_ == '/' && at_[1] == '*') { - char star{' '}, slash{' '}; - at_ += 2; - column_ += 2; - while ((*at_ != '\n' || slash == '\\') && (star != '*' || slash != '/')) { - star = slash; - slash = *at_++; - ++column_; - } - } - while (*at_ == '\\' && at_ + 2 < limit_ && at_[1] == '\n') { - BeginSourceLineAndAdvance(); - } + SkipCComments(); } else { bool rightMarginClip{ inFixedForm_ && column_ > fixedFormColumnLimit_ && !tabInCurrentLine_}; @@ -319,6 +310,28 @@ void Prescanner::NextChar() { } } +void Prescanner::SkipCComments() { + while (true) { + if (IsCComment(at_)) { + if (const char *after{SkipCComment(at_)}) { + column_ += after - at_; + // May have skipped over one or more newlines; relocate the start of + // the next line. + lineStart_ = at_ = after; + NextLine(); + } else { + Say(GetProvenance(at_), "unclosed C-style comment"_err_en_US); + break; + } + } else if (inPreprocessorDirective_ && at_[0] == '\\' && at_ + 2 < limit_ && + at_[1] == '\n' && lineStart_ < limit_) { + BeginSourceLineAndAdvance(); + } else { + break; + } + } +} + void Prescanner::SkipSpaces() { while (*at_ == ' ' || *at_ == '\t') { NextChar(); @@ -333,20 +346,60 @@ const char *Prescanner::SkipWhiteSpace(const char *p) { return p; } +const char *Prescanner::SkipWhiteSpaceAndCComments(const char *p) const { + while (true) { + if (*p == ' ' || *p == '\t') { + ++p; + } else if (IsCComment(p)) { + if (const char *after{SkipCComment(p)}) { + p = after; + } else { + break; + } + } else { + break; + } + } + return p; +} + +const char *Prescanner::SkipCComment(const char *p) const { + char star{' '}, slash{' '}; + p += 2; + while (star != '*' || slash != '/') { + if (p >= limit_) { + return nullptr; // signifies an unterminated comment + } + star = slash; + slash = *p++; + } + return p; +} + bool Prescanner::NextToken(TokenSequence &tokens) { CHECK(at_ >= start_ && at_ < limit_); if (InFixedFormSource()) { SkipSpaces(); - } else if (*at_ == ' ' || *at_ == '\t') { - // Compress white space into a single space character. - // Discard white space at the end of a line. - const auto theSpace{at_}; - NextChar(); - SkipSpaces(); - if (*at_ != '\n') { - tokens.PutNextTokenChar(' ', GetProvenance(theSpace)); - tokens.CloseToken(); - return true; + } else { + if (*at_ == '/' && IsCComment(at_)) { + // Recognize and skip over classic C style /*comments*/ when + // outside a character literal. + if (features_.ShouldWarn(LanguageFeature::ClassicCComments)) { + Say(GetProvenance(at_), "nonstandard usage: C-style comment"_en_US); + } + SkipCComments(); + } + if (*at_ == ' ' || *at_ == '\t') { + // Compress free-form white space into a single space character. + // Discard white space at the end of a line. + const auto theSpace{at_}; + NextChar(); + SkipSpaces(); + if (*at_ != '\n') { + tokens.PutNextTokenChar(' ', GetProvenance(theSpace)); + tokens.CloseToken(); + return true; + } } } if (insertASpace_) { @@ -592,9 +645,13 @@ bool Prescanner::IsFixedFormCommentLine(const char *start) const { return *p == '\n'; } -bool Prescanner::IsFreeFormComment(const char *p) const { - p = SkipWhiteSpace(p); - return *p == '!' || *p == '\n'; +const char *Prescanner::IsFreeFormComment(const char *p) const { + p = SkipWhiteSpaceAndCComments(p); + if (*p == '!' || *p == '\n') { + return p; + } else { + return nullptr; + } } std::optional Prescanner::IsIncludeLine(const char *start) const { @@ -982,8 +1039,9 @@ Prescanner::LineClassification Prescanner::ClassifyLine( IsFreeFormCompilerDirectiveLine(start)}) { return std::move(*lc); } - if (IsFreeFormComment(start)) { - return {LineClassification::Kind::Comment}; + if (const char *bang{IsFreeFormComment(start)}) { + return {LineClassification::Kind::Comment, + static_cast(bang - start)}; } } if (std::optional quoteOffset{IsIncludeLine(start)}) { diff --git a/flang/lib/parser/prescan.h b/flang/lib/parser/prescan.h index e83e377..a69cba5 100644 --- a/flang/lib/parser/prescan.h +++ b/flang/lib/parser/prescan.h @@ -140,11 +140,21 @@ private: return inFixedForm_ && !inPreprocessorDirective_ && !InCompilerDirective(); } + bool IsCComment(const char *p) const { + return p[0] == '/' && p[1] == '*' && + (inPreprocessorDirective_ || + (!inCharLiteral_ && + features_.IsEnabled(LanguageFeature::ClassicCComments))); + } + void LabelField(TokenSequence &, int outCol = 1); void SkipToEndOfLine(); void NextChar(); + void SkipCComments(); void SkipSpaces(); static const char *SkipWhiteSpace(const char *); + const char *SkipWhiteSpaceAndCComments(const char *) const; + const char *SkipCComment(const char *) const; bool NextToken(TokenSequence &); bool ExponentAndKind(TokenSequence &); void QuotedCharacterLiteral(TokenSequence &); @@ -152,7 +162,7 @@ private: bool PadOutCharacterLiteral(TokenSequence &); bool SkipCommentLine(bool afterAmpersand); bool IsFixedFormCommentLine(const char *) const; - bool IsFreeFormComment(const char *) const; + const char *IsFreeFormComment(const char *) const; std::optional IsIncludeLine(const char *) const; void FortranInclude(const char *quote); const char *IsPreprocessorDirectiveLine(const char *) const; diff --git a/flang/tools/f18/f18-parse-demo.cc b/flang/tools/f18/f18-parse-demo.cc index 83a3c3c..f1b3f9a 100644 --- a/flang/tools/f18/f18-parse-demo.cc +++ b/flang/tools/f18/f18-parse-demo.cc @@ -70,7 +70,8 @@ void CleanUpAtExit() { } } -#if _POSIX_C_SOURCE >= 199309L && defined CLOCK_PROCESS_CPUTIME_ID +#if _POSIX_C_SOURCE >= 199309L && _POSIX_TIMERS > 0 && _POSIX_CPUTIME && \ + defined CLOCK_PROCESS_CPUTIME_ID static constexpr bool canTime{true}; double CPUseconds() { struct timespec tspec; -- 2.7.4