From 6ae5fb77cb948499b37fb524a9eca5eaab6600fb Mon Sep 17 00:00:00 2001
From: "James K. Lowden" <jklowden@symas.com>
Date: Tue, 14 Jan 2025 15:01:32 -0500
Subject: [PATCH] begin updating location in lexio

---
 gcc/cobol/UAT/testsuite.src/run_functions.at  | 147 +++++-----
 gcc/cobol/UAT/testsuite.src/syn_copy.at       |  12 +-
 gcc/cobol/UAT/testsuite.src/syn_definition.at |  36 ++-
 gcc/cobol/cdf-copy.cc                         |   2 +-
 gcc/cobol/lexio.cc                            | 270 ++++++++++--------
 gcc/cobol/lexio.h                             |  49 +++-
 6 files changed, 302 insertions(+), 214 deletions(-)

diff --git a/gcc/cobol/UAT/testsuite.src/run_functions.at b/gcc/cobol/UAT/testsuite.src/run_functions.at
index 91937b1d8efd..a5de5daeeb37 100644
--- a/gcc/cobol/UAT/testsuite.src/run_functions.at
+++ b/gcc/cobol/UAT/testsuite.src/run_functions.at
@@ -5281,9 +5281,6 @@ prog.cob:22:12: error: syntax error, unexpected END_IF
 prog.cob:25:29: error: syntax error, unexpected NAME, expecting DATETIME_FMT
    25 |                            (invalid-datetime-format, 1, 1) <> SPACES
       |                             ^
-prog.cob:25:1: error: FORMATTED_DATETIME: invalid parameter value
-   25 |                            (invalid-datetime-format, 1, 1) <> SPACES
-      | ^
 prog.cob:29:12: error: syntax error, unexpected END_IF
    29 |            END-IF
       |            ^
