diff --git a/gcc/cobol/UAT/testsuite.src/syn_definition.at b/gcc/cobol/UAT/testsuite.src/syn_definition.at index dacf0eeb404d2213807ada6d58fbd638bd19b9a0..d04a897d01862a8d487b2a76dbab6100990ac678 100644 --- a/gcc/cobol/UAT/testsuite.src/syn_definition.at +++ b/gcc/cobol/UAT/testsuite.src/syn_definition.at @@ -807,10 +807,12 @@ AT_CHECK([$COMPILE_ONLY badprog.cob], [1], [], [badprog.cob:8:24: error: F1: SAME AS uses its own parent MESSAGE-TEXT-2 8 | 02 F1 SAME AS MESSAGE-TEXT-2. | ^ -badprog.cob:10:14: error: F1 created with SAME AS or TYPE TO, cannot have new member FILLER +badprog.cob:9:23: error: F1 created with SAME AS or TYPE TO, cannot have new member FILLER + 9 | 01 MT2 SAME AS MESSAGE-TEXT-2. + | ^ +badprog.cob:10:14: error: 05 FILLER is not part of an 01 record 10 | 05 FILLER PIC 9999. | ^ -badprog.cob:10:14: error: 05 FILLER is not part of an 01 record badprog.cob:11:38: error: 01 MT3 SAME AS precludes other DATA DIVISION clauses 11 | 01 MT3 SAME AS MESSAGE-TEXT-2 PIC X. | ^ diff --git a/gcc/cobol/UAT/testsuite.src/syn_file.at b/gcc/cobol/UAT/testsuite.src/syn_file.at index 0f850cf8f5fc9c4ac1366b73bc7d20edc3e109b3..e9c90f31212089ba1cbfbb259a9fd7bcaf654de5 100644 --- a/gcc/cobol/UAT/testsuite.src/syn_file.at +++ b/gcc/cobol/UAT/testsuite.src/syn_file.at @@ -116,9 +116,12 @@ AT_DATA([prog.cob], [ ]) AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[prog.cob:10: error: file name not found at 'file1' -:16: error: line 7: file2 lacks a file description detected at end of file -:16: 2 errors in DATA DIVISION, compilation ceases detected at end of file +[prog.cob:10:8: error: file name not found + 10 | FD file1. + | ^ +prog.cob:15:21: error: line 7: file2 lacks a file description + 15 | STOP RUN. + | ^ cobol1: error: failed compiling prog.cob ]) AT_CLEANUP @@ -147,7 +150,9 @@ AT_DATA([prog.cob], [ ]) AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[prog.cob:9: error: file1 was defined previously on line 7 +[prog.cob:9:15: error: file1 was defined previously on line 7 + 9 | SELECT file1 ASSIGN DISK. + | ^ cobol1: error: failed compiling prog.cob ]) AT_CLEANUP @@ -176,8 +181,9 @@ AT_DATA([prog.cob], [ ]) AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[prog.cob:13: error: line 7: file1 lacks a file description at 'PROCEDURE DIVISION' -prog.cob:13: 1 errors in DATA DIVISION, compilation ceases at 'PROCEDURE DIVISION' +[prog.cob:13:8: error: line 7: file1 lacks a file description + 13 | PROCEDURE DIVISION. + | ^ cobol1: error: failed compiling prog.cob ]) AT_CLEANUP @@ -207,8 +213,9 @@ AT_DATA([prog.cob], [ ]) AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[prog.cob:15: error: FD file1 previously defined on line 7 at 'file1' -prog.cob:17: 1 errors in DATA DIVISION, compilation ceases at 'PROCEDURE DIVISION' +[prog.cob:15:8: error: FD file1 previously defined on line 7 + 15 | FD file1. + | ^ cobol1: error: failed compiling prog.cob ]) AT_CLEANUP @@ -236,8 +243,9 @@ AT_DATA([prog.cob], [ ]) AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[prog.cob:8: error: ASSIGN clause missing for TEST-FILE -prog.cob:13: 1 errors in DATA DIVISION, compilation ceases at 'PROCEDURE DIVISION' +[prog.cob:7:15: error: ASSIGN clause missing for TEST-FILE + 7 | SELECT TEST-FILE + | ^ cobol1: error: failed compiling prog.cob ]) @@ -274,8 +282,12 @@ AT_DATA([prog.cob], [ ]) AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[prog.cob:20: error: START invalid with sequential file TEST-FILE at 'END-START' -prog.cob:22: error: START invalid with sequential file TEST-FILE2 at 'END-START' +[prog.cob:19:18: error: START invalid with sequential file TEST-FILE + 19 | START TEST-FILE KEY EQUAL TEST-REC + | ^ +prog.cob:21:18: error: START invalid with sequential file TEST-FILE2 + 21 | START TEST-FILE2 KEY EQUAL TEST-REC2 + | ^ cobol1: error: failed compiling prog.cob ]) @@ -333,16 +345,19 @@ AT_DATA([prog.cob], [ # FIXME: "is not defined" should be changed in "is not defined in file ..." AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[prog.cob:41: error: line 12: TEST-P2 of TEST-SOME is not defined in file description at 'PROCEDURE DIVISION' -prog.cob:41: error: line 12: TEST-P1 of TEST-SOME is not defined in file description at 'PROCEDURE DIVISION' -prog.cob:41: error: line 12: TEST-P3 of TEST-SOME is not defined in file description at 'PROCEDURE DIVISION' -prog.cob:41: error: line 19: NOT-THERE of TEST-FILE is not defined at 'PROCEDURE DIVISION' -prog.cob:41: error: line 19: SOME-REC of TEST-FILE is not defined in file description at 'PROCEDURE DIVISION' -prog.cob:41: error: line 19: NOT-THERE of TEST-FILE is not defined at 'PROCEDURE DIVISION' -prog.cob:41: error: line 25: NOT-IN-FILE1 of TEST-MORE is not defined at 'PROCEDURE DIVISION' -prog.cob:41: error: line 25: NOT-IN-FILE2 of TEST-MORE is not defined at 'PROCEDURE DIVISION' -prog.cob:41: error: line 25: NOT-IN-FILE1 of TEST-MORE is not defined at 'PROCEDURE DIVISION' -prog.cob:41: 9 errors in DATA DIVISION, compilation ceases at 'PROCEDURE DIVISION' +[prog.cob:41:8: error: line 12: TEST-P2 of TEST-SOME is not defined in file description + 41 | PROCEDURE DIVISION. + | ^ +prog.cob:41:8: error: line 12: TEST-P1 of TEST-SOME is not defined in file description +prog.cob:41:8: error: line 12: TEST-P3 of TEST-SOME is not defined in file description +prog.cob:41:8: error: line 19: NOT-THERE of TEST-FILE is not defined + 41 | PROCEDURE DIVISION. + | ^ +prog.cob:41:8: error: line 19: SOME-REC of TEST-FILE is not defined in file description +prog.cob:41:8: error: line 19: NOT-THERE of TEST-FILE is not defined +prog.cob:41:8: error: line 25: NOT-IN-FILE1 of TEST-MORE is not defined +prog.cob:41:8: error: line 25: NOT-IN-FILE2 of TEST-MORE is not defined +prog.cob:41:8: error: line 25: NOT-IN-FILE1 of TEST-MORE is not defined cobol1: error: failed compiling prog.cob ]) AT_CLEANUP @@ -367,8 +382,9 @@ AT_DATA([prog.cob], [ # cobc says: prog.cob:11: error: syntax error, unexpected Identifier, expecting DYNAMIC or RANDOM or SEQUENTIAL # but why? AT_CHECK([$COMPILE_ONLY prog.cob], [1], [], -[:13: error: line 12: testfile lacks a file description detected at end of file -:13: 1 errors in DATA DIVISION, compilation ceases detected at end of file +[prog.cob:12:31: error: line 12: testfile lacks a file description + 12 | STATUS IS stat. + | ^ cobol1: error: failed compiling prog.cob ]) AT_CLEANUP diff --git a/gcc/cobol/cbldiag.h b/gcc/cobol/cbldiag.h index b8663b3d18835d5ea1c8058874014dac5c73206a..2a4234a5e25e381b5a1c5db5b023a7f15f8dd412 100644 --- a/gcc/cobol/cbldiag.h +++ b/gcc/cobol/cbldiag.h @@ -41,7 +41,7 @@ bool yywarn( const char fmt[], ... ); struct YYLTYPE; #endif #ifndef YDFLTYPE -struct YDFLTYPE; +struct YDFLTYPE; #endif // an error at a location, called from the parser for semantic errors void error_msg( const YYLTYPE& loc, const char gmsgid[], ... ); diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index e12b7673ba2ec459d52abaa84466e9a62e38f342..25d8289836c695c86515b6bc733f1098cbb56630 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -608,13 +608,13 @@ struct cbl_ffi_arg_t *ffi_arg; struct ffi_args_t *ffi_args; - struct { cbl_refer_t *ffi_name, *ffi_returning; + struct { YYLTYPE loc; cbl_refer_t *ffi_name, *ffi_returning; ffi_args_t *using_params; } ffi_impl; struct { bool common, initial, recursive; } comminit; struct { enum select_clause_t clause; cbl_file_t *file; } select_clause; struct { size_t clauses; cbl_file_t *file; } select_clauses; - struct { char *on, *off; } switches; + struct { YYLTYPE loc; char *on, *off; } switches; struct cbl_domain_t *false_domain; struct { size_t also; unsigned char *low, *high; } colseq; struct { cbl_field_attr_t attr; int nbyte; } pic_part; @@ -1239,7 +1239,7 @@ opt_init_value: BINARY ZERO { $$ = constant_index(NULLS); } sprintf(ach, "%d", (int)($1.data[0])); //auto f = new_literal($1.data); auto f = new_literal(ach); - f = field_add(f); + f = field_add(@1, f); $$ = field_index(f); } | LOW_VALUES { $$ = constant_index(LOW_VALUES); } @@ -1429,7 +1429,7 @@ select: SELECT optional NAME[name] select_clauses[clauses] '.' } // install file, and set record area's name - if( (file = file_add(file)) == NULL ) YYERROR; + if( (file = file_add(@name, file)) == NULL ) YYERROR; auto ifile = symbol_index(symbol_elem_of(file)); // update keys for( auto p = file->keys; @@ -1450,7 +1450,7 @@ select: SELECT optional NAME[name] select_clauses[clauses] '.' file.line = yylineno; if( !namcpy(file.name, $name) ) YYERROR; - if( file_add(&file) == NULL ) YYERROR; + if( file_add(@name, &file) == NULL ) YYERROR; } ; selected_name: external scalar { $$ = $2; } @@ -1467,7 +1467,7 @@ selected_name: external scalar { $$ = $2; } 0, 0, 0, nonarray, 0, "", 0, cbl_field_t::linkage_t(), {len,len,0,0, $name.data, NULL, {NULL}, {NULL}}, NULL }; field.attr |= literal_attr($name.prefix); - $$ = new cbl_refer_t( field_add(&field) ); + $$ = new cbl_refer_t( field_add(@name, &field) ); } ; external: %empty /* GnuCOBOL uses EXTERNAL to control name resolution. */ @@ -1927,7 +1927,8 @@ repo_program: PROGRAM_kw NAME repo_as assert(program); prog.data.initial = program->name; } - symbol_field_add(PROGRAM, &prog); + auto e = symbol_field_add(PROGRAM, &prog); + symbol_field_location(symbol_index(e), @NAME); } ; @@ -1980,7 +1981,7 @@ special_name: dev_mnemonic field.data.domain = domain; domains.clear(); - if( field_add(&field) == NULL ) { + if( field_add(@2, &field) == NULL ) { dbgmsg("failed class"); YYERROR; } @@ -2216,7 +2217,7 @@ upsi: UPSI is NAME { assert($UPSI); size_t parent = symbol_index(symbol_field(0,0,"UPSI-0")); - cbl_field_t *field = field_alloc(FldSwitch, parent, $NAME); + cbl_field_t *field = field_alloc(@NAME, FldSwitch, parent, $NAME); if( !field ) YYERROR; field->attr = constant_e; field->data.initial = $UPSI; @@ -2225,7 +2226,7 @@ upsi: UPSI is NAME { assert($UPSI); size_t parent = symbol_index(symbol_field(0,0,"UPSI-0")); - cbl_field_t *field = field_alloc(FldSwitch, parent, $NAME); + cbl_field_t *field = field_alloc(@NAME, FldSwitch, parent, $NAME); if( !field ) YYERROR; field->attr = constant_e; field->data.initial = $UPSI; @@ -2234,12 +2235,12 @@ upsi: UPSI is NAME const uint32_t bitn = $UPSI[0] - '0', value = (1 << bitn); if( $entry.on ) { - cbl_field_t *on = field_alloc(FldSwitch, parent, $entry.on); + cbl_field_t *on = field_alloc(@NAME, FldSwitch, parent, $entry.on); if( !on ) YYERROR; on->data.upsi_mask = new cbl_upsi_mask_t(true, value); } if( $entry.off ) { - cbl_field_t *off = field_alloc(FldSwitch, parent, $entry.off); + cbl_field_t *off = field_alloc(@NAME, FldSwitch, parent, $entry.off); if( !off ) YYERROR; off->data.upsi_mask = new cbl_upsi_mask_t(false, value); } @@ -2251,12 +2252,12 @@ upsi: UPSI is NAME const uint32_t bitn = $UPSI[0] - '0', value = (1 << bitn); if( $entry.on ) { - cbl_field_t *on = field_alloc(FldSwitch, parent, $entry.on); + cbl_field_t *on = field_alloc($entry.loc, FldSwitch, parent, $entry.on); if( !on ) YYERROR; on->data.upsi_mask = new cbl_upsi_mask_t(true, value); } if( $entry.off ) { - cbl_field_t *off = field_alloc(FldSwitch, parent, $entry.off); + cbl_field_t *off = field_alloc($entry.loc, FldSwitch, parent, $entry.off); if( !off ) YYERROR; off->data.upsi_mask = new cbl_upsi_mask_t(false, value); } @@ -2264,22 +2265,26 @@ upsi: UPSI is NAME ; upsi_entry: ON status is NAME { - $$.on = $NAME; + $$.loc = @NAME; + $$.on = $NAME; $$.off = NULL; } | OFF status is NAME { - $$.on = NULL; + $$.loc = @NAME; + $$.on = NULL; $$.off = $NAME; } | OFF status is NAME[off] ON status is NAME[on] { - $$.on = $on; + $$.loc = @off; + $$.on = $on; $$.off = $off; } | ON status is NAME[on] OFF status is NAME[off] { - $$.on = $on; + $$.loc = @on; + $$.on = $on; $$.off = $off; } ; @@ -2646,12 +2651,9 @@ depending: %empty assert(e->type == SymField); odo = symbol_index(e); } else { - struct cbl_field_t fwd = { 0, - FldForward, FldInvalid, 0,0,0,0, nonarray, 0, "", - 0, cbl_field_t::linkage_t(), - {0,0,0,0, " ", NULL, {NULL}, {NULL}}, NULL }; - if( !namcpy(fwd.name, $3) ) YYERROR; - odo = field_index(field_add(&fwd)); + e = symbol_field_forward_add(PROGRAM, 0, $NAME, yylineno); + if( !e ) YYERROR; + odo = field_index(cbl_field_of(e)); } file->record_length = odo; @@ -2843,7 +2845,7 @@ index_field1: ctx_name[name] YYERROR; } - auto index = field_add(&field); + auto index = field_add(@name, &field); if( !index ) { YYERROR; } @@ -2871,7 +2873,7 @@ level_name: LEVEL ctx_name { 0,0,0,0, NULL, NULL, { NULL }, { NULL } }, NULL }; if( !namcpy(field.name, $2) ) YYERROR; - $$ = field_add(&field); + $$ = field_add(@2, &field); if( !$$ ) { YYERROR; } @@ -2894,7 +2896,7 @@ level_name: LEVEL ctx_name nonarray, yylineno, "", 0, {}, { 0,0,0,0, NULL, NULL, { NULL }, { NULL } }, NULL }; - $$ = field_add(&field); + $$ = field_add(@1, &field); if( !$$ ) { YYERROR; } @@ -3027,7 +3029,7 @@ data_descr1: level_name yywarn("%s was defined by CDF", field.name); } } - if( ($$ = field_add(&field)) == NULL ) { + if( ($$ = field_add(@name, &field)) == NULL ) { error_msg(@name, "failed level 78"); YYERROR; } @@ -3048,7 +3050,7 @@ data_descr1: level_name field.data.domain = domain; - if( ($$ = field_add(&field)) == NULL ) { + if( ($$ = field_add(@2, &field)) == NULL ) { error_msg(@NAME, "failed level 88"); YYERROR; } @@ -3076,7 +3078,7 @@ data_descr1: level_name field.data.false_value = $domains; domains.clear(); - if( ($$ = field_add(&field)) == NULL ) { + if( ($$ = field_add(@2, &field)) == NULL ) { error_msg(@NAME, "failed level 88"); YYERROR; } @@ -3112,6 +3114,7 @@ data_descr1: level_name } symbol_elem_t *orig = symbol_at(field_index($orig)); $$ = cbl_field_of(symbol_field_alias(orig, $alias)); + symbol_field_location(field_index($$), @alias); } | name66[alias] RENAMES name[orig] THRU name[thru] @@ -3174,6 +3177,7 @@ data_descr1: level_name symbol_elem_t *orig = symbol_at(field_index($orig)); symbol_elem_t *last = symbol_at(field_index($thru)); $$ = cbl_field_of(symbol_field_alias2(orig, last, $alias)); + symbol_field_location(field_index($$), @alias); } | level_name[field] data_clauses @@ -4127,7 +4131,8 @@ same_clause: SAME AS name YYERROR; } - symbol_field_same_as( field, other ); + auto e = symbol_field_same_as( field, other ); + symbol_field_location( symbol_index(e), @name ); } ; @@ -4175,7 +4180,8 @@ type_clause: TYPE to typename { cbl_field_t *field = current_field(); if( $typename ) { - symbol_field_same_as(field, $typename); + auto e = symbol_field_same_as(field, $typename); + symbol_field_location( symbol_index(e), @typename ); } } | USAGE is typename @@ -4186,7 +4192,8 @@ type_clause: TYPE to typename } cbl_field_t *field = current_field(); if( $typename ) { - symbol_field_same_as(field, $typename); + auto e = symbol_field_same_as(field, $typename); + symbol_field_location( symbol_index(e), @typename ); } } ; @@ -5984,7 +5991,7 @@ name: qname $$ = cbl_field_of(e); } } - assert($$); + gcc_assert($$); } ; @@ -7750,7 +7757,7 @@ end_start: %empty %prec START start_body: filename[file] { statement_begin(@$, START); - file_start_args.init($file); + file_start_args.init(@file, $file); parser_file_start( $file, lt_op, 0 ); } | filename[file] KEY relop name[key] @@ -7764,26 +7771,26 @@ start_body: filename[file] yywarn("START: key #%d '%s' has size %d", key, $key->name, size); } - file_start_args.init($file); + file_start_args.init(@file, $file); parser_file_start( $file, relop_of($relop), key, ksize ); } | filename[file] KEY relop name[key] with LENGTH expr { // lexer swallows IS, although relop allows it. statement_begin(@$, START); int key = $file->key_one($key); - file_start_args.init($file); + file_start_args.init(@file, $file); parser_file_start( $file, relop_of($relop), key, *$expr ); } | filename[file] FIRST { statement_begin(@$, START); - file_start_args.init($file); + file_start_args.init(@file, $file); parser_file_start( $file, lt_op, -1 ); } | filename[file] LAST { statement_begin(@$, START); - file_start_args.init($file); + file_start_args.init(@file, $file); parser_file_start( $file, gt_op, -2 ); } ; @@ -8869,7 +8876,7 @@ call_impl: CALL call_body[body] if( narg > 0 ) { pargs = use_list(params, args); } - parser_call( *$body.ffi_name, + ast_call( $body.loc, *$body.ffi_name, *$body.ffi_returning, narg, pargs, NULL, NULL, false ); current.declaratives_evaluate(); } @@ -8883,7 +8890,7 @@ call_cond: CALL call_body[body] call_excepts[except] if( narg > 0 ) { pargs = use_list(params, args); } - parser_call( *$body.ffi_name, + ast_call( $body.loc, *$body.ffi_name, *$body.ffi_returning, narg, pargs, $except.on_error, $except.not_error, false ); auto handled = ec_type_t( static_cast<size_t>(ec_program_e) | @@ -9522,7 +9529,7 @@ function_udf: FUNCTION_UDF '(' arg_list[args] ')' { return actual; } ); auto name = new_literal(strlen(L->name), L->name, quoted_e); - parser_call( name, $$, narg, args, NULL, NULL, true ); + ast_call( @1, name, $$, narg, args, NULL, NULL, true ); } | FUNCTION_UDF_0 { static const size_t narg = 0; @@ -9532,7 +9539,7 @@ function_udf: FUNCTION_UDF '(' arg_list[args] ')' { $$ = new_temporary_clone(cbl_field_of(symbol_at(L->returning))); auto name = new_literal(strlen(L->name), L->name, quoted_e); - parser_call( name, $$, narg, args, NULL, NULL, true ); + ast_call( @1, name, $$, narg, args, NULL, NULL, true ); } ; @@ -10647,8 +10654,7 @@ cdf_none: ENTER %% -#undef parser_call -void parser_call2( cbl_refer_t name, cbl_refer_t returning, +void ast_call( const YYLTYPE& loc, cbl_refer_t name, cbl_refer_t returning, size_t narg, cbl_ffi_arg_t args[], cbl_label_t *except, cbl_label_t *not_except, @@ -10662,14 +10668,15 @@ void parser_call2( cbl_refer_t name, cbl_refer_t returning, snprintf(called.name, sizeof(called.name), "_%s", name.field->data.initial); called.data = name.field->data; name.field = cbl_field_of(symbol_field_add(PROGRAM, &called)); + symbol_field_location(field_index(name.field), loc); parser_symbol_add(name.field); } - if( getenv("parser_call2") && yydebug ) { - yywarn("%s: calling %s returning %s with %zu args:", __func__, - name_of(name.field), - (returning.field)? returning.field->name : "[none]", - narg); + if( getenv("ast_call") ) { + dbgmsg("%s: calling %s returning %s with %zu args:", __func__, + name_of(name.field), + (returning.field)? returning.field->name : "[none]", + narg); for( size_t i=0; i < narg; i++ ) { const char *crv = "?"; switch(args[i].crv) { @@ -10678,8 +10685,8 @@ void parser_call2( cbl_refer_t name, cbl_refer_t returning, case by_content_e: crv = "con"; break; case by_value_e: crv = "val"; break; } - yywarn("%s: %4zu: %s @%p %s", __func__, - i, crv, args[i].refer.field, args[i].refer.field->name); + dbgmsg("%s: %4zu: %s @%p %s", __func__, + i, crv, args[i].refer.field, args[i].refer.field->name); } } parser_call( name, returning, narg, args, except, not_except, is_function ); diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h index b27ab8750912cc55e580f0bdaae38782ccfe9349..7391a9c324a67bf0e2dfa2b82da952b373432110 100644 --- a/gcc/cobol/parse_ante.h +++ b/gcc/cobol/parse_ante.h @@ -224,10 +224,9 @@ intrinsic_inconsistent_parameter( size_t n, cbl_refer_t *args ); static inline bool namcpy( cbl_name_t tgt, const char *src ) { // snprintf(3): writes at most size bytes (including the terminating NUL byte) - snprintf(tgt, sizeof(cbl_name_t), "%s", src); - if( sizeof(cbl_name_t) - 1 < strlen(src) ) { - yyerror("name truncated to '%s' (max %zu characters)", - tgt, sizeof(cbl_name_t)-1); + if( -1 == snprintf(tgt, sizeof(cbl_name_t), "%s", src) ) { + dbgmsg("logic error: name truncated to '%s' (max %zu characters)", + tgt, sizeof(cbl_name_t)-1); return false; } return true; @@ -469,15 +468,15 @@ static class file_start_args_t { cbl_file_t *file; public: file_start_args_t() : file(NULL) {} - void init( cbl_file_t *file ) { + void init( YYLTYPE loc, cbl_file_t *file ) { this->file = file; if( is_sequential(file) ) { - yyerror("START invalid with sequential file %s", file->name); + error_msg(loc, "START invalid with sequential file %s", file->name); } } bool ready() const { return file != NULL; } void call_parser_file_start() { - //// not needed: parser_file_start(file, sequentially); + // not needed: parser_file_start(file, sequentially); file = NULL; } } file_start_args; @@ -2799,7 +2798,7 @@ field_of( const char F[], int L, const char name[] ) { #define field_of( F ) field_of(__func__, __LINE__, (F)) static struct cbl_field_t * -field_add( cbl_field_t *field ) { +field_add( const YYLTYPE& loc, cbl_field_t *field ) { switch(current_data_section) { case not_data_datasect_e: case file_datasect_e: @@ -2815,7 +2814,7 @@ field_add( cbl_field_t *field ) { struct symbol_elem_t *e = symbol_field_add(PROGRAM, field); if( !e ) return NULL; - + symbol_field_location(symbol_index(e), loc); field = cbl_field_of(e); assert(field->type != FldDisplay); @@ -2968,11 +2967,11 @@ value_encoding_check( cbl_field_t *field ) { #pragma GCC diagnostic ignored "-Wmissing-field-initializers" static struct cbl_field_t * -field_alloc( cbl_field_type_t type, size_t parent, const char name[] ) { +field_alloc( const YYLTYPE& loc, cbl_field_type_t type, size_t parent, const char name[] ) { cbl_field_t *f, field = { .type = type, .usage = FldInvalid, .parent = parent, .line = yylineno }; if( !namcpy(field.name, name) ) return NULL; - f = field_add(&field); + f = field_add(loc, &field); assert(f); return f; } @@ -2988,22 +2987,19 @@ cbl_file_t protofile = { .org = file_disorganized_e, #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-truncation" static cbl_file_t * -file_add( cbl_file_t *file = NULL ) { - struct cbl_file_t proto = protofile; - proto.org = file_sequential_e; - if( !file ) file = &proto; - +file_add( YYLTYPE loc, cbl_file_t *file ) { + gcc_assert(file); struct cbl_field_t area = { .type = FldAlphanumeric, .level = 1, .line = yylineno, .data = { .capacity = 0 } }, - *field = field_add(&area); + *field = field_add(loc, &area); file->default_record = field_index(field); // install file, and set record area's name auto e = symbol_file_add(PROGRAM, file); if( !e ) { - yyerror("%s was defined previously on line %d", file->name, file->line); + error_msg(loc, "%s was defined previously on line %d", file->name, file->line); return NULL; } file = cbl_file_of(e); @@ -3030,10 +3026,12 @@ alphabet_add( cbl_encoding_t encoding ) { return cbl_alphabet_of(e); } +// The current field always exists in the symbol tablek, even if it's incomplete. static cbl_field_t * current_field(cbl_field_t * field = NULL) { static cbl_field_t *local; if( field ) local = field; + gcc_assert(field_index(local)); return local; } @@ -3477,15 +3475,13 @@ file_section_parent_set( cbl_field_t *field ) { return file_section_fd > 0; } -void parser_call2( cbl_refer_t name, cbl_refer_t returning, +void ast_call(const YYLTYPE& loc, cbl_refer_t name, + cbl_refer_t returning, size_t narg, cbl_ffi_arg_t args[], cbl_label_t *except, cbl_label_t *not_except, bool is_function ); -#define parser_call( name, returning, narg, args, except, not_except, is_function ) \ - parser_call2(name, returning, narg, args, except, not_except, is_function ) - cbl_field_t * ast_file_status_between( file_status_t lower, file_status_t upper ); @@ -3558,3 +3554,5 @@ static void ast_first_statement( int first_line ) { parser_first_statement(first_line); } } + + diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc index 8ae36fa99ef25a8acb49f7c2165b337af4e49a62..a9b456a990081a6075d2312ab0342327ee01958f 100644 --- a/gcc/cobol/symbols.cc +++ b/gcc/cobol/symbols.cc @@ -58,6 +58,20 @@ public: } }; +static std::map<size_t, YYLTYPE> field_locs; + +void +symbol_field_location( size_t ifield, const YYLTYPE& loc ) { + gcc_assert(field_at(ifield)); + field_locs[ifield] = loc; +} +YYLTYPE +symbol_field_location( size_t ifield ) { + auto p = field_locs.find(ifield); + gcc_assert(p != field_locs.end()); + return p->second; +} + static struct symbol_table_t { int fd; size_t capacity, nelem; @@ -213,6 +227,13 @@ cbl_ffi_arg_t( cbl_ffi_crv_t crv, if( refer && refer != refer->empty() ) delete refer; } +#define ERROR_FIELD(F, ...) \ + do{ \ + auto loc = symbol_field_location(field_index(F)); \ + error_msg(loc, __VA_ARGS__); \ + } while(0) + + cbl_field_t * symbol_valid_udf_args( size_t function, std::list<cbl_refer_t> args ) { auto L = cbl_label_of(symbol_at(function)); @@ -232,15 +253,16 @@ symbol_valid_udf_args( size_t function, std::list<cbl_refer_t> args ) { size_t iarg(1); e++; // skip over linkage_sect_e, which appears after the function if( e->type != SymField ) { - yyerror("FUNCTION %s has no defined parameter matching arg %zu, '%s'", - L->name, iarg, arg.field->name ); + ERROR_FIELD(arg.field, + "FUNCTION %s has no defined parameter matching arg %zu, '%s'", + L->name, iarg, arg.field->name ); return NULL; } auto tgt = cbl_field_of(e); if( ! valid_move(tgt, arg.field) ) { - yyerror("FUNCTION %s arg %zu, '%s' cannot be passed to %s, type %s", + ERROR_FIELD(tgt, "FUNCTION %s arg %zu, '%s' cannot be passed to %s, type %s", L->name, iarg, arg.field->pretty_name(), tgt->pretty_name(), 3 + cbl_field_type_str(tgt->type) ); return NULL; @@ -1245,7 +1267,7 @@ grow_redefined_group( cbl_field_t *redefined, const cbl_field_t *field ) { */ if( 1 < redefined->level ) { if( field_memsize(redefined) < field_memsize(field) ) { - yyerror("line %d: %s (size %u) larger than REDEFINES %s (size %u)", + ERROR_FIELD(field, "line %d: %s (size %u) larger than REDEFINES %s (size %u)", field->line, field->name, field_memsize(field), redefined->name, field_memsize(redefined)); @@ -1881,7 +1903,7 @@ symbols_update( size_t first, bool parsed_ok ) { if( odo != 0 ) { auto odo_field = cbl_field_of(symbol_at(odo)); // get not-FldForward if exists if( is_forward(odo_field) ) { - yyerror("table %s (line %d) DEPENDS ON %s, which is not defined", + ERROR_FIELD(field, "table %s (line %d) DEPENDS ON %s, which is not defined", field->name, field->line, odo_field->name); } else { // set odo to found field @@ -1922,7 +1944,7 @@ symbols_update( size_t first, bool parsed_ok ) { // Better to report an error than to fail mysteriously with "0 errors". if( yydebug || parse_error_count() == 0 ) { if( field->type == FldInvalid ) { - yyerror("line %d: %s %s requires PICTURE", + ERROR_FIELD(field, "line %d: %s %s requires PICTURE", field->line, field->level_str(), field->name); } else { @@ -1971,14 +1993,14 @@ symbols_update( size_t first, bool parsed_ok ) { // Verify REDEFINing field has no ODO components auto parent = symbol_redefines(field); if( parent && !is_record_area(parent) && is_variable_length(field) ) { - yyerror("line %d: REDEFINES field %s cannot be variable length", + ERROR_FIELD(field, "line %d: REDEFINES field %s cannot be variable length", field->line, field->name); return 0; } if( field->type == FldInvalid ) { dbgmsg("%s:%d: %s", __func__, __LINE__, field_str(field)); - yyerror("line %d: %s %s requires PICTURE", + ERROR_FIELD(field, "line %d: %s %s requires PICTURE", field->line, field->level_str(), field->name); continue; } @@ -2218,17 +2240,14 @@ symbol_field_parent_set( struct cbl_field_t *field ) if( prior->level < field->level ) { if( prior->has_attr(same_as_e) ) { - yyerror("%s created with SAME AS or TYPE TO, cannot have new member %s", + ERROR_FIELD(prior, "%s created with SAME AS or TYPE TO, cannot have new member %s", prior->name, field->name); return NULL; } field->parent = e - symbols.elems; if( 1 < field->level && field->level < 50 ) { if( had_picture(prior) ) { - auto efile = symbol_in_file(e); - const char *filename = efile? efile->elem.filename : NULL; - yyerrorvl(prior->line, filename, - "error: group %s cannot have PICTURE clause", prior->name); + ERROR_FIELD(prior, "group %s cannot have PICTURE clause", prior->name); return NULL; } prior->type = FldGroup; @@ -2256,7 +2275,7 @@ symbol_field_parent_set( struct cbl_field_t *field ) return false; } ); if( ! all_numeric ) { - yyerror("%s %s invalid VALUE for numeric type %s", + ERROR_FIELD(field, "%s %s invalid VALUE for numeric type %s", field->level_str(), field->name, prior->name); } } @@ -2562,7 +2581,7 @@ symbol_typedef_add( size_t program, struct cbl_field_t *field ) { assert(field->is_typedef()); if( field->is_strongdef() && field->level != 1 ) { - yyerror("%s %s STRONG TYPEDEF must be level 01", + ERROR_FIELD(field, "%s %s STRONG TYPEDEF must be level 01", field->level_str(), field->name); return NULL; } @@ -2736,7 +2755,6 @@ symbol_field_add( size_t program, struct cbl_field_t *field ) } update_symbol_map2( e ); - return e; } @@ -2993,16 +3011,15 @@ seek_parent( const symbol_elem_t *e, size_t level ) { * "The condition-name entries for a particular conditional variable * shall immediately follow the entry describing the item...." */ - struct symbol_elem_t * symbol_field_same_as( cbl_field_t *tgt, const cbl_field_t *src ) { if( target_in_src(tgt, src) ) { - yyerror("%s %s may not reference itself as part of %s %s", + ERROR_FIELD(tgt, "%s %s may not reference itself as part of %s %s", tgt->level_str(), tgt->name, src->level_str(), src->name); return NULL; } if( tgt->level == 77 && src->type == FldGroup ) { - yyerror("%s %s TYPE TO %s must be an elementary item", + ERROR_FIELD(tgt, "%s %s TYPE TO %s must be an elementary item", tgt->level_str(), tgt->name, src->name); return NULL; } @@ -3424,7 +3441,7 @@ new_literal_add( const char initial[], uint32_t len, enum cbl_field_attr_t attr if( ! field->internalize() ) { - yyerror("inconsistent string literal encoding for '%s'", initial); + ERROR_FIELD(field, "inconsistent string literal encoding for '%s'", initial); } } @@ -3720,7 +3737,7 @@ cbl_field_t::internalize() { if( 0 < inbytesleft ) { // data.capacity + inbytesleft is not correct if the remaining portion has // multibyte characters. But the fact reamins that the VALUE is too big. - yyerror("%s %s VALUE '%s' requires %zu bytes for size %u", + ERROR_FIELD(this, "%s %s VALUE '%s' requires %zu bytes for size %u", cbl_field_t::level_str(level), name, data.initial, data.capacity + inbytesleft, data.capacity ); } @@ -4761,7 +4778,7 @@ cbl_file_key_t::deforward( size_t ifile ) { auto parent = symbol_record_file(field); if( ifield == fwd ) { - yyerror("line %d: %s of %s " + ERROR_FIELD(field, "line %d: %s of %s " "is not defined", file->line, field->name, file->name); return ifield; @@ -4770,21 +4787,21 @@ cbl_file_key_t::deforward( size_t ifile ) { // relative files have numeric keys that are not part of the record if( file->org == file_relative_e ) { if( parent != NULL ) { - yyerror("line %d: RELATIVE file %s key %s " + ERROR_FIELD(field, "line %d: RELATIVE file %s key %s " "is defined in file description", file->line, file->name, field->name); return ifield; } if( field->occurs.ntimes() ) { - yyerror("line %d: RELATIVE file %s key %s " + ERROR_FIELD(field, "line %d: RELATIVE file %s key %s " "cannot have OCCURS clause", file->line, file->name, field->name); return ifield; } if( ! (is_numeric(field) && 0 == field->data.rdigits) ) { - yyerror("line %d: RELATIVE file %s key %s " - "must be integer type", - file->line, file->name, field->name); + ERROR_FIELD(field, "line %d: RELATIVE file %s key %s " + "must be integer type", + file->line, file->name, field->name); return ifield; } return ifield; @@ -4792,7 +4809,7 @@ cbl_file_key_t::deforward( size_t ifile ) { // looked-up field must have same file as parent if( ! (parent != NULL && symbol_index(symbol_elem_of(parent)) == ifile) ) { - yyerror("line %d: %s of %s " + ERROR_FIELD(field, "line %d: %s of %s " "is not defined in file description", file->line, field->name, file->name); } @@ -4826,7 +4843,7 @@ cbl_file_t::deforward() { auto field = cbl_field_of(symbol_at(user_status)); if( is_forward(field) ) { - yyerror("%s of %s never defined in FD record", + ERROR_FIELD(field, "%s of %s never defined in FD record", field->name, this->name); } } @@ -4848,7 +4865,6 @@ cbl_file_t::keys_str() const { return n + strlen(s); } ); char *output = static_cast<char*>( xcalloc(1, n) ), *p = output; - assert(output); const char *sep = ""; *p++ = '['; diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h index 997fc16db8d7cb19ed94a1219252fae62b994995..8e227af1a3aef720991895aabce59a89b7a4e7f4 100644 --- a/gcc/cobol/symbols.h +++ b/gcc/cobol/symbols.h @@ -2066,6 +2066,9 @@ struct symbol_elem_t * symbol_file_add( size_t program, struct symbol_elem_t * symbol_section_add( size_t program, struct cbl_section_t *section ); +void symbol_field_location( size_t ifield, const YYLTYPE& loc ); +YYLTYPE symbol_field_location( size_t ifield ); + bool symbol_label_section_exists( size_t program ); size_t symbol_field_capacity( const cbl_field_t *field ); diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc index 4f8f2f9db1e518cae991b6e1c37d4ce9b996fe57..695c3e18c0a8074fe7e1ed033ea29f30870ca4fd 100644 --- a/gcc/cobol/util.cc +++ b/gcc/cobol/util.cc @@ -2484,10 +2484,6 @@ dialect_error( const char term[], const char dialect[] ) { term, dialect); } -/* This is the analog to warn(3) from "err .h". The formatted message is sent - to stderr, the message from xstrerror() is appended, and processing - continues */ - bool fisdigit(int c) { return ISDIGIT(c);