From cd93d0eb6929f52df34dffd69666d1a6d130d873 Mon Sep 17 00:00:00 2001 From: "James K. Lowden" <jklowden@symas.com> Date: Sat, 20 Apr 2024 19:29:53 -0400 Subject: [PATCH] introduce named constants in PICTURE --- gcc/cobol/UAT/testsuite.src/run_regression.at | 8 ++--- gcc/cobol/UAT/testsuite.src/syn_definition.at | 11 +++--- gcc/cobol/cdfval.h | 4 +++ gcc/cobol/parse.y | 34 +++++++++++++++++++ gcc/cobol/scan.l | 13 ++++--- gcc/cobol/scan_ante.h | 6 ++-- gcc/cobol/util.cc | 9 +++-- 7 files changed, 65 insertions(+), 20 deletions(-) diff --git a/gcc/cobol/UAT/testsuite.src/run_regression.at b/gcc/cobol/UAT/testsuite.src/run_regression.at index d7e99431f18c..09a4ffef889c 100644 --- a/gcc/cobol/UAT/testsuite.src/run_regression.at +++ b/gcc/cobol/UAT/testsuite.src/run_regression.at @@ -333,10 +333,10 @@ AT_DATA([prog.cob], [ IDENTIFICATION DIVISION. DISPLAY VAR1 SPACE VAR2 SPACE VAR3 GOBACK. ]) -AT_CHECK([$COMPILE prog.cob], [1], [], [prog.cob:5: error: '(0)' invalid in PICTURE (ISO 2023 13.18.40.3) at '9(7)V9(0)' -prog.cob:6: error: '(0)' invalid in PICTURE (ISO 2023 13.18.40.3) at '9(7)V9(0)' -prog.cob:7: error: '(0)' invalid in PICTURE (ISO 2023 13.18.40.3) at '9(7)V9(0)' -prog.cob:8: error: '(0)' invalid in PICTURE (ISO 2023 13.18.40.3) at '9(7)V9(0)' +AT_CHECK([$COMPILE prog.cob], [1], [], [prog.cob:5: error: '(0)' invalid in PICTURE (ISO 2023 13.18.40.3) at '9(0)' +prog.cob:6: error: '(0)' invalid in PICTURE (ISO 2023 13.18.40.3) at '9(0)' +prog.cob:7: error: '(0)' invalid in PICTURE (ISO 2023 13.18.40.3) at '9(0)' +prog.cob:8: error: '(0)' invalid in PICTURE (ISO 2023 13.18.40.3) at '9(0)' prog.cob:9: 4 errors in DATA DIVISION, compilation ceases at 'PROCEDURE DIVISION' cobol1: error: failed compiling prog.cob ]) diff --git a/gcc/cobol/UAT/testsuite.src/syn_definition.at b/gcc/cobol/UAT/testsuite.src/syn_definition.at index 26706ea59d05..3000c2a64850 100644 --- a/gcc/cobol/UAT/testsuite.src/syn_definition.at +++ b/gcc/cobol/UAT/testsuite.src/syn_definition.at @@ -465,10 +465,11 @@ prog.cob:40: invalid picture for Alphanumeric-edited at 'NX' prog.cob:41: invalid picture for Alphanumeric-edited at 'AN' prog.cob:42: invalid picture for Alphanumeric-edited at 'AZ(3)' prog.cob:44: invalid picture for Alphanumeric-edited at 'SA' -prog.cob:67: invalid picture for Alphanumeric-edited at 'X(str-constant)' -prog.cob:68: invalid picture for Alphanumeric-edited at 'X(float-constant)' -prog.cob:69: invalid picture for Alphanumeric-edited at 'X(signed-constant)' -prog.cob:70: invalid picture for Alphanumeric-edited at 'X(unseen-constant)' +prog.cob:67: error: PICTURE '(str-constant)' requires a CONSTANT value at ')' +prog.cob:69: error: invalid PICTURE count '(-1.00000000000000000000000000000000E+00)' at ')' +prog.cob:69: error: invalid PICTURE count '(signed-constant)' at ')' +prog.cob:69: error: PICTURE count '(-1)' is negative at ')' +prog.cob:70: error: PICTURE '(unseen-constant)' requires a CONSTANT value at ')' prog.cob:80: invalid picture for Alphanumeric-edited at '$(integer-constant)' prog.cob:81: invalid picture for Alphanumeric-edited at '$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$(integer-constant)' prog.cob:86: error: unimplemented USAGE type: BIT at 'BIT' @@ -489,7 +490,7 @@ prog.cob:93: error: unimplemented USAGE type: BIT at 'BIT' prog.cob:93: syntax error at 'BIT' prog.cob:96: error: unimplemented USAGE type: BIT at 'BIT' prog.cob:96: syntax error at 'BIT' -.:97: 43 errors in DATA DIVISION, compilation ceases detected at end of file +.:97: 44 errors in DATA DIVISION, compilation ceases detected at end of file cobol1: error: failed compiling prog.cob ]) AT_CLEANUP diff --git a/gcc/cobol/cdfval.h b/gcc/cobol/cdfval.h index b99847801eab..aa98e1bd53b4 100644 --- a/gcc/cobol/cdfval.h +++ b/gcc/cobol/cdfval.h @@ -32,6 +32,7 @@ #ifndef _CDF_VAL_H_ #define _CDF_VAL_H_ +#include <assert.h> #include <stdint.h> #include <stdlib.h> @@ -78,6 +79,9 @@ struct cdfval_t : public cdfval_base_t { cdfval_base_t *self(this); *self = value; } + + bool is_numeric() const { return ! (off || string); } + int64_t as_number() const { assert(is_numeric()); return number; } }; bool diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index 5be51cf8ee42..ee779e10b88d 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -3517,6 +3517,10 @@ alphanum_part: ALNUM[picture] count --$count; $$.nbyte += $count; // AX9(3) has count 5 } + if( $count < 0 ) { + yyerrorv("error: PICTURE count '(%d)' is negative", $count ); + YYERROR; + } } ; @@ -3530,12 +3534,42 @@ nps: %empty { $$ = 0; } nine: %empty { $$ = 0; } | NINES + { + $$ = $1; + if( $$ == 0 ) { + yyerror("error: '(0)' invalid in PICTURE (ISO 2023 13.18.40.3)"); + } + } ; count: %empty { $$ = 0; } | '(' NUMSTR ')' { $$ = numstr2i( $NUMSTR.string, $NUMSTR.radix ); + if( $$ == 0 ) { + yyerror("error: '(0)' invalid in PICTURE (ISO 2023 13.18.40.3)"); + } + } + | '(' NAME ')' + { + auto value = cdf_value($NAME); + if( ! (value && value->is_numeric()) ) { + yyerrorv("error: PICTURE '(%s)' requires a CONSTANT value", $NAME ); + YYERROR; + } + auto e = symbol_field(PROGRAM, 0, $NAME); + if( e ) { // verify not floating point with nonzero fraction + auto field = cbl_field_of(e); + assert(is_literal(field)); + if( field->data.value != size_t(field->data.value) ) { + yyerrorv("error: invalid PICTURE count '(%s)'", + field->data.initial ); + } + } + $$ = value->as_number(); + if( $$ <= 0 ) { + yyerrorv("error: invalid PICTURE count '(%s)'", $NAME ); + } } ; diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l index 10cb2654caa4..2eb037340894 100644 --- a/gcc/cobol/scan.l +++ b/gcc/cobol/scan.l @@ -76,7 +76,7 @@ DOTEOL [[:blank:]]*[.]{BLANK_EOL} SKIP [[:blank:]]*SKIP[123][[:blank:]]*[.]?{BLANK_EOL} TITLE [[:blank:]]*TITLE($|[.]|[^\n]*) -COUNT [(]0*[1-9][0-9]*[)] +COUNT [(][[:digit:]]+[)] N9 9+|(9{COUNT}) NP P+|(P{COUNT}) @@ -1149,6 +1149,8 @@ USE({SPC}FOR)? { return USE; } {ALNUM}/{COUNT} { yy_push_state(picture_count); yylval.string = strdup(yytext); return picset(ALNUM); } + {ALNUM}/[(]{NAME}[)] { yy_push_state(picture_count); + yylval.string = strdup(yytext); return picset(ALNUM); } {ALNUM} { yylval.string = strdup(yytext); return picset(ALNUM); } {ALPHED} { yylval.string = strdup(yytext); return picset(ALPHED); } @@ -1166,10 +1168,11 @@ USE({SPC}FOR)? { return USE; } } <picture_count>{ - [[:blank:]]+ { /* skip */ } - [(]/[[:blank:]]*[[:digit:]] { return picset(*yytext); } - {INTEGER}/[[:blank:]]*[)] { return picset(numstr_of(yytext)); } - [)] { pop_return picset(*yytext); } + [(] { return picset(*yytext); } + [)] { pop_return picset(*yytext); } + {INTEGER} { return picset(numstr_of(yytext)); } + {NAME} { yylval.string = strdup(yytext); + return picset(NAME); } } <integer_count>{ diff --git a/gcc/cobol/scan_ante.h b/gcc/cobol/scan_ante.h index 694fef8e3d3c..f114293716bc 100644 --- a/gcc/cobol/scan_ante.h +++ b/gcc/cobol/scan_ante.h @@ -376,11 +376,11 @@ static inline int ndigit(int len) { char *input = toupper(yytext[0]) == 'V'? yytext + 1 : yytext; int n = repeat_count(input); - return n? n : len; + return n == -1? len : n; } static int -picset( int ret ) { +picset( int token ) { static const char * const eop = orig_picture + sizeof(orig_picture); char *p = orig_picture + strlen(orig_picture); @@ -388,7 +388,7 @@ picset( int ret ) { yyerrorv("PICTURE exceeds maximum size of %zu bytes", sizeof(orig_picture) - 1); } snprintf( p, eop - p, "%s", yytext ); - return ret; + return token; } static inline bool diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc index 7c2e63b3e375..f47a43e6d303 100644 --- a/gcc/cobol/util.cc +++ b/gcc/cobol/util.cc @@ -201,10 +201,13 @@ int repeat_count( const char picture[] ) { char ch; - int n = 0; + int n, count = -1; - sscanf( picture, "%c(%d)", &ch, &n ); - return n; + n = sscanf( picture, "%c(%d)", &ch, &count ); + if( count <= 0 && 4 < n ) { // parsed count is negative + count = 0; // zero is invalid; -1 means no repetition + } + return count; } const char *numed_message; -- GitLab