]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cobol: Implement ENTRY statement; finish removing ascii/ebcdic dichotomy.
authorRobert Dubner <rdubner@symas.com>
Sat, 18 Oct 2025 14:35:52 +0000 (10:35 -0400)
committerRobert Dubner <rdubner@symas.com>
Sun, 19 Oct 2025 00:49:21 +0000 (20:49 -0400)
The prior set of changes largely eliminated the assumption that the
internal codeset was either ascii or ebcdic.  These changes remove the
last vestiges of that assumption.

These changes also implement the COBOL ENTRY statement, which allows a
program-id to have more than one externally callable entry point. Since
GCC assumes the existence of an ABI that is not, repeat *not* capable of
that, it is implemented here by creating a separate function with the
name specified by the ENTRY statement.  That function sets up global
variables which cause control to be transferred to the ENTRY point when
the parent function is called re-entrantly, and then executes that call.

gcc/cobol/ChangeLog:

* genapi.cc (move_tree): Formatting.
(parser_enter_file): Incorporate global __gg__entry_label.
(enter_program_common): Remove calls to alphabet overrides.
(parser_alphabet): Change cbl_alphabet_e handling.
(parser_alphabet_use): Likewise.
(initialize_the_data): Likewise.
(establish_using): Process passed parameters in a subroutine.
(parser_division): Remove in-line parameter processing;
call establish_using() instead. Check for __gg__entry_label.
(parser_file_add): Temporary workaround for charset encoding.
(parser_file_open): Likewise.
(create_and_call): Push/pop program state around call to external.
(parser_entry): Implement new ENTRY statement feature.
(mh_source_is_literalN): Formatting.
* genapi.h (parser_entry): New ENTRY statement.
* gengen.cc (gg_create_goto_pair): Formatting.
(gg_goto_label_decl): Remove.
* gengen.h (gg_goto_label_decl): Remove.
* genutil.cc (internal_codeset_is_ebcdic): Remove.
* genutil.h (internal_codeset_is_ebcdic): Remove.
* symbols.cc (symbols_alphabet_set): Restrict alphabet scan to
program.
* symbols.h (is_elementary): Use defined constants instead of
explicit 'A'and 'N'

libgcobol/ChangeLog:

* charmaps.cc (__gg__set_internal_codeset): Eliminate ascii/ebcdic.
(__gg__text_conversion_override): Remove.
* charmaps.h (enum text_device_t):  Eliminate ascii/ebcdic.
(enum text_codeset_t): Remove.
(__gg__set_internal_codeset): Remove.
(__gg__text_conversion_override): Remove.
* gfileio.cc: Anticipate cbl_encoding_t fixes.
* libgcobol.cc (struct program_state): Incorporate
__gg__entry_label.
(__gg__pop_program_state): Eliminate unused defines.
(__gg__alphabet_use): Eliminate ascii/ebcdic dichotomy.
* valconv.cc (__gg__alphabet_create): Likewise.

13 files changed:
gcc/cobol/genapi.cc
gcc/cobol/genapi.h
gcc/cobol/gengen.cc
gcc/cobol/gengen.h
gcc/cobol/genutil.cc
gcc/cobol/genutil.h
gcc/cobol/symbols.cc
gcc/cobol/symbols.h
libgcobol/charmaps.cc
libgcobol/charmaps.h
libgcobol/gfileio.cc
libgcobol/libgcobol.cc
libgcobol/valconv.cc

index 99dfc071f2a17398d5e31496d936238157aa25bc..6fc4770ca26dd9b9cf980324c2d20190e179241d 100644 (file)
@@ -2357,7 +2357,7 @@ static void
 move_tree(  cbl_field_t  *dest,
             tree          offset,
             tree          psz_source, // psz_source is a null-terminated string
-            tree length_bump=integer_zero_node)   
+            tree length_bump=integer_zero_node)
   {
   // This routine assumes that the psz_source is in the same codeset as the
   // dest.
@@ -3774,6 +3774,7 @@ parser_enter_file(const char *filename)
     SET_VAR_DECL(var_decl_treeplet_4s             , SIZE_T_P                , "__gg__treeplet_4s"     );
     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_label             , VOID_P                  , "__gg__entry_label"     );
     }
   }
 
@@ -3865,25 +3866,6 @@ enter_program_common(const char *funcname, const char *funcname_)
   current_function->current_section = NULL;
   current_function->current_paragraph = NULL;
 
-  // Text conversion must be initialized before the code generated by
-  // parser_symbol_add runs.
-
-  // The text_conversion_override exists both in the library and in the compiler
-
-  __gg__set_internal_codeset(internal_codeset_is_ebcdic());
-  gg_call(VOID,
-          "__gg__set_internal_codeset",
-          internal_codeset_is_ebcdic()
-          ? integer_one_node : integer_zero_node,
-          NULL_TREE);
-
-  __gg__text_conversion_override(td_default_e, cs_default_e);
-  gg_call(VOID,
-          "__gg__text_conversion_override",
-          build_int_cst_type(INT, td_default_e),
-          build_int_cst_type(INT, cs_default_e),
-          NULL_TREE);
-
   gg_call(VOID,
           "__gg__codeset_figurative_constants",
           NULL_TREE);
@@ -5059,29 +5041,34 @@ parser_alphabet( cbl_alphabet_t& alphabet )
   SHOW_PARSE
     {
     SHOW_PARSE_HEADER
-    fprintf(stderr, "%s\n", alphabet.name);
+    char *psz = xasprintf(" %s ", alphabet.name);
+    SHOW_PARSE_TEXT(psz);
+    free(psz);
     switch(alphabet.encoding)
       {
       case ASCII_e:
-        fprintf(stderr, "ASCII\n");
+        psz = xasprintf("ASCII");
         break;
       case iso646_e:
-        fprintf(stderr, "ISO646\n");
+        psz = xasprintf("ISO646");
         break;
       case EBCDIC_e:
-        fprintf(stderr, "EBCDIC\n");
+        psz = xasprintf("EBCDIC");
         break;
       case UTF8_e:
-        fprintf(stderr, "UTF8\n");
+        psz = xasprintf("UTF8");
         break;
       case custom_encoding_e:
-        fprintf(stderr, "%s\n", alphabet.name);
+        psz = xasprintf("%s", alphabet.name);
         break;
       default:
         { const char * p = __gg__encoding_iconv_name( alphabet.encoding );
-          fprintf(stderr, "%s\n", p? p : "[unknown]");
+          psz = xasprintf("%s", p? p : "[unknown]");
         }
       }
+    SHOW_PARSE_TEXT(" ");
+    SHOW_PARSE_TEXT(psz);
+    free(psz);
     SHOW_PARSE_END
     }
 
