https://gcc.gnu.org/g:612c4c104ac0c2726d2de27f350040ad5f8d5776

commit r16-1836-g612c4c104ac0c2726d2de27f350040ad5f8d5776
Author: James K. Lowden <jklow...@cobolworx.com>
Date:   Mon Jun 30 16:51:49 2025 -0400

    cobol: Revise diagnostic linemap management.
    
    Update linemap filename before location in both parsers.  Rely on
    parser to update linemap. Lexer maintains location. Various small
    syntax corrections and extensions.
    
            PR cobol/120772
            PR cobol/120779
            PR cobol/120790
            PR cobol/120791
            PR cobol/120794
    
    gcc/cobol/ChangeLog:
    
            * gcobc: Supply -fPIC for shared objects.
            * genapi.cc (linemap_add): Delete empty macro.
            (parser_enter_file): Do not call linemap_add.
            (parser_leave_file): Same.
            * gengen.cc (location_from_lineno): Remove function.
            * lexio.cc (parse_replacing_term): Allow empty term.
            (cdftext::process_file): Always append to output.
            (cdftext::segment_line): Output #line directives.
            * lexio.h (struct span_t): Count lines in span.
            * parse.y: Revamp REPOSITORY, and minor syntax extensions.
            * parse_ante.h (input_file_status_notify): Update linemap filename 
before location.
            (intrinsic_token_of): Declare.
            (parser_move_carefully): Support MOVE pointer.
            * parse_util.h (intrinsic_token_of): New function.
            * scan.l: New EOF logic, accept NOT=, own yylloc and yylineno.
            * scan_ante.h (class enter_leave_t): Do not store newline count.
            (cdf_location_set): Remove declaration.
            (ydfltype_of): New function.
            (update_location): Accept location parameter.
            (reset_location): New function.
            (YY_USER_ACTION): Use update_location().
            (YY_USER_INIT): Update CDF location.
            (verify_ws): New function.
            (wait_for_the_child): Removed.
            * symbols.h (cobol_fileline_set): return line number.
            * util.cc (valid_move): Use range-based for loop.
            (struct input_file_t): Remove line_map pointer.
            (class unique_stack): New peek() member function.
            (cobol_lineno_save): Rename to overload cobol_lineno().
            (cobol_lineno): Replaces cobol_lineno_save().
            (cobol_filename): Return void.
            (location_from_lineno): New function used by genapi.cc.
            (cdf_location_set): Remove.
            (matched_length): No change.
            (cobol_fileline_set): Return line number.
            (fisspace): Remove extra semicolon.
            (fisprint): Same.
            * util.h (cobol_filename_restore): Return void.
            (cobol_lineno_save): Remove declaration.
            (cobol_lineno): Declare.

Diff:
---
 gcc/cobol/gcobc        |   7 +-
 gcc/cobol/genapi.cc    |   9 --
 gcc/cobol/gengen.cc    |   8 -
 gcc/cobol/lexio.cc     |  26 +++-
 gcc/cobol/lexio.h      |   9 ++
 gcc/cobol/parse.y      | 109 ++++++++++----
 gcc/cobol/parse_ante.h |  11 +-
 gcc/cobol/parse_util.h |   9 ++
 gcc/cobol/scan.l       | 389 +++++++++++++++++++++++++------------------------
 gcc/cobol/scan_ante.h  | 113 +++++++-------
 gcc/cobol/symbols.h    |   2 +-
 gcc/cobol/util.cc      |  83 ++++++-----
 gcc/cobol/util.h       |   5 +-
 13 files changed, 439 insertions(+), 341 deletions(-)

diff --git a/gcc/cobol/gcobc b/gcc/cobol/gcobc
index 8c2245f5f82c..01c75dd191e4 100755
--- a/gcc/cobol/gcobc
+++ b/gcc/cobol/gcobc
@@ -35,6 +35,10 @@
 ##    output set the mode variable.  Everything else is appended to the
 ##    opts variable.
 ##
+##  - -fPIC is added to the command line if $mode is "-shared".  That
+##    option applies only to "certain machines", per the gcc info
+##    manual. For this script to be portable across machines, -fPIC
+##    would have to be set more judiciously.
 
 if [ "$COBCPY" ]
 then
@@ -478,12 +482,13 @@ do
 
         *) if [ -z "$output_name" ]  # first non-option argument is source 
file name
            then
-               output_name=$(basename ${opt%.*})
+               output_name=$(basename "${opt%.*}")
                case $mode in
                    -c) output_name="$output_name".o
                        ;;
                    -shared)
                        output_name="$output_name".so
+                       opts="$opts -fPIC"
                        ;;
                esac
                opts="$opts -o $output_name"
diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index d73601cd9d07..80177886dbc6 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -3635,8 +3635,6 @@ parser_first_statement( int lineno )
     }
   }
 
-#define linemap_add(...)
-
 void
 parser_enter_file(const char *filename)
   {
@@ -3668,9 +3666,6 @@ parser_enter_file(const char *filename)
       }
     }
 
-  // Let the linemap routine know we are working on a new file:
-  linemap_add(line_table, LC_ENTER, 0, filename, 1);
-
   if( file_level == 0 )
     {
     // Build a translation_unit_decl:
@@ -3750,10 +3745,6 @@ parser_leave_file()
     SHOW_PARSE_TEXT(ach)
     SHOW_PARSE_END
     }
-  if( file_level > 0)
-    {
-    linemap_add(line_table, LC_LEAVE, false, NULL, 0);
-    }
   file_level -= 1;
   current_filename.pop_back();
 
diff --git a/gcc/cobol/gengen.cc b/gcc/cobol/gengen.cc
index 8f5968c3aa9d..e42747b16d0e 100644
--- a/gcc/cobol/gengen.cc
+++ b/gcc/cobol/gengen.cc
@@ -265,14 +265,6 @@ gg_append_var_decl(tree var_decl)
     }
   }
 
