diff --git a/gcc/cobol/UAT/failsuite.src/run_functions.at b/gcc/cobol/UAT/failsuite.src/run_functions.at index e26b0f98abf419ae16b184771a70072fa897b9ea..477152f3c04c1d1a424457c8fcb6972c3ffa9fa4 100644 --- a/gcc/cobol/UAT/failsuite.src/run_functions.at +++ b/gcc/cobol/UAT/failsuite.src/run_functions.at @@ -2823,6 +2823,8 @@ AT_CLEANUP AT_SETUP([FUNCTION STORED-CHAR-LENGTH]) AT_KEYWORDS([functions]) +AT_XFAIL_IF([test "$COB_DIALECT" != "gnu"]) + AT_DATA([prog.cob], [ IDENTIFICATION DIVISION. PROGRAM-ID. prog. diff --git a/gcc/cobol/cdf.y b/gcc/cobol/cdf.y index 82104118dd2b24aaf7a16a9444cd9acda841eba6..1a88a31fb5d2e72ee27f9c5f7b2c96d68c2d46d0 100644 --- a/gcc/cobol/cdf.y +++ b/gcc/cobol/cdf.y @@ -259,15 +259,15 @@ apply_cdf_turn( exception_turns_t& turns ) { %type <file> filename %type <files> filenames -%token BY 467 +%token BY 468 %token COPY 356 %token CDF_DISPLAY 378 -%token IN 580 +%token IN 581 %token NAME 286 %token NUMSTR 304 -%token OF 658 -%token PSEUDOTEXT 694 -%token REPLACING 716 +%token OF 659 +%token PSEUDOTEXT 695 +%token REPLACING 717 %token LITERAL 297 %token SUPPRESS 373 @@ -277,21 +277,21 @@ apply_cdf_turn( exception_turns_t& turns ) { %token CDF_IF 379 CDF_ELSE 380 CDF_END_IF 381 %token CDF_EVALUATE 382 CDF_WHEN 383 CDF_END_EVALUATE 384 -%token AS 451 CONSTANT 355 DEFINED 357 +%token AS 452 CONSTANT 355 DEFINED 357 %type <boolean> DEFINED -%token OTHER 670 PARAMETER_kw 362 OFF 659 OVERRIDE 363 -%token THRU 905 -%token TRUE_kw 780 +%token OTHER 671 PARAMETER_kw 362 OFF 660 OVERRIDE 363 +%token THRU 907 +%token TRUE_kw 782 -%token TURN 782 CHECKING 475 LOCATION 622 ON 661 WITH 806 +%token TURN 784 CHECKING 476 LOCATION 623 ON 662 WITH 808 -%left OR 906 -%left AND 907 -%right NOT 908 -%left '<' '>' '=' NE 909 LE 910 GE 911 +%left OR 908 +%left AND 909 +%right NOT 910 +%left '<' '>' '=' NE 911 LE 912 GE 913 %left '-' '+' %left '*' '/' -%right NEG 912 +%right NEG 914 %define api.prefix {ydf} %define api.token.prefix{YDF_} diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc index e412527ecd3b3f2eabffa72e8d021472739fefb3..e200f043c97fe493101f3da1f9cf2839335fd284 100644 --- a/gcc/cobol/genapi.cc +++ b/gcc/cobol/genapi.cc @@ -8638,6 +8638,13 @@ parser_intrinsic_callv( cbl_field_t *tgt, SHOW_PARSE_END } + if( function_name == substitute_billboard ) { + auto truth_of_the_matter = reinterpret_cast<cbl_substitute_t*>(refs); + warnx("%s: unimplemented: FUNCTION SUBSTITUTE", __func__); + return; + } + + TRACE1 { TRACE1_HEADER diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index 065b4209ef311ca606d17d285114e9669c79e236..4bf0586dccf3c18d540d3f09a57cc9a1a87625af 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -135,6 +135,29 @@ typedef std::map<data_category_t, struct cbl_refer_t*> category_map_t; + struct substitution_t { + enum subst_fl_t { subst_all_e, subst_first_e = 'F', subst_last_e = 'L' }; + bool anycase; + subst_fl_t first_last; + cbl_refer_t *orig, *replacement; + + substitution_t& init( bool anycase, char first_last, + cbl_refer_t *orig, cbl_refer_t *replacement ) { + this->anycase = anycase; + switch(first_last) { + case 'F': this->first_last = subst_first_e; break; + case 'L': this->first_last = subst_last_e; break; + default: + this->first_last = subst_all_e; + break; + } + this->orig = orig; + this->replacement = replacement; + return *this; + } + }; + typedef std::list<substitution_t> substitutions_t; + struct init_statement_t { bool to_value; bool to_default; @@ -409,8 +432,8 @@ %type <error_clauses> io_invalids read_eofs write_eops %type <boolean> io_invalid read_eof write_eop - global is_global -%type <number> mistake globally + global is_global anycase +%type <number> mistake globally first_last %type <use_culprit> culprits %type <labels> labels @@ -432,6 +455,8 @@ %type <refer> init_data stop_how stop_status %type <float128> cce_expr cce_factor const_value %type <prog_end> end_program1 +%type <substitution> subst_input +%type <substitutions> subst_inputs %union { bool boolean; @@ -520,6 +545,8 @@ category_map_t *replacements; init_statement_t *init_stmt; struct { cbl_special_name_t *special; vargs_t *vargs; } display; + substitution_t substitution; + substitutions_t *substitutions; } %printer { fprintf(yyo, "clauses: 0x%04x", $$); } data_clauses @@ -601,7 +628,7 @@ ALLOCATE ALPHABET ALPHABETIC ALPHABETIC_LOWER ALPHABETIC_UPPER ALPHANUMERIC ALPHANUMERIC_EDITED - ALPHED ALSO ALTERNATE ANNUITY ANY APPLY ARE + ALPHED ALSO ALTERNATE ANNUITY ANY ANYCASE APPLY ARE AREA AREAS AS ASCENDING ASIN ASSIGN AT ATAN AUTHOR @@ -693,7 +720,7 @@ SPACES SPECIAL_NAMES SQRT STANDARD STANDARD_ALPHABET STANDARD_1 STANDARD_DEVIATION STATUS STDERR STDIN STDOUT - LITERAL SUM SWITCH SYMBOL SYMBOLIC SYNCHRONIZED + LITERAL SUBSTITUTE SUM SWITCH SYMBOL SYMBOLIC SYNCHRONIZED SYSIN SYSIPT SYSLST SYSOUT SYSPCH SYSPUNCH TALLY TALLYING TAN TERMINATE TEST TEST_DATE_YYYYMMDD @@ -8475,14 +8502,14 @@ intrinsic: intrinsic0 if( ! intrinsic_call_2($$, INTEGER_OF_FORMATTED_DATE, r1, $r2) ) YYERROR; } - | SECONDS_FROM_FORMATTED_TIME '(' TIME_FMT[r1] num_operand[r2] ')' { + | SECONDS_FROM_FORMATTED_TIME '(' TIME_FMT[r1] varg[r2] ')' { location_set(@1); $$ = new_tempnumeric(); auto r1 = new_reference(new_literal($r1, quoted_e)); if( ! intrinsic_call_2($$, SECONDS_FROM_FORMATTED_TIME, r1, $r2) ) YYERROR; } - | SECONDS_FROM_FORMATTED_TIME '(' DATETIME_FMT[r1] num_operand[r2] ')' + | SECONDS_FROM_FORMATTED_TIME '(' DATETIME_FMT[r1] varg[r2] ')' { location_set(@1); $$ = new_tempnumeric(); @@ -8530,6 +8557,24 @@ intrinsic: intrinsic0 $$ = new_tempnumeric_float(); if( ! intrinsic_call_1($$, RANDOM, $r1) ) YYERROR; } + + | SUBSTITUTE '(' varg[r1] subst_inputs[inputs] ')' { + location_set(@1); + $$ = new_alphanumeric(64); + auto narg = $inputs->size(); + cbl_substitute_t args[narg]; + std::transform( $inputs->begin(), $inputs->end(), args, + []( const substitution_t& arg ) { + cbl_substitute_t output( arg.anycase, + char(arg.first_last), + arg.orig, + arg.replacement ); + return output; } ); + auto fake = reinterpret_cast<cbl_refer_t*>(args); + parser_intrinsic_callv($$, substitute_billboard, narg, fake); + } + + | TEST_NUMVAL_C '(' varg[r1] varg[r2] ')' { location_set(@1); $$ = new_alphanumeric(64); // how long? @@ -8758,8 +8803,6 @@ intrinsic: intrinsic0 $r1, $r2, $r3) ) YYERROR; } - - | intrinsic_N2 '(' expr[r1] expr[r2] ')' { location_set(@1); @@ -8787,6 +8830,14 @@ intrinsic: intrinsic0 | intrinsic_locale ; +subst_inputs: subst_input { $$ = new substitutions_t; $$->push_back($1); } + | subst_inputs subst_input { $$ = $1; $$->push_back($2); } + ; +subst_input: anycase first_last varg[v1] varg[v2] { + $$.init( $anycase, $first_last, $v1, $v2 ); + } + ; + intrinsic_locale: LOCALE_COMPARE '(' varg[r1] varg[r2] ')' { @@ -8896,6 +8947,11 @@ intrinsic0: CURRENT_DATE { $$ = new_tempnumeric_float(); parser_intrinsic_call_0( $$, "__gg__pi" ); } + | SECONDS_PAST_MIDNIGHT { + location_set(@1); + $$ = new_tempnumeric(); + intrinsic_call_0( $$, SECONDS_PAST_MIDNIGHT ); + } | UUID4 { location_set(@1); $$ = new_alphanumeric(32); // don't know correct size @@ -8982,6 +9038,10 @@ all: %empty { $$ = false; } | ALL { $$ = true; } ; +anycase: %empty { $$ = false; } + | ANYCASE { $$ = true; } + ; + as: %empty | AS ; @@ -9018,6 +9078,11 @@ file: %empty | FILE_KW ; +first_last: %empty { $$ = 0; } + | FIRST { $$ = 'F'; } + | LAST { $$ = 'L'; } + ; + is_global: %empty %prec GLOBAL { $$ = false; } | is GLOBAL { $$ = true; } ; diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h index 75e29d696acf00dad9f1193f07771536dd9a1fbf..a23f876490192c13f81abe41f7a5043a399d3c42 100644 --- a/gcc/cobol/symbols.h +++ b/gcc/cobol/symbols.h @@ -76,6 +76,7 @@ strfromf128 (char *restrict string, size_t size, #endif extern const char *numed_message; +extern const char substitute_billboard[]; enum cbl_dialect_t { dialect_gcc_e = 0x00, @@ -832,6 +833,21 @@ struct cbl_refer_t { } }; +struct cbl_substitute_t { + enum subst_fl_t { subst_all_e, subst_first_e, subst_last_e }; + bool anycase; + subst_fl_t first_last; + cbl_refer_t orig, replacement; + + cbl_substitute_t( bool anycase = false, char first_last = 0, + cbl_refer_t *orig = NULL, cbl_refer_t *replacement = NULL ) + : anycase(anycase) + , first_last(subst_fl_t(first_last)) + , orig(*orig) + , replacement(*replacement) + {} +}; + static inline const char * field_name( const cbl_field_t *f ) { return f? f->name : "(void)"; } diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc index bbc3e7824c9d56824e10f4e149eed1800de043c0..0e638d0d143b6e1afbec7c057ffe73cce66851d3 100644 --- a/gcc/cobol/util.cc +++ b/gcc/cobol/util.cc @@ -208,6 +208,7 @@ repeat_count( const char picture[] ) } const char *numed_message; +const char substitute_billboard[] = "__gg__substitute"; #include <cctype> extern int yydebug;