https://gcc.gnu.org/g:afd69fe25cd653ddd2001f9904b3ff367b0fd476

commit r17-4688-gafd69fe25cd653ddd2001f9904b3ff367b0fd476
Author: James K. Lowden <[email protected]>
Date:   Fri Sep 18 11:56:21 2026 -0400

    cobol: Integrate PICTURE automaton into parser.
    
    Technical change only.  Remove leftover code and rearrange for
    clarity. Use usual compiler include files. Prepare to replace parsing
    of alphanumeric-edited and numeric-edited.
    
    This commit also commences new whitespace policy: no committed file
    will have trailing whitespace.
    
    gcc/cobol/ChangeLog:
    
            * picture.cc (symbol_currency): Remove test harness mock-up.
            (cbl_internal_error): Same.
            (yy_flex_debug): Undefine, per usual.
            (seek_paren): Use ISALNUM.
            (is_valid_picture): Use repeat_count to resolve size.
            * scan_ante.h (repeat_count): Remove declaration.
            * util.cc (cbl_prototype_ok): Whitespace.
            (cdf_file): Same.
            (repeat_count): Same.
            (cbl_field_t::encode_numeric): Same.
            (cbl_field_t::report_invalid_initial_value): Same.
            (literal_subscript_oob): Same.
            (valid_move): Same.
            (hex2numstr): Same.
            (cobol_filename): Same.
            (gcc_location_set): Same.
            (parse_file): Same.
            (iso_cobol_word): Same.
            * util.h (repeat_count): Declare function.

Diff:
---
 gcc/cobol/picture.cc  | 602 ++++++++++++++++++++++++++------------------------
 gcc/cobol/scan_ante.h |   2 -
 gcc/cobol/util.cc     |  11 +-
 gcc/cobol/util.h      |   2 +
 4 files changed, 318 insertions(+), 299 deletions(-)

diff --git a/gcc/cobol/picture.cc b/gcc/cobol/picture.cc
index 01a723c7e9a9..965baa27afc1 100644
--- a/gcc/cobol/picture.cc
+++ b/gcc/cobol/picture.cc
@@ -1,3 +1,33 @@
+/*
+ * Copyright (c) 2021-2026 Symas Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following disclaimer
+ *   in the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of the Symas Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #include <cassert>
 #include <cctype>
 #include <cstdint>
@@ -6,23 +36,34 @@
 #include <unistd.h>
 
 #include <algorithm>
-#include <fstream>
 #include <array>
 #include <map>
-#include <set>
 #include <string>
 #include <vector>
 
-#ifdef COBOL_PICTURE
-const char * symbol_currency( char sign ) {
-  static const char mock_signs[] = "@ŁY&";
-  return strchr(mock_signs, sign);
-}
-void cbl_internal_error(const char *format_string, ...) { assert(false); }
-#else
-void cbl_internal_error(const char *format_string, ...);
-const char * symbol_currency( char sign );
-#endif
+#include "cobol-system.h"
+#include <coretypes.h>
+#include <tree.h>
+#include <fold-const.h>
+#undef yy_flex_debug
+
+#include <langinfo.h>
+
+#include <version.h>
+#include <demangle.h>
+#include <intl.h>
+#include <backtrace.h>
+#include <diagnostic.h>
+#include <opts.h>
+
+#include "util.h"
+#include "cbldiag.h"
+#include "cdfval.h"
+#include "lexio.h"
+
+#include "../../libgcobol/ec.h"
+#include "../../libgcobol/common-defs.h"
+#include "symbols.h"
 
 namespace picture_validation {
 
@@ -151,6 +192,194 @@ namespace picture_validation {
     /* CR/DB */ { { postdec_e,     'D' }, {""  "B"} },
   };
   
