Suppress syntax error after skip_balanced() fails

In this situation, skip_balanced() reports a useful error such as
(the '}' part varies depending what we're trying to skip over):

Error: Missing '}'. Reached end of input.

We now exit after such failures which avoids reporting a second more
generic error like:

Error: Syntax error in input(1).

or:

Error: Syntax error in input(3).

Fixes #2606
diff --git a/CHANGES.current b/CHANGES.current
index 9c2413e..88560cf 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -7,6 +7,17 @@
 Version 4.2.0 (in progress)
 ===========================
 
+2023-05-23: olly
+	    #2606 Improve error output when SWIG reaches EOF while looking for
+	    a closing delimiter.  This is reported with an error like:
+
+	    Error: Missing '}'. Reached end of input.
+
+	    We now exit after reporting this and so no longer report a second
+	    more generic error like:
+
+	    Error: Syntax error in input(1).
+
 2023-05-22: mmomtchev
 	    [Javascript] #2600 Improve test coverage by adding _runme.js files
 	    for 22 test cases.
diff --git a/Examples/test-suite/errors/c_missing_rbrace.stderr b/Examples/test-suite/errors/c_missing_rbrace.stderr
index 28fdd26..7cadc07 100644
--- a/Examples/test-suite/errors/c_missing_rbrace.stderr
+++ b/Examples/test-suite/errors/c_missing_rbrace.stderr
@@ -1,2 +1 @@
 c_missing_rbrace.i:3: Error: Missing '}'. Reached end of input.
-c_missing_rbrace.i:3: Error: Syntax error in input(1).
diff --git a/Examples/test-suite/errors/cpp_missing_rparenthesis.stderr b/Examples/test-suite/errors/cpp_missing_rparenthesis.stderr
index cc97f5c..5b826aa 100644
--- a/Examples/test-suite/errors/cpp_missing_rparenthesis.stderr
+++ b/Examples/test-suite/errors/cpp_missing_rparenthesis.stderr
@@ -1,2 +1 @@
 cpp_missing_rparenthesis.i:5: Error: Missing ')'. Reached end of input.
-cpp_missing_rparenthesis.i:5: Error: Syntax error in input(3).
diff --git a/Source/CParse/cparse.h b/Source/CParse/cparse.h
index a7a40c7..0a53a0b 100644
--- a/Source/CParse/cparse.h
+++ b/Source/CParse/cparse.h
@@ -34,7 +34,7 @@
   extern void Swig_cparse_cplusplusout(int);
   extern void scanner_file(File *);
   extern void scanner_next_token(int);
-  extern void skip_balanced(int startchar, int endchar);
+  extern int skip_balanced(int startchar, int endchar);
   extern String *get_raw_text_balanced(int startchar, int endchar);
   extern void skip_decl(void);
   extern void scanner_check_typedef(void);
diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c
index 2eb3f97..3395131 100644
--- a/Source/CParse/cscanner.c
+++ b/Source/CParse/cscanner.c
@@ -163,15 +163,17 @@
  *
  * Skips a piece of code enclosed in begin/end symbols such as '{...}' or
  * (...).  Ignores symbols inside comments or strings.
+ *
+ * Returns 0 if successfully skipped, -1 if EOF found first.
  * ----------------------------------------------------------------------------- */
 
-void skip_balanced(int startchar, int endchar) {
+int skip_balanced(int startchar, int endchar) {
   int start_line = Scanner_line(scan);
   Clear(scanner_ccode);
 
   if (Scanner_skip_balanced(scan,startchar,endchar) < 0) {
     Swig_error(cparse_file, start_line, "Missing '%c'. Reached end of input.\n", endchar);
-    return;
+    return -1;
   }
 
   cparse_line = Scanner_line(scan);
@@ -180,7 +182,7 @@
   Append(scanner_ccode, Scanner_text(scan));
   if (endchar == '}')
     num_brace--;
-  return;
+  return 0;
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y
index f9622be..a8d0630 100644
--- a/Source/CParse/parser.y
+++ b/Source/CParse/parser.y
@@ -2116,15 +2116,15 @@
    ------------------------------------------------------------ */
 
 except_directive : EXCEPT LPAREN identifier RPAREN LBRACE {
-                    skip_balanced('{','}');
-		    $$ = 0;
 		    Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated.  Use %%exception instead.\n");
+		    if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
+		    $$ = 0;
 	       }
 
                | EXCEPT LBRACE {
-                    skip_balanced('{','}');
-		    $$ = 0;
 		    Swig_warning(WARN_DEPRECATED_EXCEPT,cparse_file, cparse_line, "%%except is deprecated.  Use %%exception instead.\n");
+		    if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
+		    $$ = 0;
                }
 
                | EXCEPT LPAREN identifier RPAREN SEMI {
@@ -2175,7 +2175,7 @@
                  | FRAGMENT LPAREN fname COMMA kwargs RPAREN LBRACE {
 		   Hash *p = $5;
 		   String *code;
-                   skip_balanced('{','}');
+		   if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
 		   $$ = new_node("fragment");
 		   Setattr($$,"value",Getattr($3,"value"));
 		   Setattr($$,"type",Getattr($3,"type"));
@@ -2286,10 +2286,11 @@
                | INLINE LBRACE {
                  String *cpps;
 		 int start_line = cparse_line;
-		 skip_balanced('{','}');
 		 if (Namespaceprefix) {
 		   Swig_error(cparse_file, cparse_start_line, "%%inline directive inside a namespace is disallowed.\n");
-		   
+		 }
+		 if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
+		 if (Namespaceprefix) {
 		   $$ = 0;
 		 } else {
 		   String *code;
@@ -2335,7 +2336,7 @@
                }
                | INSERT LPAREN idstring RPAREN LBRACE {
 		 String *code;
-                 skip_balanced('{','}');
+		 if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
 		 $$ = new_node("insert");
 		 Setattr($$,"section",$3);
 		 Delitem(scanner_ccode,0);
@@ -3336,8 +3337,8 @@
             * to wrap.
             */
 	   | storage_class AUTO declarator cpp_const LBRACE {
-	      skip_balanced('{','}');
 	      Swig_warning(WARN_CPP14_AUTO, cparse_file, cparse_line, "Unable to deduce return type for '%s'.\n", $3.id);
+	      if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
 	   }
 	   ;
 
@@ -3373,7 +3374,7 @@
 		 }
 	       }
                | LBRACE { 
-                   skip_balanced('{','}');
+                   if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
                    $$ = 0;
                }
                | error {
@@ -3436,20 +3437,20 @@
                 ;
 
 lambda_introducer : LBRACKET {
-		  skip_balanced('[',']');
+		  if (skip_balanced('[',']') < 0) Exit(EXIT_FAILURE);
 		  $$ = 0;
 	        }
 		;
 
 lambda_template : LESSTHAN {
-		  skip_balanced('<','>');
+		  if (skip_balanced('<','>') < 0) Exit(EXIT_FAILURE);
 		  $$ = 0;
 		}
 		| empty { $$ = 0; }
 		;
 
 lambda_body : LBRACE {
-		  skip_balanced('{','}');
+		  if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
 		  $$ = 0;
 		}
 
@@ -3457,7 +3458,7 @@
 		  $$ = 0;
 		}
 		| LPAREN {
-		  skip_balanced('(',')');
+		  if (skip_balanced('(',')') < 0) Exit(EXIT_FAILURE);
 		} SEMI {
 		  $$ = 0;
 		}
@@ -4903,7 +4904,7 @@
 /* isolated catch clause. */
 
 cpp_catch_decl : CATCH LPAREN parms RPAREN LBRACE {
-                 skip_balanced('{','}');
+                 if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
                  $$ = 0;
                }
                ;
@@ -4911,7 +4912,7 @@
 /* static_assert(bool, const char*); (C++11)
  * static_assert(bool); (C++17) */
 cpp_static_assert : STATIC_ASSERT LPAREN {
-                skip_balanced('(',')');
+                if (skip_balanced('(',')') < 0) Exit(EXIT_FAILURE);
                 $$ = 0;
               }
               ;
@@ -4983,7 +4984,7 @@
 		    $$.final = $1.final;
                }
                | cpp_const LBRACE { 
-		    skip_balanced('{','}'); 
+		    if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
 		    $$.val = 0;
 		    $$.qualifier = $1.qualifier;
 		    $$.refqualifier = $1.refqualifier;
@@ -5018,7 +5019,7 @@
                      $$.final = $1.final;
                }
                | cpp_const LBRACE { 
-                     skip_balanced('{','}');
+                     if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
                      $$.val = 0;
                      $$.qualifier = $1.qualifier;
                      $$.refqualifier = $1.refqualifier;
@@ -5313,7 +5314,7 @@
 		  }		  
                }
                | EQUAL LBRACE {
-		 skip_balanced('{','}');
+		 if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
 		 $$.val = NewString(scanner_ccode);
 		 $$.rawval = 0;
                  $$.type = T_INT;
@@ -6266,7 +6267,7 @@
 	       | error RPAREN {
 		 // Avoid a parse error if we can't parse the expression decltype() is applied to.
 		 $$ = 0;
-		 skip_balanced('(',')');
+		 if (skip_balanced('(',')') < 0) Exit(EXIT_FAILURE);
 		 Clear(scanner_ccode);
 	       }
 	       ;
@@ -6928,7 +6929,7 @@
 	       }
                | type LPAREN {
 		 String *qty;
-                 skip_balanced('(',')');
+		 if (skip_balanced('(',')') < 0) Exit(EXIT_FAILURE);
 		 qty = Swig_symbol_type_qualify($1,0);
 		 if (SwigType_istemplate(qty)) {
 		   String *nstr = SwigType_namestr(qty);
@@ -7192,15 +7193,15 @@
                       Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n");
                }
                | cpp_const ctor_initializer LBRACE { 
-                    skip_balanced('{','}'); 
+                    if ($1.qualifier)
+                      Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n");
+                    if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
                     $$.have_parms = 0; 
                     $$.defarg = 0; 
                     $$.throws = $1.throws;
                     $$.throwf = $1.throwf;
                     $$.nexcept = $1.nexcept;
                     $$.final = $1.final;
-                    if ($1.qualifier)
-                      Swig_error(cparse_file, cparse_line, "Constructor cannot have a qualifier.\n");
                }
                | LPAREN parms RPAREN SEMI { 
                     Clear(scanner_ccode); 
@@ -7213,7 +7214,7 @@
 		    $$.final = 0;
                }
                | LPAREN parms RPAREN LBRACE {
-                    skip_balanced('{','}'); 
+                    if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
                     $$.parms = $2; 
                     $$.have_parms = 1; 
                     $$.defarg = 0; 
@@ -7253,7 +7254,7 @@
                ;
 
 mem_initializer : idcolon LPAREN {
-		  skip_balanced('(',')');
+		  if (skip_balanced('(',')') < 0) Exit(EXIT_FAILURE);
 		  Clear(scanner_ccode);
 		}
                 /* Uniform initialization in C++11.
@@ -7265,7 +7266,7 @@
                    };
                 */
                 | idcolon LBRACE {
-		  skip_balanced('{','}');
+		  if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
 		  Clear(scanner_ccode);
 		}
                 ;
@@ -7416,7 +7417,7 @@
 		 $$ = $1;
                }
                | LBRACE {
-                  skip_balanced('{','}');
+		  if (skip_balanced('{','}') < 0) Exit(EXIT_FAILURE);
 		  $$ = NewString(scanner_ccode);
                }
               | HBLOCK {