From e3ad636877c586983aaf46a14884cb66727f54b7 Mon Sep 17 00:00:00 2001 From: "James K. Lowden" <jklowden@symas.com> Date: Sat, 13 Apr 2024 16:12:10 -0400 Subject: [PATCH] add TYPE TO errors --- gcc/cobol/UAT/failsuite.src/typedef.at | 13 ++-- gcc/cobol/parse.y | 92 ++++++++++++++++++++------ gcc/cobol/parse_ante.h | 2 +- gcc/cobol/scan.l | 24 ++++--- gcc/cobol/symbols.cc | 22 +++++- gcc/cobol/symbols.h | 2 + 6 files changed, 117 insertions(+), 38 deletions(-) diff --git a/gcc/cobol/UAT/failsuite.src/typedef.at b/gcc/cobol/UAT/failsuite.src/typedef.at index 1340e560d400..7bf6a29234a4 100644 --- a/gcc/cobol/UAT/failsuite.src/typedef.at +++ b/gcc/cobol/UAT/failsuite.src/typedef.at @@ -211,11 +211,14 @@ AT_DATA([badprog.cob], [ ]) -AT_CHECK([$COMPILE_ONLY badprog.cob], [1], [], -[badprog.cob:8: error: item may not reference itself -badprog.cob:10: error: entry following TYPE TO may not be subordinate to it -badprog.cob:11: error: illegal combination of TYPE TO with other clauses -badprog.cob:12: error: elementary item expected +AT_CHECK([$COMPILE_ONLY -dialect mf badprog.cob], [1], [], +[badprog.cob:8: error: 02 F1 may not reference itself as part of 01 MESSAGE-TEXT-2T at 'MESSAGE-TEXT-2T' +badprog.cob:10: error: F1 created with SAME AS or TYPE TO, cannot have new member FILLER at 'FILLER' +badprog.cob:10: error: 05 FILLER on is not part of an 01 record at 'FILLER' +badprog.cob:12: error: PIC incompatible with TYPE TO +badprog.cob:12: error: 77 OUTPUT-NAME TYPE TO MESSAGE-TEXT-2T must be an elementary item at 'MESSAGE-TEXT-2T' +.:13: 5 errors in DATA DIVISION, compilation ceases detected at end of file +cobol1: error: failed compiling badprog.cob ]) AT_CLEANUP diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index 0a941575ff94..ded53436448d 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -3203,25 +3203,27 @@ data_clauses: data_clause } } | data_clauses data_clause { + const char *clause = "data"; + switch($2) { + case occurs_clause_e: clause = "OCCURS"; break; + case picture_clause_e: clause = "PIC"; break; + case usage_clause_e: clause = "USAGE"; break; + case value_clause_e: clause = "VALUE"; break; + case global_clause_e: clause = "GLOBAL"; break; + case external_clause_e: clause = "EXTERNAL"; break; + case justified_clause_e: clause = "JUSTIFIED"; break; + case redefines_clause_e: clause = "REDEFINES"; break; + case blank_zero_clause_e: clause = "BLANK WHEN ZERO"; break; + case synched_clause_e: clause = "SYNCHRONIZED"; break; + case sign_clause_e: clause = "SIGN"; break; + case based_clause_e: clause = "BASED"; break; + case same_clause_e: clause = "SAME AS"; break; + case volatile_clause_e: clause = "VOLATILE"; break; + case type_clause_e: clause = "TYPE"; break; + case typedef_clause_e: clause = "TYPEDEF"; break; + } if( ($$ & $2) == $2 ) { - const char *msg = "data"; - switch($2) { - case occurs_clause_e: msg = "OCCURS"; break; - case picture_clause_e: msg = "PIC"; break; - case usage_clause_e: msg = "USAGE"; break; - case value_clause_e: msg = "VALUE"; break; - case global_clause_e: msg = "GLOBAL"; break; - case external_clause_e: msg = "EXTERNAL"; break; - case justified_clause_e: msg = "JUSTIFIED"; break; - case redefines_clause_e: msg = "REDEFINES"; break; - case blank_zero_clause_e: msg = "BLANK WHEN ZERO"; break; - case synched_clause_e: msg = "SYNCHRONIZED"; break; - case sign_clause_e: msg = "SIGN"; break; - case based_clause_e: msg = "BASED"; break; - case same_clause_e: msg = "SAME AS"; break; - case volatile_clause_e: msg = "VOLATILE"; break; - } - yyerrorv("%s clause repeated", msg); + yyerrorv("%s clause repeated", clause); YYERROR; } @@ -3239,6 +3241,24 @@ data_clauses: data_clause $$ |= $2; + // If any implied TYPE bits are on in addition to + // type_clause_e, they're in conflict. + static const size_t type_implies = + // ALIGNED clause not implemented + blank_zero_clause_e | justified_clause_e | picture_clause_e + | sign_clause_e | synched_clause_e | usage_clause_e; + + if( type_clause_e < ($$ & (type_clause_e | type_implies)) ) { + if( $2 == type_clause_e ) { + yyerror("error: TYPE TO incompatible with ALIGNED, " + "BLANK WHEN ZERO, JUSTIFIED, PICTURE, SIGN, " + "SYNCHRONIZED, and USAGE"); + } else { + yyerrorv("error: %s incompatible with TYPE TO", clause); + } + YYERROR; + } + if( ($$ & same_clause_e) == same_clause_e ) { if( 0 < ($$ & ~same_clause_e) ) { yyerrorv("error: %02u %s SAME AS " @@ -7011,9 +7031,41 @@ set_tgts: set_tgt { ; set_operand: set_tgt | signed_literal { $$ = new_reference($1); } - | ADDRESS of PROGRAM_kw namestr + | ADDRESS of FUNCTION ctx_name[name] + { + $$ = NULL; + auto e = symbol_function(0, $name); + if( e ) { + $$ = new cbl_refer_t(cbl_label_of(e)); + } else { + e = symbol_find($name); + if( !e ) { + yyerrorv("error: %s not found", $name); + YYERROR; + } + $$ = new cbl_refer_t(cbl_field_of(e)); + } + assert($$); + } + | ADDRESS of PROGRAM_kw ctx_name[name] + { + $$ = NULL; + auto label = symbol_program(0, $name); + if( label ) { + $$ = new cbl_refer_t(label); + } else { + auto e = symbol_find($name); + if( !e ) { + yyerrorv("error: %s not found", $name); + YYERROR; + } + $$ = new cbl_refer_t(cbl_field_of(e)); + } + assert($$); + } + | ADDRESS of PROGRAM_kw LITERAL[lit] { - auto label = symbol_program(0, $namestr.data); + auto label = symbol_program(0, $lit.data); $$ = new cbl_refer_t( label ); } ; diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h index c063508d7cc6..3253d86ca53f 100644 --- a/gcc/cobol/parse_ante.h +++ b/gcc/cobol/parse_ante.h @@ -200,7 +200,7 @@ enum data_clause_t { based_clause_e = 0x0800, same_clause_e = 0x1000, volatile_clause_e = 0x2000, - type_clause_e = usage_clause_e, + type_clause_e = 0x4000, typedef_clause_e = 0x8000, }; diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l index 79eba81bf19a..10cb2654caa4 100644 --- a/gcc/cobol/scan.l +++ b/gcc/cobol/scan.l @@ -164,7 +164,7 @@ NL [[:blank:]]*\r?\n[[:blank:]]* PUSH_FILE \f?[#]FILE{SPC}PUSH{SPC}.+\f POP_FILE \f?[#]FILE{SPC}POP\f -%x procedure_div ident_state function classify when_not +%x procedure_div ident_state addr_of function classify when_not %x program_id_state comment_entries %x author_state date_state field_level field_state dot_state %x numeric_state name_state @@ -1491,7 +1491,6 @@ USE({SPC}FOR)? { return USE; } COMMAND-LINE { return COMMAND_LINE; } COMMAND-LINE-COUNT { return COMMAND_LINE_COUNT; } CONTENT { return CONTENT; } - CONTENT { return CONTENT; } DELIMITED { return DELIMITED; } DELIMITER { return DELIMITER; } ENVIRONMENT { return ENVIRONMENT; } @@ -1516,12 +1515,13 @@ USE({SPC}FOR)? { return USE; } return MIGHT_BE; } - {SORT_MERGE}{SPC}/(\f#)?{NAME} { - yy_push_state(sort_state); return SORT; } + {SORT_MERGE}{SPC}(\f#)?/{NAME} { yy_push_state(sort_state); return SORT; } + + ADDRESS{SPC}(OF{SPC})?/FUNCTION { yy_push_state(addr_of); return ADDRESS; } FUNCTION { yy_push_state(function); return FUNCTION; } - {NAME}/{OSPC}{DOTSEP} { + {NAME}/{OSPC}{DOTSEP} { int token = keyword_tok(yytext); if( token ) return token; @@ -1537,18 +1537,20 @@ USE({SPC}FOR)? { return USE; } return typed_name(yytext); } } + +<addr_of>FUNCTION { pop_return FUNCTION; } + +<when_not>NOT { yylval.number = NOT; pop_return MIGHT_BE; } + <classify>{ {ISNT}/{SPC}{NAMTYP} { yy_pop_state(); } IS/{SPC}{NAMTYP} { yy_pop_state(); } } -<when_not>{ - NOT { yy_pop_state(); yylval.number = NOT; return MIGHT_BE; } -} <sort_state>{ - {NAME} { yylval.string = strdup(yytext); - pop_return symbol_file(PROGRAM, yytext)? FILENAME : NAME; - } + {NAME} { yylval.string = strdup(yytext); + pop_return symbol_file(PROGRAM, yytext)? FILENAME : NAME; + } } <datetime_fmt>{ diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc index a2cd7eb97082..57bfe9296cad 100644 --- a/gcc/cobol/symbols.cc +++ b/gcc/cobol/symbols.cc @@ -1990,7 +1990,7 @@ symbol_field_parent_set( struct cbl_field_t *field ) cbl_field_t *parent = cbl_field_of(e); if( parent->level < field->level ) { if( parent->has_attr(same_as_e) ) { - yyerrorv("error: %s created with SAME AS, cannot have new member %s", + yyerrorv("error: %s created with SAME AS or TYPE TO, cannot have new member %s", parent->name, field->name); return NULL; } @@ -2611,6 +2611,16 @@ symbol_field_alias2( struct symbol_elem_t *e, struct symbol_elem_t *e2, return e; } +static const cbl_field_t * +symbol_field_top_level( const cbl_field_t *field ) { + while( field->parent > 0 ) { + auto e = symbol_at(field->parent); + if( e->type != SymField ) break; + field = cbl_field_of(e); + } + return field; +} + class elem_group_t { const symbol_elem_t *bog, *eog; public: @@ -2632,6 +2642,16 @@ public: struct symbol_elem_t * symbol_field_same_as( cbl_field_t *tgt, const cbl_field_t *src ) { + if( symbol_field_top_level(tgt) == symbol_field_top_level(src) ) { + yyerrorv("error: %02d %s may not reference itself as part of %02d %s", + tgt->level, tgt->name, src->level, src->name); + return NULL; + } + if( tgt->level == 77 && src->type == FldGroup ) { + yyerrorv("error: %02d %s TYPE TO %s must be an elementary item", + tgt->level, tgt->name, src->name); + return NULL; + } auto last_elem = symbol_at(field_index(tgt)); tgt->same_as(*src, src->is_typedef()); diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h index 293e66f74897..0005e0f6b3f0 100644 --- a/gcc/cobol/symbols.h +++ b/gcc/cobol/symbols.h @@ -570,8 +570,10 @@ struct cbl_field_t { type = that.type; attr |= (that.attr & external_e); attr |= same_as_e; + occurs = that.occurs; // might be partly wrong data = that.data; + if( ! (is_typedef || that.type == FldClass) ) { data.initial = NULL; data.value = 0.0; -- GitLab