From d712967df7374caf71a545020dcb58862c84d677 Mon Sep 17 00:00:00 2001
From: "James K. Lowden" <jklowden@symas.com>
Date: Sat, 27 Apr 2024 15:43:54 -0400
Subject: [PATCH] process #line directive

---
 gcc/cobol/built-gcobol |  7 +++++-
 gcc/cobol/genapi.cc    |  1 +
 gcc/cobol/parse_ante.h |  2 +-
 gcc/cobol/scan.l       |  3 +++
 gcc/cobol/symbols.h    |  1 +
 gcc/cobol/util.cc      | 50 +++++++++++++++++++++++++++++++++++++++++-
 libgcobol/constants.cc |  3 +++
 7 files changed, 64 insertions(+), 3 deletions(-)

diff --git a/gcc/cobol/built-gcobol b/gcc/cobol/built-gcobol
index 6c0030005d78..f880f4f664fc 100755
--- a/gcc/cobol/built-gcobol
+++ b/gcc/cobol/built-gcobol
@@ -1,8 +1,13 @@
 #!/bin/sh
 # Run gcobol from the build directory
 set -e
+if [ -z "$build" ]
+then 
+    build=build
+fi
+
 srcdir=$(cd ${0%/*} && git rev-parse --show-toplevel)
-objdir=$srcdir/build
+objdir=$srcdir/$build
 libdir=$(ls $objdir/$(arch)* -d)
 
 $objdir/gcc/gcobol                                      \
diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index 743635170210..0730546ba5c9 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -5376,6 +5376,7 @@ parser_arith_error(cbl_label_t *arithmetic_label)
   {
   Analyze();
   // We are entering either SIZE ERROR or NOT SIZE ERROR code
+  RETURN_IF_PARSE_ONLY;
   set_up_arith_error_label(arithmetic_label);
 
   SHOW_PARSE
diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h
index ae35a37e3e64..d3717b9fe49c 100644
--- a/gcc/cobol/parse_ante.h
+++ b/gcc/cobol/parse_ante.h
@@ -31,7 +31,7 @@ void next_sentence_label(cbl_label_t* label) {
   parser_label_label(label);
   next_sentence = NULL;
   // release codegen label structure, so it can be reused.
-  assert(label->structs.goto_trees);
+  assert(label->structs.goto_trees || mode_syntax_only());
   free(label->structs.goto_trees);
   label->structs.goto_trees = NULL;
 }
diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l
index 70fe98dd35c6..ed05268c77b3 100644
--- a/gcc/cobol/scan.l
+++ b/gcc/cobol/scan.l
@@ -163,6 +163,7 @@ NL       [[:blank:]]*\r?\n[[:blank:]]*
 
 PUSH_FILE \f?[#]FILE{SPC}PUSH{SPC}.+\f
 POP_FILE  \f?[#]FILE{SPC}POP\f
+LINE_DIRECTIVE [#]line{SPC}[[:alnum:]]+{SPC}[""''].+\n
 
 %x procedure_div ident_state addr_of function classify when_not
 %x program_id_state comment_entries
@@ -1895,6 +1896,8 @@ COPY		{
 			auto name = cobol_filename_restore();
 	   		if( yy_flex_debug ) warnx("resuming at line %4d of %s",
 						  yylineno, name? name : "<none>"); }
+
+  {LINE_DIRECTIVE} {	cobol_fileline_set(yytext); }
 }
 
 
diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h
index 317353ba1949..336f46a41fc2 100644
--- a/gcc/cobol/symbols.h
+++ b/gcc/cobol/symbols.h
@@ -2116,6 +2116,7 @@ bool cobol_filename( const char *name );
 const char * cobol_filename();
 const char * cobol_filename_restore();
 const char * cobol_lineno_save();
+const char * 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 855e8d5372ca..4399c7d93258 100644
--- a/gcc/cobol/util.cc
+++ b/gcc/cobol/util.cc
@@ -1910,7 +1910,7 @@ date_time_fmt( const char input[] ) {
 #include <stack>
 struct input_file_t {
   int lineno; const char *name;
-  input_file_t( const char *name ) : lineno(1), name(name) {}
+  input_file_t( const char *name, int lineno=1 ) : lineno(lineno), name(name) {}
   bool operator==( const input_file_t& that ) const {
     return 0 == strcmp(name, that.name);
   }
@@ -1990,6 +1990,54 @@ cobol_filename_restore() {
   return input.name;
 }
 
+const char *
+cobol_fileline_set( const char line[] ) {
+  static const char pattern[] = "#line +([[:alnum:]]+) +([\"'][^\"']+). *\n";
+  static const int cflags = REG_EXTENDED | REG_ICASE;
+  static regex_t re, *preg = NULL;
+
+  int erc; 
+  regmatch_t pmatch[4];
+
+  if( !preg ) {
+    if( (erc = regcomp(&re, pattern, cflags)) != 0 ) {
+        regerror(erc, &re, regexmsg, sizeof(regexmsg));
+        warnx( "%s:%d: could not compile regex: %s", __func__, __LINE__, regexmsg );
+        return line;
+    }
+    preg = &re;
+  }
+  if( (erc = regexec(preg, line, COUNT_OF(pmatch), pmatch, 0)) != 0 ) {
+    if( erc != REG_NOMATCH ) {
+      regerror(erc, preg, regexmsg, sizeof(regexmsg));
+      warnx( "%s:%d: could not compile regex: %s", __func__, __LINE__, regexmsg );
+      return line;
+    }
+    yyerrorv( "error: invalid #line directive: %s", line );
+    return line;
+  }
+  
+  const char
+    *line_str = xstrndup(line + pmatch[1].rm_so, pmatch[1].rm_eo),
+    *filename = xstrndup(line + pmatch[2].rm_so, pmatch[2].rm_eo);
+  int fileline;
+    
+  if( 1 != sscanf(line_str, "%d", &fileline) )
+    warn("%s:%d: line number %s", __func__, __LINE__, line_str);
+    
+  input_file_t input_file( filename, fileline );
+
+  if( input_filenames.empty() ) {
+    input_filenames.push(input_file);
+  }
+
+  input_file_t& file = input_filenames.top();
+  file = input_file;
+  yylineno = file.lineno;
+  
+  return file.name;
+}
+
 static int
 parse_file( const char filename[] )
 {
diff --git a/libgcobol/constants.cc b/libgcobol/constants.cc
index c3bcb3007cc0..ed2e06ae0ffb 100644
--- a/libgcobol/constants.cc
+++ b/libgcobol/constants.cc
@@ -52,6 +52,7 @@
 
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wwrite-strings"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 
 // There are global variables that need to be initialized at the point where
 // the very first PROGRAM-ID is executed.  This flag is used to make sure that
@@ -112,6 +113,8 @@ struct cblc_field_t __gg___2_##a = {    \
   .rdigits        = 0 ,                 \
   };
 
+
+
 unsigned char __gg__data_space[1] = {' '};
 struct cblc_field_t __gg__space = {
   .data           = __gg__data_space ,
-- 
GitLab