https://gcc.gnu.org/g:92b6485a75cabaf64f1f74ba7ab73a5204c9d0aa

commit r16-698-g92b6485a75cabaf64f1f74ba7ab73a5204c9d0aa
Author: Robert Dubner <rdub...@symas.com>
Date:   Fri May 16 11:12:04 2025 -0400

    cobol: Eliminate exception "blob"; streamline some code generation.
    
    This eliminates some of the last vestiges of creating a structure at 
host-time
    that is intended for use at target-time.
    
    It removes some unnecessary processing when exceptions are not enabled.
    
    It improves the creation of code that handles table subscripts and refmod
    parameters.
    
    gcc/cobol/ChangeLog:
    
            * cobol1.cc (cobol_langhook_handle_option): Eliminate OPT_M.
            * except.cc (cbl_enabled_exception_t::dump): Formatting.
            (symbol_declaratives_add): Remove.
            (declarative_runtime_match): Change to no-blob processing.
            * exceptg.h (declarative_runtime_match): Change declaration.
            (symbol_declaratives_add): Remove declaration.
            * gcobc: Dialect handling.
            * genapi.cc (parser_compile_ecs): Formatting; add SHOW_IF_PARSE.
            (parser_compile_dcls): Likewise.
            (parser_statement_begin): Avoid unnecessary store_location_stuff() 
call.
            (gg_get_depending_on_value): Streamline 
get_depending_on_value_from_odo().
            (depending_on_value): Likewise.
            (parser_display_field): Formatting.
            (parser_display): Handle case ENV_NAME_e.
            (parser_file_open): Avoid unnecessary store_location_stuff.
            (parser_file_close): Likewise.
            (parser_file_read): Likewise.
            (parser_file_write): Likewise.
            (parser_file_delete): Likewise.
            (parser_file_rewrite): Likewise.
            (parser_file_start): Likewise.
            (parser_intrinsic_subst): Streamline 
get_depending_on_value_from_odo().
            (parser_intrinsic_call_1): Likewise.
            (parser_lsearch_start): Likewise.
            (parser_bsearch_start): Likewise.
            (parser_sort): Likewise.
            (store_location_stuff): Avoid unnecessary assignments.
            (parser_pop_exception): Formatting.
            * genmath.cc (parser_add): Avoid var_decl_default_compute_error 
assignment
            when doing fast_add().
            (parser_subtract): Likewise.
            * genutil.cc (REFER): Macro for analyzing code generation.
            (get_integer_value): Use data_decl_node for integer value from 
FldLiteralN.
            (get_data_offset): Streamline exception code processing.
            (get_and_check_refstart_and_reflen): Likewise.
            (get_depending_on_value_from_odo): Likewise.
            (get_depending_on_value): Likewise.
            (refer_is_clean): Formatting.
            (refer_refmod_length): Streamline exception code processing.
            (refer_fill_depends): Likewise.
            (refer_offset): Likewise.
            (refer_size_dest): Likewise.
            (refer_size_source): Likewise.
            * genutil.h (get_depending_on_value_from_odo): Likewise.
            * lang-specs.h: Options definition.
            * lang.opt: -M as in c.opt.
            * lexio.h: Formatting.
            * parse.y: Expand -dialect suggestions; SECTION SEGMENT messages.
            * parse_ante.h (declarative_runtime_match): Dialect handling.
            (labels_dump): Likewise.
            (class current_tokens_t): Likewise.
            (class prog_descr_t): Make program_index size_t to prevent padding 
bytes.
            * scan.l: POP_FILE directive.
            * scan_ante.h (class enter_leave_t): Better handle line number when
            processing COPY statements.
            * symbols.cc (symbol_elem_cmp): Eliminate SymFunction.
            (symbols_dump): Likewise.
            (symbol_label_section_exists): Likewise.
            * symbols.h (NAME_MAX): Eliminate.  (Was part of SymFunction).
            (dialect_is): Improve dialect handling.
            (dialect_gcc): Likewise.
            (dialect_ibm): Likewise.
            (dialect_gnu): Likewise.
            (enum symbol_type_t): Eliminate SymFunction.
            * util.cc (symbol_type_str): Likewise.
            (class unique_stack): Option -M handling.
            (cobol_set_pp_option): Likewise.
            (parse_file): Likewise.
            * util.h (cobol_set_pp_option): Likewise.
    
    libgcobol/ChangeLog:
    
            * common-defs.h (struct cbl_declarative_t): Eliminate blobl.
            * libgcobol.cc (__gg__set_env_name): Code for 
ENVIRONMENT-NAME/VALUE.
            (__gg__set_env_value): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * cobol.dg/group1/declarative_1.cob: Handle modified exception 
handling.

Diff:
---
 gcc/cobol/cobol1.cc                             |  23 +-
 gcc/cobol/except.cc                             | 111 ++---
 gcc/cobol/exceptg.h                             |   7 +-
 gcc/cobol/gcobc                                 |   2 +-
 gcc/cobol/genapi.cc                             | 128 +++--
 gcc/cobol/genmath.cc                            |  26 +-
 gcc/cobol/genutil.cc                            | 611 +++++++++++++-----------
 gcc/cobol/genutil.h                             |   1 +
 gcc/cobol/lang-specs.h                          |   2 +-
 gcc/cobol/lang.opt                              |   5 +
 gcc/cobol/lexio.h                               |   1 -
 gcc/cobol/parse.y                               |  94 ++--
 gcc/cobol/parse_ante.h                          |  58 ++-
 gcc/cobol/scan.l                                |   2 +-
 gcc/cobol/scan_ante.h                           |  10 +-
 gcc/cobol/symbols.cc                            |  43 +-
 gcc/cobol/symbols.h                             |  40 +-
 gcc/cobol/util.cc                               |  51 +-
 gcc/cobol/util.h                                |   2 +
 gcc/testsuite/cobol.dg/group1/declarative_1.cob |   6 +-
 libgcobol/common-defs.h                         |  17 +-
 libgcobol/libgcobol.cc                          |  55 +++
 22 files changed, 700 insertions(+), 595 deletions(-)

diff --git a/gcc/cobol/cobol1.cc b/gcc/cobol/cobol1.cc
index 3bd21c783ded..63f2b37816d1 100644
--- a/gcc/cobol/cobol1.cc
+++ b/gcc/cobol/cobol1.cc
@@ -20,15 +20,15 @@ along with GCC; see the file COPYING3.  If not see
 
 
 #include "cobol-system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic.h"
-#include "opts.h"
-#include "debug.h"
-#include "langhooks.h"
-#include "langhooks-def.h"
-#include "target.h"
-#include "stringpool.h"
+#include <coretypes.h>
+#include <tree.h>
+#include <diagnostic.h>
+#include <opts.h>
+#include <debug.h>
+#include <langhooks.h>
+#include <langhooks-def.h>
+#include <target.h>
+#include <stringpool.h>
 #include "../../libgcobol/ec.h"
 #include "../../libgcobol/common-defs.h"
 #include "util.h"
@@ -39,7 +39,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "genapi.h"
 #include "../../libgcobol/exceptl.h"
 #include "exceptg.h"
-#include "util.h"
 #include "gengen.h"   // This has some GTY(()) markers
 #include "structs.h"  // This has some GTY(()) markers
 
