From e18247c1d7d435bed9cf8815830f1f9468529a2e Mon Sep 17 00:00:00 2001 From: "James K. Lowden" <jklowden@symas.com> Date: Wed, 10 Apr 2024 14:26:52 -0400 Subject: [PATCH] accept CONSTANT for date function argument --- gcc/cobol/parse.y | 4 ++++ gcc/cobol/scan.l | 26 +++++++++++++++++++-- gcc/cobol/symbols.cc | 30 +----------------------- gcc/cobol/symbols.h | 3 ++- gcc/cobol/util.cc | 54 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 32 deletions(-) diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index 783bddc9c497..783f01343fc8 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -3879,6 +3879,10 @@ type_clause: TYPE to typename typedef_clause: is TYPEDEF strong { cbl_field_t *field = current_field(); + if( field->level != 1 ) { + yyerrorv("error: %02d %s IS TYPEDEF must be level 01", + field->level, field->name); + } field->attr |= typedef_e; if( $strong ) field->attr |= strongdef_e; yywarn("warning: TYPEDEF is provisional"); diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l index 040d79c208a6..a84b366a7f5e 100644 --- a/gcc/cobol/scan.l +++ b/gcc/cobol/scan.l @@ -1569,8 +1569,30 @@ USE({SPC}FOR)? { return USE; } pop_return TIME_FMT; } {SPC} // ignore - {NAME} { yyerror("error: format must be literal"); - pop_return NO_CONDITION; } + {NAME} { + int token = NO_CONDITION; + char type = 0; + auto elem = symbol_field(PROGRAM, 0, yytext); + + if( elem->type == SymField ) { + auto f = cbl_field_of(elem); + if( f->type == FldLiteralA && f->has_attr(constant_e) ) { + type = date_time_fmt(f->data.initial); + yylval.string = strdup(f->data.initial); + } + } + switch(type) { + case 'D': token = DATETIME_FMT; break; + case 'd': token = DATE_FMT; break; + case 't': token = TIME_FMT; break; + default: + yyerror("error: format must be literal"); + pop_return token; + break; + } + pop_return token; + } + . { yyless(0); pop_return NO_CONDITION; } } diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc index 03205d82fc55..81798fc25315 100644 --- a/gcc/cobol/symbols.cc +++ b/gcc/cobol/symbols.cc @@ -1795,40 +1795,11 @@ symbols_update( size_t first, bool parsed_ok ) { if( field->level == 0 && field->is_key_name() ) continue; if( is_literal(field) && field->var_decl_node != NULL ) continue; -#if 1 if( field->is_typedef() ) { auto isym = end_of_group( symbol_index(p) ); p = symbol_at(--isym); continue; } -#else - if( 1 < field->level && field->is_typedef() ) { - if( field->parent ) { - auto e = symbol_at(field->parent); - if( e->type == SymField ) { - auto parent = cbl_field_of(e); - p = end_of_group( parent, field ); - p--; - continue; - } - warnx("%s:%s: odd: %s is TYPEDEF and has non-field parent %s", - __func__, __LINE__, field->name, symbol_type_str(e->type)); - } - p = std::find(++p, symbols_end(), - []( auto& e ) { - if( e->type == SymField ) { - auto f = cbl_field_of(e); - switch( f->level ) { - case 1: case 66: case 77: case 88: - return true; - } - } - return false; - } ); - p--; - continue; - } -#endif // Verify REDEFINing field has no ODO components auto parent = symbol_redefines(field); @@ -1845,6 +1816,7 @@ symbols_update( size_t first, bool parsed_ok ) { continue; } + assert( ! field->is_typedef() ); if( parsed_ok ) parser_symbol_add(field); } diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h index 0f0c8495e3d2..bd7f26b0cfc3 100644 --- a/gcc/cobol/symbols.h +++ b/gcc/cobol/symbols.h @@ -2082,11 +2082,12 @@ const char * cobol_lineno_save(); char *cobol_name_mangler(const char *cobol_name); bool is_elementary( enum cbl_field_type_t type ); - bool is_numeric_edited( const char picture[] ); const char * intrinsic_function_name( int token ); +char date_time_fmt( const char input[] ); + size_t current_program_index(); const char * current_declarative_section_name(); diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc index f3fea330f316..dfbbc7a89020 100644 --- a/gcc/cobol/util.cc +++ b/gcc/cobol/util.cc @@ -1840,6 +1840,60 @@ name_space_kw( const char input[], int *token ) { return keyword_of(candidate)? len1 : 0; // 1st is NAME, 2nd is keyword } +char +date_time_fmt( const char input[] ) { + if( ! input ) return 0; + +#define DATE_FMT_B "(YYYYMMDD|YYYYDDD|YYYYWwwD)" +#define DATE_FMT_E "(YYYY-MM-DD|YYYY-DDD|YYYY-Www-D)" +#define TIME_FMT1 "hhmmss([.,]s+)?" +#define TIME_FMT3 "hhmmss([.,]s+)?Z" +#define TIME_FMT5 "hhmmss([.,]s+)?[+]hhmm" +#define TIME_FMT2 "hh:mm:ss([.,]s+)?" +#define TIME_FMT4 "hh:mm:ss([.,]s+)?Z" +#define TIME_FMT6 "hh:mm:ss([.,]s+)?[+]hh:mm" + +#define TIME_FMT_B "(" TIME_FMT1 "|" TIME_FMT3 "|" TIME_FMT5 ")" +#define TIME_FMT_E "(" TIME_FMT2 "|" TIME_FMT4 "|" TIME_FMT6 ")" + + static bool compiled = false; + static struct fmts_t { + regex_t reg; char type; char pattern[256]; + } fmts[] = { + { regex_t(), 'D', "^((" DATE_FMT_B "T" TIME_FMT_B ")|(" + DATE_FMT_E "T" TIME_FMT_E "))$" }, + { regex_t(), 'd', "^(" DATE_FMT_B "|" DATE_FMT_E ")$" }, + { regex_t(), 't', "^(" TIME_FMT_B "|" TIME_FMT_E ")$" }, + }; + int erc, cflags = REG_EXTENDED | REG_ICASE, eflags=0; + regmatch_t m[5]; + char result = 0; + + if( ! compiled ) { + for( auto& fmt : fmts ) { + ////warnx( "%s: %c, %s", __func__, fmt.type, fmt.pattern ); + if( (erc = regcomp(&fmt.reg, fmt.pattern, cflags)) != 0 ) { + char msg[80]; + regerror(erc, &fmt.reg, msg, sizeof(msg)); + errx( EXIT_FAILURE, "%s: regcomp: %s", __func__, msg ); + } + } + compiled = true; + } + + ////warnx("%s: input '%s'", __func__, input); + for( auto& fmt : fmts ) { + if( 0 == regexec(&fmt.reg, input, COUNT_OF(m), m, eflags) ) { + result = fmt.type; + break; + } + } + + return result; +} + + + /* * Development suppport */ -- GitLab