>From 2c60eb843da81ecf54d6776705c098f1130573d8 Mon Sep 17 00:00:00 2001
From: Robert Dubner <[email protected]>
Date: Fri, 5 Jun 2026 11:43:59 -0400
Subject: [PATCH] cobol: Properly DISPLAY COMP-1/-2 variables when
"-dialect
 ibm" is in effect. [PR125616]
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Instead of GCOBOL's idiosyncratic display of COMP-1 and COMP-2
floating-point
variables, these changes result in IBM's specified format when "-dialect
ibm"
is in effect.

The specification says

. Internal floating-point numbers are converted to external floating-point
numbers for display such that:

- A COMP-1 item will display as if it had an external floating-point
PICTURE clause of -.9(8)E-99.
- A COMP-2 item will display as if it had an external floating-point
PICTURE clause of -.9(17)E-99.

That's what these changes implement.

        PR cobol/125616

gcc/cobol/ChangeLog:

        * genapi.cc (parser_enter_file): New __gg__dialects variable.
        (parser_division): Likewise.
        * genutil.cc: Likewise.
        * genutil.h: Likewise.
        * lang.opt.urls: Updated.
        * symbols.h (enum cbl_dialect_t): Move this enum to common-defs.h.

libgcobol/ChangeLog:

        * common-defs.h (enum cbl_dialect_t): Move cbl_dialect_t here.
        * intrinsic.cc (__gg__trim_1): Make a formal parameter const.
        * libgcobol.cc (format_for_display_internal): Change the
formatting
        of COMP-1/COMP2 when "-dialect ibm" is in force.
        (default_exception_handler): Whitespace formatting.
        (ec_type_disposition): Likewise.
        (ec_is_fatal): Likewise.

gcc/testsuite/ChangeLog:

        * cobol.dg/group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.cob: New
test.
        * cobol.dg/group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.out: New
test.
---
 gcc/cobol/genapi.cc                           |   4 +
 gcc/cobol/genutil.cc                          |   3 +
 gcc/cobol/genutil.h                           |   1 +
 gcc/cobol/lang.opt.urls                       |   6 -
 gcc/cobol/symbols.h                           |   8 --
 ...ISPLAY_IBM-formatted_COMP-1_and_COMP-2.cob |  25 ++++
 ...ISPLAY_IBM-formatted_COMP-1_and_COMP-2.out |   8 ++
 libgcobol/common-defs.h                       |   8 ++
 libgcobol/intrinsic.cc                        |   2 +-
 libgcobol/libgcobol.cc                        | 131 +++++++++++++-----
 10 files changed, 143 insertions(+), 53 deletions(-)
 create mode 100644
gcc/testsuite/cobol.dg/group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.cob
 create mode 100644
gcc/testsuite/cobol.dg/group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.out

diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index d75d39a76ad..cffb982f830 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -3012,6 +3012,7 @@ parser_enter_file(const char *filename)
     SET_VAR_DECL(var_decl_nop                     , INT
, "__gg__nop"             );
     SET_VAR_DECL(var_decl_main_called             , INT
, "__gg__main_called"     );
     SET_VAR_DECL(var_decl_entry_index             , SIZE_T
, "__gg__entry_index"     );
+    SET_VAR_DECL(var_decl_dialects                , INT
, "__gg__dialects"        );
     }
   }
 
@@ -7397,6 +7398,9 @@ parser_division(cbl_division_t division,
 
         // And then flag one-time initialization as having been done.
         gg_assign(globals_are_initialized, integer_one_node);
+
+        // Let the library know what -dialect entries are in force:
+        gg_assign(var_decl_dialects, build_int_cst_type(INT,
cbl_dialects));
         }
       ELSE
         ENDIF
diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc
index 283864c85cc..b4221a30a86 100644
--- a/gcc/cobol/genutil.cc
+++ b/gcc/cobol/genutil.cc
@@ -101,6 +101,9 @@ tree var_decl_main_called;        // int
__gg__main_called;
 // Indicates the target index of an ENTRY statement
 tree var_decl_entry_index; // void* __gg__entry_index
 
+// Indicates the dialects the compiler was set to
+tree var_decl_dialects; // void* __gg__dialects
+
 #if 0
 #define REFER(a)
 #else
diff --git a/gcc/cobol/genutil.h b/gcc/cobol/genutil.h
index aeb99c23882..e19fabf6435 100644
--- a/gcc/cobol/genutil.h
+++ b/gcc/cobol/genutil.h
@@ -60,6 +60,7 @@ extern tree var_decl_call_parameter_lengths;   // size_t
*var_decl_call_paramete
 extern tree var_decl_nop;         // int __gg__nop
 extern tree var_decl_main_called; // int __gg__main_called
 extern tree var_decl_entry_index; // void* __gg__entry_index
