diff --git a/gcc/cobol/cobol1.cc b/gcc/cobol/cobol1.cc index 2b2d9ba0f1868bc3877cd6e733501c89a91e9b14..b77871d9e135d622ea229c5d39b2574df5519a45 100644 --- a/gcc/cobol/cobol1.cc +++ b/gcc/cobol/cobol1.cc @@ -395,26 +395,6 @@ cobol_langhook_getdecls (void) return NULL; } -/* - * The plastic around case transformation isn't needed now, and might - * never be. The macro TOLOWERCASE is left over from before we were - * able to use tolower(3), and is easy to remember. If desired, the - * user can redefine it. - */ -//#ifndef TOLOWERCASE -//# define TOLOWERCASE(ch) tolower((ch)) -//#endif - -int TOLOWERCASE(int ch) - { - if( ch >= 'A' && ch <= 'Z' ) - { - ch = ch | 0x20; - } - return ch; - } - - char * cobol_name_mangler(const char *cobol_name_) { @@ -466,7 +446,7 @@ cobol_name_mangler(const char *cobol_name_) // with an underscore has_dash = true; } - *d++ = TOLOWERCASE(ch); + *d++ = TOLOWER(ch); } *d++ = '\0'; @@ -570,7 +550,7 @@ cobol_name_mangler_callback(const char *cobol_name_) // with an underscore has_dash = true; } - *d++ = TOLOWERCASE(ch); + *d++ = TOLOWER(ch); } *d++ = '\0'; diff --git a/gcc/cobol/lexio.cc b/gcc/cobol/lexio.cc index cc504683ff54f2061d6b62e4c4c5cde78a6bc224..63d68c39059be46811fa6b2bd1cfe32bc58d1abc 100644 --- a/gcc/cobol/lexio.cc +++ b/gcc/cobol/lexio.cc @@ -781,7 +781,7 @@ parse_replace_pairs( const char *stmt, const char *estmt, bool is_copy_stmt ) { char *s; if( -1 == asprintf(&s, "%s(%s)%s", befter[0], src, befter[1]) ) { - err(EXIT_FAILURE, __func__); + err(EXIT_FAILURE, "error: %s: %m", __func__); } src = s; diff --git a/gcc/cobol/lexio.h b/gcc/cobol/lexio.h index 5dfe89f72d885a4b0a33baa201fd873493b4109c..680e2b9b273e780031ebb50e7931477ff588ac8f 100644 --- a/gcc/cobol/lexio.h +++ b/gcc/cobol/lexio.h @@ -34,6 +34,7 @@ #include <cctype> #include <cstdlib> #include <cstring> + #include <err.h> #include <sys/mman.h> diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index 831df3c6ef6ed7224091398ef0829a2e615f163a..a3f1dfe1f62f3c8e963c27bf384e2d7ac38e447c 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -41,7 +41,7 @@ }; enum accept_func_t { - accept_none_e, + accept_done_e, accept_command_line_e, accept_envar_e, }; @@ -4452,10 +4452,24 @@ statement: error { | write { $$ = WRITE; } ; + /* + * ISO defines ON EXCEPTION only for Format 3 (screen). We + * implement extensions defined by MF and Fujitsu (and us) to + * use ACCEPT to interact with the command line and the + * environment. + * + * ISO ACCEPT and some others are implemented in accept_body, + * before the parser sees any ON EXCEPTION. In those cases + * accept_body returns accept_done_e to denote that the + * statement has been handled. If ON EXCEPTION is then parsed, + * it's an error. Otherwise, accept_body returns something + * else, and the relevant parser_accept_foo function is called + * in the "accept" action. + */ accept: accept_body end_accept { cbl_field_t *argi = register_find("_ARGI"); switch( $accept_body.func ) { - case accept_none_e: + case accept_done_e: break; case accept_command_line_e: if( $1.from->field == NULL ) { // take next command-line arg @@ -4476,7 +4490,7 @@ accept: accept_body end_accept { | accept_body accept_excepts[ec] end_accept { cbl_field_t *argi = register_find("_ARGI"); switch( $accept_body.func ) { - case accept_none_e: + case accept_done_e: yyerror("error: ON EXCEPTION valid only " "with ENVIRONMENT or COMAMND-LINE(n)"); break; @@ -4510,12 +4524,12 @@ end_accept: %empty %prec ACCEPT accept_body: accept_refer { - $$.func = accept_none_e;; + $$.func = accept_done_e; parser_accept(*$1, CONSOLE_e); } | accept_refer FROM DATE { - $$.func = accept_none_e; + $$.func = accept_done_e; if( $1->is_reference() ) { yyerror("subscripts are unsupported here"); YYERROR; @@ -4524,7 +4538,7 @@ accept_body: accept_refer } | accept_refer FROM DATE YYYYMMDD { - $$.func = accept_none_e;; + $$.func = accept_done_e; if( $1->is_reference() ) { yyerror("subscripts are unsupported here"); YYERROR; @@ -4533,7 +4547,7 @@ accept_body: accept_refer } | accept_refer FROM DAY { - $$.func = accept_none_e;; + $$.func = accept_done_e; if( $1->is_reference() ) { yyerror("subscripts are unsupported here"); YYERROR; @@ -4542,7 +4556,7 @@ accept_body: accept_refer } | accept_refer FROM DAY YYYYDDD { - $$.func = accept_none_e;; + $$.func = accept_done_e; if( $1->is_reference() ) { yyerror("subscripts are unsupported here"); YYERROR; @@ -4551,7 +4565,7 @@ accept_body: accept_refer } | accept_refer FROM DAY_OF_WEEK { - $$.func = accept_none_e;; + $$.func = accept_done_e; if( $1->is_reference() ) { yyerror("subscripts are unsupported here"); YYERROR; @@ -4561,7 +4575,7 @@ accept_body: accept_refer | accept_refer FROM TIME { - $$.func = accept_none_e;; + $$.func = accept_done_e; if( $1->is_reference() ) { yyerror("subscripts are unsupported here"); YYERROR; @@ -4583,7 +4597,7 @@ accept_body: accept_refer $$.from = cbl_refer_t::empty(); break; default: - $$.func = accept_none_e; + $$.func = accept_done_e; parser_accept( *$1, $acceptable->id ); } } @@ -4596,7 +4610,7 @@ accept_body: accept_refer } | accept_refer FROM COMMAND_LINE { - $$.func = accept_none_e;; + $$.func = accept_done_e; parser_accept_command_line(*$1, NULL, NULL, NULL ); } | accept_refer FROM COMMAND_LINE '(' expr ')' @@ -4607,7 +4621,7 @@ accept_body: accept_refer //// parser_accept_command_line(*$1, $expr->field ); } | accept_refer FROM COMMAND_LINE_COUNT { - $$.func = accept_none_e;; + $$.func = accept_done_e; parser_accept_command_line_count(*$1); } ; diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc index ee41f5093fdbb44baf67e873b074cd910d1c25a9..662a17ca8c42b47296d651021a03eff8a70f4c6c 100644 --- a/gcc/cobol/util.cc +++ b/gcc/cobol/util.cc @@ -28,6 +28,19 @@ * 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. + * + * The system.h file includes safe-ctype.h from libiberty, which + * disables bog-standard functions like isdigit(3) on the grounds that + * they may be affected by the locale. We include lexio.h first, so + * that it can use the standard functions. The rest of util.cc uses + * the libiberty uppercase replacements. + */ +#include "lexio.h" + #include <assert.h> #include <err.h> #include <regex.h> @@ -56,7 +69,6 @@ #include "symbols.h" #include "genapi.h" -#include "lexio.h" #pragma GCC diagnostic ignored "-Wunused-result" @@ -225,7 +237,7 @@ is_alpha_edited( const char picture[] ) { for( const char *p = picture; *p != '\0'; p++ ) { if( strchr(valid, *p) ) continue; - if( isdigit(*p) ) continue; + if( ISDIGIT(*p) ) continue; if( symbol_decimal_point() == *p ) continue; if( symbol_currency(*p) ) continue; @@ -271,7 +283,7 @@ is_numeric_edited( const char picture[] ) { for( p=picture; (p = strchr(p, ')')) != NULL; p++ ) { auto prior = p; while( picture < prior-- ) { - if( isdigit(*prior) ) continue; + if( ISDIGIT(*prior) ) continue; if( *prior == '(' ) break; numed_message = "error: unbalanced parentheses in PICTURE"; return false; @@ -285,17 +297,17 @@ is_numeric_edited( const char picture[] ) { for( p = picture; *p != '\0'; p++ ) { if( strchr(valid, *p) ) continue; - if( isdigit(*p) ) continue; + if( ISDIGIT(*p) ) continue; if( symbol_decimal_point() == *p ) continue; if( symbol_currency(*p) ) continue; switch(*p) { // test for CR or DB case 'C': case 'c': - if( toupper(*++p) == 'R' ) continue; + if( TOUPPER(*++p) == 'R' ) continue; numed_message = "error: expected CR in PICTURE"; break; case 'D': case 'd': - if( toupper(*++p) == 'B' ) continue; + if( TOUPPER(*++p) == 'B' ) continue; numed_message = "error: expected DB in PICTURE"; break; default: @@ -871,7 +883,7 @@ cbl_field_t::report_invalid_initial_value() const { } else { auto has_exponent = std::any_of( p, pend, []( char ch ) { - return toupper(ch) == 'E'; + return TOUPPER(ch) == 'E'; } ); if( !has_exponent && data.precision() < pend - p ) { yyerrorv("error: %s cannot represent VALUE '%.*s' exactly (max .%zu)", @@ -913,9 +925,9 @@ cbl_field_t::report_invalid_initial_value() const { data.initial + strlen(data.initial), []( char ch ) { - return isspace(ch) || - ispunct(ch) || - isalpha(ch); } ); + return ISSPACE(ch) || + ISPUNCT(ch) || + ISALPHA(ch); } ); } if( ! alpha_value ) { yyerrorv("error: alpha-only %s VALUE '%s' contains non-alphabetic data", @@ -1080,7 +1092,7 @@ valid_move( const struct cbl_field_t *tgt, const struct cbl_field_t *src ) }; /* Needs C++11 */ static_assert(sizeof(matrix[0]) == COUNT_OF(matrix[0]), - "matrix should be square"); + "matrix should be square"); for( const cbl_field_t *args[] = {tgt, src}, **p=args; p < args + COUNT_OF(args); p++ ) { @@ -1124,16 +1136,16 @@ valid_move( const struct cbl_field_t *tgt, const struct cbl_field_t *src ) { case 0: if( src->type == FldLiteralA && is_numericish(tgt) && !is_literal(tgt) ) { - // Allow if input string is an integer. - const char *p = src->data.initial, *pend = p + src->data.capacity; - if( p[0] == '+' || p[0] == '-' ) p++; - retval = std::all_of( p, pend, isdigit ); - if( yydebug && ! retval ) { - auto bad = std::find_if( p, pend, - []( char ch ) { return ! isdigit(ch); } ); - warnx("%s:%d: offending character '%c' at position %zu", - __func__, __LINE__, *bad, bad - p); - } + // Allow if input string is an integer. + const char *p = src->data.initial, *pend = p + src->data.capacity; + if( p[0] == '+' || p[0] == '-' ) p++; + retval = std::all_of( p, pend, isdigit ); + if( yydebug && ! retval ) { + auto bad = std::find_if( p, pend, + []( char ch ) { return ! ISDIGIT(ch); } ); + warnx("%s:%d: offending character '%c' at position %zu", + __func__, __LINE__, *bad, bad - p); + } } break; case 1: @@ -1772,7 +1784,7 @@ static size_t record_count( cbl_file_t *file ) { if( 0 != sb.st_size % size ) { warnx("file %s is %zu bytes, not a multiple of record size %zu", - file->name, sb.st_size, size); + file->name, sb.st_size, size); } return sb.st_size / size; } @@ -2013,7 +2025,7 @@ bool cobol_filename( const char *name, ino_t inode ) { input_filenames.top().lineno = yylineno = 1; if( getenv(__func__) ) { warnx(" saving %s with lineno as %d", - input_filenames.top().name, input_filenames.top().lineno); + input_filenames.top().name, input_filenames.top().lineno); } symbol_cobol_filename_begin(name); return pushed; @@ -2048,7 +2060,7 @@ cobol_filename_restore() { yylineno = input.lineno; if( getenv("cobol_filename") ) { warnx("restoring %s with lineno to %d", - input_filenames.top().name, input.lineno); + input_filenames.top().name, input.lineno); } symbol_cobol_filename_begin(input.name); return input.name;