-location_t
-location_from_lineno()
-  {
-  location_t loc;
-  loc = linemap_line_start(line_table, sv_current_line_number, 0);
-  return loc;
-  }
-
 void
 gg_append_statement(tree stmt)
   {
diff --git a/gcc/cobol/lexio.cc b/gcc/cobol/lexio.cc
index 5b6000d3c7f4..2d9fb72709f0 100644
--- a/gcc/cobol/lexio.cc
+++ b/gcc/cobol/lexio.cc
@@ -535,7 +535,7 @@ update_yylloc( const csub_match& stmt, const csub_match& 
term ) {
 
 static replacing_term_t
 parse_replacing_term( const char *stmt, const char *estmt ) {
-  gcc_assert(stmt); gcc_assert(estmt); gcc_assert(stmt < estmt);
+  gcc_assert(stmt); gcc_assert(estmt); gcc_assert(stmt <= estmt);
   replacing_term_t output(stmt);
 
   static const char pattern[] =
@@ -1830,7 +1830,7 @@ void
 cdftext::process_file( filespan_t mfile, int output, bool second_pass ) {
   static size_t nfiles = 0;
 
-  __gnu_cxx::stdio_filebuf<char> outbuf(fdopen(output, "w"), std::ios::out);
+  __gnu_cxx::stdio_filebuf<char> outbuf(fdopen(output, "a"), std::ios::out);
   std::ostream out(&outbuf);
   std::ostream_iterator<char> ofs(out);
 
@@ -1893,12 +1893,12 @@ cdftext::process_file( filespan_t mfile, int output, 
bool second_pass ) {
       continue; // No active REPLACE directive.
     }
 
-    // 1 segment for COPY, 2 for REPLACE
     std::list<span_t> segments = segment_line(mfile);
 
     for( const auto& segment : segments ) {
       std::copy(segment.p, segment.pend, ofs);
     }
+
     out.flush();
   }
   // end of file
@@ -1922,12 +1922,30 @@ cdftext::segment_line( filespan_t& mfile ) {
     return output;
   }
 
+  /*
+   * If the replacement changes the number of lines in the replaced text, we
+   * need to reset the line number, because the next statement is on a
+   * different line in the manipulated text than in the original.  Before each
+   * replacement, set the original line number.  After each replacement, set
+   * the line number after the elided text on the next line.
+   */
   for( const replace_t& segment : pending ) {
     gcc_assert(mfile.cur <= segment.before.p);
     gcc_assert(segment.before.pend <= mfile.eodata);
 
+    struct { unsigned long ante, post; } lineno = {
+      gb4(mfile.lineno()), gb4(mfile.lineno() + segment.after.nlines())
+    };
+    char *directive = lineno.ante == lineno.post?
+      nullptr : xasprintf("\n#line %lu \"%s\"\n",
+                          lineno.ante, cobol_filename());
+
+    if( directive ) 
+      output.push_back( span_t(strlen(directive), directive) );
     output.push_back( span_t(mfile.cur, segment.before.p) );
     output.push_back( span_t(segment.after.p, segment.after.pend ) );
+    if( directive ) 
+      output.push_back( span_t(strlen(directive), directive) );
 
     mfile.cur = const_cast<char*>(segment.before.pend);
   }
@@ -1943,5 +1961,3 @@ cdftext::segment_line( filespan_t& mfile ) {
 
   return output;
 }
-
-//////// End of the cdf_text.h file
diff --git a/gcc/cobol/lexio.h b/gcc/cobol/lexio.h
index 96b365491cea..eb41068d50e8 100644
--- a/gcc/cobol/lexio.h
+++ b/gcc/cobol/lexio.h
@@ -235,6 +235,8 @@ struct span_t {
 
   int size() const { return pend - p; }
 
+  size_t nlines() const { return p && pend? std::count(p, pend, '\n') : 0; }
+
   span_t dup() const {
     auto  output = new char[size() + 1];
     auto eout = std::copy(p, pend, output);
@@ -245,6 +247,13 @@ struct span_t {
     auto p = std::find(this->p, pend, '\0');
     return p != pend? p : NULL;
   }
+
+  bool at_eol() const {
+    return p < pend && '\n' == pend[-1];
+  }
+  const char * optional_eol() const {
+    return at_eol() ? "" : "\n";
+  }
 };
 
 struct replace_t {
diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y
index 660b0b4c4c23..57a41bbca718 100644
--- a/gcc/cobol/parse.y
+++ b/gcc/cobol/parse.y
@@ -692,7 +692,7 @@
 %type   <string>        fd_name picture_sym name66 paragraph_name
 %type   <literal>       literalism
 %type   <number>        bound advance_when org_clause1 read_next
-%type   <number>        access_mode multiple lock_how lock_mode
+%type   <number>        access_mode multiple lock_how lock_mode org_is
 %type   <select_clauses> select_clauses
 %type   <select_clause> select_clause  access_clause alt_key_clause
                         assign_clause collate_clause status_clause
@@ -831,6 +831,9 @@
 %type  <opt_arith>     opt_arith_type
 %type  <module_type>   module_type
 
+%type   <nameloc>       repo_func_name                        
+%type   <namelocs>      repo_func_names
+
 %union {
     bool boolean;
     int number;
@@ -840,6 +843,8 @@
     cbl_field_attr_t field_attr;
     ec_type_t ec_type;
     ec_list_t* ec_list;
+    cbl_nameloc_t  *nameloc;
+    cbl_namelocs_t *namelocs;
            declarative_list_t* dcl_list_t;
            isym_list_t* isym_list;
     struct { radix_t radix; char *string; } numstr;
@@ -2193,14 +2198,28 @@ org_clause:     org_clause1[org]
                   $$.file->org = static_cast<cbl_file_org_t>($org);
                 }
                 ;
-org_is:         %empty
-        |       ORGANIZATION is
+org_is:         %empty                 { $$ = 0; }
+        |       ORGANIZATION is        { $$ = 0; }
+        |       ORGANIZATION is RECORD { $$ = RECORD; }
+        |                       RECORD { $$ = RECORD; }
                 ;
                 // file_sequential is the proper default
-org_clause1:    org_is      SEQUENTIAL { $$ = file_sequential_e; }
-        |       org_is LINE SEQUENTIAL { $$ = file_line_sequential_e; }
-        |       org_is      RELATIVE   { $$ = file_relative_e; }
-        |       org_is      INDEXED    { $$ = file_indexed_e; }
+org_clause1:    org_is      SEQUENTIAL {
+                  $$ = $1 == RECORD? file_line_sequential_e : 
file_sequential_e;
+                }
+        |       org_is LINE SEQUENTIAL
+                {
+                  if( $1 ) error_msg(@2, "syntax error: invalid %<RECORD%>");
+                  $$ = file_line_sequential_e;
+                }
+        |       org_is      RELATIVE {
+                  if( $1 ) error_msg(@2, "syntax error: invalid %<RECORD%>");
+                  $$ = file_relative_e;
+                }
+        |       org_is      INDEXED    { 
+                  if( $1 ) error_msg(@2, "syntax error: invalid %<RECORD%>");
+                  $$ = file_indexed_e;
+                }
                 ;
 
                 /*
@@ -2328,38 +2347,61 @@ repo_expands:   %empty
 repo_interface: INTERFACE NAME repo_as repo_expands
                 ;
 
-repo_func:      FUNCTION repo_func_names INTRINSIC
-                {
-                 auto namelocs( name_queue.pop() );
-                  for( const auto& nameloc : namelocs ) {
-                      current.repository_add(nameloc.name);
+repo_func:      FUNCTION repo_func_names[namelocs] INTRINSIC {
+                  for( const auto& nameloc : *$namelocs ) {
+                    if( 0 == intrinsic_token_of(nameloc.name) ) {
+                      error_msg(nameloc.loc,
+                                "no such intrinsic function: %qs",
+                                nameloc.name);
+                      continue;
+                    }
+                    current.repository_add(nameloc.name);
                   }
                 }
         |       FUNCTION ALL INTRINSIC
                 {
                   current.repository_add_all();
                 }
-        |       FUNCTION repo_func_names
-                ;
-repo_func_names:
-                repo_func_name
-        |       repo_func_names repo_func_name
-                ;
-repo_func_name: NAME {
-                  if( ! current.repository_add($NAME) ) { // add intrinsic by 
name
-                    auto token = current.udf_in($NAME);
+        |       FUNCTION repo_func_names[namelocs] {
+                 // We allow multiple names because GnuCOBOL does.  ISO says 1.
+                  for( const auto& nameloc : *$namelocs ) {
+                    if( 0 != intrinsic_token_of(nameloc.name) ) {
+                      error_msg(nameloc.loc,
+                                "intrinsic function %qs requires INTRINSIC",
+                                nameloc.name);
+                      continue;
+                    }
+                    auto token = current.udf_in(nameloc.name);
                     if( !token ) {
-                      error_msg(@NAME, "%s is not defined here as a 
user-defined function",
-                                $NAME);
-                      current.udf_dump();
-                      YYERROR;
+                      error_msg(nameloc.loc, 
+                                "%s is not defined here as a user-defined 
function",
+                                nameloc.name);
+                      continue;
                     }
-                    auto e = symbol_function(0, $NAME);
+                    auto e = symbol_function(0, nameloc.name);
                     assert(e);
                     current.repository_add(symbol_index(e)); // add UDF to 
repository
                   }
                 }
                 ;
+repo_func_names:
+                repo_func_name[name] {
+                  $$ = new cbl_namelocs_t(1, *$name);
+                  delete $name;
+                }
+        |       repo_func_names repo_func_name[name] {
+                  $$ = $1;
+                  $$->push_back(*$name);
+                  delete $name;
+                }
+                ;
+repo_func_name: NAME repo_as {
+                  if( ! $repo_as.empty() ) {
+                    cbl_unimplemented_at(@repo_as, "%qs", $repo_as.data);
+                  }
+                  $$ = new cbl_nameloc_t(@NAME, $NAME);
+                }
+                ;
 
 repo_program:   PROGRAM_kw NAME repo_as
                 {
@@ -6383,17 +6425,17 @@ eval_abbrs:     rel_term[a] {
                  auto& ev( eval_stack.current() );
                  auto subj( ev.subject() );
                  if( !subj ) {
-                   error_msg(@1, "WHEN %s phrase exceeds "
+                   error_msg(@1, "WHEN %qs phrase exceeds "
                             "subject set count of %zu",
-                            $a.term->name(), ev.subject_count());
+                              nice_name_of($a.term->field), 
ev.subject_count());
                    YYERROR;
                  }
                  if( ! ev.compatible($a.term->field) ) {
                    auto obj($a.term->field);
                    error_msg(@1, "subject %s, type %s, "
-                            "cannot be compared %s, type %s",
-                            subj->name, 3 + cbl_field_type_str(subj->type),
-                            obj->name,  3 + cbl_field_type_str(obj->type) );
+                              "cannot be compared %s, type %s",
+                              subj->name, 3 + cbl_field_type_str(subj->type),
+                             obj->name,  3 + cbl_field_type_str(obj->type) );
                  }
                  auto result = ev.compare(*$a.term);
                  if( ! result ) YYERROR;
@@ -11850,7 +11892,10 @@ current_t::repository_add( const char name[]) {
   assert( !programs.empty() );
   function_descr_t arg = function_descr_t::init(name);
   auto parg = std::find( function_descrs, function_descrs_end, arg );
-  if( parg == function_descrs_end ) return false;
+  if( parg == function_descrs_end ) {
+    dbgmsg("%s:%d: no intrinsic %s found", __func__, __LINE__, name);
+    return false;
+  }
   auto p = programs.top().function_repository.insert(*parg);
   if( yydebug ) {
     for( auto descr : programs.top().function_repository ) {
diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h
index 3762475ee9dc..105afe9db342 100644
--- a/gcc/cobol/parse_ante.h
+++ b/gcc/cobol/parse_ante.h
@@ -102,8 +102,8 @@ void input_file_status_notify();
           (Current).last_column  = YYRHSLOC (Rhs, 0).last_column;       \
         }                                                               \
       location_dump("parse.c", __LINE__, "current", (Current));         \
-      gcc_location_set( location_set(Current) );                        \
       input_file_status_notify();                                       \
+      gcc_location_set( location_set(Current) );                        \
   } while (0)
 
 int yylex(void);
@@ -210,6 +210,9 @@ in_file_section(void) { return current_data_section == 
file_datasect_e; }
 static cbl_refer_t *
 intrinsic_inconsistent_parameter( size_t n, cbl_refer_t *args );
 
+static int
+intrinsic_token_of( const char name[] );
+
 static inline bool
 namcpy(const YYLTYPE& loc, cbl_name_t tgt, const char *src ) {
   // snprintf(3): writes at most size bytes (including the terminating NUL 
byte)
@@ -3220,6 +3223,11 @@ parser_move_carefully( const char */*F*/, int /*L*/,
       }
     } else {
       if( ! valid_move( tgt.field, src.field ) ) {
+        if( src.field->type == FldPointer &&
+            tgt.field->type == FldPointer ) {
+          if( dialect_mf() || dialect_gnu() ) return true;
+          dialect_error(src.loc, "MOVE POINTER", "mf");
+        }
         if( ! is_index ) {
           char ach[16];
           char stype[32];
@@ -3245,7 +3253,6 @@ parser_move_carefully( const char */*F*/, int /*L*/,
             sprintf(ach, ".%d", tgt.field->data.rdigits);
             strcat(dtype, ach);
             }
-
           error_msg(src.loc,  "cannot MOVE '%s' (%s) to '%s' (%s)",
                     name_of(src.field), stype,
                     name_of(tgt.field), dtype);
diff --git a/gcc/cobol/parse_util.h b/gcc/cobol/parse_util.h
index 006cea73c0a4..20847e3ef469 100644
--- a/gcc/cobol/parse_util.h
+++ b/gcc/cobol/parse_util.h
@@ -283,6 +283,15 @@ class cname_cmp {
   }
 };
 
+static int
+intrinsic_token_of( const char name[] ) {
+  auto pdescr = std::find_if( function_descrs, function_descrs_end,
+                              [name]( const function_descr_t& descr ) {
+                                return 0 == strcmp(name, descr.name);
+                              } );
+  return pdescr == function_descrs_end? 0 : pdescr->token;
+}
+
 /*
  * For variadic intrinsic functions, ensure all parameters are commensurate.
  * Return pointer in 1st inconsistent parameter type.
diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l
index 9b586e9eb48f..2fc4aea8baea 100644
--- a/gcc/cobol/scan.l
+++ b/gcc/cobol/scan.l
@@ -88,7 +88,7 @@ BLANK_EOL   [[:blank:]]*{EOL}
 BLANK_OEOL  [[:blank:]]*{EOL}?
 
 
-DOTSEP    [.][[:space:]]
+DOTSEP    [.]+[[:space:]]
 DOTEOL    [[:blank:]]*[.]{BLANK_EOL}
 
 SKIP     [[:blank:]]*SKIP[123][[:blank:]]*[.]?{BLANK_EOL}
@@ -178,7 +178,7 @@ NL       [[:blank:]]*\r?\n[[:blank:]]*
 
 PUSH_FILE \f?[#]FILE{SPC}PUSH{SPC}[^\f]+\f
 POP_FILE  \f?[#]FILE{SPC}POP\f
-LINE_DIRECTIVE [#]line{SPC}[[:alnum:]]+{SPC}[""''].+\n
+LINE_DIRECTIVE ^[#]line{SPC}[[:alnum:]]+{SPC}[""''].+\n
 
 %x procedure_div ident_state addr_of function classify
 %x program_id_state comment_entries
@@ -272,6 +272,7 @@ PROCEDURE{SPC}DIVISION      { yy_push_state(procedure_div);
 }
 
 <ident_state>{
+  ID(ENTIFICATION)?{SPC}DIVISION       { myless(0); yy_pop_state(); }
   AS{SPC}[""]  { yy_push_state(quoted2); return AS; }
   AS{SPC}['']  { yy_push_state(quoted1); return AS; }
   IS           { pop_return IS; }
@@ -328,6 +329,15 @@ CENTER             {
                  return typed_name(yytext);
                }
 
+       /* figurative constants that are otherwise matched as names */
+
+ZEROE?S?/{OSPC}{DOTSEP}                { return ZERO; }
+SPACES?/{OSPC}{DOTSEP}         { yylval.string = NULL; return SPACES; }
+QUOTES?/{OSPC}{DOTSEP}         { return QUOTES; }
+NULLS?/{OSPC}{DOTSEP}          { return NULLS; }
+LOW-VALUES?/{OSPC}{DOTSEP}     { return LOW_VALUES; }
+HIGH-VALUES?/{OSPC}{DOTSEP}    { return HIGH_VALUES; }
+
 BINARY                         { return BINARY; }
 CLASSIFICATION                 { return CLASSIFICATION; }
 CYCLE                          { return CYCLE; }
@@ -858,8 +868,9 @@ ANUM            { return ANUM; }
 ALTERNATE      { return ALTERNATE; }
 ALTER          { return ALTER; }
 ALSO           { return ALSO; }
-ALPHABET       { return ALPHABET; }
-ALPHABETIC     { return ALPHABETIC; }
+
+ALPHABET               { return ALPHABET; }
+ALPHABETIC             { return ALPHABETIC; }
 ALPHABETIC-LOWER       { return ALPHABETIC_LOWER; }
 ALPHABETIC-UPPER       { return ALPHABETIC_UPPER; }
 ALPHANUMERIC            { return ALPHANUMERIC; }
@@ -1394,10 +1405,9 @@ USE({SPC}FOR)?           { return USE; }
 <name_state>{
   ^[[:blank:]]+
   ^{BLANK_EOL}
+  {NAME}               |
   {NAME}/{OSPC}[.]     { yy_pop_state();
                          yylval.string = xstrdup(yytext); return NAME; }
-  {NAME}               { yy_pop_state();
-                         yylval.string = xstrdup(yytext); return NAME; }
 
   Z?['']                { yylval.literal.set_prefix(yytext, yyleng-1);
                          yy_push_state(quoted1); }
@@ -1501,11 +1511,11 @@ USE({SPC}FOR)?          { return USE; }
   {GREATER_THAN}{SPC}{OR_EQUAL}/[[:space:]]    { return GE; }
   {GREATER_THAN}                       { return '>'; }
 
-  {ISNT}{SPC}">="        { return '<'; }
-  {ISNT}{SPC}">"         { return LE;  }
-  {ISNT}{SPC}"="         { return NE;  }
-  {ISNT}{SPC}"<"         { return GE;  }
-  {ISNT}{SPC}"<="        { return '>'; }
+  {ISNT}{OSPC}">="        { verify_ws(yytext[yyleng - 3]); return '<'; }
+  {ISNT}{OSPC}">"         { verify_ws(yytext[yyleng - 2]); return LE;  }
+  {ISNT}{OSPC}"="         { verify_ws(yytext[yyleng - 2]); return NE;  }
+  {ISNT}{OSPC}"<"         { verify_ws(yytext[yyleng - 2]); return GE;  }
+  {ISNT}{OSPC}"<="        { verify_ws(yytext[yyleng - 3]); return '>'; }
 
   {ISNT}{SPC}GREATER{SPC}(THAN)?{SPC}{OR_EQUAL}/[[:space:]] { return '<'; }
   {ISNT}{SPC}GREATER{SPC}(THAN)?       { return LE; }
@@ -1513,13 +1523,35 @@ USE({SPC}FOR)?          { return USE; }
   {ISNT}{SPC}LESS{SPC}(THAN)?          { return GE; }
   {ISNT}{SPC}LESS{SPC}(THAN)?{SPC}{OR_EQUAL}/[[:space:]] { return '>'; }
 
-  [*]{2}{SPC}[+]       { return POW; }
-  "**"                 { return POW; }
+  [*]{2}       { return POW; }
+
+  /* 
+   * "A boolean operator specifies the type of boolean operation to be 
performed
+   *  on one or two operands, for a unary operator or binary operator,
+   *  respectively."
+   * Binary boolean operators
+   *  B-AND B-OR B-XOR
+   * Unary boolean operator
+   *  B-NOT
+   * Boolean shift operators
+   *  B-SHIFT-L B-SHIFT-LC B-SHIFT-R B-SHIFT-RC
+   */
+
+B-AND
+B-OR
+B-XOR
+B-NOT
+B-SHIFT-L
+B-SHIFT-LC
+B-SHIFT-R
+B-SHIFT-RC
+
 }
 
 <procedure_div>{
   (ID|IDENTIFICATION|ENVIRONMENT|DATA|PROCEDURE){SPC}DIVISION  {
-                           myless(0); yy_pop_state(); }
+                                 myless(0); BEGIN(INITIAL); }
+  PROGRAM-ID{OSPC}{DOTSEP}     { myless(0); BEGIN(INITIAL); }
 
   EXIT{SPC}/(PROGRAM|SECTION|PARAGRAPH|PERFORM) {
                          return EXIT; }
@@ -1586,6 +1618,7 @@ USE({SPC}FOR)?            { return USE; }
   DELIMITER                     { return DELIMITER; }
   ENVIRONMENT                   { return ENVIRONMENT; }
 
+                       /* After name state, pop out of procedure_div state. */
   END{SPC}PROGRAM        { yy_push_state(name_state);
                                   return program_level() > 1?
                                          END_SUBPROGRAM : END_PROGRAM; }
@@ -1614,22 +1647,8 @@ USE({SPC}FOR)?           { return USE; }
 
   SECTION{OSPC}[.]{SPC}/USE[[:space:]] { yylval.string = NULL; return SECTION; 
}
 
-  {NAME}{OSPC}[.]({SPC}(EJECT|SKIP[123]))*{SPC}EXIT{OSPC}/{DOTSEP} {
+  [.]({SPC}(EJECT|SKIP[123]))*{SPC}EXIT{OSPC}/{DOTSEP} {
                    // EXIT format-1 is a "continue" statement
-                   yylval.string = xstrdup(yytext);
-                  auto p = strchr(yylval.string, '.');
-                  assert(p);
-                  assert( ISSPACE(p[1]) );
-                  *p = '\0';
-                  while( p > yylval.string && ISSPACE(p[-1]) ) {
-                    *--p = '\0';
-                  }
-
-                  int token;
-                  if( 0 != (token = binary_integer_usage(yylval.string)) 
)return token;
-                   if( 0 != (token = keyword_tok(yylval.string)) ) return 
token;
-                   if( is_integer_token() ) return numstr_of(yylval.string);
-                   return typed_name(yylval.string);
                  }
   {NAME}/{OSPC}{DOTSEP} {
                   assert(YY_START == procedure_div);
@@ -2013,7 +2032,7 @@ BASIS             { yy_push_state(basis); return BASIS; }
                   }
                   return token;
                 }
-  [.][[:blank:].]+     { return '.'; }
+  [.]+[[:blank:].]+    { return '.'; }
 }
 
 <exception>{
@@ -2111,36 +2130,42 @@ BASIS           { yy_push_state(basis); return BASIS; }
 }
 
 <*>{
-  {PUSH_FILE}  {
-                       yy_set_bol(true);
-                       auto top_file = cobol_lineno_save();
-                       if( top_file ) {
-                         if( yy_flex_debug ) dbgmsg("  saving line %4d of %s",
-                                                    yylineno, top_file);
-                       }
-                       // "\f#file push <name>": name starts at offset 13.
-                       char *filename = xstrdup(yytext);
-                       filename[yyleng - 1] = '\0'; // kill the trailing 
formfeed
-                       filename += 12;
-                       if( yytext[0] != '\f' ) {
-                         dbgmsg("logic warning: filename was adjusted to %s", 
--filename);
+  {PUSH_FILE}          {
+                         yy_set_bol(true);
+                         auto top_file = cobol_lineno(yylineno);
+                         if( top_file ) {
+                           if( yy_flex_debug ) dbgmsg("  saving line %4d of 
%s",
+                                                      yylineno, top_file);
+                         }
+                         // "\f#file push <name>": name starts at offset 13.
+                         char *filename = xstrdup(yytext);
+                         filename[yyleng - 1] = '\0'; // kill the trailing 
formfeed
+                         filename += 12;
+                         if( yytext[0] != '\f' ) {
+                           dbgmsg("logic warning: filename was adjusted to %s",
+                                  --filename);
+                         }
+                         input_file_status.enter(filename);
+                         yylineno = 1;
+                         reset_location();
+                       }
+
+  {POP_FILE}           {
+                         yy_set_bol(true);
+                         input_file_status.leave();
+                         yylineno = cobol_lineno();
                        }
-                       input_file_status.enter(filename);
-               }
-
-  {POP_FILE}{OSPC}     {
-                       yy_set_bol(true);
-                       input_file_status.leave();
-               }
 
-  {LINE_DIRECTIVE} {   cobol_fileline_set(yytext); }
+  {LINE_DIRECTIVE}     {
+                         yylineno = cobol_fileline_set(yytext);
+                         reset_location();
+                       }
 }
 
 
 <*>OR                          { return OR; }
 <*>AND                         { return AND; }
 <*>{DOTSEP}[[:blank:].]+$      { return '.'; }
-<*>[*/+-]{SPC}[+]              { return *yytext; }
 <*>[().=*/+&-]                 { return *yytext; }
 <*>[[:blank:]]+
 <*>\r?\n
@@ -2154,48 +2179,48 @@ BASIS           { yy_push_state(basis); return BASIS; }
 <*>{
   ACCEPT       { return ACCEPT; }
   ACCESS       { return ACCESS; }
-  ADD  { return ADD; }
+  ADD          { return ADD; }
   ADDRESS      { return ADDRESS; }
   ADVANCING    { return ADVANCING; }
-  AFTER        { return AFTER; }
-  ALL  { return ALL; }
+  AFTER                { return AFTER; }
+  ALL          { return ALL; }
   ALLOCATE     { return ALLOCATE; }
   ALPHABET     { return ALPHABET; }
   ALPHABETIC   { return ALPHABETIC; }
   ALPHABETIC-LOWER     { return ALPHABETIC_LOWER; }
   ALPHABETIC-UPPER     { return ALPHABETIC_UPPER; }
-  ALPHANUMERIC { return ALPHANUMERIC; }
+  ALPHANUMERIC         { return ALPHANUMERIC; }
   ALPHANUMERIC-EDITED  { return ALPHANUMERIC_EDITED; }
-  ALSO { return ALSO; }
+  ALSO         { return ALSO; }
   ALTERNATE    { return ALTERNATE; }
-  AND  { return AND; }
-  ANY  { return ANY; }
+  AND          { return AND; }
+  ANY          { return ANY; }
   ANYCASE      { return ANYCASE; }
-  ARE  { return ARE; }
-  AREA { return AREA; }
-  AREAS        { return AREAS; }
-  AS   { return AS; }
+  ARE          { return ARE; }
+  AREA         { return AREA; }
+  AREAS                { return AREAS; }
+  AS           { return AS; }
   ASCENDING    { return ASCENDING; }
-  ASSIGN       { return ASSIGN; }
-  AT   { return AT; }
-  BASED        { return BASED; }
+  ASSIGN               { return ASSIGN; }
+  AT           { return AT; }
+  BASED                { return BASED; }
   BEFORE       { return BEFORE; }
   BINARY       { return BINARY; }
-  BIT  { return BIT; }
-  BLANK        { return BLANK; }
-  BLOCK        { return BLOCK_kw; }
+  BIT          { return BIT; }
+  BLANK                { return BLANK; }
+  BLOCK                { return BLOCK_kw; }
   BOTTOM       { return BOTTOM; }
-  BY   { return BY; }
-  CALL { return CALL; }
+  BY           { return BY; }
+  CALL         { return CALL; }
   CANCEL       { return CANCEL; }
-  CF   { return CF; }
-  CH   { return CH; }
+  CF           { return CF; }
+  CH           { return CH; }
   CHARACTER    { return CHARACTER; }
   CHARACTERS   { return CHARACTERS; }
-  CLASS        { return CLASS; }
-  CLOSE        { return CLOSE; }
-  CODE { return CODE; }
-  COMMA        { return COMMA; }
+  CLASS                { return CLASS; }
+  CLOSE                { return CLOSE; }
+  CODE         { return CODE; }
+  COMMA                { return COMMA; }
   COMMIT       { return COMMIT; }
   COMMON       { return COMMON; }
   CONDITION    { return CONDITION; }
@@ -2206,14 +2231,14 @@ BASIS           { yy_push_state(basis); return BASIS; }
   CONTROL      { return CONTROL; }
   CONTROLS     { return CONTROLS; }
   CONVERTING   { return CONVERTING; }
-  COPY { return COPY; }
-  COUNT        { return COUNT; }
+  COPY         { return COPY; }
+  COUNT                { return COUNT; }
   CURRENCY     { return CURRENCY; }
-  DATA { return DATA; }
-  DATE { return DATE; }
-  DAY  { return DAY; }
+  DATA         { return DATA; }
+  DATE         { return DATE; }
+  DAY          { return DAY; }
   DAY-OF-WEEK  { return DAY_OF_WEEK; }
-  DE   { return DE; }
+  DE           { return DE; }
   DECIMAL-POINT        { return DECIMAL_POINT; }
   DECLARATIVES { return DECLARATIVES; }
   DEFAULT      { return DEFAULT; }
@@ -2225,12 +2250,12 @@ BASIS           { yy_push_state(basis); return BASIS; }
   DETAIL       { return DETAIL; }
   DISPLAY      { return DISPLAY; }
   DIVIDE       { return DIVIDE; }
-  DOWN { return DOWN; }
+  DOWN         { return DOWN; }
   DUPLICATES   { return DUPLICATES; }
   DYNAMIC      { return DYNAMIC; }
-  EC   { return EC; }
-  ELSE { return ELSE; }
-  END  { return END; }
+  EC           { return EC; }
+  ELSE         { return ELSE; }
+  END          { return END; }
   END-ACCEPT   { return END_ACCEPT; }
   END-ADD      { return END_ADD; }
   END-CALL     { return END_CALL; }
@@ -2248,100 +2273,99 @@ BASIS          { yy_push_state(basis); return BASIS; }
   END-SUBTRACT { return END_SUBTRACT; }
   END-WRITE    { return END_WRITE; }
   ENVIRONMENT  { return ENVIRONMENT; }
-  EQUAL        { return EQUAL; }
-  ERROR        { return ERROR; }
+  EQUAL                { return EQUAL; }
+  ERROR                { return ERROR; }
   EVALUATE     { return EVALUATE; }
   EXCEPTION    { return EXCEPTION; }
-  EXIT { return EXIT; }
+  EXIT         { return EXIT; }
   EXTEND       { return EXTEND; }
   EXTERNAL     { return EXTERNAL; }
 
-  FD   { return FD; }
-  FINAL        { return FINAL; }
+  FD           { return FD; }
+  FINAL                { return FINAL; }
   FINALLY      { return FINALLY; }
-  FIRST        { return FIRST; }
+  FIRST                { return FIRST; }
   FOOTING      { return FOOTING; }
-  FOR  { return FOR; }
-  FREE { return FREE; }
-  FROM { return FROM; }
+  FOR          { return FOR; }
+  FREE         { return FREE; }
+  FROM         { return FROM; }
   FUNCTION     { return FUNCTION; }
   GENERATE     { return GENERATE; }
   GIVING       { return GIVING; }
   GLOBAL       { return GLOBAL; }
-  GO   { return GO; }
+  GO           { return GO; }
   GOBACK       { return GOBACK; }
-  GROUP        { return GROUP; }
+  GROUP                { return GROUP; }
   HEADING      { return HEADING; }
-  IDENTIFICATION       { return IDENTIFICATION_DIV; }
-  IF   { return IF; }
-  IN   { return IN; }
-  INDEX        { return INDEX; }
+  IF           { return IF; }
+  IN           { return IN; }
+  INDEX                { return INDEX; }
   INDEXED      { return INDEXED; }
   INDICATE     { return INDICATE; }
   INITIAL      { return INITIAL; }
   INITIALIZE   { return INITIALIZE; }
   INITIATE     { return INITIATE; }
-  INPUT        { return INPUT; }
+  INPUT                { return INPUT; }
   INSPECT      { return INSPECT; }
   INTERFACE    { return INTERFACE; }
-  INTO { return INTO; }
+  INTO         { return INTO; }
   INVOKE       { return INVOKE; }
-  IS   { return IS; }
-  KEY  { return KEY; }
-  LAST { return LAST; }
+  IS           { return IS; }
+  KEY          { return KEY; }
+  LAST         { return LAST; }
   LEADING      { return LEADING; }
-  LEFT { return LEFT; }
+  LEFT         { return LEFT; }
   LENGTH       { return LENGTH; }
-  LIMIT        { return LIMIT; }
+  LIMIT                { return LIMIT; }
   LIMITS       { return LIMITS; }
   LINAGE       { return LINAGE; }
-  LINE { return LINE; }
+  LINE         { return LINE; }
   LINE-COUNTER { return LINE_COUNTER; }
-  LINES        { return LINES; }
+  LINES                { return LINES; }
   LINKAGE      { return LINKAGE; }
   LOCAL-STORAGE        { return LOCAL_STORAGE; }
   LOCALE       { return LOCALE; }
   LOCATION     { return LOCATION; }
-  LOCK { return LOCK; }
-  MERGE        { return MERGE; }
-  MODE { return MODE; }
-  MOVE { return MOVE; }
+  LOCK         { return LOCK; }
+  MERGE                { return MERGE; }
+  MODE         { return MODE; }
+  MOVE         { return MOVE; }
   MULTIPLY     { return MULTIPLY; }
   NATIONAL     { return NATIONAL; }
   NATIONAL-EDITED      { return NATIONAL_EDITED; }
   NATIVE       { return NATIVE; }
   NEGATIVE     { return NEGATIVE; }
   NESTED       { return NESTED; }
-  NEXT { return NEXT; }
-  NO   { return NO; }
-  NOT  { return NOT; }
+  NEXT         { return NEXT; }
+  NO           { return NO; }
+  NOT          { return NOT; }
   NUMBER       { return NUMBER; }
   NUMERIC      { return NUMERIC; }
   NUMERIC-EDITED       { return NUMERIC_EDITED; }
   OCCURS       { return OCCURS; }
-  OF   { return OF; }
-  OFF  { return OFF; }
+  OF           { return OF; }
+  OFF          { return OFF; }
   OMITTED      { return OMITTED; }
-  ON   { return ON; }
-  OPEN { return OPEN; }
+  ON           { return ON; }
+  OPEN         { return OPEN; }
   OPTIONAL     { return OPTIONAL; }
   OPTIONS      { return OPTIONS; }
-  OR   { return OR; }
-  ORDER        { return ORDER; }
-  ORGANIZATION { return ORGANIZATION; }
-  OTHER        { return OTHER; }
+  OR           { return OR; }
+  ORDER                { return ORDER; }
+  ORGANI[SZ]ATION      { return ORGANIZATION; }
+  OTHER                { return OTHER; }
   OUTPUT       { return OUTPUT; }
   OVERFLOW     { return OVERFLOW_kw; }
   OVERRIDE     { return OVERRIDE; }
   PACKED-DECIMAL       { return PACKED_DECIMAL; }
-  PAGE { return PAGE; }
+  PAGE         { return PAGE; }
   PAGE-COUNTER { return PAGE_COUNTER; }
   PERFORM      { return PERFORM; }
-  PF   { return PF; }
-  PH   { return PH; }
-  PIC  { return PIC; }
+  PF           { return PF; }
+  PH           { return PH; }
+  PIC          { return PIC; }
   PICTURE      { return PICTURE; }
-  PLUS { return PLUS; }
+  PLUS         { return PLUS; }
   POINTER      { return POINTER; }
   POSITIVE     { return POSITIVE; }
   PROCEDURE    { return PROCEDURE; }
@@ -2350,15 +2374,15 @@ BASIS           { yy_push_state(basis); return BASIS; }
   PROPERTY     { return PROPERTY; }
   PROTOTYPE    { return PROTOTYPE; }
   QUOTES       { return QUOTES; }
-  RAISE        { return RAISE; }
+  RAISE                { return RAISE; }
   RAISING      { return RAISING; }
   RANDOM       { return RANDOM; }
-  RD   { return RD; }
-  READ { return READ; }
+  RD           { return RD; }
+  READ         { return READ; }
   RECORD       { return RECORD; }
   RECORDS      { return RECORDS; }
   REDEFINES    { return REDEFINES; }
-  REEL { return REEL; }
+  REEL         { return REEL; }
   REFERENCE    { return REFERENCE; }
   RELATIVE     { return RELATIVE; }
   RELEASE      { return RELEASE; }
@@ -2372,20 +2396,20 @@ BASIS           { yy_push_state(basis); return BASIS; }
   REPORTS      { return REPORTS; }
   REPOSITORY   { return REPOSITORY; }
   RESERVE      { return RESERVE; }
-  RESET        { return RESET; }
+  RESET                { return RESET; }
   RESUME       { return RESUME; }
   RETURN       { return RETURN; }
   RETURNING    { return RETURNING; }
   REWIND       { return REWIND; }
   REWRITE      { return REWRITE; }
-  RF   { return RF; }
-  RH   { return RH; }
-  RIGHT        { return RIGHT; }
+  RF           { return RF; }
+  RH           { return RH; }
+  RIGHT                { return RIGHT; }
   ROUNDED      { return ROUNDED; }
-  RUN  { return RUN; }
-  SAME { return SAME; }
+  RUN          { return RUN; }
+  SAME         { return SAME; }
   SCREEN       { return SCREEN; }
-  SD   { return SD; }
+  SD           { return SD; }
   SEARCH       { return SEARCH; }
   SECTION      { return SECTION; }
   SELECT       { return SELECT; }
@@ -2393,56 +2417,56 @@ BASIS           { yy_push_state(basis); return BASIS; }
   SEPARATE     { return SEPARATE; }
   SEQUENCE     { return SEQUENCE; }
   SEQUENTIAL   { return SEQUENTIAL; }
-  SET  { return SET; }
+  SET          { return SET; }
   SHARING      { return SHARING; }
-  SIGN { return SIGN; }
-  SIZE { return SIZE; }
-  SORT { return SORT; }
+  SIGN         { return SIGN; }
+  SIZE         { return SIZE; }
+  SORT         { return SORT; }
   SORT-MERGE   { return SORT_MERGE; }
   SOURCE       { return SOURCE; }
-  SPACE        { return SPACE; }
+  SPACE                { return SPACE; }
   SPACES       { return SPACES; }
   SPECIAL-NAMES        { return SPECIAL_NAMES; }
   STANDARD     { return STANDARD; }
   STANDARD-1   { return STANDARD_1; }
-  START        { return START; }
+  START                { return START; }
   STATUS       { return STATUS; }
-  STOP { return STOP; }
+  STOP         { return STOP; }
   SUBTRACT     { return SUBTRACT; }
-  SUM  { return SUM; }
+  SUM          { return SUM; }
   SUPPRESS     { return SUPPRESS; }
   SYMBOLIC     { return SYMBOLIC; }
   TALLYING     { return TALLYING; }
   TERMINATE    { return TERMINATE; }
-  TEST { return TEST; }
-  THAN { return THAN; }
-  THEN { return THEN; }
-  THRU { return THRU; }
-  TIME { return TIME; }
-  TIMES        { return TIMES; }
-  TO   { return TO; }
-  TOP  { return TOP; }
+  TEST         { return TEST; }
+  THAN         { return THAN; }
+  THEN         { return THEN; }
+  THRU         { return THRU; }
+  TIME         { return TIME; }
+  TIMES                { return TIMES; }
+  TO           { return TO; }
+  TOP          { return TOP; }
   TRAILING     { return TRAILING; }
 
-  TYPE { return TYPE; }
+  TYPE         { return TYPE; }
   TYPEDEF      { return TYPEDEF; }
-  UNIT { return UNIT; }
-  UNTIL        { return UNTIL; }
-  UP   { return UP; }
-  UPON { return UPON; }
-  USAGE        { return USAGE; }
-  USE  { return USE; }
-  USING        { return USING; }
-  VALUE        { return VALUE; }
+  UNIT         { return UNIT; }
+  UNTIL                { return UNTIL; }
+  UP           { return UP; }
+  UPON         { return UPON; }
+  USAGE                { return USAGE; }
+  USE          { return USE; }
+  USING                { return USING; }
+  VALUE                { return VALUE; }
   VARYING      { return VARYING; }
-  WHEN { return WHEN; }
-  WITH { return WITH; }
+  WHEN         { return WHEN; }
+  WITH         { return WITH; }
   WORKING-STORAGE      { return WORKING_STORAGE; }
-  WRITE        { return WRITE; }
+  WRITE                { return WRITE; }
 
   ZERO |
   ZEROES       |
-  ZEROS        { return ZERO; }
+  ZEROS                { return ZERO; }
 }
 
 <*>{
@@ -2479,28 +2503,13 @@ BASIS           { yy_push_state(basis); return BASIS; }
                  return NO_CONDITION;
                }
 
-<<EOF>>         {
-
-                  if( YY_START == quoted1 || YY_START == quoted2 ) {
+<quoted1,quoted2>{
+  <<EOF>>      {
                    error_msg(yylloc, "syntax error: unterminated string 
%<%s%>",
                             tmpstring);
                    return NO_CONDITION;
-                  }
-                  yypop_buffer_state();
-
-                  if ( !YY_CURRENT_BUFFER ) {
-                   return 0;
-                  }
-
-                  if( ! wait_for_the_child() ) {
-                    yyterminate();
-                  }
-                 cobol_filename_restore();
-                 parser_leave_file();
-
-                 if( yydebug ) yywarn("resume parsing '%s'", cobol_filename());
-                 yy_set_bol(true);
-                }
+               }
+}
 
 %%
 
diff --git a/gcc/cobol/scan_ante.h b/gcc/cobol/scan_ante.h
index 96b688e75128..ea304ba0d735 100644
--- a/gcc/cobol/scan_ante.h
+++ b/gcc/cobol/scan_ante.h
@@ -373,11 +373,12 @@ class enter_leave_t {
  public:
   enter_leave_t() : entering(NULL), leaving(NULL), filename(NULL) {}
   enter_leave_t(  parser_enter_file_f *entering, const char *filename )
-    : entering(entering), leaving(NULL), filename(filename) {}
+    : entering(entering), leaving(NULL), filename(filename)
+  {}
   explicit enter_leave_t(parser_leave_file_f *leaving)
     : entering(NULL), leaving(leaving), filename(NULL) {}
 
-  void notify( unsigned int newlines = 0 ) {
+  void notify() {
     if( entering ) {
       cobol_filename(filename, 0);
       if( yy_flex_debug ) dbgmsg("starting line %4d of %s",
@@ -386,10 +387,9 @@ class enter_leave_t {
       gcc_assert(leaving == NULL);
     }
     if( leaving ) {
-      auto name = cobol_filename_restore();
-      yylineno += newlines;
+      cobol_filename_restore();
       if( yy_flex_debug ) dbgmsg("resuming line %4d of %s",
-                                 yylineno, name? name : "<none>");
+                                 yylineno, cobol_filename());
       leaving();
       gcc_assert(entering == NULL);
     }
@@ -398,22 +398,17 @@ 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( enter_leave_t(parser_leave_file) );
   }
   void notify() {
     while( ! inputs.empty() ) {
       auto enter_leave = inputs.front();
-      enter_leave.notify(trailing_newlines);
+      enter_leave.notify();
       inputs.pop();
     }
   }
@@ -421,26 +416,60 @@ static class input_file_status_t {
 
 void input_file_status_notify() { input_file_status.notify(); }
 
-void cdf_location_set(YYLTYPE loc);
+/*
+ * parse.y and cdf.y each define a 4-integer struct to hold a token's 
location. 
+ * parse.y uses   YYLTYPE  yylloc;
+ * cdf.y   uses YDFLLTYPE ydflloc;
+ * 
+ * The structs have identical definitions with different types and of course
+ * names.  We define "conversion" between them for convenience. 
+ * 
+ * Each parser expects its location value to be updated whenever it calls
+ * yylex().  Therefore, here in the lexer we set both locations as each token
+ * is scanned, so that both parsers see the same location.
+ */
+static YDFLTYPE
+ydfltype_of( const YYLTYPE& loc ) {
+  YDFLTYPE output { 
+    loc.first_line,   loc.first_column,
+    loc.last_line,    loc.last_column };
+  return output;
+}
 
+/*
+ * After the input filename and yylineno are set, update the location of the
+ * scanned token.
+ */
 static void
-update_location() {
+update_location( const YYLTYPE *ploc = nullptr ) {
   YYLTYPE loc = {
     yylloc.last_line, yylloc.last_column,
     yylineno,         yylloc.last_column + yyleng
   };
+  if( ploc ) loc = *ploc;
 
-  auto nline = std::count(yytext, yytext + yyleng, '\n');
-  if( nline ) {
-    const char *p = static_cast<char*>(memrchr(yytext, '\n', yyleng));
+  const char *p = static_cast<char*>(memrchr(yytext, '\n', yyleng));
+  if( p ) {
     loc.last_column = (yytext + yyleng) - p;
   }
 
   yylloc = loc;
-  cdf_location_set(loc);
-  location_dump(__func__, __LINE__, "yylloc", yylloc);
+  ydflloc = ydfltype_of(yylloc);
+
+  dbgmsg("  SC: %s location (%d,%d) to (%d,%d)",
+         start_condition_is(),
+         yylloc.first_line, yylloc.first_column,
+         yylloc.last_line,  yylloc.last_column);
 }
 
+static void
+reset_location() {
+  static const YYLTYPE loc { yylineno, 1, yylineno, 1 };
+  update_location(&loc);
+}
+
+#define YY_USER_ACTION update_location();
+
 static void
 trim_location( int nkeep) {
   gcc_assert( 0 <= nkeep && nkeep <= yyleng );
@@ -485,7 +514,8 @@ update_location_col( const char str[], int correction = 0) {
 
 #define YY_USER_INIT do {                      \
     static YYLTYPE ones = {1,1, 1,1};          \
-    yylloc = ones;                             \
+    yylloc = ones;                              \
+    ydflloc = ydfltype_of(yylloc);              \
   } while(0)
 
 /*
@@ -494,15 +524,11 @@ update_location_col( const char str[], int correction = 
0) {
  * updates neither yylval nor yylloc.  That job is left to the actions.
  *
  * The parser relies on yylex to set yylval and yylloc each time it is
- * called. It apparently maintains a separate copy for each term, and uses
+ * called. It maintains a separate copy for each term, and uses
  * YYLLOC_DEFAULT() to update the location of nonterminals.
  */
 #define YY_DECL int lexer(void)
 
-#define YY_USER_ACTION                                                 \
-  update_location();                                                   \
-  if( yy_flex_debug ) dbgmsg("SC: %s", start_condition_is() );
-
 # define YY_INPUT(buf, result, max_size)                        \
 {                                                               \
   if( 0 == (result = lexer_input(buf, max_size, yyin)) )        \
@@ -600,6 +626,16 @@ binary_integer_usage( const char name[]) {
   return p->second.token;
 }
       
+static void
+verify_ws( const YYLTYPE& loc, const char input[], char ch ) {
+  if( ! fisspace(ch) ) {
+    if( ! (dialect_mf() || dialect_gnu()) ) {
+      dialect_error(loc, "separator space required in %qs", input);
+    }
+  }
+}
+#define verify_ws(C) verify_ws(yylloc, yytext, C)
+
 int
 binary_integer_usage_of( const char name[] ) {
   cbl_name_t uname = {};
@@ -813,35 +849,6 @@ tmpstring_append( int len ) {
 
 #define pop_return yy_pop_state(); return
 
-static bool
-wait_for_the_child(void) {
-  pid_t pid;
-  int status;
-
-  if( (pid = wait(&status)) == -1 ) {
-    yywarn("internal error: no pending child CDF parser process");
-    return false;
-  }
-
-  if( WIFSIGNALED(status) ) {
-    yywarn( "process %ld terminated by %s", 
-           static_cast<long>(pid), strsignal(WTERMSIG(status)) );
-    return false;
-  }
-  if( WIFEXITED(status) ) {
-    if( WEXITSTATUS(status) != 0 ) {
-      yywarn("process %ld exited with status %d",
-             static_cast<long>(pid), status);
-      return false;
-    }
-  }
-  if( yy_flex_debug ) {
-    yywarn("process %ld exited with status %d",
-           static_cast<long>(pid), status);
-  }
-  return true;
-}
-
 static bool is_not = false;
 
 static uint64_t
diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h
index c09fbcccf029..0b72b5cfc6c3 100644
--- a/gcc/cobol/symbols.h
+++ b/gcc/cobol/symbols.h
@@ -2197,7 +2197,7 @@ is_numeric( const cbl_field_t *field ) {
 bool cobol_filename( const char *name );
 const char * cobol_filename();
 
-const char * cobol_fileline_set( const char line[] );
+int cobol_fileline_set( const char line[] );
 
 char *cobol_name_mangler(const char *cobol_name);
 
diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc
index d8423e0ea1a4..23f605db4ed9 100644
--- a/gcc/cobol/util.cc
+++ b/gcc/cobol/util.cc
@@ -1104,10 +1104,8 @@ valid_move( const struct cbl_field_t *tgt, const struct 
cbl_field_t *src )
   static_assert(sizeof(matrix[0]) == COUNT_OF(matrix[0]),
                 "matrix should be square");
 
-  for( const cbl_field_t *args[] = {tgt, src}, **p=args;
-       p < args + COUNT_OF(args); p++ ) {
-    auto& f(**p);
-    switch(f.type) {
+  for( auto field : { src, tgt } ) {
+    switch(field->type) {
     case FldClass:
     case FldConditional:
     case FldIndex:
@@ -1119,9 +1117,9 @@ valid_move( const struct cbl_field_t *tgt, const struct 
cbl_field_t *src )
     case FldForward:
     case FldBlob:
     default:
-      if( sizeof(matrix[0]) < f.type ) {
+      if( sizeof(matrix[0]) < field->type ) {
         cbl_internal_error("logic error: MOVE %s %s invalid type:",
-                           cbl_field_type_str(f.type), f.name);
+                           cbl_field_type_str(field->type), field->name);
       }
       break;
     }
@@ -1745,11 +1743,10 @@ struct input_file_t {
   ino_t inode;
   int lineno;
   const char *name;
-  const line_map *lines;
 
   input_file_t( const char *name, ino_t inode,
-                int lineno=1, const line_map *lines = NULL )
-    : inode(inode), lineno(lineno), name(name), lines(lines)
+                int lineno=1 )
+    : inode(inode), lineno(lineno), name(name)
   {
     if( inode == 0 ) inode_set();
   }
@@ -1811,6 +1808,12 @@ class unique_stack : public std::stack<input_file_t>
     }
     return false;
   }
+
+  // Look down into the stack. peek(0) == top()
+  const input_file_t& peek( size_t n ) const {
+    gcc_assert( n < size() );
+    return c.at(size() - ++n);
+  } 
   
   void option( int opt ) { // capture other preprocessor options eventually
     assert(opt == 'M');
@@ -1867,25 +1870,42 @@ bool cobol_filename( const char *name, ino_t inode ) {
   }
   linemap_add(line_table, LC_ENTER, sysp, name, 1);
   input_filename_vestige = name;
-  bool pushed = input_filenames.push( input_file_t(name, inode, 1, lines) );
-  input_filenames.top().lineno = yylineno = 1;
+  bool pushed = input_filenames.push( input_file_t(name, inode, 1) );
   return pushed;
 }
 
 const char *
-cobol_lineno_save() {
+cobol_lineno( int lineno ) {
   if( input_filenames.empty() ) return NULL;
   auto& input( input_filenames.top() );
-  input.lineno = yylineno;
+  input.lineno = lineno;
   return input.name;
 }
 
+/*
+ * This function is called from the scanner, usually when a copybook is on top
+ * of the input stack, before the parser retrieves the token and resets the
+ * current filename.  For that reason, we normaly want to line number of the
+ * file that is about to become the current one, which is the one behind top().
+ *
+ * If somehow we arrive here when there is nothing underneath, we return the
+ * current line nubmer, or zero if there's no input.  The only consequence is
+ * that the reported line number might be wrong.
+ */
+int
+cobol_lineno() {
+  if( input_filenames.empty() ) return 0;
+  size_t n = input_filenames.size() < 2? 0 : 1;
+  const auto& input( input_filenames.peek(n) );
+  return input.lineno;
+}
+
 const char *
 cobol_filename() {
   return input_filenames.empty()? input_filename_vestige : 
input_filenames.top().name;
 }
 
-const char *
+void
 cobol_filename_restore() {
   assert(!input_filenames.empty());
   const input_file_t& top( input_filenames.top() );
@@ -1893,18 +1913,17 @@ cobol_filename_restore() {
   input_filename_vestige = top.name;
 
   input_filenames.pop();
-  if( input_filenames.empty() ) return NULL;
+  if( input_filenames.empty() ) return;
 
   auto& input = input_filenames.top();
 
-  input.lines = linemap_add(line_table, LC_LEAVE, sysp, NULL, 0);
-
-  yylineno = input.lineno;
-  return input.name;
+  linemap_add(line_table, LC_LEAVE, sysp, NULL, 0);
 }
 
 static location_t token_location;
 
+location_t location_from_lineno() { return token_location; }
+
 template <typename LOC>
 static void
 gcc_location_set_impl( const LOC& loc ) {
@@ -2038,16 +2057,6 @@ void error_msg( const YDFLTYPE& loc, const char 
gmsgid[], ... ) {
   ERROR_MSG_BODY
 }
 
-void
-cdf_location_set(YYLTYPE loc) {
-  extern YDFLTYPE ydflloc;
-
-  ydflloc.first_line =   loc.first_line;
-  ydflloc.first_column = loc.first_column;
-  ydflloc.last_line =    loc.last_line;
-  ydflloc.last_column =  loc.last_column;
-}
-
 void
 yyerror( const char gmsgid[], ... ) {
   temp_loc_t looker;
@@ -2101,7 +2110,7 @@ yyerrorvl( int line, const char *filename, const char 
fmt[], ... ) {
 static inline size_t
 matched_length( const regmatch_t& rm ) { return rm.rm_eo - rm.rm_so; }
 
-const char *
+int
 cobol_fileline_set( const char line[] ) {
   static const char pattern[] = "#line +([[:alnum:]]+) +[\"']([^\"']+). *\n";
   static const int cflags = REG_EXTENDED | REG_ICASE;
@@ -2114,7 +2123,7 @@ cobol_fileline_set( const char line[] ) {
     if( (erc = regcomp(&re, pattern, cflags)) != 0 ) {
         regerror(erc, &re, regexmsg, sizeof(regexmsg));
         dbgmsg( "%s:%d: could not compile regex: %s", __func__, __LINE__, 
regexmsg );
-        return line;
+        return 0;
     }
     preg = &re;
   }
@@ -2122,10 +2131,10 @@ cobol_fileline_set( const char line[] ) {
     if( erc != REG_NOMATCH ) {
       regerror(erc, preg, regexmsg, sizeof(regexmsg));
       dbgmsg( "%s:%d: could not compile regex: %s", __func__, __LINE__, 
regexmsg );
-      return line;
+      return 0;
     }
     error_msg(yylloc, "invalid %<#line%> directive: %s", line );
-    return line;
+    return 0;
   }
 
   const char
@@ -2139,15 +2148,13 @@ cobol_fileline_set( const char line[] ) {
   input_file_t input_file( filename, ino_t(0), fileline ); // constructor sets 
inode
 
   if( input_filenames.empty() ) {
-    input_file.lines = linemap_add(line_table, LC_ENTER, sysp, filename, 1);
     input_filenames.push(input_file);
   }
 
   input_file_t& file = input_filenames.top();
   file = input_file;
-  yylineno = file.lineno;
 
-  return file.name;
+  return file.lineno;
 }
 
 //#define TIMING_PARSE
@@ -2357,7 +2364,7 @@ bool fisdigit(int c)
 bool fisspace(int c)
   {
   return ISSPACE(c);
-  };
+  }
 int  ftolower(int c)
   {
   return TOLOWER(c);
@@ -2369,7 +2376,7 @@ int  ftoupper(int c)
 bool fisprint(int c)
   {
   return ISPRINT(c);
-  };
+  }
 
 // 8.9 Reserved words
 static const std::set<std::string> reserved_words = {
diff --git a/gcc/cobol/util.h b/gcc/cobol/util.h
index 9388b50a6804..165915a264a8 100644
--- a/gcc/cobol/util.h
+++ b/gcc/cobol/util.h
@@ -47,8 +47,9 @@ bool fisprint(int c);
 
 void cobol_set_pp_option(int opt);
 
-const char * cobol_filename_restore();
-const char * cobol_lineno_save();
+void cobol_filename_restore();
+const char * cobol_lineno( int );
+int cobol_lineno();
 
 unsigned long gb4( size_t input );

Reply via email to