+extern tree var_decl_dialects;    // void* __gg__dialects
 
 int       get_scaled_rdigits(cbl_field_t *field);
 int       get_scaled_digits(cbl_field_t *field);
diff --git a/gcc/cobol/lang.opt.urls b/gcc/cobol/lang.opt.urls
index 69493276ac1..9a9a49e78cb 100644
--- a/gcc/cobol/lang.opt.urls
+++ b/gcc/cobol/lang.opt.urls
@@ -1,8 +1,5 @@
 ; Autogenerated by regenerate-opt-urls.py from gcc/cobol/lang.opt and
generated HTML
 
-B
-UrlSuffix(gcc/Directory-Options.html#index-B)
LangUrlSuffix_D(gdc/Directory-Options.html#index-B)
-
 D
 UrlSuffix(gcc/Preprocessor-Options.html#index-D-1)
 
@@ -40,6 +37,3 @@ UrlSuffix(gcc/Directory-Options.html#index-isysroot)
LangUrlSuffix_Fortran(gfort
 isystem
 UrlSuffix(gcc/Directory-Options.html#index-isystem)
LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-isystem)
 
-idirafter
-UrlSuffix(gcc/Directory-Options.html#index-idirafter)
LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-idirafter)
-
diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h
index 45e005f35b3..b4f3bdd7bc5 100644
--- a/gcc/cobol/symbols.h
+++ b/gcc/cobol/symbols.h
@@ -50,14 +50,6 @@
 
 extern const char *numed_message;
 
-enum cbl_dialect_t {
-  dialect_iso_e = 0x00,
-  dialect_gcc_e = 0x01,
-  dialect_ibm_e = 0x02,
-  dialect_mf_e  = 0x04,
-  dialect_gnu_e = 0x08,
-};
-
 static inline const char *
 cbl_dialect_str(cbl_dialect_t dialect)  {
   switch(dialect) {
diff --git
a/gcc/testsuite/cobol.dg/group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.co
b
b/gcc/testsuite/cobol.dg/group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.co
b
new file mode 100644
index 00000000000..5be9ea22199
--- /dev/null
+++
b/gcc/testsuite/cobol.dg/group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.co
b
@@ -0,0 +1,25 @@
+       *> { dg-do run }
+       *> { dg-options "-dialect ibm" }
+       *> { dg-output-file
"group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.out" }
+        identification              division.
+        program-id.                 prog.
+        data                        division.
+        working-storage             section.
+        01  f1 comp-1 value 1.5.
+        01  f2 comp-1 value 0.1.
+        01  f3 comp-1 value -2.75.
+        01  f4 comp-1 value 1500.
+        01  f5 comp-1 value 0.001500.
+        01  d1 comp-2 value 2.71828.
+        01  d2 comp-2 value -0.0000271828.
+        procedure                   division.
+            display f1
+            display f2
+            display f3
+            display f4
+            display f5
+            display d1
+            display d2
+            goback.
+        end program                 prog.
+
diff --git
a/gcc/testsuite/cobol.dg/group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.ou
t
b/gcc/testsuite/cobol.dg/group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.ou
t
new file mode 100644
index 00000000000..9c7d7775cb6
--- /dev/null
+++
b/gcc/testsuite/cobol.dg/group2/DISPLAY_IBM-formatted_COMP-1_and_COMP-2.ou
t
@@ -0,0 +1,8 @@
+ 1.50000000E 00
+ 1.00000001E-01
+-2.75000000E 00
+ 1.50000000E 03
+ 1.50000001E-03
+ 2.71828000000000003E 00
+-2.71828000000000000E-05
+
diff --git a/libgcobol/common-defs.h b/libgcobol/common-defs.h
index 3bc9ba53e6d..78eb03c8fd7 100644
--- a/libgcobol/common-defs.h
+++ b/libgcobol/common-defs.h
@@ -407,6 +407,14 @@ enum classify_t {
   ClassKanjiType,
 };
 
+enum cbl_dialect_t {
+  dialect_iso_e = 0x00,
+  dialect_gcc_e = 0x01,
+  dialect_ibm_e = 0x02,
+  dialect_mf_e  = 0x04,
+  dialect_gnu_e = 0x08,
+};
+
 static inline const char *
 classify_str( enum classify_t classify ) {
   switch(classify) {
diff --git a/libgcobol/intrinsic.cc b/libgcobol/intrinsic.cc
index b62518f5b47..e9577f46bf5 100644
--- a/libgcobol/intrinsic.cc
+++ b/libgcobol/intrinsic.cc
@@ -3513,7 +3513,7 @@ __gg__trim_1( cblc_field_t *dest,
         const cblc_field_t *src,
               size_t        src_offset,
               size_t        src_size,
-              unsigned char *chars,
+        const unsigned char *chars,
               int           count_how ) // (args.size()<<8) + how),
   {
   /* This routine is called for ASCII/EBCDIC single-byte-code values.
Since
diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc
index 911ac06f5ef..dd7ea15dbec 100644
--- a/libgcobol/libgcobol.cc
+++ b/libgcobol/libgcobol.cc
@@ -156,6 +156,7 @@ int         __gg__rdigits                     = 0    ;
 int         __gg__nop                         = 0    ;
 int         __gg__main_called                 = 0    ;
 size_t      __gg__entry_index                 = 0    ;
+int         __gg__dialects                    = 0    ;
 
 // During SORT operations, we don't want the end-of-file condition, which
 // happens as a matter of course, from setting the EOF exception
condition.
@@ -3481,11 +3482,12 @@ format_for_display_internal(char **dest,
         {
         case 4:
           {
-          // We will convert based on the fact that for float32, any
seven-digit
-          // number converts to float32 and then back again unchanged.
+          // We will convert based on the fact that for float32, any
+          // seven-digit number converts to float32 and then back again
+          // unchanged.
 
-          // We will also format numbers so that we produce 0.01 and 1E-3
on the low
-          // side, and 9999999 and then 1E+7 on the high side
+          // We will also format numbers so that we produce 0.01 and 1E-3
on
+          // the low side, and 9999999 and then 1E+7 on the high side
           // 10,000,000 = 1E7
           char ach[64];
           _Float32 floatval = *PTRCAST(_Float32, actual_location);
@@ -3497,23 +3499,49 @@ format_for_display_internal(char **dest,
             }
           else
             {
-            p += 1;
-            int exp = atoi(p);
-            if( exp >= 6 || exp <= -5 )
+            if( __gg__dialects & dialect_ibm_e )
               {
-              // We are going to stick with the E notation, so ach has
our result
+              // IBM specifies that this look like
+              //     A COMP-1 item will display as if it had an external
+              //     floating-point PICTURE clause of -.9(8)E-99.
+              // The plus signs are suppressed.
+              if( floatval >= 0 )
+                {
+                strfromf32(ach+1, sizeof(ach), "%.8E", floatval);
+                ach[0] = ascii_space;
+                }
+              else
+                {
+                strfromf32(ach, sizeof(ach), "%.8E", floatval);
+                }
+              // Turn "E+00" to the IBM "E 00"
+              p = strchr(ach, ascii_plus);
+              if(p)
+                {
+                *p = ascii_space;
+                }
               }
             else
               {
-              // We are going to produce our number in such a way that we
specify
-              // seven signicant digits, no matter where the decimal
point lands.
-              // Note that exp is in the range of 6 to -2
+              p += 1;
+              int exp = atoi(p);
+              if( exp >= 6 || exp <= -5 )
+                {
+                // We are going to stick with the E notation, so ach has
our
+                // result
+                }
+              else
+                {
+                // We are going to produce our number in such a way that
we
+                // specify seven signicant digits, no matter where the
decimal
+                // point lands. Note that exp is in the range of 6 to -2
 
-              int precision = 9 - exp;
-              sprintf(ach, "%.*f", precision, (double)floatval );
+                int precision = 9 - exp;
+                sprintf(ach, "%.*f", precision, (double)floatval );
+                }
+              __gg__remove_trailing_zeroes(ach);
+              __gg__realloc_if_necessary(dest, dest_size, strlen(ach)+1);
               }
-            __gg__remove_trailing_zeroes(ach);
-            __gg__realloc_if_necessary(dest, dest_size, strlen(ach)+1);
             }
           strcpy(*dest, ach);
           break;
@@ -3524,8 +3552,8 @@ format_for_display_internal(char **dest,
           // We will convert based on the fact that for float32, any
15-digit
           // number converts to float64 and then back again unchanged.
 
-          // We will also format numbers so that we produce 0.01 and 1E-3
on the low
-          // side, and 9999999 and then 1E+15 on the high side
+          // We will also format numbers so that we produce 0.01 and 1E-3
on
+          // the low side, and 9999999 and then 1E+15 on the high side
           char ach[64];
           _Float64 floatval = *PTRCAST(_Float64, actual_location);
           strfromf64(ach, sizeof(ach), "%.17E", floatval);
@@ -3536,24 +3564,50 @@ format_for_display_internal(char **dest,
             }
           else
             {
-            p += 1;
-            int exp = atoi(p);
-            if( exp >= 6 || exp <= -5 )
+            if( __gg__dialects & dialect_ibm_e )
               {
-              // We are going to stick with the E notation, so ach has
our result
+              // IBM specifies that this look like
+              //     A COMP-2 item will display as if it had an external
+              //     floating-point PICTURE clause of -.9(17)E-99.
+              // The plus signs are suppressed.
+              if( floatval >= 0 )
+                {
+                strfromf64(ach+1, sizeof(ach), "%.17E", floatval);
+                ach[0] = ascii_space;
+                }
+              else
+                {
+                strfromf64(ach, sizeof(ach), "%.17E", floatval);
+                }
+              // Turn "E+00" to the IBM "E 00"
+              p = strchr(ach, ascii_plus);
+              if(p)
+                {
+                *p = ascii_space;
+                }
               }
             else
               {
-              // We are going to produce our number in such a way that we
specify
-              // seven signicant digits, no matter where the decimal
point lands.
-              // Note that exp is in the range of 6 to -2
+              p += 1;
+              int exp = atoi(p);
+              if( exp >= 6 || exp <= -5 )
+                {
+                // We are going to stick with the E notation, so ach has
our
+                // result
+                }
+              else
+                {
+                // We are going to produce our number in such a way that
we
+                // specify seven signicant digits, no matter where the
decimal
+                // point lands.  Note that exp is in the range of 6 to -2
 
-              int precision = 17 - exp;
+                int precision = 17 - exp;
 
-              sprintf(ach, "%.*f", precision, (double)floatval );
+                sprintf(ach, "%.*f", precision, (double)floatval );
+                }
+              __gg__remove_trailing_zeroes(ach);
+              __gg__realloc_if_necessary(dest, dest_size, strlen(ach)+1);
               }
-            __gg__remove_trailing_zeroes(ach);
-            __gg__realloc_if_necessary(dest, dest_size, strlen(ach)+1);
             }
           strcpy(*dest, ach);
           break;
@@ -3564,8 +3618,8 @@ format_for_display_internal(char **dest,
           // We will convert based on the fact that for float32, any
15-digit
           // number converts to float64 and then back again unchanged.
 
-          // We will also format numbers so that we produce 0.01 and 1E-3
on the low
-          // side, and 9999999 and then 1E+15 on the high side
+          // We will also format numbers so that we produce 0.01 and 1E-3
on
+          // the low side, and 9999999 and then 1E+15 on the high side
           char ach[128];
           // We can't use *(_Float64 *)actual_location;
           // That uses the SSE registers, which won't work if the source
isn't
@@ -3584,13 +3638,14 @@ format_for_display_internal(char **dest,
             int exp = atoi(p);
             if( exp >= 6 || exp <= -5 )
               {
-              // We are going to stick with the E notation, so ach has
our result
+              // We are going to stick with the E notation, so ach has
our
+              // result
               }
             else
               {
-              // We are going to produce our number in such a way that we
specify
-              // seven signicant digits, no matter where the decimal
point lands.
-              // Note that exp is in the range of 6 to -2
+              // We are going to produce our number in such a way that we
+              // specify seven signicant digits, no matter where the
decimal
+              // point lands. Note that exp is in the range of 6 to -2
 
               int precision = 36 - exp;
               char achFormat[24];
@@ -9770,8 +9825,8 @@ default_exception_handler( ec_type_t ec )
     /*
      * An enabled, unhandled fatal EC normally results in termination.
But
      * EC-I-O is a special case becase a SELECT statement with FILE
STATUS
-     * indicates the user will handle the error.  
-     * 
+     * indicates the user will handle the error.
+     *
      * Declaratives are handled first.  We are in the default handler
here,
      * which is reached only if no Declarative was matched.
      */
@@ -9854,7 +9909,7 @@ ec_type_disposition( ec_type_t type ) {
 static bool
 ec_is_fatal( ec_type_t type ) {
   ec_disposition_t disp = ec_type_disposition(type);
-  
+
   switch(disp) {
   case ec_category_nonfatal_e:
   case uc_category_nonfatal_e:
@@ -9868,7 +9923,7 @@ ec_is_fatal( ec_type_t type ) {
   case uc_category_implementor_e:
     if( MATCH_DECLARATIVE )
       warnx("%s: %s is unimplemented", __func__,
local_ec_type_str(type));
-    break;    
+    break;
   }
   return true;
 }
-- 
2.34.1

Reply via email to