]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cobol: Accept newline in refmod pattern.
authorJames K. Lowden <jklowden@cobolworx.com>
Wed, 29 Jul 2026 18:00:41 +0000 (14:00 -0400)
committerJames K. Lowden <jklowden@cobolworx.com>
Wed, 29 Jul 2026 18:01:05 +0000 (14:01 -0400)
Modify lexer recognition of refmods and correct errors in is_refmod() function.

gcc/cobol/ChangeLog:

* parse.y: Report LPAREN token as '(', not ')'.
* scan.l: Remove newline exclusion from LPAREN pattern.
* scan_ante.h (rsearch): Helper function to ensure c++11 compatibility.
(trim_location): Use rsearch function.
(is_quote): New inline function to test quotiness.
(skip_string): New function to find end of string literal.
(is_refmod): Stay in bounds.
* util.cc (gcc_location_set): Decrease debug message verbosity.

gcc/cobol/parse.y
gcc/cobol/scan.l
gcc/cobol/scan_ante.h
gcc/cobol/util.cc

index b95a5e2e8fcd4196cbfc528210de4dfe22bb6978..d6cd656085bb98f5b4ba7a371ab8cb49291692f8 100644 (file)
@@ -579,7 +579,7 @@ class locale_tgt_t {
                        LOWER_CASE "LOWER-CASE"
                        LOW_VALUES "LOW-VALUES"
                        LOWEST_ALGEBRAIC "LOWEST-ALGEBRAIC"
-                       LPAREN " )"
+                       LPAREN " ("
 
                        MANUAL MAXX "Max" MEAN MEDIAN MIDRANGE
                        MINN "Min" MULTIPLE MOD MODE
index ee85883ebf880aa8ee47b06d665ab3a50e6131b6..67bdefa91dc86f698edec1c401e211efd46ae243 100644 (file)
@@ -1915,7 +1915,7 @@ USE({SPC}FOR)?            { return USE; }
 
   [(:)]                        { return *yytext; }
   [(]/[^(:)""'']*[:][^)]*[)]   { return LPAREN; /* parentheses around a colon */ }
-  [(][^:""''\n]*[:][^)]*[)]    { // does not match foo(bar)\n:  :-(  
+  [(][^:""'']*[:][^)]*[)]      { // does not match foo(bar)\n:  :-(  
                                   int tok = is_refmod(yytext, yytext + yyleng)?
                                       int(LPAREN) : '(';
                                   myless(1);
index fa55b9b179840bd91d3f419e5215f93f4b70c42c..402600edabc733b953389c6d13cb14ed6763ea9c 100644 (file)
@@ -501,6 +501,13 @@ reset_location() {
 
 #define YY_USER_ACTION update_location();
 
+template <typename T>
+T * rsearch( T* a, T* z, T sarg ) {
+  std::reverse_iterator<T*> beg(z), end(a);
+  auto p = std::find(beg, end, sarg);
+  return p != end? p.base() : nullptr;
+}
+
 /*
  * Before calling yyless to tell the generated scanner to rescan nkeep
  * characters, set the scanner's location to reflect the cbl_loc_t of what
@@ -524,12 +531,9 @@ trim_location( int nkeep) {
     yylloc.last_column = yylloc.first_column + nkeep;
   } else {
     auto eokeep = yytext + nkeep;
-    std::reverse_iterator beg(eokeep);
-    std::reverse_iterator end(yytext);
-    auto nl = std::find(beg, end, '\n');
-    gcc_assert( nl != end );
-    gcc_assert( nl.base() != yytext );
-    yylloc.last_column = 1 + (eokeep - nl.base());
+    auto nl = rsearch(yytext, eokeep, '\n');
+    gcc_assert( nl != nullptr );
+    yylloc.last_column = 1 + (eokeep - nl);
   }
 
   gcc_assert( yylloc.first_line <= yylloc.last_line );    
@@ -1313,6 +1317,27 @@ integer_of( const char input[], bool is_hex = false) {
   return output;
 }
 
+static inline bool is_quote( const char ch ) {
+  return ch == '\'' || ch == '"';
+}
+
+static const char*
+skip_string(const char* p, const char* pend, char delimiter) {
+  p++; // Skip opening delimiter
+  while (p < pend) {
+    if (p[0] == delimiter) {
+      if (p[1] == delimiter) {
+        p += 2; // doubled delimiter is escaped 
+      } else {
+        return ++p; // Found valid closing delimiter
+      }
+    } else {
+      p++;
+    }
+  }
+  return pend;
+}
+
 /*
  * Loosely parse what might be a refmod expression.  This is used to decide
  * whether to indicate a refmod to the parser with an LPAREN token, or not,
@@ -1325,40 +1350,34 @@ integer_of( const char input[], bool is_hex = false) {
  */
 static bool
 is_refmod( const char input[], const char enput[] ) {
-       if( input == enput || *input != '(' ) return false;
-       int depth = 0;
-       bool colon_at_depth1 = false;
-       const char *p = input;
-
-       while( p < enput ) {
-               char ch = *p++;
-               if( ch == '"' || ch == '\'' ) {
-                       /* Skip quoted region; doubled quote is escape.  */
-                       const char quote = ch;
-                       while( p < enput ) {
-                               ch = *p++;
-                               if( ch == quote ) {
-                                       if( p < enput && *p == quote ) { p++; continue; }
-                                       break;
-                               }
-                       }
-                       continue;
-               }
-               if( ch == '(' ) {
-                       depth++;
-                       continue;
-               }
-               if( ch == ')' ) {
-                       depth--;
-                       if( depth < 0 ) return false;
-                       if( depth == 0 ) return colon_at_depth1;
-                       continue;
-               }
-               if( ch == ':' && depth == 1 ) {
-                       if( colon_at_depth1 ) return false;
-                       colon_at_depth1 = true;
-                       continue;
-               }
-       }
-       return false;
+  if( input == enput ) return false;
+  gcc_assert( *input == '(' );
+  int depth = 1;
+  bool colon_at_depth1 = false;
+
+  for( const char *p = input + 1; p < enput; p++ ) {
+    char ch = *p;
+    if( is_quote(ch) ) {
+      p = skip_string(p, enput, ch) - 1;
+      continue;
+    }
+    if( ch == '(' ) {
+      depth++;
+      continue;
+    }
+    if( ch == ')' ) {
+      depth--;
+      if( depth < 0 ) return false;
+      if( depth == 0 ) return colon_at_depth1;
+      continue;
+    }
+    if( ch == ':' && depth == 1 ) {
+      if( colon_at_depth1 ) return false;
+      colon_at_depth1 = true;
+      continue;
+    }
+  }
+  dbgmsg("%s:%d: '%.*s' is %sa refmod", __func__, __LINE__,
+         int(enput - input), input, colon_at_depth1? "" : "not ");
+  return colon_at_depth1;
 }
index 9e0fb368d0420a3dfc2f07d89890bb9b95fc306f..656ecfe09494aa073150a0735f89bd53d8bfbbcb 100644 (file)
@@ -3522,7 +3522,7 @@ gcc_location_set( const cbl_loc_t& loc ) {
     loc_m_1 = token_location;
   }
   
-  location_dump(__func__, __LINE__, "parser", loc, true);
+  location_dump(__func__, __LINE__, "parser", loc);
 }
 
 #ifdef NDEBUG