https://gcc.gnu.org/g:09463178dc462cd7f7cec1bf09856459702ca624
commit r17-4237-g09463178dc462cd7f7cec1bf09856459702ca624 Author: James K. Lowden <[email protected]> Date: Fri Sep 11 18:44:52 2026 -0400 cobol: Improve data-item validation. Support Implicit PICTURE per ISO 13.16.2. A data item F with VALUE and no PICTURE is initially entered into the symbol table as invalid. If item F+1 is entered and is not subordinate, and F meets the conditions for an implicit PICTURE, mark it as valid. Correct currency symbol validation, fixes RT 3681. gcc/cobol/ChangeLog: * parse.y: Emit diagnostic if symbol_currency_add fails. * parse_ante.h (update_prior_invalid_field): New function. (field_add): Use update_prior_invalid_field to validate prior field. * scan.l: Document currency-symbol domain. * symbols.cc (symbols_update): Quell redundant diagnostic. (symbol_currency_symbol_ok): Validate currency symbol. (symbol_currency_add): Use symbol_currency_symbol_ok. Diff: --- gcc/cobol/parse.y | 13 ++++++++++--- gcc/cobol/parse_ante.h | 28 ++++++++++++++++++++++++++++ gcc/cobol/scan.l | 10 ++++++++++ gcc/cobol/symbols.cc | 18 ++++++++++++++++-- 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index 6434c2685fb2..37f4ab6358f6 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -3115,7 +3115,10 @@ special_name: dev_mnemonic { error_msg(@lit, "'%s' has embedded NUL", $lit.data); YYERROR; } - symbol_currency_add( $picture_sym, $lit.data ); + if( ! symbol_currency_add($picture_sym, $lit.data) ) { + auto ch = $picture_sym[0]; + error_msg(@picture_sym, "invalid currency symbol: %qc", ch); + } } | DECIMAL_POINT is COMMA { @@ -3530,8 +3533,12 @@ data_div: %empty { parser_division( data_div_e, NULL, 0, NULL ); } } ; -data_sections: data_section - | data_sections data_section +data_sections: data_section { + update_prior_invalid_field(); + } + | data_sections data_section { + update_prior_invalid_field(); + } ; data_section: FILE_SECT '.' diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h index c3214ce75b95..b8db55e49184 100644 --- a/gcc/cobol/parse_ante.h +++ b/gcc/cobol/parse_ante.h @@ -3315,6 +3315,32 @@ group_attr( const cbl_field_t * field ) { return p->attr; } +/* + * 13.16.3 Syntax rules + * a) if the literal is alphanumeric, 'PICTURE X(length)' + * b) if the literal is boolean, 'PICTURE 1(length)' + * c) if the literal is national, 'PICTURE N(length)' + * (We don't support boolean yet.) + */ +static void +update_prior_invalid_field( const cbl_field_t *field = nullptr) { + symbol_elem_t *e = field? symbol_at(field->our_index) : symbols_end(); + e--; + if( e->type == SymDataSection ) e--; + if( (e)->type == SymField ) { + auto f = cbl_field_of(e); + if( ! field ) field = f; // fake it + if( field->level <= f->level ) { + if( f->type == FldInvalid && f->data.has_initial_value() ) { + if( f->has_attr(quoted_e) ) { + f->type = FldAlphanumeric; + assert(0 < f->char_capacity()); + } + } + } + } +} + static struct cbl_field_t * field_add( const cbl_loc_t& loc, cbl_field_t *field ) { switch(current_data_section) { @@ -3349,6 +3375,8 @@ field_add( const cbl_loc_t& loc, cbl_field_t *field ) { return NULL; break; } + } else { + update_prior_invalid_field(field); } return field; } diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l index 8b85d710e320..df76ad1da816 100644 --- a/gcc/cobol/scan.l +++ b/gcc/cobol/scan.l @@ -136,7 +136,17 @@ ALPHED {ALPHEDREQ}([AX9B0/]{COUNT}?)* NUMEDCHAR [BPVZ90/,]+{COUNT}? NUMEDCHARS {NUMEDCHAR}([.]?{NUMEDCHAR})* NUMED ([+-]{NUMEDCHARS}+)|({NUMEDCHARS}+[+-]?) + /* ISO specification 12.3.7.2: + * 27) Literal-8 may be any character from the + * computer's coded character set except for the + * following: + * a) digits 0 through 9; + * b) alphabetic characters A, B, C, D, E, N, P, R, S, V, X, Z, + * or their lowercase equivalents; or the space; + * c) characters '+' '–' ',' '.' '*' '/' ';' '(' ')' '"' '=' + */ CURRENCY [A-Zfhijklmoqtuwy\x80-\xFF]{-}[ABCDEGNPRSVXZ] +xCURRENCY [\x00-\xFF]{-}[ABCDEGNPRSVXZ 0-9 abcdegnprsvxz,.*/;()""=+-] NUMEDCUR (([.]?[$0B/Z*+,P9()V+-]|{CURRENCY}+|{COUNT})+([.][$0B/Z*+P9()V+-])*)+ NUMEDITED {NUMED}|{NUMEDCUR} diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc index bef6f116c3b8..f732a67287bb 100644 --- a/gcc/cobol/symbols.cc +++ b/gcc/cobol/symbols.cc @@ -2030,8 +2030,10 @@ symbols_update( size_t first, bool parsed_ok ) { case FldNumericDisplay: case FldNumericEdited: if( ! (field->has_attr(register_e) || field->has_attr(hex_encoded_e)) ) { - error_msg(symbol_field_location(field_index(field)), - "internal: %qs encoding not defined", field->name); + if( ! mode_syntax_only() ) { + error_msg(symbol_field_location(field_index(field)), + "internal: %qs encoding not defined", field->name); + } } break; case FldClass: @@ -5132,15 +5134,27 @@ symbol_program_local( const char tgt_name[] ) { */ std::map<char, const char *> currencies; +static bool +symbol_currency_symbol_ok( const char symbol ) { + static std::string never("ABCDEGNPRSUVXZ0-9abcdegnprsuvxz,.*/;()'\"=+-"); + return std::string::npos == never.find(symbol); +} + // cppcheck-suppress-begin [nullPointerRedundantCheck] bool symbol_currency_add( const char symbol[], const char sign[] ) { + static const std::string never("ABCDEGNPRSUVXZ0-9abcdegnprsuvxz,.*/;()'\"=+-"); // In service of CURRENCY sign PICTURE SYMBOL symbol // The single-character 'symbol' is replaced with multi-char 'sign' // by the NumericEdited processing. if( !symbol ) { symbol = xasprintf("%c", *sign); + } else { + if( ! symbol_currency_symbol_ok(symbol[0]) ) { + return false; + } } + currencies[*symbol] = sign; return true; }
