[flang] more spec work, handle classic C comments
authorpeter klausler <pklausler@nvidia.com>
Fri, 15 Mar 2019 20:57:41 +0000 (13:57 -0700)
committerpeter klausler <pklausler@nvidia.com>
Fri, 15 Mar 2019 20:57:41 +0000 (13:57 -0700)
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
flang/lib/parser/preprocessor.cc
flang/lib/parser/prescan.cc
flang/lib/parser/prescan.h
flang/tools/f18/f18-parse-demo.cc

index d971fdb..953f2cf 100644 (file)
@@ -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<LanguageFeature, LanguageFeature_enumSize>;
index 149d72a..d1c253d 100644 (file)
@@ -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) {
index 2e1c69e..8edf7e1 100644 (file)
@@ -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<std::size_t> 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<std::size_t>(bang - start)};
     }
   }
   if (std::optional<std::size_t> quoteOffset{IsIncludeLine(start)}) {
index e83e377..a69cba5 100644 (file)
@@ -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<std::size_t> IsIncludeLine(const char *) const;
   void FortranInclude(const char *quote);
   const char *IsPreprocessorDirectiveLine(const char *) const;
index 83a3c3c..f1b3f9a 100644 (file)
@@ -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;