+  ////////////////////////////////////////////////////////////////
+
+  struct transition_t {
+    state_t state;
+    char ch;
+    state_t next_state;
+
+    transition_t( state_t state,
+                  char ch,
+                  state_t next_state )
+      : state(state)
+      , ch(ch)
+      , next_state(next_state)
+    {}
+
+    bool operator<(const transition_t& that) const {
+      if (state == that.state) return ch < that.ch;      
+      return state < that.state;
+    }
+    bool operator==(const transition_t& that) const { return   match(that); }
+    bool operator!=(const transition_t& that) const { return ! match(that); }
+
+   protected: 
+    // match verifies that the row returned by std::lower_bound actually
+    // matches, and isn't the next "bigger" one.
+    bool match(const transition_t& that) const {
+      return state == that.state
+        &&   ch == that.ch;
+    }
+  };
+  
+  static std::vector<transition_t> picture_rules {
+    // Alpha and Alphanumeric
+    { none_e,          'A',  alphabetic_e },
+    { none_e,          'X',  alphanumeric_e },
+    { none_e,          'B',  alpha_ed_e },
+    { none_e,          '0',  alpha_ed_e },
+    { none_e,          '/',  alpha_ed_e },
+    { none_e,          '9',  antedec_e },   // 9 before V
+    { none_e,          'N',  national_e },
+    { none_e,          'P',  none_e },
+    { none_e,          'S',  none_e },
+    { none_e,          'V',  postdec_e, },  // V before 9
+                       
+    { none_e,          '1',  antedec_e },
+    { antedec_e,       '1',  antedec_e },
+
+    { alphabetic_e,    'A',  alphabetic_e },
+    { alphabetic_e,    'B',  alpha_ed_e },
+    { alphabetic_e,    '0',  alpha_ed_e },
+    { alphabetic_e,    '/',  alpha_ed_e },
+    { alphabetic_e,    'X',  alphanumeric_e },
+    { alphabetic_e,    '$',  numeric_ed_e },
+
+    { alphanumeric_e,  'A',  alphanumeric_e },
+    { alphanumeric_e,  'X',  alphanumeric_e },
+    { alphanumeric_e,  '9',  alphanumeric_e },
+
+    // Alpha edited
+    { alpha_ed_e,      'B',  alpha_ed_e },
+    { alpha_ed_e,      '0',  alpha_ed_e },
+    { alpha_ed_e,      '/',  alpha_ed_e },
+    { alpha_ed_e,      'A',  alpha_ed_e },
+    { alpha_ed_e,      'X',  alpha_ed_e },
+    { alpha_ed_e,      '9',  numeric_ed_e },
+    { alpha_ed_e,      'Z',  numeric_ed_e },
+    { alpha_ed_e,      '*',  numeric_ed_e },
+    { alpha_ed_e,      '+',  numeric_ed_e },
+    { alpha_ed_e,      '-',  numeric_ed_e },
+    { alpha_ed_e,      dot,  numeric_ed_e },
+    { alpha_ed_e,      com,  numeric_ed_e },
+    { alpha_ed_e,      '$',  numeric_ed_e },
+
+    { alphanumeric_e,  'B',  alpha_ed_e },
+    { alphanumeric_e,  '0',  alpha_ed_e },
+    { alphanumeric_e,  '/',  alpha_ed_e },
+    
+    // National
+    { national_e,      'N',  national_e },
+    { national_e,      '\0', alphanumeric_e },
+
+    // National edited
+    { national_e,      'B',  national_ed_e },
+    { national_e,      '0',  national_ed_e },
+    { national_e,      '/',  national_ed_e },
+
+    { national_ed_e,   'N',  national_ed_e },
+    { national_ed_e,   'B',  national_ed_e },
+    { national_ed_e,   '0',  national_ed_e },
+    { national_ed_e,   '/',  national_ed_e },
+    { national_ed_e,   '\0', alpha_ed_e },
+
+    // Numeric edited
+    // [B*] or [+-].*[+-] or (9 and [$B0/,.+-], where $ is cs.
+    { none_e,          'Z',  numeric_ed_e },
+    { none_e,          '*',  numeric_ed_e },
+    { none_e,          dot,  numeric_ed_e },
+    { none_e,          com,  numeric_ed_e },
+    { none_e,          '-',  numeric_ed_e },
+    { none_e,          '+',  numeric_ed_e },
+    { none_e,          '$',  numeric_ed_e },
+                       
+    { antedec_e,       '9',  antedec_e },
+    { antedec_e,       'A',  alphanumeric_e },
+    { antedec_e,       'P',  numeric_e },
+    { antedec_e,       'V',  numeric_e },
+    { antedec_e,       'X',  alphanumeric_e },
+    { antedec_e,       'C',  c_need_r_e },
+    { antedec_e,       'D',  d_need_b_e },
+
+    { antedec_e,       'Z',  numeric_ed_e },
+    { antedec_e,       '*',  numeric_ed_e },
+    { antedec_e,       '$',  numeric_ed_e },
+    { antedec_e,       dot,  numeric_ed_e },
+    { antedec_e,       com,  numeric_ed_e },
+                       
+    { postdec_e,       '9',  numeric_e },
+    { postdec_e,       'P',  numeric_e },
+                       
+    { numeric_e,       '9',  numeric_e },
+    { numeric_e,       'P',  numeric_e },
+
+    { numeric_e,       'Z',  numeric_ed_e },
+    { numeric_e,       '*',  numeric_ed_e },
+    { numeric_e,       'B',  numeric_ed_e },
+    { numeric_e,       '0',  numeric_ed_e },
+    { numeric_e,       '/',  numeric_ed_e },
+    { numeric_e,       dot,  numeric_ed_e },
+    { numeric_e,       com,  numeric_ed_e },
+    { numeric_e,       '+',  numeric_ed_e },
+    { numeric_e,       '-',  numeric_ed_e },
+    { numeric_e,       '$',  numeric_ed_e },
+    { numeric_e,       'C',  c_need_r_e },
+    { numeric_e,       'D',  d_need_b_e },
+
+    { numeric_ed_e,    'Z',  numeric_ed_e },
+    { numeric_ed_e,    'B',  numeric_ed_e },
+    { numeric_ed_e,    '9',  numeric_ed_e },
+    { numeric_ed_e,    '0',  numeric_ed_e },
+    { numeric_ed_e,    dot,  numeric_ed_e },
+    { numeric_ed_e,    com,  numeric_ed_e },
+    { numeric_ed_e,    '/',  numeric_ed_e },
+    { numeric_ed_e,    '-',  numeric_ed_e },
+    { numeric_ed_e,    '+',  numeric_ed_e },
+    { numeric_ed_e,    '*',  numeric_ed_e },
+    { numeric_ed_e,    '$',  numeric_ed_e },
+    { numeric_ed_e,    'P',  numeric_ed_e },
+    { numeric_ed_e,    'V',  numeric_ed_e }, // See Table 10 if in doubt. 
+    { numeric_ed_e,    'C',  c_need_r_e },
+    { numeric_ed_e,    'D',  d_need_b_e },
+
+    // End of the road
+    { c_need_r_e,      'R',  numeric_ed_e },
+    { d_need_b_e,      'B',  numeric_ed_e },
+  };
+  
+  typedef std::array<state_t, 256> automaton_elem_t;
+  typedef std::vector<automaton_elem_t> automaton_matrix_t;
+
+  const automaton_matrix_t& prepare_automaton() {
+    static automaton_matrix_t matrix(accept_e);
+    static bool ready = false;
+    if( ready ) return matrix;
+
+    int i __attribute__ ((unused)) = 0, nextra = 0;
+    for( const auto& rule : picture_rules ) {
+      unsigned char ch(rule.ch);
+
+#ifdef COBOL_PICTURE
+      if( matrix[rule.state][ch] ) {
+        nextra++;
+        fprintf(stderr, "%s: redundant rule: #%d { %s '%c' %s }\n",
+                __func__, i, 
+                state_str(rule.state), rule.ch, 
+                state_str(rule.next_state));
+      }
+#endif
+      matrix[rule.state][ch] = rule.next_state;
+      i++;
+    }
+    if( nextra ) {
+      cbl_internal_error("%s: %d redundant rules", __func__, nextra);
+    }
+    
+    ready = true;
+    return matrix;
+  }
+
   /*
    * As the picture string is validated, constraint_t captures what has been
    * seen: the preceding character and what characters have appeared that
@@ -245,7 +474,7 @@ namespace picture_validation {
              || is_numeric9_ed() );
     }
 
-    state_t decimal_state; // to lookup sequence validity
+    state_t pic_state; // to lookup sequence validity
 
     uint64_t picsym_set( char ch ) {
       switch(ch) {
@@ -300,43 +529,34 @@ namespace picture_validation {
       }
     }
 
-    /*
-     * 1) Every character except V adds to the capacity, with the caveat that
-     *    the first CURRENCY PICTURE character adds the length of the CURRENCY
-     *    SIGN string.
-     * 2) data.digits has to be the count of 9 + count of Z + count of asterisk
-     *    + (count of $ minus 1) + (count of - minus one) + (count of + minus 
1)
-     * 3) data.rdigits is the subset of 2 that is to the right of either V or
-     *    . (edited) 
-     * 
-     * For the moment, break out the fact that V should add zero.  Right now
-     * all of the regression tests assume that V, if there, adds one.  I would
-     * really rather attack the V change when everything is working.
-     */
-
     char prior_ch;