@@ -5122,6 +5109,7 @@ parser_alphabet( cbl_alphabet_t& alphabet )
               gg_get_address_of(table256),
               build_int_cst_type(INT, alphabet.low_index),
               build_int_cst_type(INT, alphabet.high_index),
+
               NULL_TREE );
       break;
       }
@@ -5137,26 +5125,31 @@ parser_alphabet_use( cbl_alphabet_t& alphabet )
   SHOW_PARSE
     {
     SHOW_PARSE_HEADER
+    char *psz = xasprintf(" %s ", alphabet.name);
+    SHOW_PARSE_TEXT(psz);
+    free(psz);
     switch(alphabet.encoding)
       {
       case ASCII_e:
-        fprintf(stderr, "ASCII\n");
+        psz = xasprintf("ASCII");
         break;
       case iso646_e:
-        fprintf(stderr, "ISO646\n");
+        psz = xasprintf("ISO646");
         break;
       case EBCDIC_e:
-        fprintf(stderr, "EBCDIC\n");
+        psz = xasprintf("EBCDIC");
         break;
       case UTF8_e:
-        fprintf(stderr, "UTF8\n");
+        psz = xasprintf("UTF8");
         break;
       case custom_encoding_e:
-        fprintf(stderr, "%s\n", alphabet.name);
+        psz = xasprintf("%s", alphabet.name);
         break;
       default:
         gcc_unreachable();
       }
+    SHOW_PARSE_TEXT(psz);
+    free(psz);
     SHOW_PARSE_END
     }
 
@@ -5174,6 +5167,7 @@ parser_alphabet_use( cbl_alphabet_t& alphabet )
       __gg__high_value_character = DEGENERATE_HIGH_VALUE;
       gg_call(VOID,
               "__gg__alphabet_use",
+              build_int_cst_type(INT, current_encoding(encoding_display_e)),
               build_int_cst_type(INT, alphabet.encoding),
               null_pointer_node,
               NULL_TREE);
@@ -5189,6 +5183,7 @@ parser_alphabet_use( cbl_alphabet_t& alphabet )
 
       gg_call(VOID,
               "__gg__alphabet_use",
+              build_int_cst_type(INT, current_encoding(encoding_display_e)),
               build_int_cst_type(INT, alphabet.encoding),
               build_int_cst_type(SIZE_T, alphabet_index),
               NULL_TREE);
@@ -6938,6 +6933,7 @@ initialize_the_data()
   // This is one-time initialization of the libgcobol program state stack
   gg_call(VOID,
           "__gg__init_program_state",
+          build_int_cst_type(INT, current_encoding(encoding_display_e)),
           NULL_TREE);
 
   __gg__currency_signs = __gg__ct_currency_signs;
@@ -6989,6 +6985,280 @@ initialize_the_data()
     }
   }
 
