diff options
Diffstat (limited to 'gcc/cobol/parse.y')
| -rw-r--r-- | gcc/cobol/parse.y | 320 |
1 files changed, 251 insertions, 69 deletions
diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index 9187a59..d54a686 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -51,7 +51,7 @@ accept_envar_e, }; - struct collating_an_t { + struct coll_alphanat_t { const char *alpha, *national; }; @@ -575,7 +575,7 @@ class locale_tgt_t { RD RECORD RECORDING RECORDS RECURSIVE REDEFINES REEL REFERENCE RELATIVE REM REMAINDER REMARKS REMOVAL RENAMES REPLACE REPLACING REPORT REPORTING REPORTS - REPOSITORY RERUN RESERVE RESTRICTED RESUME + REPOSITORY RERUN RESERVE RESTRICTED RESUME RETRY REVERSE REVERSED REWIND RF RH RIGHT ROUNDED RUN SAME SCREEN SD @@ -702,8 +702,8 @@ class locale_tgt_t { %type <number> open_io alphabet_etc %type <special_type> device_name %type <string> numed context_word ctx_name locale_spec -%type <collating_sequences> collating_sequences collating_ans -%type <collating_name> collating_an +%type <char_class_locales> char_class_locales coll_alphanats +%type <collating_name> coll_alphanat %type <literal> namestr alphabet_lit program_as repo_as %type <field> perform_cond kind_of_name %type <refer> alloc_ret @@ -738,6 +738,9 @@ class locale_tgt_t { relative_key_clause reserve_clause sharing_clause %type <file> filename read_body write_body delete_body +%type <label> delete_file_body +%type <error> delete_error delete_except delete_excepts + %type <file> start_impl start_cond start_body %type <rewrite_t> rewrite_body %type <min_max> record_vary rec_contains from_to record_desc @@ -833,6 +836,7 @@ class locale_tgt_t { global is_global anycase backward end_display exh_changed exh_named + override %type <number> mistake globally first_last %type <io_mode> io_mode @@ -874,6 +878,7 @@ class locale_tgt_t { %type <opt_init_sect> opt_init_sect %type <number> opt_init_value %type <number> locale_current loc_category user_default +%type <string> locale_name %type <token_list> loc_categories locale_tgt %type <opt_round> rounded round_between rounded_type rounded_mode %type <opt_arith> opt_arith_type @@ -901,7 +906,7 @@ class locale_tgt_t { struct { YYLTYPE loc; int token; literal_t name; } prog_end; struct { int token; special_name_t id; } special_type; struct { char locale_type; const char * name; } locale_phrase; - collating_an_t collating_sequences; + coll_alphanat_t char_class_locales; struct collating_name_t { int token; const char *name; } collating_name; struct { size_t isym; cbl_encoding_t encoding; } codeset; struct { cbl_field_type_t type; @@ -2371,6 +2376,23 @@ config_paragraphs: config_paragraph config_paragraph: SPECIAL_NAMES '.' | SPECIAL_NAMES '.' special_names '.' + { + std::reverse_iterator<symbol_elem_t *> + p(symbols_end()), + pend(symbols_begin(PROGRAM)); + for( ++p; p != pend; p++ ) { + if( p->type == SymAlphabet ) { + const auto& alphabet = *cbl_alphabet_of(&*p); + if( alphabet.encoding == no_encoding_e ) { + assert(alphabet.locale != 0 ); + const auto& missing = *cbl_locale_of(symbol_at(alphabet.locale)); + error_msg(alphabet.loc, + "ALPHABET %qs references LOCALE %qs, which is not defined", + alphabet.name, missing.name); + } + } + } + } | SOURCE_COMPUTER '.' | SOURCE_COMPUTER '.' NAME '.' | SOURCE_COMPUTER '.' NAME with_debug '.' @@ -2507,19 +2529,36 @@ with_debug: with DEBUGGING MODE { ; collations: %empty - | collation_classification - | collation_sequence - | collation_classification collation_sequence - | collation_sequence collation_classification + | char_classification + | collating_sequence + | char_classification collating_sequence + | collating_sequence char_classification ; -collation_classification: - character CLASSIFICATION collating_sequences[seq] +char_classification: + character CLASSIFICATION char_class_locales[seq] { - warn_msg(@seq, "CHARACTER CLASSIFICATION ignored"); + if( $seq.alpha ) { + auto e = symbol_locale(PROGRAM, $seq.alpha); + if( !e ) { + error_msg(@seq, "no LOCALE defined as %qs", $seq.alpha); + } else { + auto& encoding = cbl_locale_of(e)->encoding; + current.alpha_encoding(symbol_index(e), encoding); + } + } + if( $seq.national ) { + auto e = symbol_locale(PROGRAM, $seq.national); + if( !e ) { + error_msg(@seq, "no LOCALE defined as %qs", $seq.national); + } else { + auto& encoding = cbl_locale_of(e)->encoding; + current.national_encoding(symbol_index(e), encoding); + } + } } ; -collation_sequence: - program_kw collating SEQUENCE collating_sequences[seq] +collating_sequence: + program_kw collating SEQUENCE char_class_locales[seq] { if( !current.collating_sequence($seq.alpha) ) { error_msg(@seq, "collating sequence already defined as '%s'", @@ -2529,20 +2568,20 @@ collation_sequence: } ; -collating_sequences: +char_class_locales: is NAME[name] { $$.alpha = $name; $$.national = nullptr; } - | collating_ans { $$ = $1; } + | coll_alphanats { $$ = $1; } ; -collating_ans: collating_an[encoding] { - $$ = collating_an_t(); +coll_alphanats: coll_alphanat[encoding] { + $$ = coll_alphanat_t(); const char **pname = $encoding.token == ALPHANUMERIC? &$$.alpha : &$$.national; *pname = $encoding.name; } - | collating_ans collating_an[encoding] + | coll_alphanats coll_alphanat[encoding] { const char **pname = $encoding.token == ALPHANUMERIC? &$$.alpha : &$$.national; @@ -2553,7 +2592,7 @@ collating_ans: collating_an[encoding] { *pname = $encoding.name; } ; -collating_an: for alphanational is locale_phrase[locale] { +coll_alphanat: for alphanational is locale_phrase[locale] { $$.token = $alphanational; $$.name = $locale.name; if( ! $locale.name ) { @@ -2568,7 +2607,6 @@ collating_an: for alphanational is locale_phrase[locale] { keyword_str($$.token), locale_name); } - warn_msg(@locale, "LOCALE phrase ignored"); } ; @@ -2643,9 +2681,20 @@ special_name: dev_mnemonic { symbol_decimal_point_set(','); } - | LOCALE NAME is locale_spec[spec] { - current.locale($NAME, $spec); - cbl_unimplementedw("sorry, unimplemented: LOCALE %qs", $spec); + | LOCALE NAME is locale_spec[spec] + { + cbl_locale_t locale($NAME, $spec); + if( locale.encoding == no_encoding_e ) { + error_msg(@NAME, "invalid iconv LOCALE name %qs", $spec); + YYERROR; + } + if( locale.encoding == UTF8_e ) { + cbl_unimplemented("UTF-8"); + YYERROR; + } + if( ! current.locale_add(locale) ) { + error_msg(@NAME, "%qs already defined as LOCALE name", $NAME); + } } ; | upsi @@ -2655,6 +2704,8 @@ special_name: dev_mnemonic } ; locale_spec: NAME { $$ = $1; } + | UTF_8 { static char s[] ="UTF-8"; $$ = s; } + | UTF_16 { static char s[] ="UTF-16"; $$ = s; } | LITERAL { $$ = string_of($1); } ; @@ -2746,14 +2797,16 @@ device_name: SYSIN { $$.token = SYSIN; $$.id = SYSIN_e; } alphabet_name: STANDARD_ALPHABET { $$ = alphabet_add(@1, CP1252_e); } | NATIVE { $$ = alphabet_add(@1, EBCDIC_e); } | EBCDIC { $$ = alphabet_add(@1, EBCDIC_e); } - | LOCALE ctx_name + | LOCALE locale_name[name] { - auto e = symbol_alphabet(PROGRAM, $ctx_name); + auto e = symbol_locale(PROGRAM, $name); if( !e ) { - error_msg(@ctx_name, "no such ALPHABET %qs", $ctx_name); - YYERROR; - } - $$ = cbl_alphabet_of(e); + dbgmsg("no such LOCALE yet %s", $name); + cbl_locale_t locale($name); // locale is named but not defined + e = symbol_locale_add(PROGRAM, &locale); + } + cbl_alphabet_t alphabet( @name, symbol_index(e), $name); + $$ = alphabet_add(alphabet); } | alphabet_seqs { @@ -3592,7 +3645,7 @@ const_value: cce_expr value78: literalism { - cbl_field_data_t data = {}; + cbl_field_data_t data; data.capacity = capacity_cast(strlen($1.data)); data.initial = $1.data; $$.encoding = $1.encoding; @@ -3600,13 +3653,15 @@ value78: literalism } | const_value { - cbl_field_data_t data = {}; + cbl_field_data_t data; data = build_real (float128_type_node, $1); + $$.encoding = current_encoding('A'); $$.data = new cbl_field_data_t(data); } | reserved_value[value] { const auto field = constant_of(constant_index($value)); + $$.encoding = current_encoding('A'); $$.data = new cbl_field_data_t(field->data); } @@ -3638,6 +3693,7 @@ data_descr1: level_name field.type = FldLiteralN; field.data = build_real (float128_type_node, $const_value); field.data.initial = string_of($const_value); + field.codeset.set(); if( !cdf_value(field.name, cdfval_t($const_value)) ) { error_msg(@1, "%s was defined by CDF", field.name); @@ -3674,13 +3730,12 @@ data_descr1: level_name if( !cdf_value(field.name, $lit.data) ) { error_msg(@1, "%s was defined by CDF", field.name); } - if( ! field.codeset.valid() ) { - if( ! field.codeset.set(field.codeset.standard_internal.type) ) { - error_msg(@lit, "CONSTANT inconsistent with encoding %s", - cbl_alphabet_t::encoding_str(field.codeset.encoding)); - } + if( ! field.codeset.set() ) { + error_msg(@lit, "CONSTANT inconsistent with encoding %s", + cbl_alphabet_t::encoding_str(field.codeset.encoding)); } - value_encoding_check(@lit, $1, $lit.encoding); + + value_encoding_check(@lit, $1); } | level_name CONSTANT is_global FROM NAME { @@ -3718,6 +3773,7 @@ data_descr1: level_name } else { field.type = FldLiteralN; field.data.initial = string_of(field.data.value_of()); + field.codeset.set($data.encoding); if( !cdf_value(field.name, field.as_integer()) ) { yywarn("%s was defined by CDF", field.name); } @@ -3975,6 +4031,15 @@ data_descr1: level_name // Verify VALUE $field->report_invalid_initial_value(@data_clauses); + bool numerical = + $field->type == FldNumericDisplay || is_numeric($field); + + if( $field->data.initial && ! numerical ) { + if( normal_value_e == cbl_figconst_of($field->data.initial) ) { + value_encoding_check(@data_clauses, $field); + } + } + // verify REDEFINES const auto parent = parent_of($field); if( parent && $field->level == parent->level ) { @@ -4287,14 +4352,16 @@ picture_clause: PIC signed nps[fore] nines nps[aft] if( field->data.initial != NULL ) { if( 0 < field->data.capacity && field->data.capacity < uint32_t($size) ) { - auto p = blank_pad_initial( field->data.initial, - field->data.capacity, $size ); + auto p = blank_pad_initial(field->data.initial, + field->data.capacity, $size ); if( !p ) YYERROR; field->data.initial = p; } } - field->data.capacity = $size; + charmap_t *charmap = + __gg__get_charmap(field->codeset.encoding); + field->data.capacity = $size * charmap->stride(); field->data.picture = NULL; if( false ) dbgmsg("PIC alphanum_pic[size]:%d: %s", @@ -4708,14 +4775,23 @@ usage_clause1: usage BIT value_clause: VALUE all LITERAL[lit] { cbl_field_t *field = current_field(); - if( ! field->codeset.set($lit.encoding) ) { - error_msg(@lit, "VALUE inconsistent with encoding %s", - cbl_alphabet_t::encoding_str(field->codeset.encoding)); + + if( $lit.prefix[0] ) { // not the default encoding + if( ! field->codeset.set($lit.encoding) ) { + error_msg(@lit, "VALUE inconsistent with encoding %s", + cbl_alphabet_t::encoding_str(field->codeset.encoding)); + } + } else { + field->codeset.set(); } + + if( field->codeset.encoding != $lit.encoding ) { + error_msg(@lit, "PICTURE inconsistent with VALUE %s'%s'", + $lit.prefix, $lit.data); + } + field->data.initial = $lit.data; field->attr |= literal_attr($lit.prefix); - // The __gg__initialize_data routine needs to know that VALUE is a - // quoted literal. This is critical for NumericEdited variables field->attr |= quoted_e; if( field->data.capacity == 0 ) { @@ -4732,7 +4808,6 @@ value_clause: VALUE all LITERAL[lit] { } } } - value_encoding_check(@lit, field, $lit.encoding); } | VALUE all cce_expr[value] { cbl_field_t *field = current_field(); @@ -4761,11 +4836,9 @@ value_clause: VALUE all LITERAL[lit] { | VALUE all reserved_value[value] { cbl_field_t *field = current_field(); - if( ! field->codeset.valid() ) { - if( ! field->codeset.set(field->codeset.standard_internal.type) ) { - error_msg(@value, "VALUE inconsistent with encoding %s", - cbl_alphabet_t::encoding_str(field->codeset.encoding)); - } + if( ! field->codeset.set() ) { + error_msg(@value, "VALUE inconsistent with encoding %s", + cbl_alphabet_t::encoding_str(field->codeset.encoding)); } if( $value != NULLS ) { auto fig = constant_of(constant_index($value)); @@ -5017,6 +5090,7 @@ typedef_clause: is TYPEDEF strong error_msg(@2, "%s %s IS TYPEDEF must be level 01", field->level_str(), field->name); } + field->codeset.set(); field->attr |= typedef_e; if( $strong ) field->attr |= strongdef_e; if( ! current.typedef_add(field) ) { @@ -7007,6 +7081,8 @@ context_word: APPLY { static char s[] ="APPLY"; $$ = s; } // LOCK MODE clause | MULTIPLE { static char s[] ="MULTIPLE"; $$ = s; } // LOCK ON phrase + | NAT { static char s[] ="NAT"; + $$ = s; } // CONVERT function | NEAREST_AWAY_FROM_ZERO { static char s[] ="NEAREST-AWAY-FROM-ZERO"; $$ = s; } // INTERMEDIATE ROUNDING clause and ROUNDED phrase | NEAREST_EVEN { static char s[] ="NEAREST-EVEN"; @@ -8544,7 +8620,7 @@ advance_by: scalar lines { $$ = $1; } /* BUG: should accept reference */ * number of lines is negative. So, we use the * negative Number Of The Beast as a PAGE flag. */ - $$ = new_reference( new_literal("-666") ); + $$ = new_reference( new_literal(xstrdup("-666")) ); } | device_name { $$ = new_reference(literally_one); } ; @@ -8601,7 +8677,33 @@ io_invalid: INVALID key { delete: delete_impl end_delete | delete_cond end_delete + | delete_file end_delete ; +delete_file: DELETE delete_file_body[stmt] delete_error[err] { + if( ! $err.on_error ) parser_file_delete_on_exception($stmt); + if( ! $err.not_error ) parser_file_delete_not_exception($stmt); + parser_file_delete_end($stmt); + current.declaratives_evaluate(); + } +delete_file_body: + FILE_KW override filenames retry_phrase { + $$ = label_add(@$, LblXml, uniq_label("xfile")); + xml_statements.push($$); + statement_begin(@$, DELETE); + std::vector<cbl_file_t*> + filenames($filenames->files.begin(), + $filenames->files.end() ); + parser_file_delete_file( $$, filenames); + } + ; +retry_phrase: %empty + | RETRY expr TIMES + | FOR expr SECONDS + | FOREVER { + cbl_unimplemented("DELETE FILE RETRY"); + } + ; + delete_impl: DELETE delete_body[file] { file_delete_args.call_parser_file_delete(true); @@ -8634,6 +8736,63 @@ delete_body: filename[file] record $$ = $file; } ; + +delete_error: %empty %prec DELETE { + $$.on_error = $$.not_error = nullptr; + } + | delete_excepts %prec DELETE + ; +delete_excepts: delete_except[a] statements %prec DELETE + { + assert( $a.on_error || $a.not_error ); + assert( ! ($a.on_error && $a.not_error) ); + $$ = $a; + } + | delete_excepts[a] delete_except[b] statements %prec DELETE + { + if( $a.on_error && $a.not_error ) { + error_msg(@1, "too many ON ERROR clauses"); + YYERROR; + } + // "ON" and "NOT ON" could be reversed, but not duplicated. + if( $a.on_error && $b.on_error ) { + error_msg(@1, "duplicate ON ERROR clauses"); + YYERROR; + } + if( $a.not_error && $b.not_error ) { + error_msg(@1, "duplicate NOT ON ERROR clauses"); + YYERROR; + } + $$ = $a; + if( $$.on_error ) { + assert($b.not_error); + $$.not_error = $b.not_error; + } else { + assert($b.on_error); + $$.on_error = $b.on_error; + } + } + ; +delete_except: EXCEPTION + { + auto xml_stmt = xml_statements.top(); + // The value of the pointer no longer matters, only NULL or not. + $$.on_error = $$.not_error = nullptr; + switch($1) { + case EXCEPTION: + $$.on_error = xml_stmt; + parser_file_delete_on_exception(xml_stmt); + break; + case NOT: + $$.not_error = xml_stmt; + parser_file_delete_not_exception(xml_stmt); + break; + default: + gcc_unreachable(); + } + } + ; + end_delete: %empty %prec DELETE | END_DELETE ; @@ -10536,7 +10695,9 @@ function_udf: FUNCTION_UDF '(' arg_list[args] ')' { cbl_ffi_arg_t actual(param.crv, ar); return actual; } ); - auto name = new_literal(strlen(L->name), L->name, quoted_e); + // Pretend hex-encoded because that means use verbatim. + auto attr = cbl_field_attr_t(quoted_e | hex_encoded_e); + auto name = new_literal(strlen(L->name), L->name, attr); ast_call( @1, name, $$, args.size(), args.data(), NULL, NULL, true ); } | FUNCTION_UDF_0 { @@ -10547,8 +10708,11 @@ function_udf: FUNCTION_UDF '(' arg_list[args] ')' { const auto returning = cbl_field_of(symbol_at(L->returning)); $$ = new_temporary_clone(returning); $$->data.initial = returning->name; // user's name for the field - - auto name = new_literal(strlen(L->name), L->name, quoted_e); + cbl_field_attr_t call_attr + = (cbl_field_attr_t)(quoted_e|hex_encoded_e); + cbl_field_t *name = new_literal(strlen(L->name), + L->name, + call_attr); ast_call( @1, name, $$, narg, args, NULL, NULL, true ); } ; @@ -11135,6 +11299,18 @@ subst_input: anycase first_last varg[v1] varg[v2] { } ; +locale_name: NAME + { + auto e = symbol_locale(PROGRAM, $NAME); + if( !e ) { + error_msg(@NAME, "no such SPECIAL-NAMES LOCALE: %qs", $NAME); + YYERROR; + } + $$ = const_cast<char*>( + __gg__encoding_iconv_name(cbl_locale_of(e)->encoding) ); + } + ; + intrinsic_locale: LOCALE_COMPARE '(' varg[r1] varg[r2] ')' { @@ -11143,11 +11319,12 @@ intrinsic_locale: cbl_refer_t dummy = {}; if( ! intrinsic_call_3($$, LOCALE_COMPARE, $r1, $r2, &dummy) ) YYERROR; } - | LOCALE_COMPARE '(' varg[r1] varg[r2] varg[r3] ')' + | LOCALE_COMPARE '(' varg[r1] varg[r2] locale_name ')' { location_set(@1); $$ = new_alphanumeric(); - if( ! intrinsic_call_3($$, LOCALE_COMPARE, $r1, $r2, $r3) ) YYERROR; + cbl_refer_t locale(new_literal($locale_name)); + if( ! intrinsic_call_3($$, LOCALE_COMPARE, $r1, $r2, &locale) ) YYERROR; } | LOCALE_DATE '(' varg[r1] ')' @@ -11453,6 +11630,10 @@ optional: %empty { $$ = false; } | OPTIONAL { $$ = true; } ; +override: %empty { $$ = false; } + | OVERRIDE { $$ = true; } + ; + program_kw: %empty | PROGRAM_kw ; @@ -11900,6 +12081,7 @@ void ast_call( const YYLTYPE& loc, cbl_refer_t name, const cbl_refer_t& returnin if( is_literal(name.field) ) { cbl_field_t called = { FldLiteralA, quoted_e | constant_e, name.field->data, 77 }; + called.attr |= name.field->attr; snprintf(called.name, sizeof(called.name), "_%s", name.field->data.initial); name.field = cbl_field_of(symbol_field_add(PROGRAM, &called)); symbol_field_location(field_index(name.field), loc); @@ -13030,13 +13212,13 @@ struct expand_group : public std::list<cbl_refer_t> { }; -static const char * initial_default_value; - const char * wsclear() { return initial_default_value; } +static const uint32_t * initial_default_value; + const uint32_t * wsclear() { return initial_default_value; } void -wsclear( char ch ) { - static char byte = ch; - initial_default_value = &byte; +wsclear( uint32_t i ) { + static uint32_t init_val = i; + initial_default_value = &init_val; current.program_needs_initial(); } @@ -13558,16 +13740,16 @@ literal_t::set( const cbl_field_t * field ) { literal_t& literal_t::set_prefix( const char *input, size_t len ) { - encoding = current_encoding('A'); + encoding = current_encoding(display_encoding_e); assert(len < sizeof(prefix)); std::fill(prefix, prefix + sizeof(prefix), '\0'); std::transform(input, input + len, prefix, toupper); switch(prefix[0]) { case '\0': case 'Z': - encoding = current_encoding('A'); + encoding = current_encoding(display_encoding_e); break; case 'N': - encoding = current_encoding('N'); + encoding = current_encoding(national_encoding_e); if( 'X' == prefix[1] ) { cbl_unimplemented("NX literals"); } @@ -13583,7 +13765,7 @@ literal_t::set_prefix( const char *input, size_t len ) { default: gcc_unreachable(); } - assert(encoding <= iconv_YU_e); + assert(valid_encoding(encoding)); return *this; } @@ -13608,8 +13790,8 @@ literal_attr( const char prefix[] ) { case 'X': switch(prefix[0]) { case 'B': return cbl_field_attr_t(hex_encoded_e | bool_encoded_e); - case 'N': - case 'U': cbl_unimplemented("National"); return none_e; + case 'N': cbl_unimplemented("Hexadecimal National"); return none_e; + case 'U': cbl_unimplemented("Hexadecimal Unicode"); return none_e; } break; } |
