https://gcc.gnu.org/g:09463178dc462cd7f7cec1bf09856459702ca624

commit r17-4237-g09463178dc462cd7f7cec1bf09856459702ca624
Author: James K. Lowden <[email protected]>
Date:   Fri Sep 11 18:44:52 2026 -0400

    cobol: Improve data-item validation.
    
    Support Implicit PICTURE per ISO 13.16.2.  A data item F with VALUE
    and no PICTURE is initially entered into the symbol table as invalid.
    If item F+1 is entered and is not subordinate, and F meets the
    conditions for an implicit PICTURE, mark it as valid.
    
    Correct currency symbol validation, fixes RT 3681.
    
    gcc/cobol/ChangeLog:
    
            * parse.y: Emit diagnostic if symbol_currency_add fails.
            * parse_ante.h (update_prior_invalid_field): New function.
            (field_add): Use update_prior_invalid_field to validate prior field.
            * scan.l: Document currency-symbol domain.
            * symbols.cc (symbols_update): Quell redundant diagnostic.
            (symbol_currency_symbol_ok): Validate currency symbol.
            (symbol_currency_add): Use symbol_currency_symbol_ok.

Diff:
---
 gcc/cobol/parse.y      | 13 ++++++++++---
 gcc/cobol/parse_ante.h | 28 ++++++++++++++++++++++++++++
 gcc/cobol/scan.l       | 10 ++++++++++
 gcc/cobol/symbols.cc   | 18 ++++++++++++++++--
 4 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y
index 6434c2685fb2..37f4ab6358f6 100644
--- a/gcc/cobol/parse.y
+++ b/gcc/cobol/parse.y
@@ -3115,7 +3115,10 @@ special_name:   dev_mnemonic {
                     error_msg(@lit, "'%s' has embedded NUL", $lit.data);
                     YYERROR;
                   }
-                symbol_currency_add( $picture_sym, $lit.data );
+                  if( ! symbol_currency_add($picture_sym, $lit.data) ) {
+                    auto ch = $picture_sym[0];
+                    error_msg(@picture_sym, "invalid currency symbol: %qc", 
ch);
+                  }
                 }
         |       DECIMAL_POINT is COMMA
                 {
@@ -3530,8 +3533,12 @@ data_div:       %empty   { parser_division( data_div_e, 
NULL, 0, NULL ); }
                 }
                 ;
 
-data_sections:  data_section
-        |       data_sections data_section
+data_sections:  data_section {
+                  update_prior_invalid_field();
+                }
+        |       data_sections data_section {
+                  update_prior_invalid_field();
+                }
                 ;
 
 data_section:   FILE_SECT '.'
diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h
index c3214ce75b95..b8db55e49184 100644
--- a/gcc/cobol/parse_ante.h
+++ b/gcc/cobol/parse_ante.h
@@ -3315,6 +3315,32 @@ group_attr( const cbl_field_t * field ) {
   return p->attr;
 }
 
+/*       
+ * 13.16.3 Syntax rules
+ * a) if the literal is alphanumeric, 'PICTURE X(length)'
+ * b) if the literal is boolean, 'PICTURE 1(length)'
+ * c) if the literal is national, 'PICTURE N(length)'
+ * (We don't support boolean yet.)
+ */
+static void
+update_prior_invalid_field( const cbl_field_t *field = nullptr) {
+  symbol_elem_t *e = field? symbol_at(field->our_index) :  symbols_end();
+  e--;
+  if( e->type == SymDataSection ) e--;
+  if( (e)->type == SymField ) {
+    auto f = cbl_field_of(e);
+    if( ! field ) field = f; // fake it
+    if( field->level <= f->level ) {
+      if( f->type == FldInvalid && f->data.has_initial_value() ) {
+        if( f->has_attr(quoted_e) ) {
+          f->type = FldAlphanumeric;
+          assert(0 < f->char_capacity());
+        }
+      }
+    }
+  }
+}
+
 static struct cbl_field_t *
 field_add( const cbl_loc_t& loc, cbl_field_t *field ) {
   switch(current_data_section) {
@@ -3349,6 +3375,8 @@ field_add( const cbl_loc_t& loc, cbl_field_t *field ) {
       return NULL;
       break;
     }
+  } else {
+    update_prior_invalid_field(field);
   }
   return field;
 }
diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l
index 8b85d710e320..df76ad1da816 100644
--- a/gcc/cobol/scan.l
+++ b/gcc/cobol/scan.l
@@ -136,7 +136,17 @@ ALPHED   {ALPHEDREQ}([AX9B0/]{COUNT}?)*
 NUMEDCHAR  [BPVZ90/,]+{COUNT}?
 NUMEDCHARS {NUMEDCHAR}([.]?{NUMEDCHAR})*
 NUMED     ([+-]{NUMEDCHARS}+)|({NUMEDCHARS}+[+-]?)
+                        /* ISO specification 12.3.7.2:
+                        * 27) Literal-8 may be any character from the
+                        * computer's coded character set except for the
+                        * following:
+                        * a) digits 0 through 9;
+                        * b) alphabetic characters A, B, C, D, E, N, P, R, S, 
V, X, Z, 
+                        *    or their lowercase equivalents; or the space;
+                        * c) characters '+' '–' ',' '.' '*' '/' ';' '(' ')' 
'"' '='
+                        */
 CURRENCY [A-Zfhijklmoqtuwy\x80-\xFF]{-}[ABCDEGNPRSVXZ]
+xCURRENCY [\x00-\xFF]{-}[ABCDEGNPRSVXZ 0-9 abcdegnprsvxz,.*/;()""=+-]
 NUMEDCUR (([.]?[$0B/Z*+,P9()V+-]|{CURRENCY}+|{COUNT})+([.][$0B/Z*+P9()V+-])*)+
 
 NUMEDITED         {NUMED}|{NUMEDCUR}
diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc
index bef6f116c3b8..f732a67287bb 100644
--- a/gcc/cobol/symbols.cc
+++ b/gcc/cobol/symbols.cc
@@ -2030,8 +2030,10 @@ symbols_update( size_t first, bool parsed_ok ) {
           case FldNumericDisplay:
           case FldNumericEdited:
             if( ! (field->has_attr(register_e) || 
field->has_attr(hex_encoded_e)) ) {
-              error_msg(symbol_field_location(field_index(field)),
-                        "internal: %qs encoding not defined", field->name);
+              if( ! mode_syntax_only() ) {
+                error_msg(symbol_field_location(field_index(field)),
+                          "internal: %qs encoding not defined", field->name);
+              }
             }
             break;
           case FldClass:
@@ -5132,15 +5134,27 @@ symbol_program_local( const char tgt_name[] ) {
  */
 std::map<char, const char *> currencies;
 
+static bool
+symbol_currency_symbol_ok( const char symbol ) {
+  static std::string never("ABCDEGNPRSUVXZ0-9abcdegnprsuvxz,.*/;()'\"=+-");
+  return std::string::npos == never.find(symbol);
+}
+
 // cppcheck-suppress-begin [nullPointerRedundantCheck]
 bool
 symbol_currency_add( const char symbol[], const char sign[] ) {
+  static const std::string 
never("ABCDEGNPRSUVXZ0-9abcdegnprsuvxz,.*/;()'\"=+-");
   // In service of CURRENCY sign PICTURE SYMBOL symbol
   // The single-character 'symbol' is replaced with multi-char 'sign'
   // by the NumericEdited processing.
   if( !symbol ) {
     symbol = xasprintf("%c", *sign);
+  } else {
+    if( ! symbol_currency_symbol_ok(symbol[0]) ) {
+      return false;
+    }
   }
+
   currencies[*symbol] = sign;
   return true;
 }

Reply via email to