[gcc r17-2266] cobol: Support non-unique section names.

"James K. Lowden via Gcc-cvs" <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:fda1343ae84090a78a40a7c9b34b11c146985061

commit r17-2266-gfda1343ae84090a78a40a7c9b34b11c146985061
Author: James K. Lowden <[email protected]>
Date:   Wed Jul 8 15:41:04 2026 -0400

    cobol: Support non-unique section names.
    
    Correct section->paragraph map in the symbol table.  Allow section
    names to be repeated and for paragraphs in them to be PERFORMed if the
    name-pair is unique. Verify all referenced procedures are defined.
    
    gcc/cobol/ChangeLog:
    
            * genapi.cc (parser_call_targets_dump): Remove function.
            * genapi.h (parser_call_targets_dump): Same.
            * parse.y: Instantiate forward labels consistently.
            (label_add) Capture forward references for efficiency.
            (paragraph_reference) Use forward reference.
            (label_add_once): New function.
            * parse_ante.h (label_add_once): Declare function.
            (label_instantiate): New function.
            (ast_enter_exit_section): Improve debug message.
            * symbols.cc (label_cmp): Allow forward reference to have a parent.
            (cbl_label_ref_t): Remove class.
            (symbol_label): Whitespace.
            (symbols_dump): Add information to output.
            (symbol_add): Remove program label symbol-assignment to symbol_label_add.
            (cbl_label_t::str): Add information to output.
            (symbol_label_add): Assign id to program label.
            * symbols.h (class cbl_label_ref_t): Remove.
            (struct symbol_elem_t): Remove struct keyword.
            (struct cbl_label_t): Same.
            (struct cbl_special_name_t): Same.
            (struct cbl_field_t): Same.
            (symbol_typedef): Same.
            (symbol_field): Same.
            (symbol_label): Same.
            (symbol_function): Same.
            (symbol_function_any): Same.
            (symbol_program): Same.
            (symbol_literalA): Same.
            (symbol_special): Same.
            (symbol_locale): Same.
            (symbol_alphabet): Same.
            (symbol_file): Same.
            (symbol_file_record): Same.
            (struct cbl_section_t): Same.
            (symbol_section): Same.
            (parent_of): Same.
            * util.cc: (match_proc::find) Use only section and paragraph names.

Diff:
---
 gcc/cobol/genapi.cc    |  23 ---------
 gcc/cobol/genapi.h     |   1 -
 gcc/cobol/parse.y      | 130 ++++++++++++++++++++++++++++++++++++++++---------
 gcc/cobol/parse_ante.h |  23 +++++++--
 gcc/cobol/symbols.cc   |  93 +++++++++++------------------------
 gcc/cobol/symbols.h    |  69 +++++++++-----------------
 gcc/cobol/util.cc      | 122 ++++++++++++----------------------------------
 7 files changed, 207 insertions(+), 254 deletions(-)

diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index 3e2b251969b3..62efc19a0ea6 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -737,29 +737,6 @@ parser_call_target_convention( tree func )
   return cbl_call_cobol_e;
   }
 
