From 3981b63883b879227e2ef59a05a184ae0ff619ca Mon Sep 17 00:00:00 2001
From: Bob Dubner <rdubner@symas.com>
Date: Sat, 13 Apr 2024 23:19:59 -0400
Subject: [PATCH] Transition to __gg__move_literala

---
 gcc/cobol/genapi.cc    |  41 +++++-
 libgcobol/libgcobol.cc | 298 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 335 insertions(+), 4 deletions(-)

diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index 1a9e69000ff7..4238bf806b11 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -13468,10 +13468,6 @@ move_helper(cbl_refer_t destref,
 
   tree size_error = gg_define_int(0);
 
-  // gg_insert_into_assembler( "# DUBNER move_helper enter %s to %s",
-                            // sourceref.field->name,
-                            // destref.field->name );
-
   static tree stash = gg_define_variable(UCHAR_P);
   if( restore_on_error )
     {
@@ -13546,6 +13542,43 @@ move_helper(cbl_refer_t destref,
 
   //dont_be_clever:
 
+  if( !moved && sourceref.field->type == FldLiteralA)
+    {
+    SHOW_PARSE
+      {
+      SHOW_PARSE_INDENT
+      SHOW_PARSE_TEXT("__gg__move_literala")
+      }
+
+    refer_fill_dest(destref);
+
+    if(    destref.refmod.from
+        || destref.refmod.len
+        || sourceref.refmod.from
+        || sourceref.refmod.len )
+      {
+      // Let the move routine know to treat the destination as alphanumeric
+      gg_attribute_bit_set(destref.field, refmod_e);
+      }
+
+    gg_assign(size_error,
+              gg_call_expr( INT,
+                            "__gg__move_literala",
+                            3,
+                            gg_get_address_of(destref.refer_decl_node),
+                            gg_get_address_of(sourceref.refer_decl_node),
+                            build_int_cst_type(INT, rounded)));
+    if(    destref.refmod.from
+        || destref.refmod.len
+        || sourceref.refmod.from
+        || sourceref.refmod.len )
+      {
+      // Return that value to its original form
+      gg_attribute_bit_clear(destref.field, refmod_e);
+      }
+    moved = true;
+    }
+
   if( !moved )
     {
     SHOW_PARSE
diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc
index 161c150a3c64..d3e270f3029e 100644
--- a/libgcobol/libgcobol.cc
+++ b/libgcobol/libgcobol.cc
@@ -5142,6 +5142,304 @@ __gg__move( struct cblc_refer_t *dest,
   return size_error;
   }
 
+extern "C"
+int
+__gg__move_literala(struct cblc_refer_t *dest,
+                    struct cblc_refer_t *source,
+                    cbl_round_t rounded )
+  {
+  int size_error = 0; // This is the return value
+
+  bool moved = true;
+
+  __int128 value;
+  int rdigits;
+
+  cbl_figconst_t source_figconst =
+                        (cbl_figconst_t)(source->field->attr & FIGCONST_MASK);
+  cbl_field_type_t dest_type   = (cbl_field_type_t)dest->field->type;
+  cbl_field_type_t source_type = (cbl_field_type_t)source->field->type;
+  
+  if( source_type != FldLiteralA )
+    {
+    fprintf(stderr, "KILROY How the fuck did this happen?\n");
+    abort();
+    }
+
+  if( var_is_refmod(dest->field) )
+    {
+    dest_type   = FldAlphanumeric;
+    }
+
+  if( (   source_figconst == low_value_e
+      ||  source_figconst == space_value_e
+      ||  source_figconst == quote_value_e
+      ||  source_figconst == high_value_e )
+      &&
+       (    dest->field->type == FldNumericBinary
+        ||  dest->field->type == FldPacked
+        ||  dest->field->type == FldNumericBin5
+        ||  dest->field->type == FldNumericDisplay
+        ||  dest->field->type == FldFloat )
+        )
+    {
+    // Regardless of what you see below, as time went on it became clear that
+    // high-value and low-value required special processing in order to cope
+    // with code.  Or, at least, to cope with legacy tests.
+
+    // The ISO 2014 specification has this to say about the moving of figurative
+    // constants to numerics:
+
+    // 14.9.24.3, paragraph 7)
+
+    /*  NOTE: MOVE of the figurative constant QUOTE or QUOTES to a numeric data
+     *  item is an obsolete feature and is to be removed from the next edition
+     *  of standard COBOL. MOVE of figurative constants that are not numeric,
+     *  other than QUOTE or QUOTES, to a numeric item is an archaic feature of
+     *  standard COBOL and its use should be avoided
+     */
+
+    int special_char;
+    if( source_figconst == low_value_e )
+      {
+      special_char = ascii_to_internal(__gg__low_value_character);
+      }
+    else if( source_figconst == high_value_e )
+      {
+      special_char = ascii_to_internal(__gg__high_value_character);
+      }
+    else if( source_figconst == quote_value_e )
+      {
+      special_char = ascii_to_internal(__gg__quote_character);
+      }
+    else if( source_figconst == space_value_e )
+      {
+      special_char = ascii_to_internal(ascii_space);
+      }
+    memset(dest->qual_data, special_char, dest->qual_size);
+    }
+  else
+    {
+    switch( dest_type )
+      {
+      case FldGroup:
+        switch( source_type )
+          {
+          // For all other types, we just do a straight byte-for-byte move
+          case FldLiteralA:
+            alpha_to_alpha_move(dest, source, source->move_all);
+            break;
+
+          default:
+            abort();
+            moved = false;
+            break;
+          }
+
+        break;
+
+      case FldAlphanumeric:
+        {
+        switch( source_type )
+          {
+          case FldLiteralA:
+            alpha_to_alpha_move(dest, source, source->move_all);
+            break;
+
+
+          default:
+            moved = false;
+            break;
+          }
+        break;
+        }
+
+      case FldNumericBinary:
+        {
+        switch( source_type )
+          {
+          case FldLiteralA:
+            {
+            // We are moving a number to a number:
+            value = __gg__binary_value_from_refer(&rdigits, source);
+
+            if( truncation_mode == trunc_std_e )
+              {
+              if( value < 0 )
+                {
+                value = -value;
+                value %= __gg__power_of_ten(dest->field->digits);
+                value = -value;
+                }
+              else
+                {
+                value %= __gg__power_of_ten(dest->field->digits);
+                }
+              }
+
+            __gg__int128_to_refer(dest,
+                                  value,
+                                  rdigits,
+                                  rounded,
+                                  &size_error );
+            break;
+            }
+
+          default:
+            {
+            moved = false;
+            break;
+            }
+          }
+        break;
+        }
+
+      case FldNumericDisplay:
+      case FldNumericEdited:
+      case FldNumericBin5:
+      case FldPacked:
+      case FldIndex:
+        // Bin5 and Index are treated with no truncation, as if they were
+        // trunc_bin_e.  The other types aren't subject to truncation.
+        switch( source_type )
+          {
+          case FldLiteralA:
+            {
+            // We are moving a number to a number:
+            value = __gg__binary_value_from_refer(&rdigits, source);
+            __gg__int128_to_refer(      dest,
+                                       value,
+                                       rdigits,
+                                       rounded,
+                                       &size_error );
+            break;
+            }
+
+          default:
+            moved = false;
+            break;
+          }
+        break;
+
+      case FldAlphaEdited:
+        {
+        switch( source_type )
+          {
+          case FldLiteralA:
+            {
+            static size_t display_string_size = MINIMUM_ALLOCATION_SIZE;
+            static char *display_string = (char *)MALLOC(display_string_size);
+
+            size_t display_string_length = dest->qual_size;
+            __gg__realloc_if_necessary( &display_string,
+                                        &display_string_size,
+                                        display_string_length);
+
+            if( source_figconst == low_value_e )
+              {
+              memset(display_string, ascii_to_internal(__gg__low_value_character), dest->qual_size);
+              }
+            else if( source_figconst == zero_value_e )
+              {
+              memset(display_string, internal_zero, dest->qual_size);
+              }
+            else if( source_figconst == space_value_e )
+              {
+              memset(display_string, internal_space, dest->qual_size);
+              }
+            else if( source_figconst == quote_value_e )
+              {
+              memset(display_string, ascii_to_internal(__gg__quote_character), dest->qual_size);
+              }
+            else if( source_figconst == high_value_e )
+              {
+              memset(display_string, ascii_to_internal(__gg__high_value_character), dest->qual_size);
+              }
+            else
+              {
+              display_string = format_for_display_internal(
+                                &display_string,
+                                &display_string_size,
+                                source->field,
+                                (unsigned char *)source->qual_data,
+                                source->qual_size,
+                                source->address_of);
+              display_string_length = strlen(display_string);
+              }
+            __gg__string_to_alpha_edited( (char *)dest->qual_data,
+                                          display_string,
+                                          display_string_length,
+                                          dest->field->picture);
+            break;
+            }
+
+          default:
+            {
+            moved=false;
+            break;
+            }
+          }
+        break;
+        }
+
+      case FldFloat:
+        {
+        switch( source_type )
+          {
+          case FldLiteralA:
+            {
+            char ach[256];
+            size_t len = std::min(source->qual_size, sizeof(ach)-1);
+            memcpy(ach, source->qual_data, len);
+            ach[len] = '\0';
+            __gg__internal_to_console_in_place(ach, len);
+            switch( dest->field->capacity )
+              {
+              case 4:
+                {
+                *(float *)(dest->qual_data) = strtof32(ach, NULL);
+                break;
+                }
+              case 8:
+                {
+                *(double *)(dest->qual_data) = strtof64(ach, NULL);
+                break;
+                }
+              case 16:
+                {
+                *(_Float128 *)(dest->qual_data) = strtof128(ach, NULL);
+                break;
+                }
+              break;
+              }
+            break;
+            }
+
+          default:
+            {
+            moved = false;
+            break;
+            }
+          }
+        break;
+        }
+
+      default:
+        moved = false;
+        break;
+      }
+    if( !moved )
+      {
+      fprintf(stderr, "%s() %s:%d -- We were unable to do a move from "
+              "type %d to %d\n",
+              __func__, __FILE__, __LINE__,
+              source->field->type, dest->field->type);
+      exit(1);
+      }
+    }
+  return size_error;
+  }
+
 extern "C"
 void
 __gg__file_sort_ff_input(   cblc_file_t *workfile,
-- 
GitLab