@@ -357,6 +356,10 @@ cobol_langhook_handle_option (size_t scode,
             copybook_extension_add(cobol_copyext);
             return true;
 
+        case OPT_M:
+           cobol_set_pp_option('M');
+            return true;
+
         case OPT_fstatic_call:
             use_static_call( arg? true : false );
             return true;
diff --git a/gcc/cobol/except.cc b/gcc/cobol/except.cc
index 2118233dafbf..d477139a1e1a 100644
--- a/gcc/cobol/except.cc
+++ b/gcc/cobol/except.cc
@@ -78,10 +78,10 @@ ec_level( ec_type_t ec ) {
 void
 cbl_enabled_exception_t::dump( int i ) const {
   cbl_message(2, "cbl_enabled_exception_t: %2d  {%s, %s, %s, %zu}",
-             i,
-             location? "location" : "    none",
-             ec_type_str(ec),
-             file );
+              i,
+              location? "location" : "    none",
+              ec_type_str(ec),
+              file );
 }
 
 cbl_enabled_exceptions_t enabled_exceptions;
@@ -263,66 +263,6 @@ sort_supers_last( const cbl_declarative_t& a, const 
cbl_declarative_t& b ) {
 }
 
 cbl_field_t * new_temporary_decl();
-
-/*
- * For a program, create a "DECLARATIVES" entry in the symbol table,
- * representing eligible declarative sections in priorty order:
- * in-program first, followed by any global declaratives in parent
- * programs.  These decribe the USE criteria declared for each
- * declarative section.
- *
- * The field's initial value is actually an array of
- * cbl_declarartive_t, in which the first element is unused, except
- * that array[0].section represents the number of elements, starting
- * at array[1].
- *
- * The returned value is the declarative's symbol index.  It is passed
- * to match_exception, which scans it for a declarative whose criteria
- * match the raised exception.  That function returns the
- * cbl_declarative_t::section, which the program then uses to PERFORM
- * that section.
- */
-size_t
-symbol_declaratives_add( size_t program,
-                         const std::list<cbl_declarative_t>& dcls )
-{
-  auto n = dcls.size();
-  if( n == 0 ) return 0;
-
-  auto blob = new cbl_declarative_t[ 1 + n ];
-
-  auto pend = std::copy_if( dcls.begin(), dcls.end(), blob + 1,
-                            choose_declarative(program) );
-
-  std::sort( blob + 1, pend, sort_supers_last );
-
-  // Overload blob[0].section to be the count.
-  blob[0].section = (pend - blob) - 1;
-
-  size_t len = reinterpret_cast<char*>(pend)
-             - reinterpret_cast<char*>(blob);
-  assert(len == (blob[0].section + 1) * sizeof(blob[0]));
-
-  // Construct a "blob" in the symbol table.
-  static int blob_count = 1;
-  char achBlob[32];
-  sprintf(achBlob, "_DECLARATIVE_BLOB%d_", blob_count++);
-
-  cbl_field_data_t data = {};
-  data.memsize = capacity_cast(len);
-  data.capacity = capacity_cast(len);
-  data.initial = reinterpret_cast<char*>(blob);
-  data.picture = reinterpret_cast<char*>(blob);
-  cbl_field_t field = { 0, FldBlob, FldInvalid, constant_e,
-                        0, 0, 0, cbl_occurs_t(), 0, "",
-                        0, {}, data, NULL };
-  strcpy(field.name, achBlob);
-
-  auto e = symbol_field_add(program, &field);
-  parser_symbol_add(cbl_field_of(e));
-  return symbol_index(e);
-}
-
 /*
  * Generate the code to evaluate declaratives.  This is the "secret
  * section" right after END DECLARATIVES.  Its name is
@@ -345,37 +285,42 @@ size_t current_file_index();
 file_status_t current_file_handled_status();
 
 void
-declarative_runtime_match( cbl_field_t *declaratives, cbl_label_t *lave ) {
+declarative_runtime_match( const std::list<cbl_declarative_t>& declaratives,
+                          cbl_label_t *lave )
+{
   if( getenv("GCOBOL_SHOW") )
     {
     fprintf(stderr, "( %d ) %s: \n", cobol_location().first_line, __func__);
     }
   if( getenv("GCOBOL_TRACE") )
     {
-    gg_printf(">>>>>>( %d )(%s) declaratives:%s lave:%s\n",
+    gg_printf(">>>>>>( %d )(%s) declaratives: lave:%s\n",
               build_int_cst_type(INT, cobol_location().first_line),
               gg_string_literal(__func__),
-              gg_string_literal(declaratives->name),
               gg_string_literal(lave->name),
               NULL_TREE);
     }
   static auto yes = new_temporary(FldConditional);
-  static auto psection = new_temporary(FldNumericBin5);
+  static auto isection = new_temporary(FldNumericBin5);
+  static auto index = new_temporary(FldNumericBin5);
 
+  /*
+   * Generate a sequence of COBOL IF statements to match the Declarative's
+   * symbol table index to its performable section.  The entire sequence is
+   * guarded by a runtime IF that evaluates to TRUE only if the "current EC" is
+   * nonzero.  This way, when _DECLARATIVES_EVAL is performed, it does nothing
+   * if no EC was raised.
+   */
   IF( var_decl_exception_code, ne_op, integer_zero_node ) {
-    // Send blob, get declarative section index.
-    auto index = new_temporary(FldNumericBin5);
+    // Get declarative section index matching any raised EC.
     parser_match_exception(index);
-    auto p = declaratives->data.initial;
-    const auto dcls = reinterpret_cast<const cbl_declarative_t *>(p);
-    size_t ndcl = dcls[0].section; // overloaded
 
     // Compare returned index to each section index.
-    for( auto p = dcls + 1; p < dcls + 1 + ndcl; p++ ) {
-      parser_set_numeric( psection, p->section );
-      parser_relop( yes, index, eq_op, psection );
+    for( const auto& dcl : declaratives ) {
+      parser_set_numeric( isection, dcl.section );
+      parser_relop( yes, index, eq_op, isection );
       parser_if( yes );
-      auto section = cbl_label_of(symbol_at(p->section));
+      auto section = cbl_label_of(symbol_at(dcl.section));
       parser_push_exception();
       parser_perform(section);
       parser_pop_exception();
@@ -385,17 +330,15 @@ declarative_runtime_match( cbl_field_t *declaratives, 
cbl_label_t *lave ) {
     }
   }
   ELSE {
-    if( getenv("TRACE1") )
+    if( getenv("GCOBOL_TRACE") )
       {
-       gg_printf(">>>>>>( %d )(%s) __gg__exception_code is zero\n",
-                 build_int_cst_type(INT, cobol_location().first_line),
-                 gg_string_literal(__func__),
-                 NULL_TREE);
+        gg_printf(">>>>>>( %d )(%s) __gg__exception_code is zero\n",
+                  build_int_cst_type(INT, cobol_location().first_line),
+                  gg_string_literal(__func__),
+                  NULL_TREE);
       }
   }
   ENDIF
-
-  parser_label_label(lave);
 }
 
 ec_type_t
diff --git a/gcc/cobol/exceptg.h b/gcc/cobol/exceptg.h
index 1cfb8df4702a..e29e056dbf14 100644
--- a/gcc/cobol/exceptg.h
+++ b/gcc/cobol/exceptg.h
@@ -36,8 +36,8 @@
 extern const char * ec_type_str( ec_type_t type );
 extern ec_disposition_t ec_type_disposition( ec_type_t type );
 
-extern void declarative_runtime_match(cbl_field_t *declaratives,
-                                      cbl_label_t *lave );
+extern void declarative_runtime_match( const std::list<cbl_declarative_t>& 
declaratives,
+                                      cbl_label_t *lave );
 
 static inline ec_disposition_t
 ec_implemented( ec_disposition_t disposition ) {
@@ -96,9 +96,6 @@ class exception_turn_t {
 
 };
 
-size_t symbol_declaratives_add( size_t program,
-                                const std::list<cbl_declarative_t>& dcls );
-
 #endif
 
 
diff --git a/gcc/cobol/gcobc b/gcc/cobol/gcobc
index 1d469ed926ca..6154c788e1cf 100755
--- a/gcc/cobol/gcobc
+++ b/gcc/cobol/gcobc
@@ -73,7 +73,7 @@ fi
 
 exit_status=0
 skip_arg=
-opts="$copydir ${dialect:--dialect mf} $includes"
+opts="-dialect gnu $copydir ${dialect:--dialect mf} $includes"
 mode=-shared
 
 incomparable="has no comparable gcobol option"
diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index 70df86a0ffaf..1ed4cef0801f 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -80,6 +80,8 @@ bool bSHOW_PARSE = getenv("GCOBOL_SHOW");
 bool show_parse_sol = true;
 int  show_parse_indent = 0;
 
+static bool sv_is_i_o = false;
+
 #define DEFAULT_LINE_NUMBER 2
 
 #ifdef LINE_TICK
@@ -933,8 +935,20 @@ array_of_long_long(const char *name, const 
std::vector<uint64_t>& vals)
  * Performs the matched declarative, and execution continues with the next
  * statement.
  */
-tree parser_compile_ecs( const std::vector<uint64_t>& ecs )
+tree
+parser_compile_ecs( const std::vector<uint64_t>& ecs )
   {
+  if( ecs.empty() )
+    {
+    SHOW_IF_PARSE(nullptr)
+      {
+      SHOW_PARSE_HEADER
+      SHOW_PARSE_TEXT("ecs is empty");
+      SHOW_PARSE_END
+      }
+    return NULL_TREE;
+    }
+
   char ach[32];
   static int counter = 1;
   sprintf(ach, "_ecs_table_%d", counter++);
@@ -968,12 +982,23 @@ tree parser_compile_ecs( const std::vector<uint64_t>& ecs 
)
  * invoked, and thus the set of active Declaratives.  By passing them for each
  * statement, code generation is relieved of referring to global variable.
  */
-tree parser_compile_dcls( const std::vector<uint64_t>& dcls )
+tree
+parser_compile_dcls( const std::vector<uint64_t>& dcls )
   {
+  if( dcls.empty() )
+    {
+    SHOW_IF_PARSE(nullptr)
+      {
+      SHOW_PARSE_HEADER
+      SHOW_PARSE_TEXT("dcls is empty");
+      SHOW_PARSE_END
+      }
+    return NULL_TREE;
+    }
+
   char ach[32];
   static int counter = 1;
   sprintf(ach, "_dcls_table_%d", counter++);
-
   tree retval =  array_of_long_long(ach, dcls);
   SHOW_IF_PARSE(nullptr)
     {
@@ -983,7 +1008,6 @@ tree parser_compile_dcls( const std::vector<uint64_t>& 
dcls )
     SHOW_PARSE_TEXT(ach);
     SHOW_PARSE_END
     }
-
   TRACE1
     {
     TRACE1_HEADER
@@ -1036,16 +1060,28 @@ parser_statement_begin( const cbl_name_t 
statement_name, tree ecs, tree dcls )
     gg_assign(var_decl_nop, build_int_cst_type(INT, 106));
     }
 
-  store_location_stuff(statement_name);
+  // At this point, if any exception is enabled, we store the location stuff.
+  // Each file I-O routine calls store_location_stuff explicitly, because
+  // those exceptions can't be defeated.
+
+  if( enabled_exceptions.size() )
+    {
+    store_location_stuff(statement_name);
+    }
+
   gg_set_current_line_number(CURRENT_LINE_NUMBER);
 
-  gg_call(VOID,
-          "__gg__set_exception_environment",
-          ecs  ? gg_get_address_of(ecs) : null_pointer_node,
-          dcls ? gg_get_address_of(dcls) : null_pointer_node,
-          NULL_TREE);
-  
+  // if( ecs || dcls || sv_is_i_o )
+    {
+    gg_call(VOID,
+            "__gg__set_exception_environment",
+            ecs  ? gg_get_address_of(ecs) : null_pointer_node,
+            dcls ? gg_get_address_of(dcls) : null_pointer_node,
+            NULL_TREE);
+    }
+
   gcc_assert( gg_trans_unit.function_stack.size() );
+  sv_is_i_o = false;
   }
 
 static void
@@ -1516,42 +1552,28 @@ gg_default_qualification(struct cbl_field_t * /*var*/)
 //  gg_attribute_bit_clear(var, refmod_e);
   }
 
-static void
-gg_get_depending_on_value(tree depending_on, cbl_field_t *current_sizer)
+static
+void
+depending_on_value(tree depending_on, cbl_field_t *current_sizer)
   {
   // We have to deal with the possibility of a DEPENDING_ON variable,
   // and we have to apply array bounds whether or not there is a DEPENDING_ON
   // variable:
 
-  tree occurs_lower = gg_define_variable(LONG, "_lower");
-  tree occurs_upper = gg_define_variable(LONG, "_upper");
-
-  gg_assign(occurs_lower, build_int_cst_type(LONG, 
current_sizer->occurs.bounds.lower));
-  gg_assign(occurs_upper, build_int_cst_type(LONG, 
current_sizer->occurs.bounds.upper));
+//  tree occurs_lower = gg_define_variable(LONG, "_lower");
+//  tree occurs_upper = gg_define_variable(LONG, "_upper");
+//
+//  gg_assign(occurs_lower, build_int_cst_type(LONG, 
current_sizer->occurs.bounds.lower));
+//  gg_assign(occurs_upper, build_int_cst_type(LONG, 
current_sizer->occurs.bounds.upper));
 
   if( current_sizer->occurs.depending_on )
     {
-    // Get the current value of the depending_on data-item:
-    tree value = gg_define_int128();
-    get_binary_value( value,
-                      NULL,
-                      
cbl_field_of(symbol_at(current_sizer->occurs.depending_on)),
-                      size_t_zero_node);
-    gg_assign(depending_on, gg_cast(LONG, value));
-    IF( depending_on, lt_op, occurs_lower )
-    // depending_is can be no less than occurs_lower:
-      gg_assign(depending_on, occurs_lower );
-    ELSE
-      ENDIF
-    IF( depending_on, gt_op, occurs_upper )
-    // depending_is can be no greater than occurs_upper:
-      gg_assign(depending_on, occurs_upper );
-    ELSE
-      ENDIF
+    get_depending_on_value_from_odo(depending_on, current_sizer);
     }
   else
     {
-    gg_assign(depending_on, occurs_upper);
+    gg_assign(depending_on,
+              build_int_cst_type(LONG, current_sizer->occurs.bounds.upper));
     }
   }
 
@@ -5107,7 +5129,7 @@ parser_display_field(cbl_field_t *field)
  *  2.  ARG_VALUE_e, the ARGUMENT-VALUE
  *  3.  ENV_NAME_e, the ENVIRONMENT-NAME
  *  4.  ENV_VALUE_e, the ENVIRONMENT-VALUE