-void
-parser_call_targets_dump()
-  {
-    dbgmsg( "call targets for #" HOST_SIZE_T_PRINT_UNSIGNED " NOT dumping",
-            (fmt_size_t)current_program_index() );
-#if 0 // A change to call_targets rendered this routine useless.  Until we get
-      // around to repairing it, this code is left for reference.
-    for( const auto& elem : call_targets ) {
-      const auto& k = elem.first;
-      const auto& v = elem.second;
-      fprintf(stderr, "\t#%-3" GCC_PRISZ "u %s calls %s ",
-              (fmt_size_t)k.caller, cbl_label_of(symbol_at(k.caller))->name,
-              k.called);
-      char ch = '[';
-      for( auto func : v ) {
-        fprintf( stderr, "%c %s", ch, IDENTIFIER_POINTER(DECL_NAME(func)) );
-        ch = ',';
-      }
-      fprintf(stderr, " ]\n");
-    }
-#endif
-  }
-
 size_t
 parser_call_target_update( size_t caller,
                            const char plain_name[],
diff --git a/gcc/cobol/genapi.h b/gcc/cobol/genapi.h
index 773edacb7752..10bbf0074376 100644
--- a/gcc/cobol/genapi.h
+++ b/gcc/cobol/genapi.h
@@ -582,7 +582,6 @@ void parser_clear_exception();
 void parser_push_exception();
 void parser_pop_exception();
 
-void parser_call_targets_dump();
 size_t parser_call_target_update( size_t caller,
                                   const char extant[],
                                   const char mangled_tgt[] );
diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y
index 7eed35c1a015..22445ed5b4c5 100644
--- a/gcc/cobol/parse.y
+++ b/gcc/cobol/parse.y
@@ -5647,10 +5647,11 @@ sentences:      sentence {
         |       paragraph_name[para] '.'
                 {
                   location_set(@para);
-                  cbl_label_t *label = label_add(@para, LblParagraph, $para);
-                  if( !label ) {
-                    YYERROR;
-                  }
+                  cbl_label_t
+                    *label = label_instantiate(@para, PROGRAM, LblParagraph,
+                                               current.program_section(),
+                                               $para);
+                  assert(label);
                   ast_enter_paragraph(@para, label);
                   current.new_paragraph(label);
                   apply_declaratives();
@@ -5664,10 +5665,11 @@ sentences:      sentence {
         |       sentences paragraph_name[para] '.'
                 {
                   location_set(@para);
-                  cbl_label_t *label = label_add(@para, LblParagraph, $para);
-                  if( !label ) {
-                    YYERROR;
-                  }
+                  cbl_label_t
+                    *label = label_instantiate(@para, PROGRAM, LblParagraph,
+                                               current.program_section(),
+                                               $para);
+                  assert(label);
                   ast_enter_paragraph(@para, label);
                   current.new_paragraph(label);
                   apply_declaratives();
@@ -7048,7 +7050,7 @@ if_statements:  %empty        %prec ADD
         |       statements    %prec ADD
         |       NEXT SENTENCE %prec ADD
                 {
-                  next_sentence = label_add(LblNone, "next_sentence", 0);
+                  next_sentence = label_add_once(LblNone, "next_sentence");
                   parser_label_goto(next_sentence);
                 }
                 ;
@@ -7110,7 +7112,7 @@ eval_case:      eval_objects statements %prec ADD {
                 {
 		  auto& ev( eval_stack.current() );
 		  ev.write_when_label();
-                  next_sentence = label_add(LblNone, "next_sentence", 0);
+                  next_sentence = label_add_once(LblNone, "next_sentence");
                   parser_label_goto(next_sentence);
                 }
                 ;
@@ -8017,14 +8019,14 @@ cce_factor:     NUMSTR {
 section_name:	NAME section_kw '.'
                 {
                   statement_begin(@1, SECTION);
-		  $$ = label_add(@1, LblSection, $1);
+		  $$ = label_instantiate(@1, PROGRAM, LblSection, 0, $1);
                   ast_enter_section(@1, $$);
                   apply_declaratives();
                 }
 	|	NAME section_kw // lexer swallows '.' before USE
                 <label>{
                   statement_begin(@1, SECTION);
-		  $$ = label_add(@1, LblSection, $1);
+		  $$ = label_instantiate(@1, PROGRAM, LblSection, 0, $1);
                   ast_enter_section(@1, $$);
                   apply_declaratives();
                 } [label]
@@ -9812,7 +9814,7 @@ search_2_case:  WHEN { parser_bsearch_conditional(search_current()); }
 
 search_stmts:   statements    %prec ADD
         |       NEXT SENTENCE %prec ADD {
-                  next_sentence = label_add(LblNone, "next_sentence", 0);
+                  next_sentence = label_add_once(LblNone, "next_sentence");
                   parser_label_goto(next_sentence);
                 }
                 ;
@@ -10891,13 +10893,16 @@ label_1:        qname
 
                   if( namelocs.size() == 2 ) {
 		    auto nameloc = namelocs.front();
-                    cbl_label_t *sect = label_add(nameloc.loc, LblSection, nameloc.name);
+                    cbl_label_t *sect = symbol_label(PROGRAM,
+                                                     LblSection, 0, nameloc.name);
+                    if( !sect ) sect = label_add(nameloc.loc, LblNone, nameloc.name);
                     isect = symbol_index(symbol_elem_of(sect));
                   }
 
                   $$ = paragraph_reference(@1, para, isect);
                   assert($$);
-                  dbgmsg( "using procedure %s of line %d", $$->name, $$->line );
+                  size_t isym = symbol_index(symbol_elem_of($$));
+                  dbgmsg( "using procedure #%lu %s of line %d", isym, $$->name, $$->line );
                 }
         |       NUMSTR
                 {
@@ -13213,7 +13218,7 @@ class label_named {
 typedef label_named<LblSection> section_named;
 typedef label_named<LblParagraph> paragraph_named;
 
-static struct cbl_label_t *
+static cbl_label_t *
 label_add( const cbl_loc_t& loc,
 	   enum cbl_label_type_t type, const char name[] ) {
   size_t parent = 0;
@@ -13256,20 +13261,86 @@ label_add( const cbl_loc_t& loc,
 
   assert( !(p->type == LblSection && p->parent > 0) );
 
+  if( type == LblNone ) {
+    auto isym = symbol_index(symbol_elem_of(p));
+    current.forward_add(isym);
+    dbgmsg("%s: add forward %s %s #%lu", __func__,
+           p->type_str(), p->name, (unsigned long)isym);
+  }
   return p;
 }
 
+/*
+ * Special treatment for the "next_sentence" label, which the compiler creates and
+ * remains LblNone.
+ */
+static cbl_label_t *
+label_add_once( cbl_label_type_t type, const char name[] ) {
+  cbl_label_t *L = symbol_label(PROGRAM, type, 0, name);
+  if( L ) return L;
+
+  cbl_label_t label = { type, 0, 0 }; // no parent, line 0
+  strcpy(label.name, name);
+  
+  return symbol_label_add(PROGRAM, &label);
+}
+
 /*
  * Many label names are defined statically and so are guaranteed to be in
  * bounds. Often they are created far away from the yacc metavariables, so
  * there's no location to access.
  */
-static struct cbl_label_t *
+static cbl_label_t *
 label_add( enum cbl_label_type_t type, const char name[], int line ) {
   cbl_loc_t loc { line, 1, line, 1 };
   return label_add(loc, type, name);
 }
 
+// When a Section or Paragraph is defined, first see if a LblNone exists for
+// it.  If so, imbue it as now defined. Else create one.  
+static cbl_label_t *
+label_instantiate( const cbl_loc_t& loc, size_t program,
+                          cbl_label_type_t type, size_t section,
+                          const char name[] )
+{
+  cbl_label_t *label = symbol_label(program, type, section, name);
+  if( ! label && type == LblParagraph ) {
+    // A forward reference could be mistakenly attached to a section with no
+    // such paragraph.
+    auto& forwards = current.forwards();
+
+    for( auto isym : forwards ) {
+      auto para = cbl_label_of(symbol_at(isym));
+      if( para->type == LblNone ) {
+        if( 0 == strcasecmp(para->name, name) ) {
+          assert(para->parent);
+          auto sect = cbl_label_of(symbol_at(para->parent));            
+          if( 0 == strcasecmp(sect->name, current.section()->name) ) {
+            // The current section has the same name as a prior one, and that
+            // prior one was parsed without instantiating a forward reference
+            // that was attached to it.  So, use it.  
+            label = para;
+            forwards.erase(isym);
+            break;
+          }
+        }
+      }
+    }
+  }
+  if( label && label->type == LblNone ) {
+    label->type = type;
+    label->parent = section;
+    label->line = loc.first_line;
+    dbgmsg("%s:%d: instantiated %s", __func__, __LINE__, label->str());
+    return label;
+  }
+
+  label = label_add(loc, type, name);
+  dbgmsg("%s:%d: add %s", __func__, __LINE__, label->str());
+  
+  return label;
+}
+
 cbl_label_t *
 perform_t::ec_labels_t::new_label( cbl_label_type_t type,
 				   const cbl_name_t role )
@@ -13309,15 +13380,28 @@ perform_t::ec_labels_t::new_label( cbl_label_type_t type,
 static struct cbl_label_t *
 paragraph_reference( const cbl_loc_t& loc, const char name[], size_t section )
 {
-  // A reference has line == 0.  It is LblParagraph if the section is
-  // explicitly named, else LblNone (because we don't know).
-  struct cbl_label_t *p, label = { section? LblParagraph : LblNone, section };
+  dbgmsg("%s: find '%s' in section #%lu", __func__, name, (unsigned long)section);
+  // A reference has line == 0.  It is LblNone, possibly with a parent, until instantiated.
+  cbl_label_t label = { LblNone, section };
   assert(strlen(name) < sizeof(label.name)); // caller ensures
   strcpy(label.name, name);
-  if( label.type == LblNone ) assert(label.parent == 0);
 
-  p = symbol_label_add(PROGRAM, &label);
-  assert(p);
+  auto p = symbol_label(PROGRAM, LblParagraph, label.parent, label.name);
+  if( !p && section == 0 ) {
+    p = symbol_label(PROGRAM, LblSection, label.parent, label.name);
+  }
+  if( ! p  ) {
+    p = symbol_label_add(PROGRAM, &label);
+    assert(p);
+    if( p->type == LblNone ) {
+      auto isym = symbol_index(symbol_elem_of(p));
+      current.forward_add(isym);
+      dbgmsg("%s: add forward %s %s #%lu in section %lu", __func__,
+             p->type_str(), p->name,
+             (unsigned long)isym, (unsigned long)p->parent);
+    }
+  }
+  
   const char *para_name = p->name;
   const char *sect_name = section? cbl_label_of(symbol_at(section))->name : NULL;
   
diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h
index db574def42e7..01d546cb85ae 100644
--- a/gcc/cobol/parse_ante.h
+++ b/gcc/cobol/parse_ante.h
@@ -941,10 +941,15 @@ struct tgt_list_t {
   list<cbl_num_result_t> targets;
 };
 
-static struct cbl_label_t *
+static cbl_label_t *
 label_add( const cbl_loc_t& loc, enum cbl_label_type_t type, const char name[] );
-static struct cbl_label_t *
+static cbl_label_t *
+label_add_once( cbl_label_type_t type, const char name[] );
+static cbl_label_t *
 label_add( enum cbl_label_type_t type, const char name[], int line );
+static cbl_label_t *
+label_instantiate( const cbl_loc_t& loc, size_t program,
+                   cbl_label_type_t type, size_t section, const char name[]);
 
 static struct cbl_label_t *
 paragraph_reference( const cbl_loc_t& loc, const char name[], size_t section );
@@ -1714,6 +1719,7 @@ static class current_t {
   program_stack_t programs;
   unique_typedefs_t typedefs;
   std::set<function_descr_t> udfs;
+  std::set<size_t> undefined_labels;
   int first_statement;
   bool in_declaratives;
   // from command line or early TURN
@@ -1979,6 +1985,14 @@ static class current_t {
     return client->second;
   }
 
+  void forward_add( size_t isym ) {
+    assert( LblNone == cbl_label_of(symbol_at(isym))->type );
+    undefined_labels.insert(isym);
+  }
+  auto& forwards() {
+    return undefined_labels;
+  }
+
   void alpha_encoding( size_t isym, cbl_encoding_t encoding ) {
     prog_descr_t& program = programs.top();
     program.alphabet.alpha.set(isym, encoding);
@@ -2189,7 +2203,6 @@ static class current_t {
         }
       callers_we_have_seen.insert(caller);
       }
-      if( yydebug ) parser_call_targets_dump();
     }
 
     parser_leave_paragraph( programs.top().paragraph );
@@ -3526,8 +3539,8 @@ ast_enter_exit_section( cbl_label_t * section ) {
     parser_leave_section(prior.sect);
   }
   if( section ) {
-    dbgmsg( "%s:%d: entering section %s", __func__, __LINE__,
-            section->name );
+    dbgmsg( "%s:%d: entering section #%lu %s", __func__, __LINE__,
+            (unsigned long)symbol_index(symbol_elem_of(section)), section->name );
     parser_enter_section(section);
     parser_enter_paragraph(paragraph);
   }
diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc
index 565abb51799b..951eac6a955d 100644
--- a/gcc/cobol/symbols.cc
+++ b/gcc/cobol/symbols.cc
@@ -386,6 +386,7 @@ special_pair_cmp( const cbl_special_name_t& key,
  * Key                 Element       New    Effect
  * type  parent  line  type  parent  type
  * None     -          None     -           unqualified ref matches decl
+ * None     S          Para     -             qualified ref matches forward decl
  * None     -          Sect     -           unqualified ref matches section
  * None     -          Para     x           unqualified ref matches any para
  * Sect     -          None     -    Sect   section definition updates decl
@@ -407,14 +408,13 @@ static bool label_cmp( const cbl_label_t& key,
   switch( key.type ) {
 
   case LblNone:
-    assert(0 == key.explicit_parent());
     assert(0 == key.line);
     switch( elem.type ) {
-    case LblNone:
     case LblSection:
       assert(!elem.explicit_parent());
       return true;
       break;
+    case LblNone:
     case LblParagraph:
       return true;
       break;
@@ -427,6 +427,7 @@ static bool label_cmp( const cbl_label_t& key,
     assert(0 == key.explicit_parent());
     switch( elem.type ) {
     case LblNone:
+      return true;
     case LblSection:
       assert(!elem.explicit_parent());
       return true;
@@ -439,17 +440,18 @@ static bool label_cmp( const cbl_label_t& key,
   case LblParagraph:
     switch( elem.type ) {
     case LblNone:
-      if(elem.explicit_parent()) {
-        cbl_errx( "%s:%d: LblNone '%s' has parent #%zu",
-             __func__, __LINE__, elem.name, elem.parent );
+      // dbgmsg("%s:%d: para %s: key parent %zu, LblNone elem parent %zu", __func__, __LINE__, 
+      //        key.name, key.parent, elem.parent);
+      // Undefined label element with matching parent or no parent.
+      if( key.parent == elem.parent || elem.parent == 0 ) { 
+        return key.line == 0 || elem.line == 0 || key.line == elem.line;
       }
-      assert(!elem.explicit_parent());
-      return true;
       break;
     case LblParagraph:
-      if( key.parent == elem.parent ) { // explicit or implicit
+      // dbgmsg("%s:%d: para %s: key parent %zu, elem parent %zu", __func__, __LINE__, 
+      //        key.name, key.parent, elem.parent);
+      if( key.parent == 0 || key.parent == elem.parent ) { // explicit or implicit
         return key.line == 0 || elem.line == 0 || key.line == elem.line;
-        // negative key.line never matches (causing insertion)
       }
       break;
     default:
@@ -562,24 +564,7 @@ symbol_elem_cmp( const void *K, const void *E )
   return strcasecmp(cbl_field_of(k)->name, cbl_field_of(e)->name);
 }
 
-cbl_label_ref_t::
-cbl_label_ref_t( size_t program, const cbl_label_t& context, int line,
-                 const char name[], size_t isect )
-  : qualified(isect != 0)
-  , context(context)
-  , line(line)
-  , handle(NULL)
-{
-  cbl_label_type_t type = isect? LblParagraph : LblNone;
-  struct cbl_label_t label = { type, isect, line };
-  assert(strlen(name) < sizeof(label.name));
-  strcpy(label.name, name);
-
-  target = symbol_label_add(program, &label);
-  assert(target);
-}
-
-struct cbl_label_t *
+cbl_label_t *
 symbol_label( size_t program, cbl_label_type_t type, size_t section,
               const char name[],
               const char os_name[] )
@@ -608,7 +593,7 @@ symbol_label( size_t program, cbl_label_type_t type, size_t section,
                       break;
                     case LblNone: case LblSection: case LblParagraph:
                       return label_cmp(key, elem, true);
-                        break;
+                      break;
                     default:
                       if( key.parent != elem.parent ) { // allow zero parent of LblNone
                         if( !(elem.type == LblNone && elem.explicit_parent() == 0) ) return false;
@@ -1141,8 +1126,9 @@ symbols_dump( size_t first, bool header ) {
       }
       break;
     case SymLabel:
+      if( cbl_label_of(e)->type == LblLoop ) continue;
       s = xasprintf("%4" GCC_PRISZ "u %-18s %s", (fmt_size_t)e->program,
-                    "Labe1l", e->elem.label.str());
+                    "Label", e->elem.label.str());
       if( LblProgram == cbl_label_of(e)->type ) {
         const auto& L = *cbl_label_of(e);
         if( L.os_name ) {
@@ -2584,21 +2570,9 @@ symbol_add( struct symbol_elem_t *elem )
     cbl_field_of(elem)->our_index = symbols.nelem;
   }
 
-  struct symbol_elem_t *p =
-    static_cast<struct symbol_elem_t *>(lsearch( elem, symbols.elems,
+  auto p = static_cast<symbol_elem_t *>(lsearch( elem, symbols.elems,
                                                  &symbols.nelem, sizeof(*elem),
                                                  symbol_elem_cmp ) );
-  assert(symbols.nelem > 1);
-
-  if( is_program(*p) ) {
-    assert(p->program == 0 || p->elem.label.os_name != NULL);
-    p->program = p - symbols.elems;
-  }
-
-  if( p->program == 0 ) {
-    p->program = p[-1].program;
-  }
-
   return p;
 }
 
@@ -4408,7 +4382,7 @@ cbl_label_t::str() const {
   char *buf;
   switch(type) {
   case LblParagraph:
-    buf = xasprintf("%-12s %s OF '%s', line %d", type_str() + 3, name,
+    buf = xasprintf("%-12s %s OF #%ld %s, line %d", type_str() + 3, name, parent, 
                     parent? cbl_label_of(symbol_at(parent))->name : "", line);
     break;
   case LblProgram:
@@ -4514,40 +4488,29 @@ common_callables_update( const size_t iprog ) {
 cbl_label_t *
 symbol_label_add( size_t program, cbl_label_t *input )
 {
-  cbl_label_t *label = symbol_label(program, input->type,
-                                    input->parent, input->name);
-
-  if( label && label->type == LblNone ) {
-    label->type = input->type;
-    label->parent = input->parent;
-    label->line = input->line;
-
-    return label;
-  }
-
-  // Set the program's mangled name, dehyphenated and uniqified by parent index.
   if( input->type == LblProgram ) {
+    // Set the program's mangled name, dehyphenated and uniqified by parent index.
     char *psz = cobol_name_mangler(input->name);
     input->mangled_name = xasprintf("%s." HOST_SIZE_T_PRINT_UNSIGNED,
                                     psz, (fmt_size_t)input->parent);
     free(psz);
   }
 
-  struct symbol_elem_t
-    elem { program, *input }, *e = &elem;
+  symbol_elem_t elem { program, *input }, *e = &elem;
 
-  assert(0 <= e->elem.label.line);
-  e->elem.label.line = -e->elem.label.line; // force insertion
+  e = symbol_append(elem);
+  assert(e);
 
-  if( (e = symbol_add(&elem)) == NULL ) {
-    cbl_errx("%s:%d: could not add '%s'", __func__, __LINE__, label->name);
+  if( is_program(*e) ) {
+    assert(e->program == 0 || e->elem.label.os_name != NULL);
+    e->program = e - symbols.elems;
   }
-  assert(e);
 
-  common_callables_update( symbol_index(e) );
+  if( e->program == 0 ) {
+    e->program = e[-1].program;
+  }
 
-  // restore munged line number unless symbol_add returned an existing label
-  if( e->elem.label.line < 0 ) e->elem.label.line = -e->elem.label.line;
+  common_callables_update( symbol_index(e) );
 
   symbols.labelmap_add(e);
   return cbl_label_of(e);
diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h
index 5fd2f0917fed..3744b3a7f616 100644
--- a/gcc/cobol/symbols.h
+++ b/gcc/cobol/symbols.h
@@ -1559,26 +1559,6 @@ struct cbl_label_t {
 
 struct parser_tgt_t;
 
-class cbl_label_ref_t {
-  bool qualified;             // caller mentioned paragraph & section
-  cbl_label_t *target;
-  const cbl_label_t& context; // section called from
-  int line;                   // point of reference
-  parser_tgt_t *handle;
-public:
-  cbl_label_ref_t( size_t program, const cbl_label_t& context, int line,
-                   const char name[], size_t isect = 0 );
-
-  cbl_label_t * target_of() { return target; }
-
-  parser_tgt_t * handle_of(parser_tgt_t *parser_tgt) {
-    return this->handle = parser_tgt;
-  }
-  parser_tgt_t * handle_of() {
-    return this->handle;
-  }
-};
-
 static inline bool
 label_lessthan( const cbl_label_t & a, const cbl_label_t & b ) {
   if ( a.type == LblNone || b.type == LblNone || a.type == b.type ) {
@@ -2867,35 +2847,34 @@ cbl_namelist_t teed_up_names();
 
 size_t end_of_group( size_t igroup );
 
-struct symbol_elem_t * symbol_typedef( size_t program, std::list<const char *> names );
-struct symbol_elem_t * symbol_typedef( size_t program, const char name[] );
-struct symbol_elem_t * symbol_field( size_t program,
-                                     size_t parent, const char name[] );
-struct cbl_label_t *   symbol_label( size_t program, cbl_label_type_t type,
-                                     size_t section, const char name[],
-                                     const char os_name[] = NULL );
-struct symbol_elem_t * symbol_function( size_t parent,
-                                        const char name[], bool prototype = false );
-struct cbl_label_t *   symbol_function_any( size_t parent, const char name[] );
-struct cbl_label_t *   symbol_program( size_t parent,
-                                       const char name[], bool prototype = false );
-
-struct symbol_elem_t * symbol_literalA( size_t program, const char name[] );
-
-struct cbl_special_name_t * symbol_special( special_name_t id );
-struct symbol_elem_t * symbol_special( size_t program, const char name[] );
-struct symbol_elem_t * symbol_locale( size_t program, const char name[] );
-struct symbol_elem_t * symbol_alphabet( size_t program, const char name[] );
-
-struct symbol_elem_t * symbol_file( size_t program, const char name[] );
-struct cbl_field_t   * symbol_file_record( const cbl_file_t *file );
+symbol_elem_t * symbol_typedef( size_t program, std::list<const char *> names );
+symbol_elem_t * symbol_typedef( size_t program, const char name[] );
+symbol_elem_t * symbol_field( size_t program, size_t parent, const char name[] );
+cbl_label_t *   symbol_label( size_t program, cbl_label_type_t type,
+                              size_t section, const char name[],
+                              const char os_name[] = NULL );
+symbol_elem_t * symbol_function( size_t parent,
+                                 const char name[], bool prototype = false );
+cbl_label_t *   symbol_function_any( size_t parent, const char name[] );
+cbl_label_t *   symbol_program( size_t parent,
+                                const char name[], bool prototype = false );
+
+symbol_elem_t * symbol_literalA( size_t program, const char name[] );
+
+cbl_special_name_t * symbol_special( special_name_t id );
+symbol_elem_t * symbol_special( size_t program, const char name[] );
+symbol_elem_t * symbol_locale( size_t program, const char name[] );
+symbol_elem_t * symbol_alphabet( size_t program, const char name[] );
+
+symbol_elem_t * symbol_file( size_t program, const char name[] );
+cbl_field_t   * symbol_file_record( const cbl_file_t *file );
 cbl_file_t::varying_t symbol_file_record_sizes( struct cbl_file_t *file );
-struct cbl_section_t * symbol_section( size_t program,
-                                       struct cbl_section_t *section );
+cbl_section_t * symbol_section( size_t program,
+                                struct cbl_section_t *section );
 
 size_t symbol_label_id( const cbl_label_t *label );
 
-struct cbl_field_t * parent_of( const cbl_field_t *f );
+cbl_field_t * parent_of( const cbl_field_t *f );
  const cbl_field_t * occurs_in( const cbl_field_t *f );
 
 cbl_field_t *rename_not_ok( const cbl_field_t *first, const cbl_field_t *last);
diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc
index 0d8c88a03afd..4cc19c3ac3e7 100644
--- a/gcc/cobol/util.cc
+++ b/gcc/cobol/util.cc
@@ -2685,29 +2685,9 @@ namespace match_proc {
     }
   };
 
-  struct proc_t {
-    size_t n, isym; // index of first of n matching pairs
-    std::string para, sect;
-    proc_t( size_t n, size_t isym,
-            const std::string& para,
-            const std::string& sect )
-      : n(n), isym(isym), para(para), sect(sect)
-    {}
-    bool operator<( const proc_t& that ) const {
-      if( para == that.para ) {
-        return sect < that.sect;
-      }
-      return para < that.para;
-    }
-    static bool implicit( const std::string& input ) {
-      return input[0] == '_';
-    }
-  };
-
   class procedures_t {
     std::set<sect_t> sects;
     std::set<para_t> paras;
-    std::set<proc_t> procs;
     friend bool statements_verify();
     template <typename T>
     // If the element name is not unique, set its isym to 0 so it can't be referenced.
@@ -2739,21 +2719,6 @@ namespace match_proc {
           }
         }
       }
-      // join sections and paragraphs, unreduced
-      std::vector<proc_t> all;
-      for( const auto& para : paras ) {
-        std::set<sect_t> parents;
-        std::copy_if( sects.begin(), sects.end(), std::inserter(parents, parents.begin()),
-                      [para]( const auto& sect ) {
-                        return sect.is_unique()
-                          &&   para.parent_name() == sect.name;
-                      } );
-        std::transform( parents.begin(), parents.end(), std::back_inserter(all), 
-                        [para]( const auto& sect ) {
-                          proc_t proc(1, para.isym, para.name, sect.name);
-                          return proc;
-                        } );
-      }
       // insert paragraph procedures
       struct stat_t {
         size_t n, isym;
@@ -2764,59 +2729,32 @@ namespace match_proc {
           return *this;
         }
       };
-      std::map<proc_t, stat_t> nprocs;
-      for( const auto& proc : all ) {
-        if( ! proc.implicit(proc.para) ) {
-          auto& stat = nprocs[proc];
-          stat.update( proc.isym );
-        }
-      }
-      std::transform(nprocs.begin(), nprocs.end(), std::inserter(procs, procs.begin()),
-                     []( const auto& elem ) {
-                       proc_t proc ( elem.second.n, elem.second.isym,
-                                     elem.first.para, elem.first.sect );
-                       const char * para = proc.para.empty()? "" : proc.para.c_str();
-                       const char * sect = proc.sect.empty()? "" : proc.sect.c_str();
-                       dbgmsg("%s: insert para #%ld %s of %s", __func__,
-                              proc.isym, para, sect);
-                       return proc;
-                     } );
       // insert section procedures
       std::map<sect_t, stat_t> nsects;
       for( const auto& sect : sects ) {
         auto& stat = nsects[sect];
         stat.update( sect.isym );
       }
-      std::transform(nsects.begin(), nsects.end(), std::inserter(procs, procs.begin()),
-                     []( const auto& elem ) {
-                       proc_t proc ( elem.second.n, elem.second.isym,
-                                     std::string(), elem.first.name );
-                       const char * para = proc.para.empty()? "" : proc.para.c_str();
-                       const char * sect = proc.sect.empty()? "" : proc.sect.c_str();
-                       dbgmsg("%s: insert sect #%ld %s of %s", __func__,
-                              proc.isym, para, sect);
-                       return proc;
-                     } );
     }
 
     stmt_t::found_t
     find( const stmt_t& stmt, const stmt_t::tgt_t& tgt ) {
       if( tgt.empty() ) return stmt_t::found_t();
       std::string curr ( lcase( cbl_label_of(symbol_at(stmt.curr))->name ) );
-      std::set<proc_t> matched;
+      std::set<para_t> matched;
 
       // Match a paragraph name tgt.proc within curr, the current section.
-      std::copy_if(procs.cbegin(), procs.cend(),
+      std::copy_if(paras.cbegin(), paras.cend(),
                    std::inserter(matched, matched.begin()),
-                   [curr, tgt](const auto& proc) {
-                     return match_in_section(proc, tgt, curr);
+                   [curr, tgt](const auto& para) {
+                     return match_in_section(para, tgt, curr);
                    });
       // Match a section name if unqualified and unique.
       if( matched.empty() && tgt.qual.empty() ) {
         // target does not name a paragraph
-        if( std::none_of(procs.cbegin(), procs.cend(),
-                         [tgt](const auto& proc) {
-                           return match_any_paragraph(proc, tgt);
+        if( std::none_of(paras.cbegin(), paras.cend(),
+                         [tgt](const auto& para) {
+                           return match_any_paragraph(para, tgt);
                          }) ) {
           // target may name a section
           if( ! sects.empty() ) {
@@ -2825,52 +2763,59 @@ namespace match_proc {
             fake.name = tgt.name;
             auto p = sects.find(fake); // matches by name only, not isym
             if( p != sects.end() && p->is_unique()) {
-              proc_t proc ( 1, p->isym, std::string(), p->name );
-              matched.insert(proc);
+              para_t para( p->isym );
+              matched.insert(para);
             }
           }
         }
       }
       if( matched.empty() ){
         // Match a paragraph or section anywhere in the program.
-        std::copy_if(procs.cbegin(), procs.cend(),
+        std::copy_if(paras.cbegin(), paras.cend(),
                      std::inserter(matched, matched.begin()),
-                     [tgt](const auto& proc) {
-                       return match(proc, tgt);
+                     [tgt](const auto& para) {
+                       return match(para, tgt);
                    });
       };
 
       size_t n = matched.size();
       stmt_t::found_t found = {n, 0};
       if( n ) {
-        const proc_t& proc(*matched.begin());
-        found.isym = proc.isym;
+        const para_t& para(*matched.begin());
+        found.isym = para.isym;
+        if( yydebug && 1 < n ) {
+          for( const auto& para : matched ) {
+            fprintf(stderr, "procedures_t::find:%d: ambig: %s of #%lu, %s\n", __LINE__,
+                    para.name.c_str(), (unsigned long)para.parent, 
+                    para.parent_name().c_str());
+          }
+        }
       }
       return found;
     }
   protected:
-    static bool match_in_section( const proc_t& proc,
+    static bool match_in_section( const para_t& para,
                                   const stmt_t::tgt_t& tgt,
                                   const std::string& curr )
     {
-      return proc.para == tgt.name && proc.sect == curr
+      return para.name == tgt.name && para.parent_name() == curr
         &&   (tgt.qual == curr || tgt.qual.empty());
     }
-    static bool match_any_paragraph( const proc_t& proc,
+    static bool match_any_paragraph( const para_t& para,
                                      const stmt_t::tgt_t& tgt )
     {
       assert( tgt.qual.empty() ); 
-      return proc.para == tgt.name;
+      return para.name == tgt.name;
     }
-    static bool match( const proc_t& proc,
+    static bool match( const para_t& para,
                        const stmt_t::tgt_t& tgt )
     {
       if( tgt.qual.empty() ) {
-        return proc.sect == tgt.name
-          ||   proc.para == tgt.name;
+        return para.parent_name() == tgt.name
+          ||   para.name == tgt.name;
       } 
-      return proc.para == tgt.name
-        &&   proc.sect == tgt.qual;
+      return para.name == tgt.name
+        &&   para.parent_name() == tgt.qual;
     }
 
     void dump(const stmt_t& stmt) {
@@ -2896,13 +2841,6 @@ namespace match_proc {
         fprintf(stderr, "\t" "#%lu %s of #%lu\n",
                 (unsigned long)para.isym, para.name.c_str(), (unsigned long)para.parent);
       }
-      fprintf(stderr, "%lu Procedures:\n", (unsigned long)procs.size());
-      for( auto proc : procs ) {
-        std::string section("");
-        if( ! proc.sect.empty() ) section += "of " + proc.sect;
-        fprintf(stderr, "\t" "n=%lu %s %s\n",
-                (unsigned long)proc.isym, proc.para.c_str(), section.c_str());
-      }
       return;
     }
   }; // procedures
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.