@@ -5453,114 +5450,114 @@ AT_DATA([prog.cob], [
         END PROGRAM datetime.
 ])
 AT_CHECK([$COMPILE prog.cob], [1], [],
-[prog.cob:7:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+[prog.cob:7:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
     7 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-DDDThhmmss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:8:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:8:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
     8 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-DDDThhmmss+hhmm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:9:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:9:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
     9 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-DDDThhmmss.ssss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:10:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:10:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    10 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-DDDThhmmss.ssss+hhmm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:11:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:11:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    11 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-DDDThhmmss.ssssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:12:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:12:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    12 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-DDDThhmmssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:13:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:13:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    13 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-MM-DDThhmmss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:14:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:14:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    14 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-MM-DDThhmmss+hhmm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:15:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:15:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    15 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-MM-DDThhmmss.ssss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:16:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:16:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    16 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-MM-DDThhmmss.ssss+hhmm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:17:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:17:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    17 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-MM-DDThhmmss.ssssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:18:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:18:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    18 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-MM-DDThhmmssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:19:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:19:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    19 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-Www-DThhmmss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:20:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:20:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    20 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-Www-DThhmmss+hhmm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:21:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:21:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    21 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-Www-DThhmmss.ssss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:22:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:22:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    22 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-Www-DThhmmss.ssss+hhmm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:23:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:23:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    23 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-Www-DThhmmss.ssssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:24:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:24:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    24 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYY-Www-DThhmmssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:25:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:25:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    25 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYDDDThh:mm:ss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:26:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:26:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    26 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYDDDThh:mm:ss+hh:mm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:27:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:27:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    27 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYDDDThh:mm:ss.ssss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:28:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:28:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    28 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYDDDThh:mm:ss.ssss+hh:mm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:29:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:29:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    29 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYDDDThh:mm:ss.ssssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:30:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:30:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    30 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYDDDThh:mm:ssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:31:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:31:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    31 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYMMDDThh:mm:ss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:32:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:32:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    32 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYMMDDThh:mm:ss+hh:mm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:33:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:33:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    33 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYMMDDThh:mm:ss.ssss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:34:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:34:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    34 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYMMDDThh:mm:ss.ssss+hh:mm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:35:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:35:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    35 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYMMDDThh:mm:ss.ssssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:36:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:36:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    36 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYMMDDThh:mm:ssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:37:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:37:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    37 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYWwwDThh:mm:ss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:38:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:38:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    38 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYWwwDThh:mm:ss+hh:mm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:39:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:39:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    39 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYWwwDThh:mm:ss.ssss" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:40:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:40:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    40 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYWwwDThh:mm:ss.ssss+hh:mm" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:41:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:41:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    41 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYWwwDThh:mm:ss.ssssZ" 128623 45296.987654321 -300).
-      |                                             ^
-prog.cob:42:45: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
+      |                                              ^
+prog.cob:42:46: error: syntax error, unexpected LITERAL, expecting DATETIME_FMT
    42 |         DISPLAY FUNCTION FORMATTED-DATETIME("YYYYWwwDThh:mm:ssZ" 128623 45296.987654321 -300).
-      |                                             ^
+      |                                              ^
 cobol1: error: failed compiling prog.cob
 ])
 AT_CLEANUP
diff --git a/gcc/cobol/UAT/testsuite.src/syn_copy.at b/gcc/cobol/UAT/testsuite.src/syn_copy.at
index 9965d5ba49c9..19ca1c91946e 100644
--- a/gcc/cobol/UAT/testsuite.src/syn_copy.at
+++ b/gcc/cobol/UAT/testsuite.src/syn_copy.at
@@ -279,13 +279,13 @@ AT_DATA([copy3.CPY],
        01 TEST-VAR3 PIC X(2) VALUE "V3".
 ])
 AT_CHECK([$COMPILE_ONLY prog.cob], [1], [],
-[cobol1: warning: depth line copybook filename
+[depth line copybook filename
                  ----- ---- ------------------------------------------------
-cobol1: warning:     1    1 prog.cob
-cobol1: warning:     2    1 copy1.CPY
-cobol1: warning:     3    1 copy2.CPY
-cobol1: warning:     4    1 copy3.CPY
-copy3.CPY:1: recursive copybook: 'copy1.CPY' includes itself
+    1    1 prog.cob
+    2    1 copy1.CPY
+    3    1 copy2.CPY
+    4    1 copy3.CPY
+cobol1: error: recursive copybook: 'copy1.CPY' includes itself
 cobol1: error: failed compiling prog.cob
 ])
 AT_CLEANUP
diff --git a/gcc/cobol/UAT/testsuite.src/syn_definition.at b/gcc/cobol/UAT/testsuite.src/syn_definition.at
index 46fd904a4378..efe6c025d029 100644
--- a/gcc/cobol/UAT/testsuite.src/syn_definition.at
+++ b/gcc/cobol/UAT/testsuite.src/syn_definition.at
@@ -131,7 +131,9 @@ AT_DATA([prog.cob], [
 ])
 
 AT_CHECK([$COMPILE_ONLY prog.cob], [1], [],
-[prog.cob:3: error: COMMON may be used only in a contained program at 'COMMON'
+[prog.cob:3:33: error: COMMON may be used only in a contained program
+    3 |        PROGRAM-ID.      prog IS COMMON.
+      |                                 ^
 cobol1: error: failed compiling prog.cob
 ])
 
@@ -155,7 +157,9 @@ AT_DATA([prog.cob], [
 
 # better: prog.cob:8: error: 'X IN X' is not defined
 AT_CHECK([$COMPILE_ONLY prog.cob], [1], [],
-[prog.cob:9: error: symbol 'X' not found at 'END-DISPLAY'
+[prog.cob:8:26: error: symbol 'X' not found
+    8 |            DISPLAY X IN X
+      |                          ^
 cobol1: error: failed compiling prog.cob
 ])
 
@@ -220,13 +224,27 @@ AT_DATA([prog.cob], [
 ])
 
 AT_CHECK([$COMPILE_ONLY prog.cob], [1], [],
-[prog.cob:11: syntax error at 'NOT-DEFINED'
-prog.cob:16: syntax error at 'NOT-DEFINED'
-prog.cob:24: syntax error at '''
-prog.cob:30: syntax error at 'TESTME'
-prog.cob:37: error: symbol 'NOT-DEFINED' not found at 'CONTINUE'
-prog.cob:42: ELSE not valid in WHEN at 'ELSE'
-prog.cob:48: error: symbol 'broken' not found at 'WHEN'
+[prog.cob:11:28: error: syntax error, unexpected NAME, expecting CLASS_NAME or OMITTED
+   11 |             WHEN TESTME IS NOT-DEFINED
+      |                            ^
+prog.cob:16:32: error: syntax error, unexpected NAME, expecting CLASS_NAME or OMITTED
+   16 |               IF NOT TESTME IS NOT-DEFINED
+      |                                ^
+prog.cob:24:28: error: syntax error, unexpected LITERAL, expecting CLASS_NAME or OMITTED
+   24 |             WHEN TESTME IS 'ABC'
+      |                            ^
+prog.cob:30:28: error: syntax error, unexpected NAME, expecting CLASS_NAME or OMITTED
+   30 |             WHEN TESTME IS TESTME
+      |                            ^
+prog.cob:36:31: error: symbol 'NOT-DEFINED' not found
+   36 |             WHEN TESTME NOT = NOT-DEFINED
+      |                               ^
+prog.cob:42:18: error: ELSE not valid in WHEN
+   42 |             WHEN TESTME ELSE NOT-DEFINED
+      |                  ^
+prog.cob:47:20: error: symbol 'broken' not found
+   47 |           EVALUATE broken
+      |                    ^
 cobol1: error: failed compiling prog.cob
 ])
 AT_CLEANUP
diff --git a/gcc/cobol/cdf-copy.cc b/gcc/cobol/cdf-copy.cc
index d30bc031c471..a98d789f8eed 100644
--- a/gcc/cobol/cdf-copy.cc
+++ b/gcc/cobol/cdf-copy.cc
@@ -170,7 +170,7 @@ esc( size_t len, const char input[] ) {
 }
 
 static int
-asdfglob_error(const char *epath, int eerrno) {
+glob_error(const char *epath, int eerrno) {
   yyerror("COPY file search: '%s': %s", epath, xstrerror(eerrno));
   return 0;
 }
diff --git a/gcc/cobol/lexio.cc b/gcc/cobol/lexio.cc
index d2f9d453dd45..9098a414b546 100644
--- a/gcc/cobol/lexio.cc
+++ b/gcc/cobol/lexio.cc
@@ -144,9 +144,7 @@ remove_inline_comment( char *bol, char *eol ) {
 
 static void
 erase_line( char *src, char *esrc ) {
-  if( yy_flex_debug ) {
-    yywarn( "%s: erasing %.*s from input", __func__, int(esrc-src), src);
-  }
+  dbgmsg( "%s: erasing %.*s from input", __func__, int(esrc-src), src);
   erase_source(src, esrc);
 }
 
@@ -265,15 +263,13 @@ recognize_replacements( filespan_t mfile, std::list<replace_t>& pending_replacem
         found = span_t( cm[1].first, cm[1].second );
         if( yy_flex_debug ) {
           size_t n = count_newlines(mfile.data, found.p);
-          yywarn("%s:%d first '%.*s' is on line %zu (offset %zu)", __func__, __LINE__,
-                directive.before.size(), directive.before.p,
-                ++n, found.p - mfile.data);
+          dbgmsg("%s:%d first '%.*s' is on line %zu (offset %zu)", __func__, __LINE__,
+		 directive.before.size(), directive.before.p,
+		 ++n, found.p - mfile.data);
         }
       } else {
-        if( yy_flex_debug ) {
-          yywarn("%s:%d not found: '%s' in \n'%.*s'", __func__, __LINE__,
-                directive.before.p, int(strlen(directive.before.p)), mfile.cur);
-        }
+	dbgmsg("%s:%d not found: '%s' in \n'%.*s'", __func__, __LINE__,
+	      directive.before.p, int(strlen(directive.before.p)), mfile.cur);
       }
       futures.push_back( future_replacement_t(directive, found) );
     }
@@ -297,11 +293,11 @@ recognize_replacements( filespan_t mfile, std::list<replace_t>& pending_replacem
 
     if( yy_flex_debug ) {
       size_t n = std::count((const char *)mfile.data, recognized.before.p, '\n');
-      yywarn( "%s:%d: line %zu @ %zu: '%s'\n/%.*s/%.*s/", __func__, __LINE__,
-             ++n, next.found.p - mfile.data,
-             next.directive.before.p,
-             int(recognized.before.size()), recognized.before.p,
-             int(recognized.after.size()), recognized.after.p );
+      dbgmsg( "%s:%d: line %zu @ %zu: '%s'\n/%.*s/%.*s/", __func__, __LINE__,
+	      ++n, next.found.p - mfile.data,
+	      next.directive.before.p,
+	      int(recognized.before.size()), recognized.before.p,
+	      int(recognized.after.size()), recognized.after.p );
     }
 
     // Update the futures element for this pattern
@@ -315,9 +311,9 @@ recognize_replacements( filespan_t mfile, std::list<replace_t>& pending_replacem
       next.found = span_t( cm[1].first, cm[1].second );
       size_t n = std::count((const char *)mfile.data, next.found.p, '\n');
       if( false )
-        yywarn("%s:%d next '%.*s' will be on line %zu (offset %zu)", __func__, __LINE__,
-              next.directive.before.size(), next.directive.before.p,
-              ++n, next.found.p - mfile.data);
+        dbgmsg("%s:%d next '%.*s' will be on line %zu (offset %zu)", __func__, __LINE__,
+	       next.directive.before.size(), next.directive.before.p,
+	       ++n, next.found.p - mfile.data);
     }
     pnext = std::min_element(futures.begin(), futures.end());
   }
@@ -351,10 +347,8 @@ check_source_format_directive( filespan_t& mfile ) {
       break;
     }
     mfile.cur = const_cast<char*>(cm[0].second);
-    if( yy_flex_debug ) {
-      yywarn( "%s:%d: %s format set, on line %zu", __func__, __LINE__,
-             indicator.column == 7? "FIXED" : "FREE", mfile.lineno );
-    }
+    dbgmsg( "%s:%d: %s format set, on line %zu", __func__, __LINE__,
+	    indicator.column == 7? "FIXED" : "FREE", mfile.lineno() );
     erase_line(const_cast<char*>(cm[0].first),
                const_cast<char*>(cm[0].second));
   }
@@ -385,13 +379,8 @@ struct buffer_t : public bytespan_t {
   }
 
   void show() const {
-    char *output;
     gcc_assert(data <= pos);
-    if( -1 == asprintf( &output, "%.*s", int(pos - data), data ) ) {
-      return;
-    }
-    yywarn("flex input buffer: '%s'\n[xelf]", output);
-    free(output);
+    dbgmsg("flex input buffer: '%.*s'\n[xelf]", int(pos - data), data);
   }
   void dump() const {
     if( getenv("lexer_input") ) show();
@@ -456,6 +445,71 @@ struct replacing_term_t {
   }
 };
 
+extern YYLTYPE yylloc;
+
+static const char *
+last_newline (const char *p, const char *pend ) {
+  size_t len = pend - p;
+  return static_cast<const char *>( memrchr( p, '\n', len ) );
+}
+/*
+ * For some statement parsed with regex_search, set yyloc to indicate the line
+ * and column spans of the term.  Assume stmt begins at the start of a line. 
+ */
+static void
+update_yylloc( const csub_match& stmt, const csub_match& term ) {
+  gcc_assert(stmt.first <= term.first && term.second <= stmt.second);
+
+  class dump_loc_on_exit {
+   public:
+    dump_loc_on_exit() {
+      if( getenv( "update_yylloc" ) )
+	location_dump( "update_yylloc", __LINE__, "begin", yylloc);
+    }
+    ~dump_loc_on_exit() {
+      if( getenv( "update_yylloc" ) )
+	location_dump( "update_yylloc", __LINE__, "end  ", yylloc);
+    }
+  } dloe;
+  
+  size_t nline = std::count( stmt.first, term.second, '\n' );
+  size_t n = std::count( term.first, term.second, '\n' );
+  
+  if( nline ) {
+    yylloc.last_line += nline;
+    yylloc.first_line = yylloc.last_line - n;
+  }
+
+  /*
+   * Set the column span for the term.
+   */
+  const char *p = last_newline(stmt.first, stmt.second);
+  if( !p ) { // no newlines in entire statement
+    yylloc.first_column = (term.first - stmt.first) + 1;
+    yylloc.last_column =  (term.second - stmt.first) + 1;
+    return;
+  }
+
+  p = last_newline(stmt.first, term.first);
+  if( !p ) { // no newlines before term
+    yylloc.first_column = (term.first - stmt.first) + 1;
+    p = last_newline(term.first, term.second);
+    gcc_assert(p); // newline must be in term
+    yylloc.last_column = (term.second - p) + 1;
+    return;
+  }
+  
+  const char *bol = p; // bol points to last newline before term
+  
+  yylloc.first_column = term.first - bol;
+  p = last_newline(term.first, term.second);
+  if( p ) { // term has newlines, too
+    yylloc.last_column =  (p - term.first);
+  } else {
+    yylloc.last_column = yylloc.first_column + term.length();
+  }
+}
+
 static replacing_term_t
 parse_replacing_term( const char *stmt, const char *estmt ) {
   gcc_assert(stmt); gcc_assert(estmt); gcc_assert(stmt < estmt);
@@ -499,9 +553,8 @@ parse_replacing_term( const char *stmt, const char *estmt ) {
     output.done = output.matched = true;
     output.stmt = cm[0];
     gcc_assert(output.stmt.pend[-1] == '.');
-    if( yy_flex_debug )
-      yywarn("%s:%d: done at '%.*s'", __func__, __LINE__,
-            output.term.size(), output.term.p);
+    dbgmsg("%s:%d: done at '%.*s'", __func__, __LINE__,
+	   output.term.size(), output.term.p);
     return output;
   }
 
@@ -517,20 +570,19 @@ parse_replacing_term( const char *stmt, const char *estmt ) {
       output.done = '.' == output.stmt.pend[0] && ISSPACE(output.stmt.pend[1]);
       if( output.done ) output.stmt.pend++;
     }
-    if( yy_flex_debug )
-      yywarn("%s:%d: %s '%.*s'", __func__, __LINE__,
-            output.done? "done at" : "term is",
-            output.term.size(), output.term.p);
+    dbgmsg("%s:%d: %s '%.*s'", __func__, __LINE__,
+	   output.done? "done at" : "term is",
+	   output.term.size(), output.term.p);
     return output;
   }
 
   if( yy_flex_debug ) { // should be looking only for words
-    yywarn("%s:%d: not done, working with '%.*s'", __func__, __LINE__,
+    dbgmsg("%s:%d: not done, working with '%.*s'", __func__, __LINE__,
           cm[0].length(), cm[0].first);
     int i=0;
     for( auto m : cm ) {
       if( m.matched )
-        yywarn("%4d) '%.*s'", i, m.length(), m.first);
+        dbgmsg("%4d) '%.*s'", i, m.length(), m.first);
       i++;
     }
   }
@@ -538,9 +590,8 @@ parse_replacing_term( const char *stmt, const char *estmt ) {
   if( !cm[8].matched ) {
     output.matched = output.stmt.p < output.term.p;
     gcc_assert(output.matched);
-    if( yy_flex_debug )
-      yywarn("%s:%d: term is '%.*s'", __func__, __LINE__,
-            output.term.size(), output.term.p);
+    dbgmsg("%s:%d: term is '%.*s'", __func__, __LINE__,
+	   output.term.size(), output.term.p);
     return output;
   }
 
@@ -554,6 +605,7 @@ parse_replacing_term( const char *stmt, const char *estmt ) {
       }
     }
     if( extraneous_replacing ) {
+      update_yylloc( cm[0], cm[8] );
       yywarn("syntax error: invalid '%.*s'", cm[8].length(), cm[8].first);
       output.matched = false;
       return output;
@@ -563,9 +615,8 @@ parse_replacing_term( const char *stmt, const char *estmt ) {
   gcc_assert(cm[8].matched);
   gcc_assert(0 < output.term.size());
 
-  if( yy_flex_debug )
-    yywarn("%s:%d: more words starting at '%.80s'", __func__, __LINE__,
-          output.term.pend);
+  dbgmsg("%s:%d: more words starting at '%.80s'", __func__, __LINE__,
+	 output.term.pend);
 
   static const char term_pattern[] =
     "^[[:space:]]+"
@@ -620,8 +671,8 @@ parse_replacing_term( const char *stmt, const char *estmt ) {
   if( yy_flex_debug ) {
     const char *status = "unmatched";
     if( output.matched ) status = output.done? "done" : "matched";
-    yywarn("%s:%d: %s term is '%.*s'", __func__, __LINE__, status,
-          output.term.size(), output.term.p? output.term.p : "");
+    dbgmsg("%s:%d: %s term is '%.*s'", __func__, __LINE__, status,
+	   output.term.size(), output.term.p? output.term.p : "");
   }
   return output;
 }
@@ -651,19 +702,17 @@ parse_replacing_pair( const char *stmt, const char *estmt ) {
         pair.stmt.pend = parsed.stmt.pend;
         pair.replace.after = parsed.term;
       } else {
-        if( yy_flex_debug ) {
-          yywarn("%s:%d: not matched '%.*s'", __func__, __LINE__,
-                pair.stmt.size(), pair.stmt.p);
-        }
+	dbgmsg("%s:%d: not matched '%.*s'", __func__, __LINE__,
+	       pair.stmt.size(), pair.stmt.p);
       }
     }
     if( yy_flex_debug ) {
       const char *status = "unmatched";
       if( pair.matched() ) status = pair.done()? "done" : "matched";
-      yywarn("%s:%d: [%s] replacing '%.*s' with '%.*s'", __func__, __LINE__,
-            status,
-            pair.replace.before.size(), pair.replace.before.p,
-            pair.replace.after.size(), pair.replace.after.p);
+      dbgmsg("%s:%d: [%s] replacing '%.*s' with '%.*s'", __func__, __LINE__,
+	     status,
+	     pair.replace.before.size(), pair.replace.before.p,
+	     pair.replace.after.size(), pair.replace.after.p);
     }
   } else {
     for( auto p = stmt; (p = std::find(p, estmt, '.')) < estmt; p++ ) {
@@ -719,11 +768,11 @@ parse_replace_pairs( const char *stmt, const char *estmt, bool is_copy_stmt ) {
       // Report findings.
       if( false && yy_flex_debug ) {
         for( size_t i=0; i < cm.size(); i++ ) {
-          yywarn("%s: %s %zu: '%.*s'", __func__,
-                cm[i].matched? "Pair" : "pair",
-                i,
-                cm[i].matched? int(cm[i].length()) : 0,
-                cm[i].matched? cm[i].first : "");
+          dbgmsg("%s: %s %zu: '%.*s'", __func__,
+		 cm[i].matched? "Pair" : "pair",
+		 i,
+		 cm[i].matched? int(cm[i].length()) : 0,
+		 cm[i].matched? cm[i].first : "");
         }
       }
       gcc_assert(cm[3].matched);
@@ -761,15 +810,11 @@ parse_replace_pairs( const char *stmt, const char *estmt, bool is_copy_stmt ) {
       default:
         gcc_assert(false);
       }
-      yywarn("%s:%d: dealing with %.*s", __func__, __LINE__,
-            int(parsed.leading_trailing.size()), parsed.leading_trailing.p);
+      dbgmsg("%s:%d: dealing with %.*s", __func__, __LINE__,
+	     int(parsed.leading_trailing.size()), parsed.leading_trailing.p);
     }
 
-    char *s;
-    if( -1 == asprintf(&s, "%s(%s)%s", befter[0], src, befter[1]) ) {
-      cbl_err("%s: %m", __func__);
-    }
-    src = s;
+    src = xasprintf("%s(%s)%s", befter[0], src, befter[1]);
 
     struct {  span_t before, after; }  output;
     output.before = span_t(strlen(src), src);
@@ -784,13 +829,13 @@ parse_replace_pairs( const char *stmt, const char *estmt, bool is_copy_stmt ) {
   }
 
   if( yy_flex_debug ) {
-    yywarn( "%s:%d: %s: %zu pairs parsed from  '%.*s'", __func__, __LINE__,
-           parsed.done()? "done" : "not done",
-           pairs.size(), parsed.stmt.size(), parsed.stmt.p );
+    dbgmsg( "%s:%d: %s: %zu pairs parsed from  '%.*s'", __func__, __LINE__,
+	    parsed.done()? "done" : "not done",
+	    pairs.size(), parsed.stmt.size(), parsed.stmt.p );
     int i = 0;
     for( const auto& replace : pairs ) {
-      yywarn("%s:%d:%4d: '%s' => '%s'", __func__, __LINE__,
-            ++i, replace.before.p, replace.after.p);
+      dbgmsg("%s:%d:%4d: '%s' => '%s'", __func__, __LINE__,
+	     ++i, replace.before.p, replace.after.p);
     }
   }
   if( !parsed.done() ) {
@@ -850,9 +895,9 @@ parse_copy_directive( filespan_t& mfile ) {
       if( yy_flex_debug ) {
         size_t nnl = 1 + count_newlines(mfile.data, copy_stmt.p);
         size_t nst = 1 + count_newlines(copy_stmt.p, copy_stmt.pend);
-        yywarn("%s:%d: line %zu: COPY directive is %zu lines '%.*s'",
-              __func__, __LINE__,
-              nnl, nst, copy_stmt.size(), copy_stmt.p);
+        dbgmsg("%s:%d: line %zu: COPY directive is %zu lines '%.*s'",
+	       __func__, __LINE__,
+	       nnl, nst, copy_stmt.size(), copy_stmt.p);
       }
     }
   }
@@ -865,11 +910,11 @@ parse_copy_directive( filespan_t& mfile ) {
     outcome.partial_line = span_t(mfile.cur, copy_stmt.p);
 
     if( yy_flex_debug ) {
-      yywarn("%zu expressions", std::count(pattern, pattern + sizeof(pattern), '('));
+      dbgmsg("%zu expressions", std::count(pattern, pattern + sizeof(pattern), '('));
       int i = 0;
       for( const auto& m : cm ) {
         if( m.matched )
-          yywarn("%s:%d: %2d: '%.*s'", __func__, __LINE__,
+          dbgmsg("%s:%d: %2d: '%.*s'", __func__, __LINE__,
                 i, int(m.length()), m.first);
         i++;
       }
@@ -885,8 +930,7 @@ parse_copy_directive( filespan_t& mfile ) {
     }
     outcome.fd = copybook.open( xstrndup(copybook_name.first, copybook_name.length()) );
     if( outcome.fd == -1 ) { // let parser report missing copybook
-      if( yy_flex_debug )
-        yywarn("%s: copybook '%s' not found", __func__, copybook.current()->source);
+      dbgmsg("%s: copybook '%s' not found", __func__, copybook.current()->source);
       return outcome;
     }
 
@@ -947,10 +991,8 @@ parse_replace_last_off( filespan_t& mfile ) {
     }
   }
 
-  if( yy_flex_debug ) {
-    yywarn( "%s:%d: line %zu: parsed '%.*s', ", __func__, __LINE__,
-           mfile.lineno, int(cm[0].length()), cm[0].first );
-  }
+  dbgmsg( "%s:%d: line %zu: parsed '%.*s', ", __func__, __LINE__,
+	  mfile.lineno(), int(cm[0].length()), cm[0].first );
 
   // Remove statement from input
   erase_line(const_cast<char*>(cm[0].first),
@@ -960,7 +1002,7 @@ parse_replace_last_off( filespan_t& mfile ) {
 }
 
 static span_t
-parse_replace_text( filespan_t& mfile, size_t current_lineno ) {
+parse_replace_text( filespan_t& mfile ) {
   static const char pattern[] =
     /* 0 */    "REPLACE"
     /* 1 */    "([[:space:]]+ALSO)?"
@@ -975,30 +1017,31 @@ parse_replace_text( filespan_t& mfile, size_t current_lineno ) {
     ;
   static regex re(pattern, extended_icase);
   cmatch cm;
+  const size_t current_lineno(mfile.lineno());
 
   if( false && yy_flex_debug ) {
     auto pend = mfile.eol;
     gcc_assert(mfile.line_length() > 2);
     if( pend[-1] == '\n' ) pend -= 2;
     auto len = int(pend - mfile.cur);
-    yywarn("%s:%d: line %zu: parsing '%.*s", __func__, __LINE__,
+    dbgmsg("%s:%d: line %zu: parsing '%.*s", __func__, __LINE__,
           current_lineno, len, mfile.cur);
   }
 
   if( ! regex_search(mfile.ccur(), (const char *)mfile.eodata, cm, re) ) {
-    if( yy_flex_debug ) yywarn( "%s:%d: line %zu: not a REPLACE statement:\n'%.*s'",
-                               __func__, __LINE__, current_lineno,
-                               int(mfile.line_length()), mfile.cur );
+    dbgmsg( "%s:%d: line %zu: not a REPLACE statement:\n'%.*s'",
+	    __func__, __LINE__, current_lineno,
+	    int(mfile.line_length()), mfile.cur );
     return span_t();
   }
 
   // Report findings.
     if( yy_flex_debug ) {
-      yywarn("%zu expressions", std::count(pattern, pattern + sizeof(pattern), '('));
+      dbgmsg("%zu expressions", std::count(pattern, pattern + sizeof(pattern), '('));
       int i = 0;
       for( const auto& m : cm ) {
         if( m.matched )
-          yywarn("%s:%d: %2d: '%.*s'", __func__, __LINE__,
+          dbgmsg("%s:%d: %2d: '%.*s'", __func__, __LINE__,
                 i, int(m.length()), m.first);
         i++;
       }
@@ -1023,11 +1066,11 @@ parse_replace_text( filespan_t& mfile, size_t current_lineno ) {
   replace_directives.push( replacements );
 
   if( yy_flex_debug ) {
-    yywarn( "%s:%d: line %zu: %zu pairs parsed from  '%.*s'", __func__, __LINE__,
+    dbgmsg( "%s:%d: line %zu: %zu pairs parsed from  '%.*s'", __func__, __LINE__,
            current_lineno, replacements.size(), int(replace_stmt.size()), replace_stmt.p );
     for( const auto& replace : replacements ) {
       int i = 0;
-      yywarn("%s:%d:%4d: '%s' => '%s'", __func__, __LINE__,
+      dbgmsg("%s:%d:%4d: '%s' => '%s'", __func__, __LINE__,
             ++i, replace.before.p, replace.after.p);
     }
   }
@@ -1040,7 +1083,7 @@ parse_replace_text( filespan_t& mfile, size_t current_lineno ) {
 }
 
 static span_t
-parse_replace_directive( filespan_t& mfile, size_t current_lineno ) {
+parse_replace_directive( filespan_t& mfile ) {
   static const char *most_recent_buffer, *next_directive;
   static bool off_coming_up;
   static const char pattern[] =
@@ -1082,7 +1125,7 @@ parse_replace_directive( filespan_t& mfile, size_t current_lineno ) {
     if( off_coming_up ) {
       parse_replace_last_off(mfile);
     } else {
-      erased = parse_replace_text(mfile, current_lineno);
+      erased = parse_replace_text(mfile);
     }
   }
   return erased;
@@ -1103,8 +1146,8 @@ bytespan_t::append( const char *input, const char *eoinput ) {
 #define LEXIO 0
 #if LEXIO
   auto nq = std::count_if(data, eodata, isquote);
-  yywarn("%s:%3d:  input ------ '%.*s'", __func__, __LINE__, int(eoinput - input), input);
-  yywarn("%s:%3d:  precondition '%.*s' (%zu: %s)", __func__, __LINE__,
+  dbgmsg("%s:%3d:  input ------ '%.*s'", __func__, __LINE__, int(eoinput - input), input);
+  dbgmsg("%s:%3d:  precondition '%.*s' (%zu: %s)", __func__, __LINE__,
         int(size()), data, nq, in_string()? "in string" : "not in string");
 #endif
   if( !in_string() ) { // Remove trailing space unless it's part of a literal.
@@ -1129,7 +1172,7 @@ bytespan_t::append( const char *input, const char *eoinput ) {
   eodata = pend;
 
 #if LEXIO
-  yywarn("%s:%3d: postcondition '%.*s'", __func__, __LINE__, int(size() + len) - 1, data);
+  dbgmsg("%s:%3d: postcondition '%.*s'", __func__, __LINE__, int(size() + len) - 1, data);
 #endif
 
   return eodata;
@@ -1164,7 +1207,7 @@ mapped_file( FILE *input ) {
       cbl_err( "%s: could not map fd %d", __func__, fd );
     }
 
-    mfile.lineno = 0;
+    mfile.lineno_reset();
     mfile.data = mfile.cur = mfile.eol = mfile.eodata = static_cast<char*>(p);
     mfile.eodata += sb.st_size;
   }
@@ -1311,8 +1354,7 @@ preprocess_filter_add( const char input[] ) {
   
   auto filename = find_filter(filter);
   if( !filename ) {
-    yywarn("preprocessor '%s/%s' not found", 
-                getcwd(NULL, 0), filter);
+    yywarn("preprocessor '%s/%s' not found", getcwd(NULL, 0), filter);
     return false;
   }
   preprocessor_filters.push_back( std::make_pair(xstrdup(filename), options) );
@@ -1438,10 +1480,9 @@ cdftext::lex_open( const char filename[] ) {
 
 int
 cdftext::open_input( const char filename[] ) {
-  extern int yydebug;
   int fd = open(filename, O_RDONLY);
   if( fd == -1 ) {
-    if( yydebug ) yywarn( "could not open '%s'", filename );
+    dbgmsg( "could not open '%s': %m", filename );
   }
 
   verbose_file_reader = NULL != getenv("GCOBOL_TEMPDIR");
@@ -1498,7 +1539,7 @@ cdftext::map_file( int fd ) {
           cbl_err( "%s: could not prepare map file from FIFO %d",
               __func__, input);
         }
-        if( false ) yywarn("%s: copied %ld bytes from FIFO", 
+        if( false ) dbgmsg("%s: copied %ld bytes from FIFO", 
                                 __func__, nout);
       }
     }
@@ -1512,7 +1553,7 @@ cdftext::map_file( int fd ) {
       cbl_err( "%s: could not map fd %d", __func__, fd );
     }
 
-    mfile.lineno = 0;
+    mfile.lineno_reset();
     mfile.data = mfile.cur = mfile.eol = mfile.eodata = static_cast<char*>(p);
     mfile.eodata += sb.st_size;
   }
@@ -1552,14 +1593,13 @@ cdftext::free_form_reference_format( int input ) {
       const char * pend =
         std::find(p, const_cast<const char *>(mfile.eodata), '\n');
       if( 6 < pend - p ) break;
-      p = ++pend;
+      p = pend;
+      if( p < mfile.eodata) p++;
     }
     if( valid_sequence_area(p, mfile.eodata) ) indicator.column = 7;
 
-    if( yy_flex_debug ) {
-      yywarn("%s:%d: %s format detected", __func__, __LINE__,
-            indicator.column == 7? "FIXED" : "FREE");
-    }
+    dbgmsg("%s:%d: %s format detected", __func__, __LINE__,
+	   indicator.column == 7? "FIXED" : "FREE");
   }
 
   while( mfile.next_line() ) {
@@ -1633,7 +1673,7 @@ cdftext::free_form_reference_format( int input ) {
         __attribute__ ((fallthrough));
       default: // flag other characters in indicator area
         if( ! ISSPACE(indcol[0]) ) {
-          yyerrorvl( mfile.lineno, cobol_filename(), 
+          yyerrorvl( mfile.lineno(), cobol_filename(), 
                      "error: stray indicator '%c' (0x%x): \"%.*s\"",
                      indcol[0], indcol[0],
                      int(mfile.line_length() - 1), mfile.cur );
@@ -1643,7 +1683,7 @@ cdftext::free_form_reference_format( int input ) {
       }
     }
     current.line.update(mfile.cur, mfile.eol, right_margin());
-    current.lineno = mfile.lineno;
+    current.lineno = mfile.lineno();
   } // next line
 
   return source_buffer;
@@ -1703,16 +1743,16 @@ cdftext::process_file( filespan_t mfile, int output, bool second_pass ) {
 
   // parse CDF directives
   while( mfile.next_line() ) {
+    yylloc = mfile.as_location();
     auto copied = parse_copy_directive(mfile);
     if( copied.parsed && copied.fd != -1 ) {
       gcc_assert(copied.erased_lines.p);
       std::copy_if(copied.erased_lines.p, copied.erased_lines.pend, ofs,
                    []( char ch ) { return ch == '\n'; } );
       struct { int in, out; filespan_t mfile; } copy;
-      if( yy_flex_debug )
-        yywarn("%s:%d: line %zu, opening %s on fd %d", __func__, __LINE__,
-              mfile.lineno,
-              copybook.current()->source, copybook.current()->fd);
+      dbgmsg("%s:%d: line %zu, opening %s on fd %d", __func__, __LINE__,
+	     mfile.lineno(),
+	     copybook.current()->source, copybook.current()->fd);
       copy.in = copybook.current()->fd;
       copy.mfile = free_form_reference_format( copy.in );
 
@@ -1737,7 +1777,7 @@ cdftext::process_file( filespan_t mfile, int output, bool second_pass ) {
       cobol_filename_restore();
     }
 
-    auto erased = parse_replace_directive(mfile, mfile.lineno);
+    auto erased = parse_replace_directive(mfile);
     if( erased.p ) {
       std::copy_if( erased.p, erased.pend, ofs,
                     []( char ch ) { return ch == '\n'; } );
@@ -1763,7 +1803,7 @@ cdftext::process_file( filespan_t mfile, int output, bool second_pass ) {
       nlines.after  = std::count(segments.back().p, segments.back().pend, '\n');
       if( nlines.delta() < 0 ) {
         yywarn("line %zu: REPLACED %zu lines with %zu lines, "
-              "line count off by %d", mfile.lineno,
+              "line count off by %d", mfile.lineno(),
               nlines.before, nlines.after, nlines.delta());
       }
       int nnl = nlines.delta();
diff --git a/gcc/cobol/lexio.h b/gcc/cobol/lexio.h
index 9e0375e0fa92..d7354b79deb8 100644
--- a/gcc/cobol/lexio.h
+++ b/gcc/cobol/lexio.h
@@ -114,20 +114,43 @@ struct bytespan_t {
   }
 };
 
+/* Location type.  Borrowed from parse.h as generated by Bison. */
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
+{
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+};
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+void location_dump( const char func[], int line,
+		    const char tag[], const YYLTYPE& loc);
+
 struct filespan_t : public bytespan_t {
   char *cur, *eol, *quote;
-  size_t lineno;
  private:
+  size_t iline, icol;
   size_t line_quote72;
   static char empty_file[8];
  public:
-  filespan_t() : cur(data), eol(data), quote(NULL), lineno(0), line_quote72(0)
+  filespan_t()
+    : cur(data), eol(data), quote(NULL), iline(0), icol(0), line_quote72(0)
   {}
   filespan_t(void *p, size_t len)
     : bytespan_t( static_cast<char*>(p), static_cast<char*>(p) + len )
-    , cur(data), eol(data), quote(NULL), lineno(0), line_quote72(0)
+    , cur(data), eol(data), quote(NULL), iline(0), line_quote72(0)
   {}
 
+  size_t lineno() const { return iline; }
+  
+  void lineno_reset()  { iline = 0; }
+  size_t colno( size_t icol )  { return this->icol = icol; }
+
   bool nada() const { return data == empty_file; }
   void use_nada() {
     assert(!data);
@@ -143,12 +166,12 @@ struct filespan_t : public bytespan_t {
    * column 72, the continuation line must start with two consecutive
    * quotation marks."
    */
-  bool was_quote72() const { return lineno == line_quote72 + 1; }
+  bool was_quote72() const { return iline == line_quote72 + 1; }
 
   size_t next_line() {
     // Before advancing, mark the current line as ending in a quote, if true.
     if( is_reference_format() && 72 <= line_length() ) {
-      if( isquote(cur[71]) ) { line_quote72 = lineno; }
+      if( isquote(cur[71]) ) { line_quote72 = iline; }
     }
 
     cur = eol;
@@ -159,7 +182,8 @@ struct filespan_t : public bytespan_t {
 
     if( eol < eodata ) {
       ++eol;
-      ++lineno;
+      ++iline;
+      icol = 0;
     }
     return eol - cur;
   }
@@ -172,6 +196,15 @@ struct filespan_t : public bytespan_t {
     auto p = std::find_if( cur, eol, []( char ch ) { return !fisspace(ch); } );
     return p == eol;
   }
+
+  YYLTYPE as_location() const {
+    YYLTYPE loc;
+
+    loc.first_line = loc.last_line = 1 + iline;
+    loc.first_column = loc.last_column = 1 + icol;
+    return loc;
+  }
+  
 };
 
 #if USE_STD_REGEX
@@ -188,9 +221,9 @@ struct span_t {
  protected:
   void verify() const {
     if( !p ) {
-      yywarn("span_t::span_t: p is NULL");
+      dbgmsg("span_t::span_t: p is NULL");
     } else if( ! (p <= pend) ) {
-      yywarn("span_t::span_t: p %p > pend %p", p, pend);
+      dbgmsg("span_t::span_t: p %p > pend %p", p, pend);
     } 
     assert(p && p <= pend);
   }
-- 
GitLab