+static
+void
+establish_using(size_t nusing,
+                cbl_ffi_arg_t args[] )
+  {
+  if( nusing )
+    {
+    for(size_t i=0; i<nusing; i++)
+      {
+      // This code is relevant at compile time.  It takes each
+      // expected formal parameter and tacks it onto the end of the
+      // function's arguments chain.
+
+      char *ach = xasprintf("_p_%s", args[i].refer.field->name);
+
+      size_t nbytes = 0;
+      tree par_type = tree_type_from_field_type(args[i].refer.field, nbytes);
+      if( par_type == FLOAT )
+        {
+        par_type = SSIZE_T;
+        }
+      if( par_type == DOUBLE )
+        {
+        par_type = SSIZE_T;
+        }
+      if( par_type == FLOAT128 )
+        {
+        par_type = INT128;
+        }
+      chain_parameter_to_function(current_function->function_decl, par_type, ach);
+      free(ach);
+      }
+
+    // During the call, we saved the parameter_count and an array of variable
+    // lengths.  We need to look at those values if, and only if, one or more
+    // of our USING arguments has an OPTIONAL flag or if one of our targets is
+    // marked as VARYING.
+    bool check_for_parameter_count = false;
+    for(size_t i=0; i<nusing; i++)
+      {
+      if( args[i].optional )
+        {
+        check_for_parameter_count = true;
+        break;
+        }
+      if( args[i].refer.field->attr & any_length_e )
+        {
+        check_for_parameter_count = true;
+        break;
+        }
+      }
+
+    if( check_for_parameter_count )
+      {
+      IF( var_decl_call_parameter_signature,
+          eq_op,
+          gg_cast(CHAR_P, current_function->function_address) )
+        {
+        // We know to use var_decl_call_parameter_count, so unflag this
+        // pointer to avoid problems in the ridiculous possibility of
+        // COBOL-A calls C_B calls COBOL_A
+        gg_assign(var_decl_call_parameter_signature,
+                  gg_cast(CHAR_P, null_pointer_node));
+        }
+      ELSE
+        {
+        // We were apparently called by a C routine, not a COBOL routine, so
+        // make sure we don't get shortchanged by a count left behind from an
+        // earlier COBOL call.
+        gg_assign(var_decl_call_parameter_count,
+                  build_int_cst_type(INT, A_ZILLION));
+        }
+      ENDIF
+      }
+    else
+      {
+      // None of our parameters require a count, so make sure we don't get
+      // bamboozled by a count left behind from an earlier COBOL call.
+      gg_assign(var_decl_call_parameter_count,
+                build_int_cst_type(INT, A_ZILLION));
+      }
+
+    // There are 'nusing' elements in the PROCEDURE DIVISION USING list.
+
+    tree parameter = NULL_TREE;
+    tree rt_i = gg_define_int();
+    for(size_t i=0; i<nusing; i++)
+      {
+      // And this compiler code generates run-time execution code. The
+      // generated code picks up, at run time, the variable we just
+      // established in the chain at compile time.
+
+      // It makes more sense if you don't think about it too hard.
+
+      // We need to be able to restore prior arguments when doing recursive
+      // calls:
+      IF( member(args[i].refer.field->var_decl_node, "data"),
+          ne_op,
+          gg_cast(UCHAR_P, null_pointer_node) )
+        {
+        gg_call(VOID,
+                "__gg__push_local_variable",
+                gg_get_address_of(args[i].refer.field->var_decl_node),
+                NULL_TREE);
+        }
+      ELSE
+        ENDIF
+
+      tree base = gg_define_variable(UCHAR_P);
+      gg_assign(rt_i, build_int_cst_type(INT, i));
+      //gg_printf("The rt_i counter is %d\n", rt_i, NULL_TREE);
+      IF( rt_i, lt_op , var_decl_call_parameter_count )
+        {
+        if( i == 0 )
+          {
+          // This is the first parameter.
+          parameter = DECL_ARGUMENTS(current_function->function_decl);
+          }
+        else
+          {
+          // These are subsequent parameters
+          parameter = TREE_CHAIN(parameter);
+          }
+        gg_assign(base, gg_cast(UCHAR_P, parameter));
+
+        if( args[i].refer.field->attr & any_length_e )
+          {
+          // gg_printf("side channel: Length of \"%s\" is %ld\n",
+                    // member(args[i].refer.field->var_decl_node, "name"),
+                    // gg_array_value(var_decl_call_parameter_lengths, rt_i),
+                    // NULL_TREE);
+
+          // Get the length from the global lengths[] side channel.  Don't
+          // forget to use the length mask on the table value.
+          gg_assign(member(args[i].refer.field->var_decl_node, "capacity"),
+                    gg_array_value(var_decl_call_parameter_lengths, rt_i));
+          }
+        }
+      ELSE
+        {
+        gg_assign(base, gg_cast(UCHAR_P, null_pointer_node));
+        }
+        ENDIF
+
+      // Arriving here means that we are processing an instruction like
+      // this:
+      // PROCEDURE DIVISION USING using[0] using[1] ... using using[nusing-1]
+
+      // When __gg__call_parameter_count is equal to A_ZILLION, then this is
+      // an OTHER-TO-COBOL call and the var_decl_call_parameter_lengths array
+      // is not valid
+
+      cbl_ffi_crv_t crv = args[i].crv;
+      cbl_field_t *new_var = args[i].refer.field;
+
+      if( crv == by_value_e )
+        {
+        switch(new_var->type)
+          {
+          case FldGroup:
+          case FldAlphanumeric:
+          case FldAlphaEdited:
+          case FldNumericEdited:
+            crv = by_reference_e;
+            break;
+          default:
+            break;
+          }
+        }
+
+      if( crv == by_value_e )
+        {
+        // 'parameter' is the 64-bit or 128-bit value that was placed on the stack
+
+        size_t nbytes;
+        tree_type_from_field_type(new_var, nbytes);
+        tree parm = gg_define_variable(INT128);
+
+        if( nbytes <= 8 )
+          {
+          // Our input is a 64-bit number
+          if( new_var->attr & signable_e )
+            {
+            IF( gg_bitwise_and( gg_cast(SIZE_T, base),
+                                build_int_cst_type(SIZE_T, 0x8000000000000000ULL)),
+                ne_op,
+                gg_cast(SIZE_T, integer_zero_node) )
+              {
+              // Our input is a negative number
+              gg_assign(parm, gg_cast(INT128, integer_minus_one_node));
+              }
+            ELSE
+              {
+              // Our input is a positive number
+              gg_assign(parm, gg_cast(INT128, integer_zero_node));
+              }
+            ENDIF
+            }
+          else
+            {
+            // This is a 64-bit positive number:
+            gg_assign(parm, gg_cast(INT128, integer_zero_node));
+            }
+          }
+        // At this point, parm has been set to 0 or -1
+
+        gg_memcpy(gg_get_address_of(parm),
+                  gg_get_address_of(base),
+                  build_int_cst_type(SIZE_T, nbytes));
+
+        tree array_type = build_array_type_nelts(UCHAR, new_var->data.capacity);
+        tree data_decl_node = gg_define_variable( array_type,
+                                                  NULL,
+                                                  vs_static);
+        gg_assign( member(new_var->var_decl_node, "data"),
+                          gg_get_address_of(data_decl_node) );
+
+        // And then move it into place
+        gg_call(VOID,
+                "__gg__assign_value_from_stack",
+                gg_get_address_of(new_var->var_decl_node),
+                parm,
+                NULL_TREE);
+        // We now have to handle an oddball situation.  It's possible we are
+        // dealing with
+        //
+        //    linkage section.
+        //    01 var1
+        //    01 var2 redefines var1
+        //
+        // If so, we have to give var2::data_pointer the same value as
+        // var1::data_pointer
+        //
+        size_t our_index = symbol_index(symbol_elem_of(new_var));
+        size_t next_index  = our_index + 1;
+        // Look ahead in the symbol table for the next LEVEL01/77
+        for(;;)
+          {
+          symbol_elem_t *e = symbol_at(next_index);
+          if( e->type != SymField )
+            {
+            break;
+            }
+          cbl_field_t *next_var = cbl_field_of(e);
+          if( !next_var )
+            {
+            break;
+            }
+          if( next_var->level == LEVEL01 || next_var->level == LEVEL77 )
+            {
+            if( next_var->parent == our_index )
+              {
+              gg_assign(member(next_var->var_decl_node, "data"),
+                        member(new_var->var_decl_node, "data"));
+              }
+            break;
+            }
+          next_index += 1;
+          }
+        }
+      else
+        {
+        // 'parameter' is a reference, so it it becomes the data member of
+        // the cblc_field_t COBOL variable.
+        gg_assign(member(args[i].field()->var_decl_node, "data"), base);
+
+        // We need to apply base + offset to the LINKAGE variable
+        // and all of its children
+        propogate_linkage_offsets( args[i].field(), base );
+        }
+      }
+    }
+  }
+
 void
 parser_division(cbl_division_t division,
                 cbl_field_t *returning,
@@ -7187,273 +7457,6 @@ parser_division(cbl_division_t division,
     // length.  We establish those lengths based on the types of the target
     // for each USING.
 
-    for(size_t i=0; i<nusing; i++)
-      {
-      // This code is relevant at compile time.  It takes each
-      // expected formal parameter and tacks it onto the end of the
-      // function's arguments chain.
-
-      sprintf(ach, "_p_%s", args[i].refer.field->name);
-
-      size_t nbytes = 0;
-      tree par_type = tree_type_from_field_type(args[i].refer.field, nbytes);
-      if( par_type == FLOAT )
-        {
-        par_type = SSIZE_T;
-        }
-      if( par_type == DOUBLE )
-        {
-        par_type = SSIZE_T;
-        }
-      if( par_type == FLOAT128 )
-        {
-        par_type = INT128;
-        }
-      chain_parameter_to_function(current_function->function_decl, par_type, ach);
-      }
-
-    if( nusing )
-      {
-      // During the call, we saved the parameter_count and an array of variable
-      // lengths.  We need to look at those values if, and only if, one or more
-      // of our USING arguments has an OPTIONAL flag or if one of our targets is
-      // marked as VARYING.
-      bool check_for_parameter_count = false;
-      for(size_t i=0; i<nusing; i++)
-        {
-        if( args[i].optional )
-          {
-          check_for_parameter_count = true;
-          break;
-          }
-        if( args[i].refer.field->attr & any_length_e )
-          {
-          check_for_parameter_count = true;
-          break;
-          }
-        }
-
-      if( check_for_parameter_count )
-        {
-        IF( var_decl_call_parameter_signature,
-            eq_op,
-            gg_cast(CHAR_P, current_function->function_address) )
-          {
-          // We know to use var_decl_call_parameter_count, so unflag this
-          // pointer to avoid problems in the ridiculous possibility of
-          // COBOL-A calls C_B calls COBOL_A
-          gg_assign(var_decl_call_parameter_signature,
-                    gg_cast(CHAR_P, null_pointer_node));
-          }
-        ELSE
-          {
-          // We were apparently called by a C routine, not a COBOL routine, so
-          // make sure we don't get shortchanged by a count left behind from an
-          // earlier COBOL call.
-          gg_assign(var_decl_call_parameter_count,
-                    build_int_cst_type(INT, A_ZILLION));
-          }
-        ENDIF
-        }
-      else
-        {
-        // None of our parameters require a count, so make sure we don't get
-        // bamboozled by a count left behind from an earlier COBOL call.
-        gg_assign(var_decl_call_parameter_count,
-                  build_int_cst_type(INT, A_ZILLION));
-        }
-
-      // There are 'nusing' elements in the PROCEDURE DIVISION USING list.
-
-      tree parameter = NULL_TREE;
-      tree rt_i = gg_define_int();
-      for(size_t i=0; i<nusing; i++)
-        {
-        // And this compiler code generates run-time execution code. The
-        // generated code picks up, at run time, the variable we just
-        // established in the chain at compile time.
-
-        // It makes more sense if you don't think about it too hard.
-
-        // We need to be able to restore prior arguments when doing recursive
-        // calls:
-        IF( member(args[i].refer.field->var_decl_node, "data"),
-            ne_op,
-            gg_cast(UCHAR_P, null_pointer_node) )
-          {
-          gg_call(VOID,
-                  "__gg__push_local_variable",
-                  gg_get_address_of(args[i].refer.field->var_decl_node),
-                  NULL_TREE);
-          }
-        ELSE
-          ENDIF
-
-        tree base = gg_define_variable(UCHAR_P);
-        gg_assign(rt_i, build_int_cst_type(INT, i));
-        //gg_printf("The rt_i counter is %d\n", rt_i, NULL_TREE);
-        IF( rt_i, lt_op , var_decl_call_parameter_count )
-          {
-          if( i == 0 )
-            {
-            // This is the first parameter.
-            parameter = DECL_ARGUMENTS(current_function->function_decl);
-            }
-          else
-            {
-            // These are subsequent parameters
-            parameter = TREE_CHAIN(parameter);
-            }
-          gg_assign(base, gg_cast(UCHAR_P, parameter));
-
-          if( args[i].refer.field->attr & any_length_e )
-            {
-            // gg_printf("side channel: Length of \"%s\" is %ld\n",
-                      // member(args[i].refer.field->var_decl_node, "name"),
-                      // gg_array_value(var_decl_call_parameter_lengths, rt_i),
-                      // NULL_TREE);
-
-            // Get the length from the global lengths[] side channel.  Don't
-            // forget to use the length mask on the table value.
-            gg_assign(member(args[i].refer.field->var_decl_node, "capacity"),
-                      gg_array_value(var_decl_call_parameter_lengths, rt_i));
-            }
-          }
-        ELSE
-          {
-          gg_assign(base, gg_cast(UCHAR_P, null_pointer_node));
-          }
-          ENDIF
-
-        // Arriving here means that we are processing an instruction like
-        // this:
-        // PROCEDURE DIVISION USING using[0] using[1] ... using using[nusing-1]
-
-        // When __gg__call_parameter_count is equal to A_ZILLION, then this is
-        // an OTHER-TO-COBOL call and the var_decl_call_parameter_lengths array
-        // is not valid
-
-        cbl_ffi_crv_t crv = args[i].crv;
-        cbl_field_t *new_var = args[i].refer.field;
-
-        if( crv == by_value_e )
-          {
-          switch(new_var->type)
-            {
-            case FldGroup:
-            case FldAlphanumeric:
-            case FldAlphaEdited:
-            case FldNumericEdited:
-              crv = by_reference_e;
-              break;
-            default:
-              break;
-            }
-          }
-
-        if( crv == by_value_e )
-          {
-          // 'parameter' is the 64-bit or 128-bit value that was placed on the stack
-
-          size_t nbytes;
-          tree_type_from_field_type(new_var, nbytes);
-          tree parm = gg_define_variable(INT128);
-
-          if( nbytes <= 8 )
-            {
-            // Our input is a 64-bit number
-            if( new_var->attr & signable_e )
-              {
-              IF( gg_bitwise_and( gg_cast(SIZE_T, base),
-                                  build_int_cst_type(SIZE_T, 0x8000000000000000ULL)),
-                  ne_op,
-                  gg_cast(SIZE_T, integer_zero_node) )
-                {
-                // Our input is a negative number
-                gg_assign(parm, gg_cast(INT128, integer_minus_one_node));
-                }
-              ELSE
-                {
-                // Our input is a positive number
-                gg_assign(parm, gg_cast(INT128, integer_zero_node));
-                }
-              ENDIF
-              }
-            else
-              {
-              // This is a 64-bit positive number:
-              gg_assign(parm, gg_cast(INT128, integer_zero_node));
-              }
-            }
-          // At this point, parm has been set to 0 or -1
-
-          gg_memcpy(gg_get_address_of(parm),
-                    gg_get_address_of(base),
-                    build_int_cst_type(SIZE_T, nbytes));
-
-          tree array_type = build_array_type_nelts(UCHAR, new_var->data.capacity);
-          tree data_decl_node = gg_define_variable( array_type,
-                                                    NULL,
-                                                    vs_static);
-          gg_assign( member(new_var->var_decl_node, "data"),
-                            gg_get_address_of(data_decl_node) );
-
-          // And then move it into place
-          gg_call(VOID,
-                  "__gg__assign_value_from_stack",
-                  gg_get_address_of(new_var->var_decl_node),
-                  parm,
-                  NULL_TREE);
-          // We now have to handle an oddball situation.  It's possible we are
-          // dealing with
-          //
-          //    linkage section.
-          //    01 var1
-          //    01 var2 redefines var1
-          //
-          // If so, we have to give var2::data_pointer the same value as
-          // var1::data_pointer
-          //
-          size_t our_index = symbol_index(symbol_elem_of(new_var));
-          size_t next_index  = our_index + 1;
-          // Look ahead in the symbol table for the next LEVEL01/77
-          for(;;)
-            {
-            symbol_elem_t *e = symbol_at(next_index);
-            if( e->type != SymField )
-              {
-              break;
-              }
-            cbl_field_t *next_var = cbl_field_of(e);
-            if( !next_var )
-              {
-              break;
-              }
-            if( next_var->level == LEVEL01 || next_var->level == LEVEL77 )
-              {
-              if( next_var->parent == our_index )
-                {
-                gg_assign(member(next_var->var_decl_node, "data"),
-                          member(new_var->var_decl_node, "data"));
-                }
-              break;
-              }
-            next_index += 1;
-            }
-          }
-        else
-          {
-          // 'parameter' is a reference, so it it becomes the data member of
-          // the cblc_field_t COBOL variable.
-          gg_assign(member(args[i].field()->var_decl_node, "data"), base);
-
-          // We need to apply base + offset to the LINKAGE variable
-          // and all of its children
-          propogate_linkage_offsets( args[i].field(), base );
-          }
-        }
-      }
-
     gg_call(VOID,
             "__gg__pseudo_return_bookmark",
           NULL_TREE);
@@ -7504,6 +7507,25 @@ parser_division(cbl_division_t division,
     // logic for backing up one line, which is needed to correctly step through
     // COBOL code with GDB-COBOL.  So, we clear it here.
     current_location_minus_one_clear();
+
+    // It is at this point that we check to see if the call to this function
+    // is a re-entry because of an ENTRY statement:
+
+    IF( var_decl_entry_label, ne_op, null_pointer_node )
+      {
+      // This is an ENTRY re-entry.  The processing of USING variables was
+      // done in parser_entry, so now we jump to the label
+      static tree loc = gg_define_variable(VOID_P, vs_static);
+      gg_assign(loc, var_decl_entry_label);
+      gg_assign(var_decl_entry_label, gg_cast(VOID_P, null_pointer_node));
+      gg_goto(loc);
+      }
+    ELSE
+      {
+      }
+      ENDIF
+
+    establish_using(nusing, args);
     }
   }
 
@@ -9683,7 +9705,10 @@ parser_file_add(struct cbl_file_t *file)
           build_int_cst_type(INT, (int)file->optional),
           build_int_cst_type(SIZE_T, varies.min),
           build_int_cst_type(SIZE_T, varies.max),
-          build_int_cst_type(INT, (int)file->codeset.encoding),
+/*  Right now, file->codeset.encoding is not being set properly.  Remove this
+    comment and fix the following code when that's repaired.  */
+//          build_int_cst_type(INT, (int)file->codeset.encoding),
+          build_int_cst_type(INT, current_encoding(encoding_display_e)),
           build_int_cst_type(INT, (int)file->codeset.alphabet),
           NULL_TREE);
   file->var_decl_node = new_var_decl;
