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>