-   public:
+    const char decimal_point;
     int nplus, nminus;
+    cbl_field_data_t field_data;
+   public:
+    const char *bad_repeat;
 
     constraint_t()
       : symbol_mask(0)
-      , decimal_state(none_e)
+      , pic_state(none_e)
       , prior_ch('\0')
+      , decimal_point(symbol_decimal_point())
       , nplus(0), nminus(0)
+      , bad_repeat(nullptr)
     {}
-    constraint_t& operator=( char ch ) {
+    constraint_t& append( char ch, size_t len ) {
       picsym_set(ch);
       prior_ch = ch;
       if( ch == '+' ) nplus++;
       if( ch == '-' ) nminus++;
+      update_capacity(1 + len);
       observe_the_dot(ch);
       return *this;
     }
     char prior() const { return prior_ch; }
 
-    state_t automaton(state_t state) { return decimal_state = state; }
-    state_t automaton() const { return decimal_state; }
-
+    state_t picture_state(state_t state) { return pic_state = state; }
+    state_t picture_state() const { return pic_state; }
 
     state_t state() const {
       if( is_alphabetic() )   return alphabetic_e;
@@ -357,7 +577,7 @@ namespace picture_validation {
      * headings in ISO Table 10.
      */
     bool day_follows_night( char ch ) {
-      auto p = followers.find( follow_key_t {decimal_state, prior_ch} );
+      auto p = followers.find( follow_key_t {pic_state, prior_ch} );
       if( p != followers.end() ) {
         const auto& candidates(p->second);
         auto pnext = std::find( candidates.begin(), candidates.end(), ch );
@@ -365,233 +585,44 @@ namespace picture_validation {
       }
       return false;    
     }
-  protected:
-    void observe_the_dot( char ch ) {
-      if( decimal_state == none_e ) decimal_state = antedec_e;
-      if( ch == '.' || ch == 'V' ) decimal_state = postdec_e;    }
-  } constraint;
-
-  ////////////////////////////////////////////////////////////////
-
-  struct transition_t {
-    state_t state;
-    char ch;
-    state_t next_state;
-
-    transition_t( state_t state,
-                  char ch,
-                  state_t next_state )
-      : state(state)
-      , ch(ch)
-      , next_state(next_state)
-    {}
-
-    bool operator<(const transition_t& that) const {
-      if (state == that.state) return ch < that.ch;      
-      return state < that.state;
-    }
-    bool operator==(const transition_t& that) const { return   match(that); }
-    bool operator!=(const transition_t& that) const { return ! match(that); }
-
-   protected: 
-    // match verifies that the row returned by std::lower_bound actually
-    // matches, and isn't the next "bigger" one.
-    bool match(const transition_t& that) const {
-      return state == that.state
-        &&   ch == that.ch;
-    }
-  };
-  
-  static std::vector<transition_t> picture_rules {
-    // Alpha and Alphanumeric
-    { none_e,          'A',  alphabetic_e },
-    { none_e,          'X',  alphanumeric_e },
-    { none_e,          'B',  alpha_ed_e },
-    { none_e,          '0',  alpha_ed_e },
-    { none_e,          '/',  alpha_ed_e },
-    { none_e,          '9',  antedec_e },   // 9 before V
-    { none_e,          'N',  national_e },
-    { none_e,          'P',  none_e },
-    { none_e,          'S',  none_e },
-    { none_e,          'V',  postdec_e, },  // V before 9
-                       
-    { none_e,          '1',  antedec_e },
-    { antedec_e,       '1',  antedec_e },
-
-    { alphabetic_e,    'A',  alphabetic_e },
-    { alphabetic_e,    'B',  alpha_ed_e },
-    { alphabetic_e,    '0',  alpha_ed_e },
-    { alphabetic_e,    '/',  alpha_ed_e },
-    { alphabetic_e,    'X',  alphanumeric_e },
-    { alphabetic_e,    '$',  numeric_ed_e },
-
-    { alphanumeric_e,  'A',  alphanumeric_e },
-    { alphanumeric_e,  'X',  alphanumeric_e },
-    { alphanumeric_e,  '9',  alphanumeric_e },
-
-    // Alpha edited
-    { alpha_ed_e,      'B',  alpha_ed_e },
-    { alpha_ed_e,      '0',  alpha_ed_e },
-    { alpha_ed_e,      '/',  alpha_ed_e },
-    { alpha_ed_e,      'A',  alpha_ed_e },
-    { alpha_ed_e,      'X',  alpha_ed_e },
-    { alpha_ed_e,      '9',  numeric_ed_e },
-    { alpha_ed_e,      'Z',  numeric_ed_e },
-    { alpha_ed_e,      '*',  numeric_ed_e },
-    { alpha_ed_e,      '+',  numeric_ed_e },
-    { alpha_ed_e,      '-',  numeric_ed_e },
-    { alpha_ed_e,      dot,  numeric_ed_e },
-    { alpha_ed_e,      com,  numeric_ed_e },
-    { alpha_ed_e,      '$',  numeric_ed_e },
-
-    { alphanumeric_e,  'B',  alpha_ed_e },
-    { alphanumeric_e,  '0',  alpha_ed_e },
-    { alphanumeric_e,  '/',  alpha_ed_e },
-    
-    // National
-    { national_e,      'N',  national_e },
-    { national_e,      '\0', alphanumeric_e },
-
-    // National edited
-    { national_e,      'B',  national_ed_e },
-    { national_e,      '0',  national_ed_e },
-    { national_e,      '/',  national_ed_e },
-
-    { national_ed_e,   'N',  national_ed_e },
-    { national_ed_e,   'B',  national_ed_e },
-    { national_ed_e,   '0',  national_ed_e },
-    { national_ed_e,   '/',  national_ed_e },
-    { national_ed_e,   '\0', alpha_ed_e },
-
-    // Numeric edited
-    // [B*] or [+-].*[+-] or (9 and [$B0/,.+-], where $ is cs.
-    { none_e,          'Z',  numeric_ed_e },
-    { none_e,          '*',  numeric_ed_e },
-    { none_e,          dot,  numeric_ed_e },
-    { none_e,          com,  numeric_ed_e },
-    { none_e,          '-',  numeric_ed_e },
-    { none_e,          '+',  numeric_ed_e },
-    { none_e,          '$',  numeric_ed_e },
-                       
-    { antedec_e,       '9',  antedec_e },
-    { antedec_e,       'A',  alphanumeric_e },
-    { antedec_e,       'P',  numeric_e },
-    { antedec_e,       'V',  numeric_e },
-    { antedec_e,       'X',  alphanumeric_e },
-    { antedec_e,       'C',  c_need_r_e },
-    { antedec_e,       'D',  d_need_b_e },
 
-    { antedec_e,       'Z',  numeric_ed_e },
-    { antedec_e,       '*',  numeric_ed_e },
-    { antedec_e,       '$',  numeric_ed_e },
-    { antedec_e,       dot,  numeric_ed_e },
-    { antedec_e,       com,  numeric_ed_e },
-                       
-    { postdec_e,       '9',  numeric_e },
-    { postdec_e,       'P',  numeric_e },
-                       
-    { numeric_e,       '9',  numeric_e },
-    { numeric_e,       'P',  numeric_e },
-
-    { numeric_e,       'Z',  numeric_ed_e },
-    { numeric_e,       '*',  numeric_ed_e },
-    { numeric_e,       'B',  numeric_ed_e },
-    { numeric_e,       '0',  numeric_ed_e },
-    { numeric_e,       '/',  numeric_ed_e },
-    { numeric_e,       dot,  numeric_ed_e },
-    { numeric_e,       com,  numeric_ed_e },
-    { numeric_e,       '+',  numeric_ed_e },
-    { numeric_e,       '-',  numeric_ed_e },
-    { numeric_e,       '$',  numeric_ed_e },
-    { numeric_e,       'C',  c_need_r_e },
-    { numeric_e,       'D',  d_need_b_e },
-
-    { numeric_ed_e,    'Z',  numeric_ed_e },
-    { numeric_ed_e,    'B',  numeric_ed_e },
-    { numeric_ed_e,    '9',  numeric_ed_e },
-    { numeric_ed_e,    '0',  numeric_ed_e },
-    { numeric_ed_e,    dot,  numeric_ed_e },
-    { numeric_ed_e,    com,  numeric_ed_e },
-    { numeric_ed_e,    '/',  numeric_ed_e },
-    { numeric_ed_e,    '-',  numeric_ed_e },
-    { numeric_ed_e,    '+',  numeric_ed_e },
-    { numeric_ed_e,    '*',  numeric_ed_e },
-    { numeric_ed_e,    '$',  numeric_ed_e },
-    { numeric_ed_e,    'P',  numeric_ed_e },
-    { numeric_ed_e,    'V',  numeric_ed_e }, // See Table 10 if in doubt. 
-    { numeric_ed_e,    'C',  c_need_r_e },
-    { numeric_ed_e,    'D',  d_need_b_e },
-
-    // End of the road
-    { c_need_r_e,      'R',  numeric_ed_e },
-    { d_need_b_e,      'B',  numeric_ed_e },
-  };
-  
-  typedef std::array<unsigned char, 256> automaton_elem_t;
-  typedef std::vector<automaton_elem_t> automaton_matrix_t;
-
-  const automaton_matrix_t& prepare_automaton() {
-    static automaton_matrix_t matrix(accept_e);
-    static bool ready = false;
-    if( ready ) return matrix;
-
-    int i __attribute__ ((unused)) = 0, nextra = 0;
-    for( const auto& rule : picture_rules ) {
-      unsigned char ch(rule.ch);
-
-#ifdef COBOL_PICTURE
-      if( matrix[rule.state][ch] ) {
-        nextra++;
-        fprintf(stderr, "%s: redundant rule: #%d { %s '%c' %s }\n",
-                __func__, i, 
-                state_str(rule.state), rule.ch, 
-                state_str(rule.next_state));
+    void prior_repeats( int n ) {
+      if( prior_ch != 'P' ) {
+        update_capacity(n);
       }
-#endif
-      matrix[rule.state][ch] = rule.next_state;
-      i++;
     }
-    if( nextra ) {
-      cbl_internal_error("%s: %d redundant rules", __func__, nextra);
+
+  protected:
+    void observe_the_dot( char ch ) {
+      if( pic_state == none_e ) pic_state = antedec_e;
+      if( ch == decimal_point || ch == 'V' ) pic_state = postdec_e;
     }
-    
-    ready = true;
-    return matrix;
-  }
-  
-  void sort_rules() {
-#ifdef COBOL_PICTURE
-    // During development, verify the ruleset is unique. 
-    std::set<transition_t> U;
-    int i=0;
-    for( const auto& r : picture_validation::picture_rules ) {
-      auto result = U.insert(r);
-      if( ! result.second ) {
-        auto extra = result.first;
-        fprintf(stderr, "%s: redundant rule: #%d { %s '%c' %s }\n",
-                __func__, i, 
-                state_str(extra->state),
-                extra->ch, 
-                state_str(extra->next_state));
+    /*
+     * 1) Every character except V adds to the capacity, with the caveat that
+     *    the first CURRENCY PICTURE character adds the length of the CURRENCY
+     *    SIGN string.
+     * 2) data.digits has to be the count of 9 + count of Z + count of asterisk
+     *    + (count of $ minus 1) + (count of - minus one) + (count of + minus 
1)
+     * 3) data.rdigits is the subset of 2 that is to the right of either V or
+     *    . (edited) 
+     * 
+     * For the moment, break out the fact that V should add zero.  Right now
+     * all of the regression tests assume that V, if there, adds one.  I would
+     * really rather attack the V change when everything is working.
+     */
+    void update_capacity( int n = 1) {
+      static const std::string nonsize( "PVCRDB" );
+      
+      if( std::string::npos == nonsize.find(prior_ch) ) {
+        field_data.add_capacity(n);
+        if( pic_state == postdec_e ) {
+          field_data.rdigits += n;
+        }
       }
-      i++;
     }
-#endif
-    std::sort( picture_validation::picture_rules.begin(),
-               picture_validation::picture_rules.end() );
-    auto extra = std::unique( picture_validation::picture_rules.begin(),
-                              picture_validation::picture_rules.end() );
-    if( extra != picture_validation::picture_rules.end() ) {
-#ifndef COBOL_PICTURE
-      cbl_internal_error("%s: redundant rule: { %s %qc %s }", __func__, 
-                         state_str(extra->state),
-                         extra->ch, 
-                         state_str(extra->next_state));
-#endif
-      assert(false && "Redundant rules detected"); 
-    }
-  }
-}
+
+  };
+} // end namespace
 
 using picture_validation::transition_t;
 using picture_validation::state_t;
@@ -603,7 +634,7 @@ using picture_validation::state_t;
 static const char *
 seek_paren( const char *p, const char *epicture ) {
   for( p++; p < epicture; p++ ) {
-    if( ! isalnum(*p) ) {
+    if( ! ISALNUM(*p) ) {
       switch(*p) {
       case '-':
       case '_':
@@ -632,16 +663,9 @@ end_of_picture( const char *p, const char *epicture ) {
 
 std::pair<const char *, state_t>
 is_valid_picture(const char picture[]) {
-  static bool sorted = false;
-  if( ! sorted ) {
-    picture_validation::sort_rules();
-    sorted = true;
-  }
-  
-  const auto& rules( picture_validation::picture_rules );
-  // reset the global constraint structure. 
-  auto& constraint(picture_validation::constraint);
-  constraint = picture_validation::constraint_t();
+  picture_validation::constraint_t constraint;
+  const picture_validation::automaton_matrix_t&
+    automaton = picture_validation::prepare_automaton();
 
   if( ! picture ) {
     return {picture, picture_validation::invalid_e};
@@ -653,6 +677,7 @@ is_valid_picture(const char picture[]) {
     // Advance lookahead past any count, which might be name.
     // No picture begins with a '('. 
     if( picture < p && *p == '(' && p+1 < epicture  ) {
+      const char *paren = p;
       p = seek_paren(p, epicture);
       if( *p != ')' ) {
         return {p, picture_validation::invalid_e};
@@ -661,47 +686,48 @@ is_valid_picture(const char picture[]) {
         return {p, picture_validation::invalid_e};
       }
       p++;
+      auto result = repeat_count(--paren);
+      int len = result.first;
+      if( len == 0 ) {
+        dbgmsg("%s: odd zero repeat_count for '%s'", __func__, paren);
+        constraint.bad_repeat = paren;
+        return {paren, picture_validation::invalid_e};
+      }
+      constraint.prior_repeats(len);
     }
 
-    // Dot as last character is period separator because the lexer defines
-    // end-of-picture as a space.
     if( end_of_picture(p, epicture) ) break;
 
     // Now p is fixed, but ch might be a currency symbol
-    char ch = toupper(*p);
+    char ch = TOUPPER(*p);
     
     // Is the current character ever allowed to follow the prior? 
+    size_t currency_len = 0;
     if( ! constraint.day_follows_night(ch) ) {
-      if( symbol_currency(ch) ) {
+      const char *currency = symbol_currency(ch);
+      if( currency ) {
         ch = '$';
+        currency_len = strlen(currency);
       } else {
         if( verbose ) 
           fprintf(stderr,  "no %2zu: %c -> %c (%s)\n",
                   p - picture, constraint.prior(), ch,
-                  picture_validation::state_str(constraint.automaton()) );
+                  picture_validation::state_str(constraint.picture_state()) );
         return {p, picture_validation::invalid_e};
       }
     }
 
-    // Consult the rules.
-    picture_validation::transition_t query { state, ch, state };
-    
-    auto prule = std::lower_bound(rules.begin(), rules.end(), query);
+    // Update constraint record and advance to the next state.
+    constraint.append(ch, currency_len);
+    state = automaton[state][ch];
 
-    if( prule == rules.end() || *prule != query ) {
-      state_t state = p == epicture?
-        constraint.state() : picture_validation::invalid_e;
-      return {p, state};
+    if( verbose ) {
+      fprintf(stderr,  "ok %2zu: %c (next: %s)\n",
+              p - picture, ch, picture_validation::state_str(state));
+    }
+    if( state == picture_validation::invalid_e ) {
+      return {p, picture_validation::invalid_e};
     }
-
-    if( verbose ) 
-      fprintf(stderr,  "ok %2zu: %c (%s)\n",
-              p - picture, ch,
-              picture_validation::state_str(prule->next_state) );
-
-    // Advance to the next state.
-    constraint = ch;
-    state = prule->next_state;
   }
 
   return {epicture, constraint.state()};
diff --git a/gcc/cobol/scan_ante.h b/gcc/cobol/scan_ante.h
index 729800062099..f87db5657035 100644
--- a/gcc/cobol/scan_ante.h
+++ b/gcc/cobol/scan_ante.h
@@ -58,8 +58,6 @@ int repository_function_tok( const char name[] );
 
 void next_sentence_label(cbl_label_t*);
 
-std::pair<int, int> repeat_count(const char picture[]);
-
 size_t program_level();
 
 static int ydfparse(void);
diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc
index e45252259816..3085b01bec70 100644
--- a/gcc/cobol/util.cc
+++ b/gcc/cobol/util.cc
@@ -28,12 +28,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/*
- * This file supports parsing without requiring access to the symbol
- * table definition.  Unlike the Bison input, this file brings in gcc
- * header files.
- */
-
 #include "cobol-system.h"
 #include <coretypes.h>
 #include <tree.h>
@@ -2182,7 +2176,7 @@ literal_subscript_oob( const cbl_refer_t& r, size_t& isub 
/* output */)  {
   for( isub=0; isub < ndim; isub++ ) {
     const auto& subscript = r.subscripts[isub];
     const auto& occurs = dims[isub]->occurs;
-    
+
     if( ! occurs.subscript_ok(subscript.field) ) {
       break; // found one
     }
@@ -2550,7 +2544,7 @@ hex2numstr( const char input[] ) {
 
   int n = sscanf(++input, "%c%" GCC_PRISZ "x%c", &q, &value, &q);
   assert(n == 3 && (q == '\'' || q == '"'));
-         
+
   return xasprintf("%lu", value);
 }
 
@@ -4672,4 +4666,3 @@ iso_cobol_word( const std::string& name, bool 
include_context ) {
   }
   return ok;
 }
-
diff --git a/gcc/cobol/util.h b/gcc/cobol/util.h
index b99533944376..2cf91dcd2b27 100644
--- a/gcc/cobol/util.h
+++ b/gcc/cobol/util.h
@@ -45,6 +45,8 @@ void cobol_filename_restore();
 const char * cobol_lineno( int );
 int cobol_lineno(void);
 
+std::pair<int, int> repeat_count(const char picture[]);
+
 unsigned long gb4( size_t input );
 
 template <typename P>

Reply via email to