@@ -9776,7 +9801,7 @@ parser_file_open( struct cbl_file_t *file, int mode_char )
     gg_call( CHAR_P,
              "__gg__convert_encoding",
              psz,
-             build_int_cst_type(INT, 
+             build_int_cst_type(INT,
                                 field_of_name->codeset.encoding),
              build_int_cst_type(INT,
                                 DEFAULT_CHARMAP_SOURCE),
@@ -13274,7 +13299,9 @@ create_and_call(size_t narg,
     {
     // Because no explicit returning value is expected, we just call it.  We
     // expect COBOL routines to set RETURN-CODE when they think it necessary.
+    push_program_state();
     gg_append_statement(call_expr);
+    pop_program_state();
     }
 
   for( size_t i=0; i<narg; i++ )
@@ -13482,10 +13509,79 @@ parser_entry_activate( size_t iprog, const cbl_label_t *declarative )
   assert(iprog == symbol_elem_of(declarative)->program);
   }
 
-// Define ENTRY point with alternative LINKAGE
+static tree entry_goto;
+static tree entry_label;
+static tree entry_addr;
+
 void
-parser_entry( cbl_field_t */*name*/, size_t /*narg*/, cbl_ffi_arg_t */*args*/ )
+parser_entry( const cbl_field_t *name, size_t nusing, cbl_ffi_arg_t *args )
   {
+  // We are implementing the ENTRY statement, which creates an alternative
+  // entry point into the current program-id.  There is no actual way to do
+  // that literally.  So, we are going to create a separate routine that sets
+  // things up and then calls the current routine with the information it needs
+  // to transfer processing to the ENTRY point.
+
+  SHOW_PARSE
+    {
+    SHOW_PARSE_HEADER
+    SHOW_PARSE_FIELD( " ENTRY ", name)
+    SHOW_PARSE_END
+    }
+
+  // Get the name of the program that contains the ENTRY statement.
+  char *name_of_parent = xstrdup(current_function->our_name);
+
+  // Get the name of the ENTRY point.
+  // cppcheck-suppress nullPointerRedundantCheck
+  char *psz = cobol_name_mangler(name->data.initial);
+
+  // Create a goto/label pair.  The label will be set up here; the goto will
+  // be used when we re-enter the containing function:
+
+  gg_create_goto_pair(&entry_goto,
+                      &entry_label,
+                      &entry_addr);
+
+  // Start creating the ENTRY function.
+  tree function_decl = gg_define_function( VOID,
+                                           psz,
+                                           psz,
+                                           NULL_TREE);
+  free(psz);
+
+  // Modify the default settings for this entry point
+    TREE_ADDRESSABLE(function_decl) = 0;
+    TREE_USED(function_decl) = 0;
+    TREE_NOTHROW(function_decl) = 0;
+    TREE_STATIC(function_decl) = 1;
+    DECL_EXTERNAL (function_decl) = 0;
+    TREE_PUBLIC (function_decl) = 1;
+    DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT(function_decl) = 1;
+
+  // When the ENTRY function point is called, we process its "using"
+  // parameters:
+  establish_using(nusing, args);
+
+  // Put the entry_label into the global variable that will be picked up
+  // when the containing program-id is re-entered:
+  gg_assign(var_decl_entry_label, entry_addr);
+
+  // Get the function address of the containing function.
+  tree gfa = gg_get_function_address(VOID, name_of_parent);
+  free(name_of_parent);
+
+  // Call the containing function
+  gg_append_statement(gg_call_expr_list(VOID,
+                                        gfa,
+                                        0,
+                                        NULL));
+  // We are done with the ENTRY function:
+  gg_finalize_function();
+
+  // Lay down the address of the label that matches var_decl_entry_label;
+  // the containing program-id will jump to this point.
+  gg_append_statement(entry_label);
   }
 
 void
@@ -14522,7 +14618,7 @@ mh_source_is_literalN(cbl_refer_t &destref,
         // __gg__string_to_alpha_edited expects the source string to be in
         // the same encoding as the target:
         size_t len = strlen(sourceref.field->data.initial);
-        char *src = 
+        char *src =
          static_cast<char *>(xmalloc(len+1));
         memcpy( src,
                 sourceref.field->data.initial,
index b86be8e97909837db29943a214420911256cf8c5..1aafc651a2b0fc50031e6bc608baaf681c708e52 100644 (file)
@@ -558,8 +558,9 @@ void parser_call( cbl_refer_t name,
 
 void parser_entry_activate( size_t iprog, const cbl_label_t *declarative );
 
-void parser_entry( cbl_field_t *name,
-                   size_t narg = 0, cbl_ffi_arg_t args[] = NULL);
+void parser_entry( const cbl_field_t *name,
+                   size_t narg = 0,
+                   cbl_ffi_arg_t args[] = NULL);
 
 bool is_ascending_key(const cbl_refer_t& key);
 
index 3ad33442119c8fb505d553543ba4e7112302c2a2..f3642f2d736f4277b844d4ac5723235f17d183d7 100644 (file)
@@ -1830,7 +1830,10 @@ gg_build_logical_expression(tree operand_a,
   }
 
 void
-gg_create_goto_pair(tree *goto_expr, tree *label_expr, tree *label_addr, const char *name)
+gg_create_goto_pair(tree *goto_expr,
+                    tree *label_expr,
+                    tree *label_addr,
+                    const char *name)
   {
   // We are going to create a pair of expressions for our
   // caller.  They are a matched set of goto/label expressions,
@@ -1886,16 +1889,6 @@ gg_create_goto_pair(tree *goto_expr,
   *label_addr = gg_get_address_of(*label_decl);
   }
 
-void
-gg_goto_label_decl(tree label_decl)
-  {
-  tree goto_expr  = build1_loc( gg_token_location(),
-                                GOTO_EXPR,
-                                void_type_node,
-                                label_decl);
-  gg_append_statement(goto_expr);
-  }
-
 void
 gg_create_goto_pair(tree *goto_expr, tree *label_expr)
   {
index 96e69dd3ac7096d3865e4bb3e1f2f6ab22337385..e785ac7819af278805778c236825c016137ca6c5 100644 (file)
@@ -495,7 +495,6 @@ void gg_create_goto_pair( tree *goto_expr,
                           tree *label_expr,
                           tree *label_addr,
                           tree *label_decl);
-void gg_goto_label_decl(tree label_decl);
 
 // Used for implementing SECTIONS and PARAGRAPHS.  When you have a
 // void *pointer = &&label, gg_goto is the same as
index 33057ff934542810602c32f3d2e93d09a96e296b..56b6b83728b55c3c5e5ed5186a6deaf74dd0ca06 100644 (file)
@@ -50,8 +50,6 @@
 #include "../../libgcobol/exceptl.h"
 #include "exceptg.h"
 
-bool internal_codeset_is_ebcdic() { return gcobol_feature_internal_ebcdic(); }
-
 bool exception_location_active = true;
 bool skip_exception_processing = true;
 
@@ -107,8 +105,13 @@ tree var_decl_treeplet_4s; // SIZE_T_P                , "__gg__treeplet_4s"
 // wasn't successful figuring out how to create an actual NOP assembly language
 // instruction, I instead gg_assign(var_decl_nop, integer_zero_node)
 tree var_decl_nop;                // int         __gg__nop;
+
+// Indicates which routine main() called
 tree var_decl_main_called;        // int         __gg__main_called;
 
+// Indicates the target label for an ENTRY statement
+tree var_decl_entry_label; // void* __gg__entry_label
+
 #if 0
 #define REFER(a)
 #else
index e53e11a46bb26ae1304a2228d19891455f13f58c..251b1c11631ba7c2d29570fe23ca4db2d02fa2dc 100644 (file)
@@ -30,8 +30,6 @@
 #ifndef _GENUTIL_H_
 #define _GENUTIL_H_
 
-bool internal_codeset_is_ebcdic();
-
 extern bool exception_location_active;
 extern bool skip_exception_processing;
 
@@ -79,9 +77,9 @@ extern tree var_decl_treeplet_3s; // SIZE_T_P                , "__gg__treeplet_3
 extern tree var_decl_treeplet_4f; // cblc_field_pp_type_node , "__gg__treeplet_4f"
 extern tree var_decl_treeplet_4o; // SIZE_T_P                , "__gg__treeplet_4o"
 extern tree var_decl_treeplet_4s; // SIZE_T_P                , "__gg__treeplet_4s"
-
 extern tree var_decl_nop;         // int __gg__nop
 extern tree var_decl_main_called; // int __gg__main_called
+extern tree var_decl_entry_label; // void* __gg__entry_label
 
 int       get_scaled_rdigits(cbl_field_t *field);
 int       get_scaled_digits(cbl_field_t *field);
index d575119ba2873edef91e61ce0bdd9b8ee45d1788..b6f4a37f6797f8e0102ced3445f053fea99792b2 100644 (file)
@@ -1643,7 +1643,7 @@ symbols_alphabet_set( size_t program, const char name[]) {
   };
 
   // Define alphabets for codegen.
-  std::for_each(symbols_begin(), symbols_end(), alpha() );
+  std::for_each(symbols_begin(program), symbols_end(), alpha() );
 
   // Set collation sequence before parser_symbol_add.
   if( name ) {
index ea607db4dbb697e3d61694d63d806ac2d0b59023..b24283ae1b9f668b07077abf0a9a386c5ee20274 100644 (file)
@@ -503,6 +503,13 @@ const char * __gg__encoding_iconv_name( cbl_encoding_t encoding );
 
 bool is_elementary( enum cbl_field_type_t type );
 
+// These were introduced to discourage the use of 
+//    current_encoding('A') and current_encoding('N')
+enum
+  {
+  encoding_display_e  = 'A',
+  encoding_national_e = 'N'
+  };
 cbl_encoding_t current_encoding( char a_or_n );
 
 /*  In cbl_field_t:
index 5d43f0b756ab14c643ac541a754bb9f59d57ba22..61481a64d3626bfb9f11e6c20c396b702374bf09 100644 (file)
@@ -94,13 +94,6 @@ char *__gg__ct_currency_signs[256];  // Compile-time currency signs
 // And we will take some pains to figure out if the source code file was done
 // as UTF-8; if not, we will assume 1252/8859-1
 
-// __gg__ebcdic_codeset_in_use is the ultimate determinator of whether the
-// internal codeset is ASCII/CP1252 or EBCDIC/CP1140.
-bool __gg__ebcdic_codeset_in_use = false ;
-
-static text_codeset_t source_codeset  = cs_cp1252_e;
-static text_codeset_t console_codeset = cs_default_e;
-
 #define UNICODE_REPLACEMENT 0xFFFD  // This a white question mark in a black diamond
 #define ASCII_REPLACEMENT 0x87     // In CP1252, 0x87 is a double-dagger
 
@@ -235,74 +228,6 @@ __gg__ebcdic_to_cp1252_collation[256] =
     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0xFF,
     };
 
-
-// Here is the list of function pointers establish which ones of the paired
-// possibilities of conversion routines are actually in use.
-
-extern "C"
-void __gg__set_internal_codeset(int use_ebcdic)
-    {
-    __gg__ebcdic_codeset_in_use = !!use_ebcdic;
-    }
-
-extern "C"
-void __gg__text_conversion_override(text_device_t device,
-                                    text_codeset_t codeset)
-    {
-    // Establish the default sourcecode and console codesets, and
-    // establish the codeset conversion routines:
-
-    switch(device)
-        {
-        case td_default_e:
-          {
-          // We are setting our codesets to the defaults
-
-          // First, sort out the console:
-
-          // It is my understanding that the environment variable LANG is
-          // supposed to be set by the terminal to indicate the terminal's
-          // current character set.  Let's use that as the winner, even if
-          // that's not quite the way locale(3) works.
-          const char *envLANG = getenv("LANG");
-          if( !envLANG )
-            {
-            // This is odd.  No "LANG"?
-            envLANG = setlocale(LC_CTYPE, NULL);
-            }
-          if( !envLANG )
-            {
-            // This is even more odd. Pick something as a backup to the backup
-            envLANG = "UTF-8";
-            }
-          if( envLANG )
-            {
-            if( strcasestr(envLANG, "UTF-8") )
-              {
-              console_codeset = cs_utf8_e;
-              }
-            else
-              {
-              // If it isn't UTF-8, then figure on it being CP1252 as a
-              // convenient way of specifying an SBC codeset.
-              console_codeset  = cs_cp1252_e;
-              }
-            }
-          break;
-          }
-
-        case td_sourcecode_e:
-            // Explicitly set the source code codeset:
-            source_codeset = codeset;
-            break;
-
-        case td_console_e:
-            // Explicitly set the console codeset:
-            console_codeset = codeset;
-            break;
-        }
-    }
-
 static encodings_t encodings[] = {
   { iconv_437_e, "437" },
   { iconv_500_e, "500" },
index 15be0ea1bc08ce843784cbe152d0c958148736aa..4abbfd06147348198020ec6b1951c2ca071dd278 100644 (file)
@@ -112,8 +112,6 @@ extern char **__gg__currency_signs       ;
 extern int    __gg__default_currency_sign;
 extern char  *__gg__ct_currency_signs[256];  // Compile-time currency signs
 
-extern bool __gg__ebcdic_codeset_in_use;
-
 #define NULLCH ('\0')
 #define DEGENERATE_HIGH_VALUE 0xFF
 #define DEGENERATE_LOW_VALUE 0x00
@@ -202,21 +200,6 @@ extern bool __gg__ebcdic_codeset_in_use;
 #define ascii_newline          ((uint8_t)('\n'))
 #define ascii_return           ((uint8_t)('\r'))
 
-enum text_device_t
-    {
-    td_default_e,
-    td_sourcecode_e,
-    td_console_e,
-    };
-
-enum text_codeset_t
-    {
-    cs_default_e,
-    cs_utf8_e,
-    cs_cp1252_e,
-    cs_cp1140_e
-    };
-
 extern unsigned char __gg__data_space[1]       ;
 extern unsigned char __gg__data_low_values[1]  ;
 extern unsigned char __gg__data_zeros[1]       ;
@@ -234,19 +217,6 @@ extern const unsigned short __gg__cp1140_to_cp1252_values[256];
 extern const unsigned short __gg__cp1252_to_ebcdic_collation[256];
 extern const unsigned short __gg__ebcdic_to_cp1252_collation[256];
 
-// As described above, we have a number of operations we need to accomplish. But
-// the actual routines are dependent on whether EBCDIC or ASCII is in use. We
-// implement that by having a function pointer for each function; those pointers
-// are established when the __gg__ebcdic_codeset_in_use variable is established.
-
-// These routines convert a single ASCII character to either ASCII or EBCDIC
-
-extern "C" void __gg__set_internal_codeset(int use_ebcdic);
-
-extern "C"
-void __gg__text_conversion_override(text_device_t device,
-                                    text_codeset_t codeset);
-
 const char * __gg__encoding_iconv_name( cbl_encoding_t encoding );
 cbl_encoding_t __gg__encoding_iconv_type( const char *name );
 
index 6d3bb5db84a3fccca91d44fd3e0d5420b6f222b4..16d75b0f186411b6795925f19861d9b74751277d 100644 (file)
@@ -330,12 +330,6 @@ __gg__file_init(
   {
   if( !(file->flags & file_flag_initialized_e) )
     {
-    if( encoding != iconv_CP1140_e && __gg__ebcdic_codeset_in_use )
-      {
-      // This code is to be eliminated when 'encoding' is valid.
-      encoding = iconv_CP1140_e;
-      }
-
     charmap_t *charmap = __gg__get_charmap(encoding);
 
     file->name                = strdup(name);
index c355051e43aab067b770264a0347ad34294e9b75..3d1161c8576f2825343260cebe204215db8fef26 100644 (file)
@@ -139,6 +139,7 @@ int         __gg__default_compute_error       = 0    ;
 int         __gg__rdigits                     = 0    ;
 int         __gg__nop                         = 0    ;
 int         __gg__main_called                 = 0    ;
+void       *__gg__entry_label                 = NULL ;
 cbl_encoding_t __gg__console_encoding         = no_encoding_e    ;
 
 // During SORT operations, we don't want the end-of-file condition, which
@@ -484,16 +485,7 @@ struct program_state
 
     memset(rt_currency_signs, 0, sizeof(rt_currency_signs));
 
-    // The default collating sequence:
-    if( __gg__ebcdic_codeset_in_use )
-      {
-      rt_collation = __gg__cp1140_to_cp1252_values;
-      }
-    else
-      {
-      rt_collation = __gg__one_to_one_values;
-      }
-//    rt_collation = __gg__one_to_one_values;
+    rt_collation = __gg__one_to_one_values;
     rt_program_name = NULL;
     }
 
@@ -694,21 +686,13 @@ void
 __gg__pop_program_state()
   {
   program_states.pop_back();
-
-// #define decimal_point        (program_states.back().rt_decimal_point)
-// #define decimal_separator    (program_states.back().rt_decimal_separator)
-// #define quote_character      (program_states.back().rt_quote_character)
-// #define low_value_character  (program_states.back().rt_low_value_character)
-// #define high_value_character (program_states.back().rt_high_value_character)
-
   __gg__decimal_point        = program_states.back().rt_decimal_point        ;
   __gg__decimal_separator    = program_states.back().rt_decimal_separator    ;
   __gg__quote_character      = program_states.back().rt_quote_character      ;
   __gg__low_value_character  = program_states.back().rt_low_value_character  ;
   __gg__high_value_character = program_states.back().rt_high_value_character ;
   __gg__currency_signs       = program_states.back().rt_currency_signs       ;
-
-}
+  }
 
 static
 int
@@ -10733,7 +10717,8 @@ __gg__set_pointer(cblc_field_t       *target,
 
 extern "C"
 void
-__gg__alphabet_use( cbl_encoding_t encoding,
+__gg__alphabet_use( cbl_encoding_t alphabetic_encoding,
+                    cbl_encoding_t encoding,
                     size_t alphabet_index)
   {
   // We simply replace the values in the current program_state.  If the
@@ -10743,26 +10728,35 @@ __gg__alphabet_use( cbl_encoding_t encoding,
   if( program_states.empty() )
     {
     // When there is no DATA DIVISION, program_states can be empty when
-    // we arrive here.  So, we need to remedy that:
+    // we arrive here.  So, we need to remedy that.
     initialize_program_state();
     }
 
+  const charmap_t *charmap_alphabetic = __gg__get_charmap(alphabetic_encoding);
+
   switch( encoding )
     {
     case ASCII_e:
     case iso646_e:
+      // This is one of the very common standard situations; where we are using
+      // something like a CP1252 Western European ASCII-like character set.
+
       __gg__low_value_character  = DEGENERATE_LOW_VALUE;
       __gg__high_value_character = DEGENERATE_HIGH_VALUE;
 
       program_states.back().rt_low_value_character   = DEGENERATE_LOW_VALUE;
       program_states.back().rt_high_value_character  = DEGENERATE_HIGH_VALUE;
 
-      if( !__gg__ebcdic_codeset_in_use )
+      if( !charmap_alphabetic->is_like_ebcdic() )
         {
+        // The codeset is ascii-like, and the collation is ascii, so we use
+        // one-to-one values:
         program_states.back().rt_collation = __gg__one_to_one_values;
         }
       else
         {
+        // The codeset is ebcdic-like, but the collation is specified as
+        // ascii-like.  So, we need that collation:
         program_states.back().rt_collation = __gg__ebcdic_to_cp1252_collation;
         }
 
@@ -10774,12 +10768,16 @@ __gg__alphabet_use( cbl_encoding_t encoding,
 
       program_states.back().rt_low_value_character   = DEGENERATE_LOW_VALUE;
       program_states.back().rt_high_value_character  = DEGENERATE_HIGH_VALUE;
-      if( __gg__ebcdic_codeset_in_use )
+      if( charmap_alphabetic->is_like_ebcdic() )
         {
+        // The alphanumeric codeset is ebcdic-like, and so is the specified
+        // collation:
         program_states.back().rt_collation = __gg__one_to_one_values;
         }
       else
         {
+        // The alphanumeric codeset is ebcdic-like, but the specified collation
+        // is ascii-like:
         program_states.back().rt_collation = __gg__cp1252_to_ebcdic_collation;
         }
       break;
index 7d28c9013b151e54e75182f47b8e72c2c776dcc7..de4e6f7b35bd28a007608c8a0c860b56373109e3 100644 (file)
@@ -79,6 +79,9 @@ __gg__alphabet_create(  cbl_encoding_t encoding,
 
   if( it == __gg__alphabet_states.end() )
     {
+    // This is an alphabet we don't know about.  So just assume the collation
+    // is the same as the character ordering:
+
     alphabet_state new_state;
     new_state.low_char  = low_char;
     new_state.high_char = high_char;