- * that need special care and feeding. 
+ * that need special care and feeding.
  */
 void
 parser_display( const struct cbl_special_name_t *upon,
@@ -5169,6 +5191,18 @@ parser_display( const struct cbl_special_name_t *upon,
         gg_assign(file_descriptor, integer_two_node);
         break;
 
+      case ENV_NAME_e:
+        // This Part I of the slightly absurd method of using DISPLAY...UPON
+        // to fetch, or set, environment variables.
+        gg_call(VOID,
+                "__gg__set_env_name",
+                gg_get_address_of(refs[0].field->var_decl_node),
+                refer_offset(refs[0]),
+                refer_size_source(refs[0]),
+                NULL_TREE);
+         return;
+         break;
+
       default:
         if( upon->os_filename[0] )
           {
@@ -9281,6 +9315,7 @@ parser_file_open( struct cbl_file_t *file, int mode_char )
     quoted_name = true;
     }
 
+  sv_is_i_o = true;
   store_location_stuff("OPEN");
   gg_call(VOID,
           "__gg__file_open",
@@ -9332,6 +9367,7 @@ parser_file_close( struct cbl_file_t *file, 
file_close_how_t how )
   // We are done with the filename.  The library routine will free "filename"
   // memory and set it back to null
 
+  sv_is_i_o = true;
   store_location_stuff("CLOSE");
   gg_call(VOID,
           "__gg__file_close",
@@ -9417,6 +9453,7 @@ parser_file_read( struct cbl_file_t *file,
     where = 1;
     }
 
+  sv_is_i_o = true;
   store_location_stuff("READ");
   gg_call(VOID,
           "__gg__file_read",
@@ -9551,6 +9588,7 @@ parser_file_write( cbl_file_t *file,
     record_area = cbl_field_of(symbol_at(file->default_record));
     }
 
+  sv_is_i_o = true;
   store_location_stuff("WRITE");
   gg_call(VOID,
           "__gg__file_write",
@@ -9620,6 +9658,7 @@ parser_file_delete( struct cbl_file_t *file, bool 
/*sequentially*/ )
     SHOW_PARSE_END
     }
 
+  sv_is_i_o = true;
   store_location_stuff("DELETE");
   gg_call(VOID,
           "__gg__file_delete",
@@ -9676,6 +9715,7 @@ parser_file_rewrite(cbl_file_t *file,
     record_area = cbl_field_of(symbol_at(file->default_record));
     }
 
+  sv_is_i_o = true;
   store_location_stuff("REWRITE");
   gg_call(VOID,
           "__gg__file_rewrite",
@@ -9785,6 +9825,7 @@ parser_file_start(struct cbl_file_t *file,
                       refer_offset(length_ref));
     }
 
+  sv_is_i_o = true;
   store_location_stuff("START");
   gg_call(VOID,
           "__gg__file_start",
@@ -10320,6 +10361,7 @@ parser_intrinsic_subst( cbl_field_t *f,
     TRACE1_END
     }
 
+  sv_is_i_o = true;
   store_location_stuff("SUBSTITUTE");
   unsigned char *control_bytes = (unsigned char *)xmalloc(argc * 
sizeof(unsigned char));
   cbl_refer_t *arg1 = (cbl_refer_t *)xmalloc(argc * sizeof(cbl_refer_t));
@@ -10512,7 +10554,7 @@ parser_intrinsic_call_1( cbl_field_t *tgt,
     if( is_table(ref1.field) && !ref1.nsubscript )
       {
       static tree depending_on = gg_define_variable(LONG, "..pic1_dep");
-      gg_get_depending_on_value(depending_on, ref1.field);
+      depending_on_value(depending_on, ref1.field);
       gg_call(VOID,
               "__gg__int128_to_field",
               gg_get_address_of(tgt->var_decl_node),
@@ -10822,7 +10864,7 @@ parser_lsearch_start(   cbl_label_t *name,
       {
       // Extract the number of elements in that rightmost dimension.
       lsearch->limit = gg_define_variable(LONG);
-      gg_get_depending_on_value(lsearch->limit, current);
+      depending_on_value(lsearch->limit, current);
       break;
       }
     current = parent_of(current);
@@ -11059,7 +11101,7 @@ parser_bsearch_start(   cbl_label_t* name,
 
   // Assign the left and right values:
   gg_assign(bsearch->left, build_int_cst_type(LONG, 1));
-  gg_get_depending_on_value(bsearch->right, current);
+  depending_on_value(bsearch->right, current);
 
   // Create the variable that will take the compare result.
   bsearch->compare_result = gg_define_int();
@@ -11344,7 +11386,7 @@ parser_sort(cbl_refer_t tableref,
   tree ascending = gg_array_of_size_t( total_keys, flattened_ascending );
 
   tree depending_on = gg_define_variable(LONG, "_sort_size");
-  gg_get_depending_on_value(depending_on, table);
+  depending_on_value(depending_on, table);
 
   if( alphabet )
     {
@@ -13389,8 +13431,6 @@ store_location_stuff(const cbl_name_t statement_name)
   if( exception_location_active && !current_declarative_section_name() )
     {
     // We need to establish some stuff for EXCEPTION- function processing
-    gg_assign(var_decl_exception_source_file,
-              gg_string_literal(current_filename.back().c_str()));
 
     gg_assign(var_decl_exception_program_id,
               gg_string_literal(current_function->our_unmangled_name));
@@ -13522,7 +13562,7 @@ parser_pop_exception()
   {
   gg_call(VOID, "__gg__exception_pop", NULL_TREE);
   }
-  
+
 void
 parser_clear_exception()
   {
diff --git a/gcc/cobol/genmath.cc b/gcc/cobol/genmath.cc
index 721aafb236ae..edf3f22f68eb 100644
--- a/gcc/cobol/genmath.cc
+++ b/gcc/cobol/genmath.cc
@@ -756,12 +756,6 @@ parser_add( size_t nC, cbl_num_result_t *C,
     TRACE1_END
     }
 
-  tree compute_error = (tree)compute_error_p;
-  if( compute_error == NULL )
-    {
-    gg_assign(var_decl_default_compute_error, integer_zero_node);
-    compute_error = gg_get_address_of(var_decl_default_compute_error);
-    }
   bool handled = false;
 
   if( fast_add( nC, C,
@@ -772,6 +766,13 @@ parser_add( size_t nC, cbl_num_result_t *C,
     }
   else
     {
+    tree compute_error = (tree)compute_error_p;
+    if( compute_error == NULL )
+      {
+      gg_assign(var_decl_default_compute_error, integer_zero_node);
+      compute_error = gg_get_address_of(var_decl_default_compute_error);
+      }
+
     bool computation_is_float =    is_somebody_float(nA, A)
                                 || is_somebody_float(nC, C);
     // We now start deciding which arithmetic routine we are going to use:
@@ -1452,13 +1453,6 @@ parser_subtract(size_t nC, cbl_num_result_t *C, // C = B 
- A
 
   bool handled = false;
 
-  tree compute_error = (tree)compute_error_p;
-  if( compute_error == NULL )
-    {
-    gg_assign(var_decl_default_compute_error, integer_zero_node);
-    compute_error = gg_get_address_of(var_decl_default_compute_error);
-    }
-
   if( fast_subtract(nC, C,
                     nA, A,
                     nB, B,
@@ -1468,6 +1462,12 @@ parser_subtract(size_t nC, cbl_num_result_t *C, // C = B 
- A
     }
   else
     {
+    tree compute_error = (tree)compute_error_p;
+    if( compute_error == NULL )
+      {
+      gg_assign(var_decl_default_compute_error, integer_zero_node);
+      compute_error = gg_get_address_of(var_decl_default_compute_error);
+      }
     bool computation_is_float =    is_somebody_float(nA, A)
                                 || is_somebody_float(nC, C);
 
diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc
index 3235c380cf82..d0aaf2b3215f 100644
--- a/gcc/cobol/genutil.cc
+++ b/gcc/cobol/genutil.cc
@@ -107,13 +107,13 @@ tree var_decl_nop;                // int         
__gg__nop;
 tree var_decl_main_called;        // int         __gg__main_called;
 
 #if 0
-#define REFER
+#define REFER(a)
 #else
-#define REFER do                                \
+#define REFER(a) do                                \
   {                                             \
   if( getenv("REFER") )                         \
     {                                           \
-    fprintf(stderr, "REFER %s\n", __func__);    \
+    fprintf(stderr, "REFER %s %s\n", __func__, a);    \
     }                                           \
   }while(0);
 #endif
@@ -232,16 +232,17 @@ tree_type_from_digits(size_t digits, int signable)
   }
 
 void
-get_integer_value(tree value,
+get_integer_value(tree value, // We know this is a LONG
                   cbl_field_t *field,
                   tree         offset,
                   bool check_for_fractional_digits)
   {
-  if(field->type == FldLiteralN)
+  if( field->type == FldLiteralN && field->data.rdigits==0 )
     {
+    gg_assign(value, gg_cast(LONG, field->data_decl_node));
+    return;
     }
 
-
   Analyze();
   // Call this routine when you know the result has to be an integer with no
   // rdigits.  This routine became necessary the first time I saw an
@@ -292,15 +293,248 @@ get_any_capacity(cbl_field_t *field)
     }
   }
 
-static tree
-get_data_offset(cbl_refer_t &refer,
-                int *pflags = NULL)
+/*  This routine, used by both get_data_offset and refer_refmod_length,
+    fetches the refmod_from and refmod_length.  If ec-bound-ref-mod checking
+    is enabled, it does those checks and sets the exception condition when they
+    are violated.
+
+    The return value for refstart is the actual offset, that is val(7:3) 
returns
+    the value 7-1, that is, 6.
+    */
+static
+void
+get_and_check_refstart_and_reflen(  tree         refstart,// LONG returned 
value
+                                    tree         reflen,  // LONG returned 
value
+                                    cbl_refer_t &refer)
   {
-  REFER;
-  if( getenv("REFER") )
+  if( !enabled_exceptions.match(ec_bound_ref_mod_e) )
     {
-    fprintf(stderr, "      %s %s\n", refer.field->name, 
refer.field->data.initial);
+    // This is normal operation -- no exception checking.  Thus, we won't
+    // be trying to check for boundaries or integerness.  And the programmer
+    // is accepting the responsibility for bad code:  "If you specify
+    // disaster, disaster is what you get."
+
+    get_integer_value(refstart,
+                      refer.refmod.from->field,
+                      refer_offset(*refer.refmod.from));
+    gg_decrement(refstart);
+
+    if( refer.refmod.len )
+      {
+      // The length was specified, so that's what we return:
+      get_integer_value(reflen,
+                        refer.refmod.len->field,
+                        refer_offset(*refer.refmod.len));
+      }
+    else
+      {
+      // The length was not specified, so we need to return the distance
+      // between refmod.from and the end of the field:
+      gg_assign(reflen, gg_subtract( get_any_capacity(refer.field), refstart) 
);
+      }
+    return;
+    }
+
+  // ec_bound_ref_mode_e checking is enabled:
+
+  get_integer_value(refstart,
+                    refer.refmod.from->field,
+                    refer_offset(*refer.refmod.from),
+                    CHECK_FOR_FRACTIONAL_DIGITS);
+
+  IF( var_decl_rdigits,
+      ne_op,
+      integer_zero_node )
+    {
+    // The value for refstart had non-zero decimal places.  This is an
+    // error condition:
+    set_exception_code(ec_bound_ref_mod_e);
+    gg_assign(refstart, gg_cast(LONG, integer_one_node));
+    gg_assign(var_decl_rdigits, integer_zero_node);
+    }
+  ELSE
+    ENDIF
+
+  // Make refstart zero-based:
+  gg_decrement(refstart);
+
+  IF( refstart, lt_op, build_int_cst_type(LONG, 0 ) )
+    {
+    // A negative value for refstart is an error condition:
+    set_exception_code(ec_bound_ref_mod_e);
+    gg_assign(refstart, gg_cast(LONG, integer_zero_node));
+    // Set reflen to one here, because otherwise it won't be established.
+    gg_assign(reflen, gg_cast(TREE_TYPE(reflen), integer_one_node));
+    }
+  ELSE
+    {
+    IF( refstart, gt_op, gg_cast(TREE_TYPE(refstart), 
get_any_capacity(refer.field)) )
+      {
+      // refstart greater than zero is an error condition:
+      set_exception_code(ec_bound_ref_mod_e);
+      gg_assign(refstart, gg_cast(LONG, integer_zero_node));
+      // Set reflen to one here, because otherwise it won't be established.
+      gg_assign(reflen, gg_cast(TREE_TYPE(reflen), integer_one_node));
+      }
+    ELSE
+      {
+      if( refer.refmod.len )
+        {
+        get_integer_value(reflen,
+                          refer.refmod.len->field,
+                          refer_offset(*refer.refmod.len),
+                          CHECK_FOR_FRACTIONAL_DIGITS);
+        IF( var_decl_rdigits,
+            ne_op,
+            integer_zero_node )
+          {
+          // length is not an integer, which is an error condition
+          set_exception_code(ec_bound_ref_mod_e);
+          gg_assign(reflen, gg_cast(LONG, integer_one_node));
+          gg_assign(var_decl_rdigits, integer_zero_node);
+          }
+        ELSE
+          {
+          // The length is an integer, so we can keep going.
+          IF( reflen, lt_op, gg_cast(LONG, integer_one_node) )
+            {
+            // length is too small, which is an error condition.
+            set_exception_code(ec_bound_ref_mod_e);
+            gg_assign(reflen, gg_cast(LONG, integer_one_node));
+            }
+          ELSE
+            {
+            IF( gg_add(refstart, reflen),
+                gt_op,
+                gg_cast(TREE_TYPE(refstart), get_any_capacity(refer.field)) )
+              {
+              // Start + Length is too large, which yet again is an error
+              // condition
+              set_exception_code(ec_bound_ref_mod_e);
+
+              // Our intentions are honorable.  But at this point, where
+              // we notice that start + length is too long, the
+              // get_data_offset routine has already been run and
+              // it's too late to actually change the refstart.  There are
+              // theoretical solutions to this -- mainly,
+              // get_data_offset needs to check the start + len for
+              // validity.  But I am not going to do it now.  Think of this
+              // as the TODO item.
+              gg_assign(refstart, gg_cast(LONG, integer_zero_node));
+              gg_assign(reflen, gg_cast(LONG, integer_one_node));
+              }
+            ELSE
+              {
+              // There are no problems, so there is no error condition, and
+              // refstart and reflen are correct.
+              }
+              ENDIF
+            }
+            ENDIF
+          }
+          ENDIF
+        }
+      else
+        {
+        // There is no refmod length, so we default to the remaining characters
+        gg_assign(reflen, gg_subtract(get_any_capacity(refer.field),
+                                      refstart));
+        }
+      }
+      ENDIF
     }
+    ENDIF
+  }
+
+void
+get_depending_on_value_from_odo(tree retval, cbl_field_t *odo)
+  {
+  /*  This routine, called only when we know there is an OCCURS DEPENDING ON
+      clause, returns the current value of the DEPENDING ON variable.  When
+      ec_bound_odo_e is turned on, and there is any kind of ec-bound-odo
+      error condition, the value returned is occurs.bounds.lower.
+
+      This should ensure that there is no memory violation in the event of a
+      declarative with a RESUME NEXT STATEMENT, or before the default_condition
+      processing can do a controlled exit.
+      */
+  cbl_field_t *depending_on;
+  depending_on = cbl_field_of(symbol_at(odo->occurs.depending_on));
+
+  if( !enabled_exceptions.match(ec_bound_odo_e) )
+    {
+    // With no exception testing, just pick up the value.  If there is a
+    // the programmer will simply have to live with the consequences.
+    get_integer_value(retval,
+                      depending_on,
+                      NULL);
+    return;
+    }
+
+  // Bounds checking is enabled, so we test the DEPENDING ON value to be 
between
+  // the lower and upper OCCURS limits:
+  get_integer_value(retval,
+                    depending_on,
+                    NULL,
+                    CHECK_FOR_FRACTIONAL_DIGITS);
+
+  IF( var_decl_rdigits, ne_op, integer_zero_node )
+    {
+    // This needs to evaluate to an integer
+    set_exception_code(ec_bound_odo_e);
+    gg_assign(retval, build_int_cst_type(TREE_TYPE(retval), 
odo->occurs.bounds.lower));
+    gg_assign(var_decl_rdigits, integer_zero_node);
+    }
+  ELSE
+    ENDIF
+
+  IF( retval, gt_op, build_int_cst_type(TREE_TYPE(retval), 
odo->occurs.bounds.upper) )
+    {
+    set_exception_code(ec_bound_odo_e);
+    gg_assign(retval, build_int_cst_type(TREE_TYPE(retval), 
odo->occurs.bounds.lower));
+    }
+  ELSE
+    {
+    IF( retval, lt_op, build_int_cst_type(TREE_TYPE(retval), 
odo->occurs.bounds.lower) )
+      {
+      set_exception_code(ec_bound_odo_e);
+      gg_assign(retval, build_int_cst_type(TREE_TYPE(retval), 
odo->occurs.bounds.lower));
+      }
+    ELSE
+      ENDIF
+    IF( retval, lt_op, gg_cast(TREE_TYPE(retval), integer_zero_node) )
+      {
+      set_exception_code(ec_bound_odo_e);
+      gg_assign(retval, gg_cast(TREE_TYPE(retval), integer_zero_node));
+      }
+    ELSE
+      ENDIF
+    }
+    ENDIF
+  }
+
+static
+void
+get_depending_on_value(tree retval, cbl_refer_t &refer)
+  {
+  /*  This routine, called only when we know there is an OCCURS DEPENDING ON
+      clause, returns the current value of the DEPENDING ON variable.  When
+      ec_bound_odo_e is turned on, and there is any kind of ec-bound-odo
+      error condition, the value returned is occurs.bounds.lower.
+
+      This should ensure that there is no memory violation in the event of a
+      declarative with a RESUME NEXT STATEMENT, or before the default_condition
+      processing can do a controlled exit.
+      */
+  cbl_field_t *odo = symbol_find_odo(refer.field);
+  get_depending_on_value_from_odo(retval, odo);
+  }
+
+static
+tree
+get_data_offset(cbl_refer_t &refer,
+                int *pflags = NULL)
+  {
   Analyze();
   // This routine returns a tree which is the size_t offset to the data in the
   // refer/field
@@ -316,10 +550,9 @@ get_data_offset(cbl_refer_t &refer,
   int all_flags = 0;
   int all_flag_bit = 1;
 
-  static tree value64 = gg_define_variable(LONG, ".._gdos_value64", 
vs_file_static);
-
   if( refer.nsubscript )
     {
+    REFER("subscript");
     // We have at least one subscript:
 
     // Figure we have three subscripts, so nsubscript is 3
@@ -355,29 +588,6 @@ get_data_offset(cbl_refer_t &refer,
       // Pick up the integer value of the subscript:
       tree subscript  = gg_define_variable(LONG);
 
-      get_integer_value(subscript,
-                        refer.subscripts[i].field,
-                        refer_offset(refer.subscripts[i]),
-                        CHECK_FOR_FRACTIONAL_DIGITS);
-      IF( var_decl_rdigits,
-          ne_op,
-          integer_zero_node )
-        {
-        // The subscript isn't an integer
-        set_exception_code(ec_bound_subscript_e);
-        gg_assign(var_decl_rdigits, integer_zero_node);
-        }
-      ELSE
-        {
-        }
-      ENDIF
-
-      // gg_printf("%s(): We have a subscript of %d from %s\n",
-                  // gg_string_literal(__func__),
-                  // subscript,
-                  // gg_string_literal(refer.subscripts[i].field->name),
-                  // NULL_TREE);
-
       if( (refer.subscripts[i].field->attr & FIGCONST_MASK) == zero_value_e )
         {
         // This refer is a figconst ZERO; we treat it as an ALL ZERO
@@ -389,98 +599,94 @@ get_data_offset(cbl_refer_t &refer,
         // Flag this position as ALL
         all_flags |= all_flag_bit;
         }
-      all_flag_bit <<= 1;
-
-      // Subscript is now a one-based integer
-      // Make it zero-based:
-
-      gg_decrement(subscript);
-      // gg_printf("process_this_exception is true\n", NULL_TREE);
-      IF( subscript, lt_op, gg_cast(TREE_TYPE(subscript), integer_zero_node) )
-        {
-        // The subscript is too small
-        set_exception_code(ec_bound_subscript_e);
-        gg_assign(subscript, build_int_cst_type(TREE_TYPE(subscript), 0));
-        }
-      ELSE
+      else
         {
-        // gg_printf("parent->occurs.ntimes() is %d\n", 
build_int_cst_type(INT, parent->occurs.ntimes()), NULL_TREE);
-        IF( subscript,
-            ge_op,
-            build_int_cst_type(TREE_TYPE(subscript), parent->occurs.ntimes()) )
+        if( !enabled_exceptions.match(ec_bound_subscript_e) )
           {
-          // The subscript is too large
-          set_exception_code(ec_bound_subscript_e);
-          gg_assign(subscript, build_int_cst_type(TREE_TYPE(subscript), 0));
+          // With no exception testing, just pick up the value
+          get_integer_value(subscript,
+                            refer.subscripts[i].field,
+                            refer_offset(refer.subscripts[i]));
           }
-        ELSE
+        else
           {
-          // We have a good subscript:
-          // Check for an ODO violation:
-          if( parent->occurs.depending_on )
+          get_integer_value(subscript,
+                            refer.subscripts[i].field,
+                            refer_offset(refer.subscripts[i]),
+                            CHECK_FOR_FRACTIONAL_DIGITS);
+          IF( var_decl_rdigits,
+              ne_op,
+              integer_zero_node )
+            {
+            // The subscript isn't an integer
+            set_exception_code(ec_bound_subscript_e);
+            gg_assign(subscript, build_int_cst_type(TREE_TYPE(subscript), 1));
+            gg_assign(var_decl_rdigits, integer_zero_node);
+            }
+          ELSE
             {
-            cbl_field_t *depending_on = 
cbl_field_of(symbol_at(parent->occurs.depending_on));
-            get_integer_value(value64, depending_on);
-            IF( subscript, ge_op, value64 )
+            IF( subscript, lt_op, gg_cast(TREE_TYPE(subscript), 
integer_one_node) )
               {
-              set_exception_code(ec_bound_odo_e);
+              // The subscript is too small
+              set_exception_code(ec_bound_subscript_e);
+              gg_assign(subscript, build_int_cst_type(TREE_TYPE(subscript), 
1));
               }
             ELSE
+              {
+              IF( subscript,
+                  ge_op,
+                  build_int_cst_type(TREE_TYPE(subscript), 
parent->occurs.ntimes()) )
+                {
+                // The subscript is too large
+                set_exception_code(ec_bound_subscript_e);
+                gg_assign(subscript, build_int_cst_type(TREE_TYPE(subscript), 
1));
+                }
+              ELSE
+                {
+                }
+                ENDIF
+              }
               ENDIF
             }
+          ENDIF
+          }
+        }
+
+      all_flag_bit <<= 1;
+
+      // Although we strictly don't need to look at the ODO value at this 
point,
+      // we do want it checked for the purposes of ec-bound-odo
 
-          tree augment = gg_multiply(subscript, get_any_capacity(parent));
-          gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, augment)));
+      if( enabled_exceptions.match(ec_bound_odo_e) )
+        {
+        if( parent->occurs.depending_on )
+          {
+          static tree value64 = gg_define_variable(LONG, ".._gdos_value64", 
vs_file_static);
+          cbl_field_t *odo = symbol_find_odo(parent);
+          get_depending_on_value_from_odo(value64, odo);
           }
-          ENDIF
         }
-        ENDIF
+
+      // Subscript is now a one-based integer
+      // Make it zero-based:
+
+      gg_decrement(subscript);
+
+      tree augment = gg_multiply(subscript, get_any_capacity(parent));
+      gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, augment)));
+
       parent = parent_of(parent);
       }
     }
 
   if( refer.refmod.from )
     {
+    REFER("refmod refstart");
     // We have a refmod to deal with
     static tree refstart = gg_define_variable(LONG, "..gdo_refstart", 
vs_file_static);
+    static tree reflen   = gg_define_variable(LONG, "..gdo_reflen", 
vs_file_static);
+    get_and_check_refstart_and_reflen(refstart, reflen, refer);
 
-    get_integer_value(refstart,
-                      refer.refmod.from->field,
-                      refer_offset(*refer.refmod.from),
-                      CHECK_FOR_FRACTIONAL_DIGITS);
-    IF( var_decl_rdigits,
-        ne_op,
-        integer_zero_node )
-      {
-      // refmod offset is not an integer, and has to be
-      set_exception_code(ec_bound_ref_mod_e);
-      gg_assign(var_decl_rdigits, integer_zero_node);
-      }
-    ELSE
-      ENDIF
-
-    // Make refstart zero-based:
-    gg_decrement(refstart);
-
-    IF( refstart, lt_op, gg_cast(LONG, integer_zero_node) )
-      {
-      set_exception_code(ec_bound_ref_mod_e);
-      gg_assign(refstart, gg_cast(LONG, integer_zero_node));
-      }
-    ELSE
-      {
-      tree capacity = get_any_capacity(refer.field);  // This is a size_t
-      IF( refstart, gt_op, gg_cast(LONG, capacity) )
-        {
-        set_exception_code(ec_bound_ref_mod_e);
-        gg_assign(refstart, build_int_cst_type(TREE_TYPE(refstart), 0));
-        }
-      ELSE
-        ENDIF
-      }
-      ENDIF
-
-    // We have a good refstart
     gg_assign(retval, gg_add(retval, gg_cast(SIZE_T, refstart)));
     }
 
@@ -489,11 +695,6 @@ get_data_offset(cbl_refer_t &refer,
     *pflags = all_flags;
     }
 
-
-//  gg_printf("*****>>>>> %s(): returning %p\n",
-//            gg_string_literal(__func__),
-//            retval,
-//            NULL_TREE);
   return retval;
   }
 
@@ -1734,7 +1935,7 @@ refer_is_clean(cbl_refer_t &refer)
     // It is routine for a refer to have no field.  It happens when the parser
     // passes us a refer for an optional parameter that has been omitted, for
     // example.
-    
+
     // It is also the case that a FldLiteralN will never have suscripts, or the
     // like.
     return true;
@@ -1749,195 +1950,43 @@ refer_is_clean(cbl_refer_t &refer)
           ;
   }
 
+
 /*  This routine returns the length portion of a refmod(start:length) 
reference.
     It extracts both the start and the length so that it can add them together
     to make sure that result falls within refer.capacity.
+
+    This routine shouldn't be called unless there is refmod involved.
     */
 static
 tree  // size_t
 refer_refmod_length(cbl_refer_t &refer)
   {
-  REFER;
   Analyze();
-  if( refer.refmod.from || refer.refmod.len )
-    {
-    static tree refstart = gg_define_variable(LONG, "..rrl_refstart", 
vs_file_static);
-    static tree reflen   = gg_define_variable(LONG, "..rrl_reflen", 
vs_file_static);
+  REFER("refstart and reflen");
+  static tree refstart = gg_define_variable(LONG, "..rrl_refstart", 
vs_file_static);
+  static tree reflen   = gg_define_variable(LONG, "..rrl_reflen", 
vs_file_static);
 
-    tree rt_capacity = get_any_capacity(refer.field); // This is a size_t
-
-    get_integer_value(refstart,
-                      refer.refmod.from->field,
-                      refer_offset(*refer.refmod.from),
-                      CHECK_FOR_FRACTIONAL_DIGITS);
-    IF( var_decl_rdigits,
-        ne_op,
-        integer_zero_node )
-      {
-      set_exception_code(ec_bound_ref_mod_e);
-      gg_assign(refstart, gg_cast(LONG, integer_one_node));
-      gg_assign(var_decl_rdigits, integer_zero_node);
-      }
-    ELSE
-      ENDIF
+  get_and_check_refstart_and_reflen( refstart, reflen, refer);
 
-    // Make refstart zero-based:
-    gg_decrement(refstart);
+  // Arrive here with a valid value for reflen:
 
-    IF( refstart, lt_op, build_int_cst_type(LONG, 0 ) )
-      {
-      set_exception_code(ec_bound_ref_mod_e);
-      gg_assign(refstart, gg_cast(LONG, integer_zero_node));
-      // Set reflen to one here, because otherwise it won't be established.
-      gg_assign(reflen, gg_cast(TREE_TYPE(reflen), integer_one_node));
-      }
-    ELSE
-      {
-      IF( refstart, gt_op, gg_cast(TREE_TYPE(refstart), rt_capacity) )
-        {
-        set_exception_code(ec_bound_ref_mod_e);
-        gg_assign(refstart, gg_cast(LONG, integer_zero_node));
-        // Set reflen to one here, because otherwise it won't be established.
-        gg_assign(reflen, gg_cast(TREE_TYPE(reflen), integer_one_node));
-        }
-      ELSE
-        {
-        if( refer.refmod.len )
-          {
-          get_integer_value(reflen,
-                            refer.refmod.len->field,
-                            refer_offset(*refer.refmod.len),
-                            CHECK_FOR_FRACTIONAL_DIGITS);
-          IF( var_decl_rdigits,
-              ne_op,
-              integer_zero_node )
-            {
-            // length is not an integer
-            set_exception_code(ec_bound_ref_mod_e);
-            gg_assign(reflen, gg_cast(LONG, integer_one_node));
-            gg_assign(var_decl_rdigits, integer_zero_node);
-            }
-          ELSE
-            {
-            }
-          ENDIF
-
-          IF( reflen, lt_op, gg_cast(LONG, integer_one_node) )
-            {
-            // length is too small
-            set_exception_code(ec_bound_ref_mod_e);
-            gg_assign(reflen, gg_cast(LONG, integer_one_node));
-            }
-          ELSE
-            {
-            IF( gg_add(refstart, reflen),
-                gt_op,
-                gg_cast(TREE_TYPE(refstart), rt_capacity) )
-              {
-              // Start + Length is too large
-              set_exception_code(ec_bound_ref_mod_e);
-
-              // Our intentions are honorable.  But at this point, where
-              // we notice that start + length is too long, the
-              // get_data_offset routine has already been run and
-              // it's too late to actually change the refstart.  There are
-              // theoretical solutions to this -- mainly,
-              // get_data_offset needs to check the start + len for
-              // validity.  But I am not going to do it now.  Think of this
-              // as the TODO item.
-              gg_assign(refstart, gg_cast(LONG, integer_zero_node));
-              gg_assign(reflen, gg_cast(LONG, integer_one_node));
-              }
-            ELSE
-              ENDIF
-            }
-            ENDIF
-          }
-        else
-          {
-          // There is no refmod length, so we default to the remaining 
characters
-          tree subtract_expr = gg_subtract( rt_capacity,
-                                            refstart);
-          gg_assign(reflen, subtract_expr);
-          }
-        }
-        ENDIF
-      }
-      ENDIF
-
-    // Arrive here with valid values for refstart and reflen:
-
-    return gg_cast(SIZE_T, reflen);
-    }
-  else
-    {
-    return size_t_zero_node;
-    }
+  return gg_cast(SIZE_T, reflen);
   }
 
 static
 tree // size_t
 refer_fill_depends(cbl_refer_t &refer)
   {
-  REFER;
+  REFER("");
   // This returns a positive number which is the amount a depends-limited
   // capacity needs to be reduced.
   Analyze();
   cbl_field_t *odo = symbol_find_odo(refer.field);
-  cbl_field_t *depending_on;
-  depending_on = cbl_field_of(symbol_at(odo->occurs.depending_on));
-  // refer.field has a relevant DEPENDING ON clause
-
-  // gg_printf("var is %s type is %s\n",
-            // gg_string_literal(refer.field->name),
-            // gg_string_literal(cbl_field_type_str(refer.field->type)),
-            // NULL_TREE);
-  // gg_printf("   odo is %s\n", gg_string_literal(odo->name), NULL_TREE);
-
-  // gg_printf("      depending_on is %s\n", 
gg_string_literal(depending_on->name), NULL_TREE);
-  // fprintf(stderr,
-          // "symbol_find_odo found %s, with depending_on %s\n",
-          // odo->name,
-          // depending_on->name);
 
   static tree value64 = gg_define_variable(LONG, "..rfd_value64", 
vs_file_static);
-  get_integer_value(value64,
-                    depending_on,
-                    NULL,
-                    CHECK_FOR_FRACTIONAL_DIGITS);
-  IF( var_decl_rdigits, ne_op, integer_zero_node )
-    {
-    // This needs to evaluate to an integer
-    set_exception_code(ec_bound_odo_e);
-    gg_assign(value64, build_int_cst_type(TREE_TYPE(value64), 
odo->occurs.bounds.upper));
-    gg_assign(var_decl_rdigits, integer_zero_node);
-    }
-  ELSE
-    ENDIF
 
-  IF( value64, gt_op, build_int_cst_type(TREE_TYPE(value64), 
odo->occurs.bounds.upper) )
-    {
-    set_exception_code(ec_bound_odo_e);
-    gg_assign(value64, build_int_cst_type(TREE_TYPE(value64), 
odo->occurs.bounds.upper));
-    }
-  ELSE
-    {
-    IF( value64, lt_op, build_int_cst_type(TREE_TYPE(value64), 
odo->occurs.bounds.lower) )
-      {
-      set_exception_code(ec_bound_odo_e);
-      gg_assign(value64, build_int_cst_type(TREE_TYPE(value64), 
odo->occurs.bounds.lower));
-      }
-    ELSE
-      ENDIF
-    IF( value64, lt_op, gg_cast(TREE_TYPE(value64), integer_zero_node) )
-      {
-      set_exception_code(ec_bound_odo_e);
-      gg_assign(value64, gg_cast(TREE_TYPE(value64), integer_zero_node));
-      }
-    ELSE
-      ENDIF
-    }
-    ENDIF
+  get_depending_on_value(value64, refer);
+
   // value64 is >= zero and < bounds.upper
 
   // We multiply the ODO value by the size of the data capacity to get the
@@ -1958,11 +2007,10 @@ refer_offset(cbl_refer_t &refer,
   {
   // This routine calculates the effect of a refer offset on the
   // refer.field->data location.  When there are subscripts, the data location
-  // gets augmented by the (subscript-1)*element_size calculation.  And when 
+  // gets augmented by the (subscript-1)*element_size calculation.  And when
   // there is a refmod, the data location additionally gets augmented by
   // (refmod.from-1)
 
-  REFER;
   if( !refer.field )
     {
     // It's common for the field to be missing.  It generally means that an
@@ -1981,10 +2029,9 @@ refer_offset(cbl_refer_t &refer,
   }
 
 static
-tree
+tree   // size_t
 refer_size(cbl_refer_t &refer, refer_type_t refer_type)
   {
-  REFER;
   Analyze();
   static tree retval = gg_define_variable(SIZE_T, "..rs_retval", 
vs_file_static);
 
@@ -2026,14 +2073,12 @@ refer_size(cbl_refer_t &refer, refer_type_t refer_type)
 tree  // size_t
 refer_size_dest(cbl_refer_t &refer)
   {
-  REFER;
   return refer_size(refer, refer_dest);
   }
 
 tree  // size_t
 refer_size_source(cbl_refer_t &refer)
   {
-  REFER;
   /*  There are oddities involved with refer_size_source and refer_size_dest.
       See the comments in refer_has_depends for some explanation.  There are
       other considerations, as well.  For example, consider a move, where you
diff --git a/gcc/cobol/genutil.h b/gcc/cobol/genutil.h
index 82444816f1f2..2f4bc36eace7 100644
--- a/gcc/cobol/genutil.h
+++ b/gcc/cobol/genutil.h
@@ -154,4 +154,5 @@ void      build_array_of_treeplets( int ngroup,
 void      build_array_of_fourplets( int ngroup,
                                     size_t N,
                                     cbl_refer_t *refers);
+void      get_depending_on_value_from_odo(tree retval, cbl_field_t *odo);
 #endif
diff --git a/gcc/cobol/lang-specs.h b/gcc/cobol/lang-specs.h
index 78e84c034648..b7f15179a044 100644
--- a/gcc/cobol/lang-specs.h
+++ b/gcc/cobol/lang-specs.h
@@ -34,7 +34,7 @@
     {".CBL", "@cobol", 0, 0, 0},
     {"@cobol",
         "cobol1 %i %(cc1_options) "
-        "%{D*} %{E} %{I*} %{fmax-errors*} %{fsyntax-only*} "
+        "%{D*} %{E} %{I*} %{M} %{fmax-errors*} %{fsyntax-only*} "
         "%{fcobol-exceptions*} "
         "%{copyext} "
         "%{fstatic-call} %{fdefaultbyte} "
diff --git a/gcc/cobol/lang.opt b/gcc/cobol/lang.opt
index 59278a147e99..1f2a61629b9f 100644
--- a/gcc/cobol/lang.opt
+++ b/gcc/cobol/lang.opt
@@ -38,6 +38,11 @@ Cobol Joined Separate
 ;;  -I <dir>   Add copybook search directory
 ; Documented in c.opt
 
+M
+Cobol
+; Documented in c.opt
+
+
 dialect
 Cobol Joined Separate Enum(dialect_type) EnumBitSet Var(cobol_dialect)
 Accept COBOL constructs used by non-ISO compilers
diff --git a/gcc/cobol/lexio.h b/gcc/cobol/lexio.h
index cf7f53a3c5bb..ed642afbf16a 100644
--- a/gcc/cobol/lexio.h
+++ b/gcc/cobol/lexio.h
@@ -43,7 +43,6 @@
 #define SPACE ' '
 
 bool lexer_echo();
-
 bool is_reference_format();
 
 static inline bool isquote( char ch ) {
diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y
index cecdd2244a5e..cb96c9073618 100644
--- a/gcc/cobol/parse.y
+++ b/gcc/cobol/parse.y
@@ -1346,8 +1346,16 @@
     // more integer friendly.  Any integer value that can be expressed in 1
     // to MAX_FIXED_POINT_DIGITS digits is converted to a string without a
     // decimal point and no exponent.
+
     char *pdot = strchr(psz, '.');
+    gcc_assert(pdot);
     char *pe = strchr(psz, 'e');
+    if( !pe )
+      {
+      // The most likely cause of this is a "0.0" result.
+      strcpy(psz, "0");
+      return;
+      }
     char *pnz = pe-1;
     while(*pnz == '0')
       {
@@ -2277,7 +2285,9 @@ config_paragraphs: config_paragraph
 config_paragraph:
                 SPECIAL_NAMES '.'
         |       SPECIAL_NAMES '.' specials '.'
+        |       SOURCE_COMPUTER  '.' 
         |       SOURCE_COMPUTER  '.' NAME with_debug '.'
+        |       OBJECT_COMPUTER  '.' 
         |       OBJECT_COMPUTER  '.' NAME collating_sequence[name] '.'
                 {
                   if( $name ) {
@@ -4015,8 +4025,8 @@ picture_clause: PIC signed nps[fore] nines nps[aft]
                   cbl_field_t *field = current_field();
 
                  if( field->type == FldNumericBin5 &&
-                     field->data.capacity == 0  &&
-                     dialect_mf() )
+                     field->data.capacity == 0xFF  &&
+                     (dialect_gnu() || dialect_mf()) )
                  { // PIC X COMP-X or COMP-9
                    if( ! field->has_attr(all_x_e) ) {
                      error_msg(@2, "COMP PICTURE requires all X's or all 9's");
@@ -4024,6 +4034,7 @@ picture_clause: PIC signed nps[fore] nines nps[aft]
                    }
                  } else {
                     if( !field_type_update(field, FldAlphanumeric, @$) ) {
+                     dbgmsg("alnum_pic: %s", field_str(field));
                       YYERROR;
                     }
                  }
@@ -4240,21 +4251,21 @@ usage_clause1:  usage BIT
                      case FldAlphanumeric:   // PIC X COMP-5 or COMP-X
                        assert( field->data.digits == 0 );
                        assert( field->data.rdigits == 0 );
-                       if( dialect_mf() ) {
+                       if( (dialect_mf() || dialect_gnu()) ) {
                           field->type = $comp.type;
                          field->clear_attr(signable_e);
                        } else {
                          error_msg(@comp, "numeric USAGE invalid "
                                           "with Alpnanumeric PICTURE");
-                         dialect_error(@1, "Alpnanumeric COMP-5 or COMP-X", 
"mf");
+                         dialect_error(@1, "Alpnanumeric COMP-5 or COMP-X", 
"mf or gnu");
                          YYERROR;
                        }
                         break;
                      case FldNumericDisplay: // PIC 9 COMP-5 or COMP-X
                        if( $comp.capacity == 0xFF ) { // comp-x is a bit like 
comp-5
                          assert( field->data.digits == field->data.capacity );
-                         if( ! dialect_mf() ) {
-                                 dialect_error(@1, "COMP-X", "mf");
+                         if( ! (dialect_mf() || dialect_gnu()) ) {
+                                 dialect_error(@1, "COMP-X", "mf or gnu");
                          }
                        }
                         field->type = $comp.type;
@@ -4321,21 +4332,21 @@ usage_clause1:  usage BIT
                      case FldAlphanumeric:   // PIC X COMP-5 or COMP-X
                        assert( field->data.digits == 0 );
                        assert( field->data.rdigits == 0 );
-                       if( dialect_mf() ) {
+                       if( (dialect_mf() || dialect_gnu()) ) {
                           field->type = $comp.type;
                          field->clear_attr(signable_e);
                        } else {
                          error_msg(@comp, "numeric USAGE invalid "
                                           "with Alpnanumeric PICTURE");
-                         dialect_error(@1, "Alpnanumeric COMP-5 or COMP-X", 
"mf");
+                         dialect_error(@1, "Alpnanumeric COMP-5 or COMP-X", 
"mf or gnu");
                          YYERROR;
                        }
                         break;
                      case FldNumericDisplay: // PIC 9 COMP-5 or COMP-X
                        if( $comp.capacity == 0xFF ) { // comp-x is a bit like 
comp-5
                          assert( field->data.digits == field->data.capacity );
-                         if( ! dialect_mf() ) {
-                                 dialect_error(@1, "COMP-X", "mf");
+                         if( ! (dialect_mf() || dialect_gnu()) ) {
+                                 dialect_error(@1, "COMP-X", "mf or gnu");
                          }
                        }
                         field->type = $comp.type;
@@ -5236,9 +5247,19 @@ acceptable:     device_name
                 {
                   $$ = special_of($1);
                   if( !$$ ) {
-                    error_msg(@NAME, "no such environment mnemonic name: %s", 
$NAME);
-                    YYERROR;
-                  }
+                   const special_name_t *special_type = 
cmd_or_env_special_of($NAME);
+                   if( !special_type ) {
+                      error_msg(@NAME, "no such special name '%s'", $NAME);
+                      YYERROR;
+                   }
+                   // Add the name now, as a convenience. 
+                   cbl_special_name_t special = { 0, *special_type };
+                   namcpy(@NAME, special.name, $NAME);
+
+                   symbol_elem_t *e = symbol_special_add(PROGRAM, &special);
+                   $$ = cbl_special_name_of(e);
+                 }
+                 assert($$);
                 }
                 ;
 
@@ -7114,9 +7135,21 @@ section_kw:     SECTION
                 {
                   if( $1 ) {
                    if( *$1 == '-' ) {
-                     error_msg(@1, "SECTION segment %s is negative", $1);
+                     error_msg(@1, "SECTION segment %<%s%> is negative", $1);
                     } else {
-                      cbl_unimplementedw("SECTION segment %s was ignored", $1);
+                     if( dialect_ibm() ) {
+                       int sectno;
+                       sscanf($1, "%u", &sectno);
+                       if( ! (0 <= sectno && sectno <= 99) ) {
+                         error_msg(@1, "SECTION segment %<%s%> must be 0-99", 
$1);
+                       } else {
+                         if(false) { // stand-in for warning, someday.
+                           yywarn("SECTION segment %<%s%> was ignored", $1);
+                         }
+                       }
+                     } else {
+                       cbl_unimplemented("SECTION segment %<%s%> is not ISO 
syntax", $1);
+                     }
                     }
                  }
                 }
@@ -7498,18 +7531,7 @@ perform_except:  perform_start
                perform_ec_finally
                END_PERFORM
                 {
-                 auto perf = perform_current();
-                 // produce blob, jumped over by FINALLY paragraph
-                 size_t iblob = symbol_declaratives_add( PROGRAM, perf->dcls );
-                 auto lave = perf->ec_labels.new_label(LblParagraph, "lave");
-                 auto handlers = cbl_field_of(symbol_at(iblob));
-
-                 // install blob
-                 parser_label_label(perf->ec_labels.init);
-                 declarative_runtime_match(handlers, lave);
-
-                 // uninstall blob
-                 parser_label_label(perf->ec_labels.fini);
+                 cbl_unimplemented("PERFORM Format 3");
                 }
                ;
 
@@ -12920,10 +12942,22 @@ mode_syntax_only() {
 
 void
 cobol_dialect_set( cbl_dialect_t dialect ) {
-  cbl_dialect = dialect;
-  if( dialect & dialect_ibm_e ) cobol_gcobol_feature_set(feature_embiggen_e);
+  switch(dialect) {
+  case dialect_gcc_e:
+    break;
+  case dialect_ibm_e:
+    cobol_gcobol_feature_set(feature_embiggen_e);
+    break;
+  case dialect_mf_e:
+    break;
+  case dialect_gnu_e:
+    if( 0 == (cbl_dialects & dialect) ) { // first time
+      tokens.equate(YYLTYPE(), "BINARY-DOUBLE", "BINARY-C-LONG");
+    }
+    break;
+  }    
+  cbl_dialects |= dialect;
 }
-cbl_dialect_t cobol_dialect() { return cbl_dialect; }
 
 static bool internal_ebcdic_locked = false;
 
diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h
index 0369f7b1acbe..997ad4f4698a 100644
--- a/gcc/cobol/parse_ante.h
+++ b/gcc/cobol/parse_ante.h
@@ -47,9 +47,6 @@
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 
-extern void declarative_runtime_match(cbl_field_t *declaratives,
-                                      cbl_label_t *lave );
-
 extern YYLTYPE yylloc;
 
 extern int yylineno, yyleng, yychar;
@@ -73,7 +70,7 @@ void apply_declaratives();
 const char * keyword_str( int token );
 void labels_dump();
 
-cbl_dialect_t cbl_dialect;
+unsigned int cbl_dialects;
 size_t cbl_gcobol_features;
 
 static enum cbl_division_t current_division;
@@ -1035,7 +1032,7 @@ class current_tokens_t {
   int find( const cbl_name_t name, bool include_intrinsics ) {
     return tokens.find(name, include_intrinsics);
   }
-  bool equate( const YYLTYPE& loc, cbl_name_t keyword, const cbl_name_t alias 
) {
+  bool equate( const YYLTYPE& loc, const cbl_name_t keyword, const cbl_name_t 
alias ) {
     int token; 
     if( 0 == (token = binary_integer_usage_of(keyword)) ) {
       if( 0 == (token = keyword_tok(keyword)) ) {
@@ -1054,7 +1051,7 @@ class current_tokens_t {
   bool undefine( const YYLTYPE& loc, cbl_name_t keyword ) {
     return tokens.undefine(loc, keyword);
   }
-  bool substitute( const YYLTYPE& loc, cbl_name_t keyword, const cbl_name_t 
alias ) {
+  bool substitute( const YYLTYPE& loc, const cbl_name_t keyword, const 
cbl_name_t alias ) {
     int token; 
     if( 0 == (token = binary_integer_usage_of(keyword)) ) {
       if( 0 == (token = keyword_tok(keyword)) ) {
@@ -1476,7 +1473,7 @@ class prog_descr_t {
   std::set<std::string> call_targets, subprograms;
  public:
   std::set<function_descr_t> function_repository;
-  size_t program_index, declaratives_index;
+  size_t program_index;
   cbl_label_t *declaratives_eval, *paragraph, *section;
   const char *collating_sequence;
   struct locale_t {
@@ -1494,7 +1491,6 @@ class prog_descr_t {
 
   prog_descr_t( size_t isymbol )
     : program_index(isymbol)
-    , declaratives_index(0)
     , declaratives_eval(NULL)
     , paragraph(NULL)
     , section(NULL)
@@ -2101,10 +2097,6 @@ static class current_t {
     assert(!programs.empty());
     return programs.top().program_index;
   }
-  size_t  program_declaratives(void) const {
-    if( programs.empty() ) return 0;
-    return programs.top().declaratives_index;
-  }
   const cbl_label_t * program(void) {
     return programs.empty()?
                 NULL : cbl_label_of(symbol_at(programs.top().program_index));
@@ -2118,12 +2110,16 @@ static class current_t {
 
   bool is_first_statement( const YYLTYPE& loc )  {
     if( ! in_declaratives && first_statement == 0 ) {
-      if( ! symbol_label_section_exists(program_index()) ) {
-        if( ! dialect_ibm() ) {
-          error_msg(loc,
-                    "Per ISO a program with DECLARATIVES must begin with a 
SECTION, "
-                    "requires -dialect ibm");
-        }
+      auto eval = programs.top().declaratives_eval;
+      if( eval ) {
+       size_t ilabel = symbol_index(symbol_elem_of(eval));
+       if( ! symbol_label_section_exists(ilabel) ) {
+         if( ! dialect_ibm() ) {
+           error_msg(loc,
+                     "Per ISO a program with DECLARATIVES must begin with a 
SECTION, "
+                     "requires -dialect ibm");
+         }
+       }
       }
       first_statement = loc.first_line;
       return true;
@@ -2214,24 +2210,25 @@ static class current_t {
 
     declaratives.runtime.dcl = parser_compile_dcls(declaratives.encode());
 
-    size_t idcl = symbol_declaratives_add(program_index(), 
declaratives.as_list());
-    programs.top().declaratives_index = idcl;
-
     // Create section to evaluate declaratives.  Given them unique names so
     // that we can figure out what is going on in a trace or looking at the
     // assembly language.
-    static int eval_count=1;
-    char eval[32];
-    char lave[32];
+    static int eval_count = 1;
+    char eval[32], lave[32];
+    
     sprintf(eval, "_DECLARATIVES_EVAL%d", eval_count);
-    sprintf(lave, "_DECLARATIVES_LAVE%d", eval_count);
-    eval_count +=1 ;
+    sprintf(lave, "_DECLARATIVES_LAVE%d", eval_count++);
 
     struct cbl_label_t*& eval_label = programs.top().declaratives_eval;
     eval_label = label_add(LblSection, eval, yylineno);
     struct cbl_label_t * lave_label = label_add(LblSection, lave, yylineno);
+
     ast_enter_section(eval_label);
-    declarative_runtime_match(cbl_field_of(symbol_at(idcl)), lave_label);
+
+    declarative_runtime_match(declaratives.as_list(), lave_label);
+    
+    parser_label_label(lave_label);
+    
     return lave_label;
   }
 
@@ -2261,11 +2258,10 @@ static class current_t {
 
   /*
    * END DECLARATIVES causes:
-   *   1. Add DECLARATIVES symbol, containing criteria blob.
-   *   2. Create section _DECLARATIVES_EVAL
+   *   1. Create section _DECLARATIVES_EVAL
    *      and exit label _DECLARATIVES_LAVE
-   *   3. declarative_runtime_match generates runtime evaluation "ladder".
-   *   4. After a declarative is executed, control branches to the exit label.
+   *   2. declarative_runtime_match generates runtime evaluation "ladder".
+   *   3. After a declarative is executed, control branches to the exit label.
    *
    * After each verb, we call declaratives_evaluate,
    * which PERFORMs _DECLARATIVES_EVAL.
diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l
index dfc0c3087aed..5ca27282b23e 100644
--- a/gcc/cobol/scan.l
+++ b/gcc/cobol/scan.l
@@ -2124,7 +2124,7 @@ BASIS             { yy_push_state(basis); return BASIS; }
                        input_file_status.enter(filename);
                }
 
-  {POP_FILE}   {
+  {POP_FILE}{OSPC}     {
                        yy_set_bol(true);
                        input_file_status.leave();
                }
diff --git a/gcc/cobol/scan_ante.h b/gcc/cobol/scan_ante.h
index c8c93ed79c55..f60f5d52c470 100644
--- a/gcc/cobol/scan_ante.h
+++ b/gcc/cobol/scan_ante.h
@@ -372,7 +372,7 @@ class enter_leave_t {
   enter_leave_t(parser_leave_file_f *leaving)
     : entering(NULL), leaving(leaving), filename(NULL) {}
 
-  void notify() {
+  void notify( unsigned int newlines = 0 ) {
     if( entering ) {
       cobol_filename(filename, 0);
       if( yy_flex_debug ) dbgmsg("starting line %4d of %s",
@@ -382,6 +382,7 @@ class enter_leave_t {
     }
     if( leaving ) {
       auto name = cobol_filename_restore();
+      yylineno += newlines;
       if( yy_flex_debug ) dbgmsg("resuming line %4d of %s",
                                  yylineno, name? name : "<none>");
       leaving();
@@ -392,17 +393,22 @@ class enter_leave_t {
 
 static class input_file_status_t {
   std::queue <enter_leave_t> inputs;
+  unsigned int trailing_newlines = 0;
  public:
   void enter(const char *filename) {
     inputs.push( enter_leave_t(parser_enter_file, filename) );
   }
   void leave() {
+    // Add the number of newlines following the POP to yylineno when it's 
restored. 
+    trailing_newlines = std::count(yytext, yytext + yyleng, '\n');
+    if( trailing_newlines && yy_flex_debug )
+      dbgmsg("adding %u lines after POP", trailing_newlines);
     inputs.push( parser_leave_file );
   }
   void notify() {
     while( ! inputs.empty() ) {
       auto enter_leave = inputs.front();
-      enter_leave.notify();
+      enter_leave.notify(trailing_newlines);
       inputs.pop();
     }
   }
diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc
index 1d0acf90fa6a..dc91fadbf1f3 100644
--- a/gcc/cobol/symbols.cc
+++ b/gcc/cobol/symbols.cc
@@ -487,9 +487,6 @@ symbol_elem_cmp( const void *K, const void *E )
   case SymDataSection:
     return k->elem.section.type == e->elem.section.type ? 0 : 1;
     break;
-  case SymFunction:
-    return strcmp(k->elem.function.name, e->elem.function.name);
-    break;
   case SymField:
     if( has_parent(k) && cbl_field_of(k)->parent != cbl_field_of(e)->parent ) {
       return 1;
@@ -1065,10 +1062,6 @@ symbols_dump( size_t first, bool header ) {
       s = xasprintf("%4" GCC_PRISZ "u %-18s line %d", (fmt_size_t)e->program,
                     cbl_section_of(e)->name(), cbl_section_of(e)->line);
       break;
-    case SymFunction:
-      s = xasprintf("%4" GCC_PRISZ "u %-15s %s", (fmt_size_t)e->program,
-                    "Function", e->elem.function.name);
-      break;
     case SymField: {
       auto field = cbl_field_of(e);
       char *odo_str = NULL;
@@ -3749,39 +3742,27 @@ symbol_label_add( size_t program, cbl_label_t *input )
 }
 
 /*
- * Under ISO (and not IBM) Declaratives are followed by a Section name.  When
- * the first statement is parsed, verify, if Declaratives were used, that it
+ * Under ISO (and not IBM) Declaratives are followed by a Section name.  If
+ * Declaratives were used, when the first statement is parsed verify that it
  * was preceeded by a Section name.
  */
 bool
-symbol_label_section_exists( size_t program ) {
-  auto pblob = std::find_if( symbols_begin(program), symbols_end(),
-                               []( const auto& sym ) {
-                                 if( sym.type == SymField ) {
-                                   auto& f( sym.elem.field );
-                                   return f.type == FldBlob;
-                                 }
-                                 return false;
-                               } );
-  if( pblob == symbols_end() ) return true; // Section name not required
-
-  bool has_section = std::any_of( ++pblob, symbols_end(),
-                               []( const auto& sym ) {
-                                 if( sym.type == SymLabel ) {
+symbol_label_section_exists( size_t eval_label_index ) {
+  auto eval = symbols_begin(eval_label_index);
+  bool has_section = std::any_of( ++eval, symbols_end(),
+                               [program = eval->program]( const auto& sym ) {
+                                 if( program == sym.program && sym.type == 
SymLabel ) {
                                    auto& L(sym.elem.label);
-                                   if( L.type == LblSection ) {
-                                     if( L.name[0] != '_' ) { // not implicit
-                                       return true; // Section name exists
-                                     }
-                                   }
+                                  // true if the symbol is an explicit label.
+                                   return L.type == LblSection &&  L.name[0] 
!= '_'; 
                                  }
                                  return false;
                                } );
   if( yydebug && ! has_section ) {
-    symbols_dump(program, true);
+    symbols_dump(eval_label_index, true);
   }
-  // Return true if no Declaratives, because the (non-)requirement is met.
-  // Return false if Declaratives exist, because no Section name was found.
+  // Return true if a user-defined SECTION was found after the Declaratives
+  // label section. 
   return has_section;
 }
 
diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h
index e27290773b55..4a86c676a84d 100644
--- a/gcc/cobol/symbols.h
+++ b/gcc/cobol/symbols.h
@@ -46,11 +46,6 @@
 #include <string>
 #include <vector>
 
-// Provide fallback definition.
-#ifndef NAME_MAX
-#define NAME_MAX 255
-#endif
-
 #define PICTURE_MAX 64
 
 extern const char *numed_message;
@@ -62,19 +57,22 @@ enum cbl_dialect_t {
   dialect_gnu_e = 0x04,
 };
 
-extern cbl_dialect_t cbl_dialect;
+// Dialects may be combined. 
+extern unsigned int cbl_dialects;
 void cobol_dialect_set( cbl_dialect_t dialect );
-cbl_dialect_t dialect_is();
 
+// GCC dialect means no other dialects
 static inline bool dialect_gcc() {
-  return dialect_gcc_e  == cbl_dialect;
+  return dialect_gcc_e == cbl_dialects;
 }
-
 static inline bool dialect_ibm() {
-  return dialect_ibm_e == (cbl_dialect & dialect_ibm_e);
+  return dialect_ibm_e == (cbl_dialects & dialect_ibm_e);
 }
 static inline bool dialect_mf() {
-  return dialect_mf_e  == (cbl_dialect & dialect_mf_e );
+  return dialect_mf_e  == (cbl_dialects & dialect_mf_e );
+}
+static inline bool dialect_gnu() {
+  return dialect_gnu_e  == (cbl_dialects & dialect_gnu_e );
 }
 
 enum cbl_gcobol_feature_t {
@@ -220,7 +218,6 @@ bool decimal_is_comma();
 
 enum symbol_type_t {
   SymFilename,
-  SymFunction,
   SymField,
   SymLabel,                     // section, paragraph, or label
   SymSpecial,
@@ -1475,14 +1472,6 @@ struct cbl_alphabet_t {
   }
 };
 
-// a function pointer
-typedef void ( *cbl_function_ptr ) ( void );
-
-struct cbl_function_t {
-  char name[NAME_MAX];
-  cbl_function_ptr func;
-};
-
 static inline const char *
 file_org_str( enum cbl_file_org_t org ) {
   switch ( org ) {
@@ -1638,7 +1627,6 @@ struct symbol_elem_t {
   size_t program;
   union symbol_elem_u {
     char *filename;
-    cbl_function_t     function;
     cbl_field_t        field;
     cbl_label_t        label;
     cbl_special_name_t special;
@@ -1692,9 +1680,6 @@ struct symbol_elem_t {
     case SymFilename:
       elem.filename = that.elem.filename;
       break;
-    case SymFunction:
-      elem.function = that.elem.function;
-      break;
     case SymField:
       elem.field = that.elem.field;
       break;
@@ -1814,13 +1799,6 @@ const cbl_label_t * symbol_program_local( const char 
called[] );
 
 bool redefine_field( cbl_field_t *field );
 
-// Functions to correctly extract the underlying type.
-static inline struct cbl_function_t *
-cbl_function_of( struct symbol_elem_t *e ) {
-  assert(e->type == SymFunction);
-  return &e->elem.function;
-}
-
 static inline struct cbl_section_t *
 cbl_section_of( struct symbol_elem_t *e ) {
   assert(e->type == SymDataSection);
diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc
index 87b19b64f1fd..75a0b26c0a91 100644
--- a/gcc/cobol/util.cc
+++ b/gcc/cobol/util.cc
@@ -100,8 +100,6 @@ symbol_type_str( enum symbol_type_t type )
     switch(type) {
     case SymFilename:
         return "SymFilename";
-    case SymFunction:
-        return "SymFunction";
     case SymField:
         return "SymField";
     case SymLabel:
@@ -1764,7 +1762,21 @@ struct input_file_t {
 
 class unique_stack : public std::stack<input_file_t>
 {
+  friend void cobol_set_pp_option(int opt);
+  bool option_m;
+  std::set<std::string> all_names;
+  
+  const char *
+  no_wd( const char *wd, const char *name ) {
+    int i;
+    for( i=0; wd[i] == name[i]; i++ ) i++;
+    if( wd[i] == '\0' && name[i] == '/' ) i++;
+    return yydebug? name : name + i;
+  }
+
  public:
+  unique_stack() : option_m(false) {}
+  
   bool push( const value_type& value ) {
     auto ok = std::none_of( c.cbegin(), c.cend(),
                             [value]( auto& that ) {
@@ -1772,6 +1784,7 @@ class unique_stack : public std::stack<input_file_t>
                                 } );
     if( ok ) {
       std::stack<input_file_t>::push(value);
+      all_names.insert(value.name);
       return true;
     }
     size_t n = c.size();
@@ -1792,12 +1805,23 @@ class unique_stack : public std::stack<input_file_t>
     }
     return false;
   }
-  const char *
-  no_wd( const char *wd, const char *name ) {
-    int i;
-    for( i=0; wd[i] == name[i]; i++ ) i++;
-    if( wd[i] == '\0' && name[i] == '/' ) i++;
-    return yydebug? name : name + i;
+  
+  void option( int opt ) { // capture other preprocessor options eventually
+    assert(opt == 'M');
+    option_m = true;
+  }
+  int option() const {
+    return option_m?  'M' : 0;
+  }
+
+  void print() const {
+    std::string input( top().name );
+    printf( "%s: ", input.c_str() );
+    for( auto name : all_names ) {
+      if( name != input ) 
+       printf( "\\\n\t%s ", name.c_str() );
+    }
+    printf("\n");
   }
 };
 
@@ -1806,6 +1830,12 @@ static unique_stack input_filenames;
 static std::map<std::string, ino_t> old_filenames;
 static const unsigned int sysp = 0;  // not a C header file, cf. line-map.h
 
+void cobol_set_pp_option(int opt) {
+  // capture other preprocessor options eventually
+  assert(opt == 'M');
+  input_filenames.option_m = true;
+}
+                                 
 /*
  * Maintain a stack of input filenames.  Ensure the files are unique (by
  * inode), to prevent copybook cycles. Before pushing a new name, Record the
@@ -2137,6 +2167,11 @@ parse_file( const char filename[] )
 
   parser_enter_file(filename);
 
+  if( input_filenames.option() == 'M' ) {
+    input_filenames.print();
+    return 0;
+  }
+
   cbl_timespec start;
 
   int erc = yyparse();
diff --git a/gcc/cobol/util.h b/gcc/cobol/util.h
index 20d735d49824..9a968ea16510 100644
--- a/gcc/cobol/util.h
+++ b/gcc/cobol/util.h
@@ -43,6 +43,8 @@ int  ftolower(int c);
 int  ftoupper(int c);
 bool fisprint(int c);
 
+void cobol_set_pp_option(int opt);
+
 const char * cobol_filename_restore();
 const char * cobol_lineno_save();
 
diff --git a/gcc/testsuite/cobol.dg/group1/declarative_1.cob 
b/gcc/testsuite/cobol.dg/group1/declarative_1.cob
index ec68e9c6c3a8..744495a19eff 100644
--- a/gcc/testsuite/cobol.dg/group1/declarative_1.cob
+++ b/gcc/testsuite/cobol.dg/group1/declarative_1.cob
@@ -1,14 +1,14 @@
 *> { dg-do run }
 *> { dg-output {Turning EC\-ALL CHECKING OFF \-\- Expecting \+00\.00 from 
ACOS\(\-3\)(\n|\r\n|\r)} }
-*> { dg-output {      \+00\.00      TABL\(VSIX\) is 1(\n|\r\n|\r)} }
+*> { dg-output {      \+00\.00      TABL\(VSIX\) is 6(\n|\r\n|\r)} }
 *> { dg-output {Turning EC\-ARGUMENT\-FUNCTION CHECKING ON(\n|\r\n|\r)} }
 *> { dg-output {      Expecting \+0\.00 and DECLARATIVE FOR 
EC\-ARGUMENT\-FUNCTION(\n|\r\n|\r)} }
 *> { dg-output {      DECLARATIVE FOR EC\-ARGUMENT\-FUNCTION(\n|\r\n|\r)} }
-*> { dg-output {      \+00\.00      TABL\(VSIX\) is 1(\n|\r\n|\r)} }
+*> { dg-output {      \+00\.00      TABL\(VSIX\) is 6(\n|\r\n|\r)} }
 *> { dg-output {Turning EC\-ARGUMENT CHECKING ON(\n|\r\n|\r)} }
 *> { dg-output {      Expecting \+0\.00 and DECLARATIVE FOR 
EC\-ARGUMENT\-FUNCTION(\n|\r\n|\r)} }
 *> { dg-output {      DECLARATIVE FOR EC\-ARGUMENT\-FUNCTION(\n|\r\n|\r)} }
-*> { dg-output {      \+00\.00      TABL\(VSIX\) is 1(\n|\r\n|\r)} }
+*> { dg-output {      \+00\.00      TABL\(VSIX\) is 6(\n|\r\n|\r)} }
 *> { dg-output {Turning EC\-ALL CHECKING ON(\n|\r\n|\r)} }
 *> { dg-output {      Expecting \+0\.00 and DECLARATIVE 
EC\-ARGUMENT\-FUNCTION(\n|\r\n|\r)} }
 *> { dg-output {      Followed by DECLARATIVE EC\-ALL for TABL\(6\) 
access(\n|\r\n|\r)} }
diff --git a/libgcobol/common-defs.h b/libgcobol/common-defs.h
index e3471c5ccc3d..8c4858ccc61a 100644
--- a/libgcobol/common-defs.h
+++ b/libgcobol/common-defs.h
@@ -458,25 +458,11 @@ struct cbl_enabled_exception_t {
 struct cbl_declarative_t {
   enum { files_max = 16 };
   size_t section; // implies program
-  uint32_t global;  // See the note below
+  bool global;
   ec_type_t type;
   uint32_t nfile, files[files_max];
   cbl_file_mode_t mode;
 
-/*  The ::global member originally was "bool global".  A bool, however, 
occupies
-    only one byte of storage.  The structure, in turn, is constructed on
-    four-byte boundaries for members, so there were three padding bytes between
-    the single byte of global and the ::type member.
-
-    When used to create a "blob", where the structure was treated as a stream
-    of bytes that were used to create a constructor for an array of bytes,
-    valgrind noticed that those three padding bytes were not initialized, and
-    generated the appropriate error message.  This made it hard to find other
-    problems.
-
-    Changing the declaration from "bool" to "uint32_t" seems to have eliminated
-    the valgrind error without affecting overall performance.  */
-
   cbl_declarative_t( cbl_file_mode_t mode = file_mode_none_e )
     : section(0), global(false)
     , type(ec_none_e)
@@ -524,7 +510,6 @@ struct cbl_declarative_t {
   constexpr cbl_declarative_t& operator=(const cbl_declarative_t&) = default;
 
   std::vector<uint64_t> encode() const;
-  void decode( const std::vector<uint64_t>& encoded );
 
   /*
    * Sort file names before file modes, and file modes before non-IO.
diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc
index 56b1a7bf5876..6bae27a3c671 100644
--- a/libgcobol/libgcobol.cc
+++ b/libgcobol/libgcobol.cc
@@ -13108,3 +13108,58 @@ __gg__set_exception_environment( uint64_t *ecs, 
uint64_t *dcls )
   prior.dcls = dcls;
   }
 
+static char *sv_envname = NULL;
+
+extern "C"
+void
+__gg__set_env_name( cblc_field_t   *var,
+                    size_t          offset,
+                    size_t          length )
+  {
+  free(sv_envname);
+  sv_envname = (char *)malloc(length+1);
+  memcpy(sv_envname, var->data+offset, length);
+  sv_envname[length] = '\0';
+  }
+
+extern "C"
+void
+__gg__set_env_value(cblc_field_t   *value,
+                    size_t          offset,
+                    size_t          length )
+  {
+  size_t name_length  = strlen(sv_envname);
+  size_t value_length = length;
+
+  static char   *env        = NULL;
+  static size_t  env_length = 0;
+  static char   *val        = NULL;
+  static size_t  val_length = 0;
+  if( env_length < name_length+1 )
+    {
+    env_length = name_length+1;
+    env = (char *)realloc(env, env_length);
+    }
+  if( val_length < value_length+1 )
+    {
+    val_length = value_length+1;
+    val = (char *)realloc(val, val_length);
+    }
+
+  // The name and the value arrive in the internal codeset:
+  memcpy(env, sv_envname, name_length);
+  env[name_length] = '\0';
+  memcpy(val, value->data+offset, value_length);
+  val[value_length] = '\0';
+
+  // Get rid of leading and trailing internal_space characters
+  char *trimmed_env = brute_force_trim(env);
+  char *trimmed_val = brute_force_trim(val);
+
+  // Conver them to the console codeset
+  __gg__internal_to_console_in_place(trimmed_env, strlen(trimmed_env));
+  __gg__internal_to_console_in_place(trimmed_val, strlen(trimmed_val));
+
+  // And now, anticlimactically, set the variable:
+  setenv(trimmed_env, trimmed_val, 1);
+  }

Reply via email to