diff --git a/gcc/cobol/UAT/bugsuite.src/bugs.at b/gcc/cobol/UAT/bugsuite.src/bugs.at index 5709380d3b20e3894bd75e58e540be67b6b4122f..c9c13ef337b75bb12daff79cfbe14681c7b7c96a 100644 --- a/gcc/cobol/UAT/bugsuite.src/bugs.at +++ b/gcc/cobol/UAT/bugsuite.src/bugs.at @@ -32,3 +32,39 @@ AT_CHECK([$COMPILE prog.cob], [0], [], []) AT_CHECK([./a.out], [1], [], []) AT_CLEANUP +AT_SETUP([Repeated program-id causes a crash]) +AT_KEYWORDS([bugs]) +AT_DATA([prog.cob], []) +AT_CHECK([$COMPILE prog.cob], [0], [ + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + PROCEDURE DIVISION. + DISPLAY "Hi." + END PROGRAM prog. + + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + PROCEDURE DIVISION. + DISPLAY "Hi." + END PROGRAM prog. +], []) +AT_CHECK([./a.out], [1], [], []) +AT_CLEANUP + +AT_SETUP([Repeated variable name should be an error]) +AT_KEYWORDS([bugs]) +AT_DATA([prog.cob], [ + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 redundant PIC 9. + 01 redundant PIC 9. + PROCEDURE DIVISION. + DISPLAY redundant + DISPLAY "Hi". + END PROGRAM prog. +]) +AT_CHECK([$COMPILE prog.cob], [0], [], []) +AT_CHECK([./a.out], [1], [], []) +AT_CLEANUP diff --git a/gcc/cobol/UAT/failsuite.src/run_functions.at b/gcc/cobol/UAT/failsuite.src/run_functions.at index b2489a37159033abc59505271507d6b69de96e03..6cd43f4ae8b692cae9e4eccc369654786022cca2 100644 --- a/gcc/cobol/UAT/failsuite.src/run_functions.at +++ b/gcc/cobol/UAT/failsuite.src/run_functions.at @@ -416,7 +416,6 @@ AT_DATA([prog.cob], [ CALL "subprog" USING BY CONTENT FUNCTION CONCAT("Abc" "D") STOP RUN. - END PROGRAM prog. *> bzzt *> ***************************** IDENTIFICATION DIVISION. @@ -431,6 +430,7 @@ AT_DATA([prog.cob], [ DISPLAY TESTING GOBACK. END PROGRAM subprog. + END PROGRAM prog. *> bzzt ]) AT_CHECK([$COMPILE prog.cob], [0], [], []) @@ -1522,29 +1522,19 @@ AT_CLEANUP AT_SETUP([FUNCTION LENGTH]) AT_KEYWORDS([functions]) -AT_XFAIL_IF([test "$national" != "ready"]) - AT_DATA([prog.cob], [ IDENTIFICATION DIVISION. PROGRAM-ID. prog. DATA DIVISION. WORKING-STORAGE SECTION. 01 X PIC S9(4)V9(4) VALUE -1.5. - 01 N PIC N(9). 01 TEST-FLD PIC S9(04)V9(02). PROCEDURE DIVISION. - MOVE FUNCTION LENGTH ( X ) - TO TEST-FLD + MOVE FUNCTION LENGTH ( X ) TO TEST-FLD IF TEST-FLD NOT = 8 DISPLAY 'LENGTH "00128" wrong: ' TEST-FLD END-DISPLAY END-IF - MOVE FUNCTION LENGTH ( N ) - TO TEST-FLD - IF TEST-FLD NOT = 9 - DISPLAY 'LENGTH N(9) wrong: ' TEST-FLD - END-DISPLAY - END-IF MOVE FUNCTION LENGTH ( '00128' ) TO TEST-FLD @@ -1552,40 +1542,25 @@ AT_DATA([prog.cob], [ DISPLAY 'LENGTH "00128" wrong: ' TEST-FLD END-DISPLAY END-IF - * note: we currently do not support items of category boolean... - *> MOVE FUNCTION LENGTH ( b'100' ) - *> TO TEST-FLD - *> IF TEST-FLD NOT = 3 - *> DISPLAY 'LENGTH b"100" wrong: ' TEST-FLD - *> END-DISPLAY - *> END-IF + MOVE FUNCTION LENGTH ( x'a0' ) TO TEST-FLD IF TEST-FLD NOT = 1 DISPLAY 'LENGTH x"a0" wrong: ' TEST-FLD END-DISPLAY END-IF + MOVE FUNCTION LENGTH ( z'a0' ) TO TEST-FLD IF TEST-FLD NOT = 3 DISPLAY 'LENGTH z"a0" wrong: ' TEST-FLD END-DISPLAY END-IF - MOVE FUNCTION LENGTH ( n'a0' ) - TO TEST-FLD - IF TEST-FLD NOT = 2 - DISPLAY 'LENGTH n"a0" wrong: ' TEST-FLD - END-DISPLAY - END-IF - STOP RUN. -]) -AT_CHECK([$COMPILE prog.cob], [0], [], -[prog.cob:7: warning: handling of USAGE NATIONAL is unfinished; implementation is likely to be changed -prog.cob:48: warning: handling of national literal is unfinished; implementation is likely to be changed + STOP RUN. ]) +AT_CHECK([$COMPILE prog.cob], [0], [], []) AT_CHECK([$COBCRUN_DIRECT ./a.out], [0], [], []) - AT_CLEANUP @@ -2951,8 +2926,6 @@ AT_CLEANUP AT_SETUP([FUNCTION SUBSTITUTE-CASE]) AT_KEYWORDS([functions]) -AT_XFAIL_IF([test "$COB_DIALECT" != "gnu"]) - AT_DATA([prog.cob], [ IDENTIFICATION DIVISION. PROGRAM-ID. prog. @@ -2962,7 +2935,8 @@ AT_DATA([prog.cob], [ 01 Z PIC X(20). PROCEDURE DIVISION. MOVE "ABC111444555defxxabc" TO Y. - MOVE FUNCTION SUBSTITUTE-CASE (Y "abc" "zz" "55" "666") + MOVE FUNCTION SUBSTITUTE (Y anycase "abc" "zz" + anycase "55" "666") TO Z. IF Z NOT = "zz1114446665defxxzz" DISPLAY Z @@ -2977,8 +2951,6 @@ AT_CLEANUP AT_SETUP([FUNCTION SUBSTITUTE-CASE with reference mod]) AT_KEYWORDS([functions]) -AT_XFAIL_IF([test "$COB_DIALECT" != "gnu"]) - AT_DATA([prog.cob], [ IDENTIFICATION DIVISION. PROGRAM-ID. prog. @@ -2988,8 +2960,9 @@ AT_DATA([prog.cob], [ 01 Z PIC X(20). PROCEDURE DIVISION. MOVE "abc111444555defxxabc" TO Y. - MOVE FUNCTION SUBSTITUTE-CASE - ( Y "ABC" "zz" "55" "666" ) (2 : 9) + MOVE FUNCTION SUBSTITUTE + ( Y anycase "ABC" "zz" + anycase "55" "666" ) (2 : 9) TO Z. IF Z NOT = "z11144466" DISPLAY Z @@ -3577,13 +3550,10 @@ AT_DATA([prog.cob], [ AT_CHECK([$COMPILE prog.cob], [0], [], []) AT_CHECK([$COBCRUN_DIRECT ./a.out], [0], [], []) - AT_CLEANUP - AT_SETUP([FUNCTION TEST-NUMVAL-F]) AT_KEYWORDS([functions]) - AT_DATA([prog.cob], [ IDENTIFICATION DIVISION. PROGRAM-ID. prog. @@ -3610,19 +3580,19 @@ AT_DATA([prog.cob], [ DISPLAY "Test 5 fail" END-DISPLAY END-IF. - IF FUNCTION TEST-NUMVAL-F ("1 +") NOT = 0 + IF FUNCTION TEST-NUMVAL-F ("1 +") NOT = 3 DISPLAY "Test 6 fail" END-DISPLAY END-IF. - IF FUNCTION TEST-NUMVAL-F ("1 -") NOT = 0 + IF FUNCTION TEST-NUMVAL-F ("1 -") NOT = 3 DISPLAY "Test 7 fail" END-DISPLAY END-IF. - IF FUNCTION TEST-NUMVAL-F ("1 +-") NOT = 4 + IF FUNCTION TEST-NUMVAL-F ("1 +-") NOT = 3 DISPLAY "Test 8 fail" END-DISPLAY END-IF. - IF FUNCTION TEST-NUMVAL-F ("1 -+") NOT = 4 + IF FUNCTION TEST-NUMVAL-F ("1 -+") NOT = 3 DISPLAY "Test 9 fail" END-DISPLAY END-IF. @@ -3634,11 +3604,11 @@ AT_DATA([prog.cob], [ DISPLAY "Test 11 fail" END-DISPLAY END-IF. - IF FUNCTION TEST-NUMVAL-F ("1.1 +") NOT = 0 + IF FUNCTION TEST-NUMVAL-F ("1.1 +") NOT = 5 DISPLAY "Test 12 fail" END-DISPLAY END-IF. - IF FUNCTION TEST-NUMVAL-F ("1.1 -") NOT = 0 + IF FUNCTION TEST-NUMVAL-F ("1.1 -") NOT = 5 DISPLAY "Test 13 fail" END-DISPLAY END-IF. @@ -3650,7 +3620,7 @@ AT_DATA([prog.cob], [ DISPLAY "Test 15 fail" END-DISPLAY END-IF. - IF FUNCTION TEST-NUMVAL-F ("1.1 -CR") NOT = 6 + IF FUNCTION TEST-NUMVAL-F ("1.1 -CR") NOT = 5 DISPLAY "Test 16 fail" END-DISPLAY END-IF. @@ -3666,22 +3636,19 @@ AT_DATA([prog.cob], [ DISPLAY "Test 19 fail" END-DISPLAY END-IF. - IF FUNCTION TEST-NUMVAL-F ("+1.1 E001") NOT = 7 + IF FUNCTION TEST-NUMVAL-F ("+1.1 E+01") NOT = 0 DISPLAY "Test 20 fail" END-DISPLAY END-IF. STOP RUN. ]) - AT_CHECK([$COMPILE prog.cob], [0], [], []) AT_CHECK([$COBCRUN_DIRECT ./a.out], [0], [], []) - AT_CLEANUP AT_SETUP([FUNCTION TRIM]) AT_KEYWORDS([functions]) - AT_DATA([prog.cob], [ IDENTIFICATION DIVISION. PROGRAM-ID. prog. @@ -3695,13 +3662,11 @@ AT_DATA([prog.cob], [ END-DISPLAY. STOP RUN. ]) - AT_CHECK([$COMPILE prog.cob], [0], [], []) AT_CHECK([$COBCRUN_DIRECT ./a.out], [0], [a#b.c%d+e$ a#b.c%d+e$ ]) - AT_CLEANUP diff --git a/gcc/cobol/UAT/testsuite.src/syn_misc.at b/gcc/cobol/UAT/testsuite.src/syn_misc.at index 564e459cbcbaa2d5cc9222b20984e703a00bc852..791cb5f9dc07c541b80d056d3c79583a7680d748 100644 --- a/gcc/cobol/UAT/testsuite.src/syn_misc.at +++ b/gcc/cobol/UAT/testsuite.src/syn_misc.at @@ -477,12 +477,12 @@ AT_DATA([prog2.cob], [ . ]) AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[prog.cob:7: ANY LENGTH valid only for 01 in LIKAGE SECTION of a contained program at 'LENGTH' +[prog.cob:7: ANY LENGTH valid only for 01 in LINKAGE SECTION of a contained program at 'LENGTH' prog.cob:9: 1 errors in DATA DIVISION, compilation ceases at 'PROCEDURE DIVISION' cobol1: error: failed compiling prog.cob ]) AT_CHECK([$COMPILE_ONLY prog2.cob], [1], [], -[prog2.cob:7: ANY LENGTH valid only for 01 in LIKAGE SECTION of a contained program at 'LENGTH' +[prog2.cob:7: ANY LENGTH valid only for 01 in LINKAGE SECTION of a contained program at 'LENGTH' prog2.cob:9: 1 errors in DATA DIVISION, compilation ceases at 'PROCEDURE DIVISION' cobol1: error: failed compiling prog2.cob ]) @@ -505,7 +505,7 @@ AT_DATA([prog.cob], [ ]) AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[prog.cob:7: ANY LENGTH valid only for 01 in LIKAGE SECTION of a contained program at 'LENGTH' +[prog.cob:7: ANY LENGTH valid only for 01 in LINKAGE SECTION of a contained program at 'LENGTH' prog.cob:9: 1 errors in DATA DIVISION, compilation ceases at 'PROCEDURE DIVISION' cobol1: error: failed compiling prog.cob ]) diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc index db96951322f8edce3166ff822fbcfa105fc04864..7967f894c290712791a3fb16ed7f46688238dbbc 100644 --- a/gcc/cobol/genapi.cc +++ b/gcc/cobol/genapi.cc @@ -3233,7 +3233,8 @@ enter_program_common(const char *funcname, const char *funcname_) } void -parser_enter_program(const char *funcname_) +parser_enter_program( const char *funcname_, + bool is_function) // True for user-defined-function { // The first thing we have to do is mangle this name. This is safe even // though the end result will be mangled again, because the mangler doesn't @@ -3262,18 +3263,21 @@ parser_enter_program(const char *funcname_) SHOW_PARSE_END } - if( next_program_is_main ) + if( !is_function ) { - next_program_is_main = false; - if(main_entry_point) + if( next_program_is_main ) { - build_main_that_calls_something(main_entry_point); - free(main_entry_point); - main_entry_point = NULL; - } - else - { - build_main_that_calls_something(funcname); + next_program_is_main = false; + if(main_entry_point) + { + build_main_that_calls_something(main_entry_point); + free(main_entry_point); + main_entry_point = NULL; + } + else + { + build_main_that_calls_something(funcname); + } } } @@ -5448,10 +5452,24 @@ parser_division(cbl_division_t division, if( args[i].crv == by_value_e ) { // 'parameter' is the 64-bit value that was placed on the stack + cbl_field_t *new_var = args[i].refer.field; + + // We need to allocate memory for it. + char achDataName[256]; + sprintf(achDataName, "..vardata_%lu", sv_data_name_counter++); + + tree array_type = build_array_type_nelts(UCHAR, new_var->data.capacity); + tree data_decl_node = gg_define_variable( array_type, + achDataName, + vs_stack); + gg_assign( member(new_var->var_decl_node, "data"), + gg_get_address_of(data_decl_node) ); + + // And then move it into place gg_call(VOID, "__gg__assign_value_from_stack", 2, - gg_get_address_of(args[i].refer.field->var_decl_node), + gg_get_address_of(new_var->var_decl_node), parameter); } else @@ -8622,7 +8640,42 @@ parser_intrinsic_numval_c( cbl_field_t *f, cbl_refer_t& currency, bool anycase, bool test_numval_c ) // true for TEST-NUMVAL-C -{} + { + SHOW_PARSE + { + SHOW_PARSE_HEADER + SHOW_PARSE_END + } + TRACE1 + { + TRACE1_HEADER + TRACE1_END + } + refer_fill_source(input); + refer_fill_source(currency); + if( locale || anycase ) + { + gcc_assert(false); + } + if( test_numval_c ) + { + gg_call(INT, + "__gg__test_numval_c", + 3, + gg_get_address_of(f->var_decl_node), + gg_get_address_of(input .refer_decl_node), + gg_get_address_of(currency.refer_decl_node)); + } + else + { + gg_call(INT, + "__gg__numval_c", + 3, + gg_get_address_of(f->var_decl_node), + gg_get_address_of(input .refer_decl_node), + gg_get_address_of(currency.refer_decl_node)); + } + } void parser_intrinsic_subst( cbl_field_t *f, @@ -10736,9 +10789,9 @@ parser_call( cbl_refer_t name, arguments[i] = location; //gg_printf(">>>>>Calling %ld location is %p\n", build_int_cst_type(SIZE_T, i), arguments[i], NULL_TREE); - // BY REFERENCE variables might -- might! -- be going into an ANY LENGTH + // BY REFERENCE variables might be going into an ANY LENGTH // linkage variable in the called program. So, just in case, we need - // to provide a length through the global table. + // to provide a length through the global table. gg_assign(gg_array_value(var_decl_call_parameter_lengths, i), length); break; } @@ -10756,6 +10809,11 @@ parser_call( cbl_refer_t name, gg_memcpy(arguments[i], location, length); //gg_printf(">>>>>Calling %ld location is %p\n", build_int_cst_type(SIZE_T, i), arguments[i], NULL_TREE); + + // BY CONTENT variables might be going into an ANY LENGTH + // linkage variable in the called program. So, just in case, we need + // to provide a length through the global table. + gg_assign(gg_array_value(var_decl_call_parameter_lengths, i), length); break; } @@ -14187,7 +14245,6 @@ parser_local_add(struct cbl_field_t *new_var ) vs_stack); gg_assign( member(new_var->var_decl_node, "data"), gg_get_address_of(data_decl_node) ); - } cbl_refer_t wrapper; wrapper.field = new_var; diff --git a/gcc/cobol/genapi.h b/gcc/cobol/genapi.h index ea37e6bf0200f6470879716d6c7fc858b30539d1..cac09aa5ab3f7c57d893747735901e4b9a317634 100644 --- a/gcc/cobol/genapi.h +++ b/gcc/cobol/genapi.h @@ -52,7 +52,7 @@ void parser_next_is_main(bool is_main); void parser_internal_is_ebcdic(bool is_ebcdic); void parser_division( cbl_division_t division, cbl_field_t *ret, size_t narg, cbl_ffi_arg_t args[] ); -void parser_enter_program(const char *funcname); +void parser_enter_program(const char *funcname, bool is_function); void parser_leave_program(); void parser_accept( struct cbl_refer_t refer, enum special_name_t special_e); diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index 9823bcad38a23a61651c29502ef9ed9a0e3b8c1a..5927ea8c5ca3510c7a0e7286d72cb02c5eac5ac9 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -946,7 +946,7 @@ program_id: PROGRAM_ID dot namestr[name] program_as program_attrs[attr] dot current_division = identification_div_e; parser_division( identification_div_e, NULL, 0, NULL ); location_set(@1); - parser_enter_program( name ); + parser_enter_program( name, false ); if( symbols_begin() == symbols_end() ) { symbol_table_init(); } @@ -969,7 +969,7 @@ function_id: FUNCTION '.' NAME program_as program_attrs[attr] '.' current_division = identification_div_e; parser_division( identification_div_e, NULL, 0, NULL ); statement_begin(@1, FUNCTION); - parser_enter_program( $NAME ); + parser_enter_program( $NAME, true ); if( symbols_begin() == symbols_end() ) { symbol_table_init(); } @@ -3016,10 +3016,13 @@ data_descr1: level_name if( ! ($field->data.capacity + 1 == strlen($field->data.initial) && p[-1] == '!') ) { char *msg; - asprintf(&msg, "warning: VALUE of %s " + if(asprintf(&msg, "warning: VALUE of %s " "has length %zu, exceeding its size (%u)", $field->name, strlen($field->data.initial), - $field->data.capacity); + $field->data.capacity) == -1) { + warnx("Some kind of error in asprintf() %s %d", __func__, __LINE__); + } + yywarn(msg); } } @@ -3632,7 +3635,7 @@ any_length: ANY LENGTH current_data_section == linkage_datasect_e && 1 < current.program_level()) ) { yyerror("ANY LENGTH valid only " - "for 01 in LIKAGE SECTION of a contained program"); + "for 01 in LINKAGE SECTION of a contained program"); YYERROR; } field->attr |= any_length_e; @@ -8557,7 +8560,7 @@ intrinsic: function_udf ; | NUMVAL_C '(' varg[r1] numval_locale[r2] anycase ')' { location_set(@1); - $$ = new_tempnumeric_float(); + $$ = new_tempnumeric(); parser_intrinsic_numval_c( $$, *$r1, $r2.is_locale, *$r2.arg2, $anycase ); } @@ -8599,7 +8602,7 @@ intrinsic: function_udf | TEST_NUMVAL_C '(' varg[r1] numval_locale[r2] anycase ')' { location_set(@1); - $$ = new_alphanumeric(64); + $$ = new_tempnumeric(); parser_intrinsic_numval_c( $$, *$r1, $r2.is_locale, *$r2.arg2, $anycase, true ); } @@ -8848,7 +8851,11 @@ intrinsic: function_udf | intrinsic_locale ; -numval_locale: %empty { $$.is_locale = false; $$.arg2 = NULL; } +numval_locale: %empty { + static cbl_refer_t empty; + $$.is_locale = false; + $$.arg2 = ∅ + } | LOCALE NAME { $$.is_locale = true; $$.arg2 = NULL; yyerror("unimplemented: NUMVAL_C LOCALE"); YYERROR; } diff --git a/gcc/cobol/parse_util.h b/gcc/cobol/parse_util.h index 3022e8d9deaa4f1398508e2f5fabf2c771c89237..59093ed807a1e4890af8a07e44d30886968b86c2 100644 --- a/gcc/cobol/parse_util.h +++ b/gcc/cobol/parse_util.h @@ -208,9 +208,9 @@ static const intrinsic_args_t intrinsic_args[] = { { TEST_DAY_YYYYDDD, "TEST-DAY-YYYYDDD", "__gg__test_day_yyyyddd", "I", FldNumericBin5 }, { TEST_FORMATTED_DATETIME, "TEST-FORMATTED-DATETIME", - "__gg__test_formatted_datetime", "XX", FldAlphanumeric }, + "__gg__test_formatted_datetime", "XX", FldNumericBin5 }, { TEST_NUMVAL, "TEST-NUMVAL", - "__gg__test_numval", "X", FldAlphanumeric }, + "__gg__test_numval", "X", FldNumericBin5 }, { TEST_NUMVAL_C, "TEST-NUMVAL-C", "__gg__test_numval_c", "XXU", FldNumericBin5 }, { TEST_NUMVAL_F, "TEST-NUMVAL-F", @@ -245,6 +245,7 @@ static const intrinsic_args_t *eoargs = intrinsic_args + COUNT_OF(intrinsic_args); static const char intrinsic_unimplemented[][40] = { + "argle-bargle", // gives ::find something to chew on // "__gg__bit_of", // "__gg__bit_to_char", // "__gg__display_of", diff --git a/libgcobol/intrinsic.cc b/libgcobol/intrinsic.cc index df98b3433bfb461cbc3d0f3c9ca2dff95d9bffc2..d8ca2eed95ccf03a7ed4e26d8dc87e0a35fea94a 100644 --- a/libgcobol/intrinsic.cc +++ b/libgcobol/intrinsic.cc @@ -2030,192 +2030,291 @@ __gg__mod(cblc_field_t *dest, cblc_refer_t *source1, cblc_refer_t *source2) NULL); } -static -int +static int numval(cblc_field_t *dest, cblc_refer_t *input) { - size_t errcode = 0; + // Returns the one-based character position of a bad character + // returns zero if it is okay + + char *p = (char *)input->qual_data; + char *pend = p + input->qual_size; - char *p = (char *)input->qual_data; - char *pstart = p; - char *pend = p + input->qual_size; + int errpos = 0; + __int128 retval = 0; + int retval_rdigits = 0; - _Float128 retval = 0; - int sign = 0; - int rdigits = 0; - int rdigit_bump = 0; + bool saw_digit= false; char decimal_point = __gg__get_decimal_point(); - - // We will do this as a state machine: - - enum + bool in_fraction = false; + bool leading_sign = false; + bool is_negative = false; + enum { - first_space, - first_sign, - before_digits, - in_digits, - after_digits, - second_sign, - final_space, - } state = first_space; + SPACE1, + SPACE2, + DIGITS, + SPACE3, + SPACE4, + } state = SPACE1; + if( input->qual_size == 0 ) + { + errpos = 1; + goto done; + } while( p < pend ) { char ch = *p++; + errpos += 1; switch( state ) { - case first_space : - if( ch != internal_space ) + case SPACE1: + // We tolerate spaces, and expect to end with a sign, digit, + // or decimal point: + if( ch == internal_space ) { - state = first_sign; - p -= 1; + continue; } - break; - - case first_sign : if( ch == internal_plus ) { - sign = 1; - state = before_digits; + leading_sign = true; + state = SPACE2; + break; } - else if( ch == internal_minus ) + if( ch == internal_minus ) { - sign = -1; - state = before_digits; + leading_sign = true; + is_negative = true; + state = SPACE2; + break; } - else if( (ch >= internal_0 && ch <= internal_9) - || ch == decimal_point ) + if( ch >= internal_0 && ch <= internal_9 ) { - state = in_digits; - p -= 1; + saw_digit = true; + retval = ch & 0xF; + state = DIGITS; + break; } - else + if( ch == decimal_point ) { - // We have a bad character: - errcode = p - pstart; - state = final_space; - p = pend; + in_fraction = true; + state = DIGITS; + break; } + // This is a bad character; errpos is correct + goto done; break; - case before_digits : - if( ch != internal_space ) + case SPACE2: + // We tolerate spaces, and expect to end with a digit or decimal point: + if( ch == internal_space ) { - state = in_digits; - p -= 1; + break; + } + if( ch >= internal_0 && ch <= internal_9 ) + { + saw_digit = true; + retval = ch & 0xF; + state = DIGITS; + break; } + if( ch == decimal_point ) + { + in_fraction = true; + state = DIGITS; + break; + } + // This is a bad character; errpos is correct + goto done; break; - case in_digits : - // The only thing allowed here are digits and the decimal separator: + case DIGITS: + // We tolerate digits. We tolerate one decimal point. We expect to + // end with a space, a sign, "DB" or "CR", or the the end of the string + // It's a bit complicated + if( ch >= internal_0 && ch <= internal_9 ) { - // We have a digit. - rdigits += rdigit_bump; + saw_digit = true; retval *= 10; - retval += ch & 0x0F; + retval += ch & 0xF; + if( in_fraction ) + { + retval_rdigits += 1; + } + break; } - else if( ch == decimal_point && rdigit_bump) + if( ch == decimal_point && in_fraction ) { - // We have a decimal_point, which is against the rules: - errcode = p - pstart; - state = final_space; - p = pend; + // Only one decimal is allowed + goto done; } - else if( ch == decimal_point ) + if( ch == decimal_point ) { - rdigit_bump = 1; + in_fraction = true; + break; } - else + if( ch == internal_space ) { - // We something that isn't a digit or decimal separator: - state = after_digits; - p -= 1; + state = SPACE3; + break; } - break; - - case after_digits : - if( ch == internal_space ) + if( ch == internal_plus && leading_sign) { - continue; + // We are allowed leading or trailing signs, but not both + goto done; } - if( sign ) + if( ch == internal_minus && leading_sign) { - // We already saw a sign character - state = final_space; + // We are allowed leading or trailing signs, but not both + goto done; } - else + if( ch == internal_plus ) { - state = second_sign; + state = SPACE4; + break; } - p -= 1; + if( ch == internal_minus ) + { + is_negative = true; + state = SPACE4; + break; + } + if( tolower(ch) == 'd' ) + { + if( leading_sign ) + { + goto done; + } + ch = *p++; + errpos += 1; + if( p > pend || tolower(ch) != 'b' ) + { + goto done; + } + is_negative = true; + state = SPACE4; + break; + } + if( tolower(ch) == 'c' ) + { + if( leading_sign ) + { + goto done; + } + ch = *p++; + errpos += 1; + if( p > pend || tolower(ch) != 'r' ) + { + goto done; + } + is_negative = true; + state = SPACE4; + break; + } + // This is a bad character; errpos is correct + goto done; break; - case second_sign : - if( ch == internal_plus ) + case SPACE3: + // We tolerate spaces, or we end with a sign: + if( ch == internal_space ) { - sign = 1; + break; } - else if( ch == internal_minus ) + if( ch == internal_plus && leading_sign) { - sign = -1; + // We are allowed leading or trailing signs, but not both + goto done; } - else if( (ch == internal_D || ch == internal_d) - && p < pend - && (*p == internal_B || *p == internal_b) ) + if( ch == internal_minus && leading_sign) { - sign = -1; - p += 1; + // We are allowed leading or trailing signs, but not both + goto done; } - else if( (ch == internal_C || ch == internal_c) - && p < pend - && (*p == internal_R || *p == internal_r) ) + if( ch == internal_plus ) { - sign = -1; - p += 1; + state = SPACE4; + break; } - else + if( ch == internal_minus ) { - // We have an invalid character - errcode = p - pstart; - state = final_space; - p = pend; + is_negative = true; + state = SPACE4; + break; } - state = final_space; + if( tolower(ch) == 'd' ) + { + if( leading_sign ) + { + goto done; + } + ch = *p++; + errpos += 1; + if( p > pend || tolower(ch) != 'b' ) + { + goto done; + } + is_negative = true; + state = SPACE4; + break; + } + if( tolower(ch) == 'c' ) + { + if( leading_sign ) + { + goto done; + } + ch = *p++; + errpos += 1; + if( p > pend || tolower(ch) != 'r' ) + { + goto done; + } + is_negative = true; + state = SPACE4; + break; + } + goto done; break; - - case final_space : + case SPACE4: if( ch == internal_space ) { - continue; + break; } - // We have a non-space where there should be only space - errcode = p - pstart; - p = pend; + goto done; break; } } - if( sign == 0 ) + if( saw_digit ) { - sign = 1; + errpos = 0; } - retval *= sign; - - if( state != after_digits && state != final_space && state != in_digits ) + else if( p == pend ) { - errcode = pend - pstart + 1; + // If we got to the end without seeing adigit, we need to bump the + // error pointer: + errpos += 1; } - if( dest ) + done: + if(errpos) { - retval /= __gg__power_of_ten(rdigits); - - __gg__float128_to_field(dest, - retval, - truncation_e, - NULL); + retval = 0; } - return (int)errcode; + if( is_negative ) + { + retval = -retval; + } + if(dest) + { + __gg__int128_to_field(dest, + retval, + retval_rdigits, + truncation_e, + NULL); + } + return errpos; } static @@ -2524,7 +2623,23 @@ extern "C" void __gg__numval(cblc_field_t *dest, cblc_refer_t *source) { - numval(dest, source); + int errpos = numval(dest, source); + if( errpos ) + { + exception_raise(ec_argument_function_e); + } + } + +extern "C" +void +__gg__test_numval(cblc_field_t *dest, cblc_refer_t *source) + { + int retval = numval(NULL, source); + __gg__int128_to_field(dest, + retval, + NO_RDIGITS, + truncation_e, + NULL); } extern "C" @@ -2534,6 +2649,18 @@ __gg__numval_c(cblc_field_t *dest, cblc_refer_t *source, cblc_refer_t *currency) numval_c(dest, source, currency); } +extern "C" +void +__gg__test_numval_c(cblc_field_t *dest, cblc_refer_t *source, cblc_refer_t *currency) + { + int retval = numval_c(NULL, source, currency); + __gg__int128_to_field(dest, + retval, + NO_RDIGITS, + truncation_e, + NULL); + } + extern "C" void __gg__ord(cblc_field_t *dest, cblc_refer_t *input ) @@ -3236,30 +3363,6 @@ __gg__test_day_yyyyddd( cblc_field_t *dest, cblc_refer_t *source) NULL); } -extern "C" -void -__gg__test_numval(cblc_field_t *dest, cblc_refer_t *source) - { - int retval = numval(NULL, source); - __gg__int128_to_field(dest, - retval, - NO_RDIGITS, - truncation_e, - NULL); - } - -extern "C" -void -__gg__test_numval_c(cblc_field_t *dest, cblc_refer_t *source, cblc_refer_t *currency) - { - int retval = numval_c(NULL, source, currency); - __gg__int128_to_field(dest, - retval, - NO_RDIGITS, - truncation_e, - NULL); - } - extern "C" void __gg__upper_case(cblc_field_t *dest, cblc_refer_t *input ) @@ -4354,7 +4457,7 @@ floating_format_tester(char const * const f, char * const f_end) state = DIGITS1; break; } - if( decimal_point ) + if( ch == decimal_point ) { state = DIGITS2; break; @@ -4493,7 +4596,6 @@ __gg__numval_f( cblc_field_t *dest, if( error || var->qual_size >= 256 ) { - fprintf(stderr, " - bad char at %d - ", error); exception_raise(ec_argument_function_e); } else @@ -4518,6 +4620,23 @@ __gg__numval_f( cblc_field_t *dest, NULL); } +extern "C" +void +__gg__test_numval_f(cblc_field_t *dest, + cblc_refer_t *var) + { + char *data = (char * )var->qual_data; + char *data_end = data + var->qual_size; + + int error = floating_format_tester(data, data_end); + + __gg__int128_to_field(dest, + error, + NO_RDIGITS, + truncation_e, + NULL); + } + static bool ismatch(char *a1, char *a2, char *b1, char *b2) { diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc index 98f466625f9507ada3579a831fa5f529f18eb6d3..c4098e8b426c725c707cc35673f21a889fbaa236 100644 --- a/libgcobol/libgcobol.cc +++ b/libgcobol/libgcobol.cc @@ -8174,8 +8174,11 @@ __gg__assign_value_from_stack(cblc_field_t *dest, size_t parameter) case FldGroup: case FldAlphanumeric: case FldAlphaEdited: + case FldNumericEdited: if( dest->capacity >= 1) { + warnx("%s is not valid for BY VALUE", dest->name); + exit(1); memset(dest->data, internal_space, dest->capacity); // A single 8-bit character was placed in the 64-bit entry on the // stack. @@ -8206,7 +8209,6 @@ __gg__assign_value_from_stack(cblc_field_t *dest, size_t parameter) case FldPacked: case FldNumericBin5: case FldNumericDisplay: - case FldNumericEdited: case FldLiteralN: case FldIndex: case FldPointer: