cobol: Expose warnings as command-line options.

Introduce 45 warning options, integrated with dialects.
	Update documentation with warning options and syntax supported by
	each dialect.

gcc/cobol/ChangeLog:

	PR cobol/119329
	PR cobol/119331
	PR cobol/120786
	* Make-lang.in: Add cobol/messages.o to cobol1 sources.
	* cbldiag.h (yywarn): Remove function.
	(struct cbl_loc_t): Introduce new location type independent of Bison.
	(enum cbl_diag_id_t): Enumerate diagnostic messages.
	(cbl_message): New function.
	(dialect_ok): Test for dialect, emit standard message.
	(dialect_not_ok): Emit standard message if syntax excluded by dialect.
	(dialect_error): Remove function.
	(cbl_unimplementedw): Use cbl_diag_id_t.
	(cbl_unimplemented): Whitespace.
	* cdf.y: Update token values.
	* cobol1.cc (enable_exceptions): Use cbl_message.
	(cobol_warning): Declare function.
	(cobol_langhook_handle_option): Add 44 new warning options.
	(cobol_langhook_type_for_mode): Remove function.
	* except.cc (cbl_enabled_exception_t::dump): Remove function.
	* exceptg.h (class exception_turn_t): Use cbl_diag_id_t.
	* gcobol.1: Document dialect syntax and new warning options.
	* genapi.cc (parser_label_label): Remove unused warning.
	* gengen.cc (gg_find_field_in_struct): Use cbl_internal_error.
	(gg_printf): Same.
	(gg_fprintf): Same.
	(gg_define_function): Same.
	(gg_get_function_decl): Same.
	(gg_call_expr): Same.
	(gg_call): Same.
	* lang-specs.h: Add warning options.
	* lang.opt: Add ISO dialect and options.
	* lexio.cc (parse_replacing_term): Use cbl_message.
	(parse_replacing_pair): Same.
	(preprocess_filter_add): Same.
	(cdftext::echo_input): Same.
	(cdftext::lex_open): Same.
	(cdftext::open_input): Same.
	* messages.cc: New file implements cbl_message.
	* parse.y: Use cbl_message.
	* parse_ante.h (dialect_proscribed): Remove function.
	(parser_move_carefully): Use dialect_ok.
	(goodnight_gracie): Convert warning to debug message.
	* scan.l: Use dialect_ok.
	* scan_ante.h (scanner_parsing): Use cbl_diag_id_t.
	(scanner_parsing_toggle): Same.
	(scanner_parsing_pop): Same.
	(verify_ws): Same.
	(level_of): Same.
	(typed_name): Same.
	(integer_of): Same.
	* scan_post.h (datetime_format_of): Use cbl_internal_error.
	(prelex): Emit only debug messages.
	* show_parse.h: Use cbl_internal_error.
	* symbols.cc (symbols_update): Remove dialect test because parser's problem.
	(cbl_field_t::internalize): Use cbl_message.
	* symbols.h (enum cbl_dialect_t): Add ISO to cbl_dialect_t.
	(cbl_dialect_str): Recognize ISO dialect.
	(dialect_has): New function.
	(cbl_diagnostic_kind): New function.
	(cbl_dialect_kind): New function.
	(struct cbl_alphabet_t): Emit only debug message.
	* token_names.h: Regenerate.
	* util.cc (gb4): Emit only debug message.
	(current_token_location): Add overload to set token_location.
	(yywarn): Remove function.
	(cobol_fileline_set): Use cbl_message.
	(cobol_parse_files): Same.
	(cbl_message): New diagnostic message function uses cbl_diag_id_t.
	(cbl_diagnostic_kind): New function.
	(cbl_diagnostic_option): New function.
	(cbl_unimplementedw): Use cbl_diag_id_t.
	(dialect_error): Remove function.
	* util.h (cbl_message): Remove obsolete prototype for cbl_message.
This commit is contained in:
James K. Lowden
2025-12-01 16:08:55 -05:00
parent cf78d40265
commit d9a64bf6a6
24 changed files with 2051 additions and 993 deletions

View File

@@ -71,6 +71,7 @@ cobol1_OBJS = \
cobol/genmath.o \
cobol/gengen.o \
cobol/lexio.o \
cobol/messages.o \
cobol/parse.o \
cobol/scan.o \
cobol/structs.o \

View File

@@ -46,7 +46,6 @@ const char * cobol_filename();
* diagnostic framework and use text that can be localized.
*/
void yyerror( const char fmt[], ... ) ATTRIBUTE_GCOBOL_DIAG(1, 2);
bool yywarn( const char fmt[], ... ) ATTRIBUTE_GCOBOL_DIAG(1, 2);
/* Location type. Borrowed from parse.h as generated by Bison. */
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
@@ -78,6 +77,110 @@ struct YDFLTYPE
#endif
struct cbl_loc_t {
int first_line;
int first_column;
int last_line;
int last_column;
cbl_loc_t( const YYLTYPE& loc )
: first_line(loc.first_line)
, first_column(loc.first_column)
, last_line(loc.last_line)
, last_column(loc.last_column)
{}
operator YYLTYPE() const {
return { first_line, first_column, last_line, last_column };
}
};
/*
* Naming Convention: Names end with a letter that indicates
* their kind:
* F fatal, "fatal error: "
* I ice, "internal compiler error: "
* E error, "error: "
* S sorry, "sorry, unimplemented: "
* W warning, "warning: "
* A anachronism, "anachronism: "
* N note, "note: "
* D debug, "debug: "
*/
enum cbl_diag_id_t : uint64_t {
CdfNotFoundW,
CdfParameterW,
EcUnknownW,
LexIncludeE,
LexIncludeOkN,
LexIndicatorE,
LexInputN,
LexLineE,
LexPreprocessE,
LexReplaceE,
LexSeparatorE,
IbmEjectE,
IbmEqualAssignE,
IbmLengthOf,
IbmProcedurePointer,
IbmSectionNegE,
IbmSectionRangeE,
IbmSectionSegmentW,
IbmStopNumber,
IbmVolatileE,
IbmVolatileW, // dialect warning for ignored syntax
IsoResume,
MfBinaryLongLong,
MfCallGiving,
MfCdfDollar,
MfComp6,
MfCompX,
MfLevel_1_Occurs,
MfLevel78,
MfMovePointer,
MfReturningNum,
MfUsageTypename,
MfTrailing,
Par78CdfDefinedW,
ParIconvE,
ParInfoI,
ParLangInfoW,
ParLiteral2W,
ParLocaleW,
ParNoCorrespondingW,
ParNumstrW,
ParUnresolvedProcE,
SynApplyCommit,
SynFileCodeSet,
SynHighOrderBit,
SynRecordingMode,
SynSetLocaleTo,
SynSetToLocale,
DiagDiagDiag // always last
};
bool cbl_message( cbl_diag_id_t id, const char msg[], ... )
ATTRIBUTE_GCOBOL_DIAG(2, 3);
bool cbl_message( cbl_loc_t loc, cbl_diag_id_t id, const char msg[], ... )
ATTRIBUTE_GCOBOL_DIAG(3, 4);
bool
dialect_ok( const cbl_loc_t& loc, cbl_diag_id_t id, const char term[], bool ok = true );
static inline bool
dialect_not_ok( const cbl_loc_t& loc, cbl_diag_id_t id, const char term[] ) {
return dialect_ok(loc, id, term, false);
}
// Diagnostic format specifiers are documented in gcc/pretty-print.cc
// an error at a location, called from the parser for semantic errors
void error_msg( const YYLTYPE& loc, const char gmsgid[], ... )
@@ -91,16 +194,15 @@ warn_msg( const YYLTYPE& loc, const char gmsgid[], ... )
void error_msg_direct( const char gmsgid[], ... )
ATTRIBUTE_GCOBOL_DIAG(1, 2);
void dialect_error( const YYLTYPE& loc, const char term[], const char dialect[] );
// for CDF and other warnings that refer back to an earlier line
// (not in diagnostic framework yet)
void yyerrorvl( int line, const char *filename, const char fmt[], ... )
ATTRIBUTE_PRINTF_3;
void cbl_unimplementedw(const char *gmsgid, ...) ATTRIBUTE_GCOBOL_DIAG(1, 2); // warning
void cbl_unimplemented(const char *gmsgid, ...) ATTRIBUTE_GCOBOL_DIAG(1, 2); // error
void cbl_unimplementedw(cbl_diag_id_t id, const char *gmsgid, ...)
ATTRIBUTE_GCOBOL_DIAG(2, 3); // warning
void cbl_unimplemented(const char *gmsgid, ...)
ATTRIBUTE_GCOBOL_DIAG(1, 2); // error
void cbl_unimplemented_at( const YYLTYPE& loc, const char *gmsgid, ... )
ATTRIBUTE_GCOBOL_DIAG(2, 3);

View File

@@ -201,7 +201,7 @@ apply_cdf_turn( const exception_turn_t& turn ) {
%type <cdfarg> namelit name_any name_one
%type <string> name subscript subscripts inof
%token <boolean> BOOL
%token <number> FEATURE 366 NUMBER 303 EXCEPTION_NAME 280 "EXCEPTION NAME"
%token <number> FEATURE 367 NUMBER 304 EXCEPTION_NAME 280 "EXCEPTION NAME"
%type <cdfval> cdf_expr
%type <cdfval> cdf_relexpr cdf_reloper cdf_and cdf_bool_expr
@@ -213,52 +213,52 @@ apply_cdf_turn( const exception_turn_t& turn ) {
%type <number> cdf_stackable
%token BY 487
%token COPY 363
%token CDF_DISPLAY 385 ">>DISPLAY"
%token BY 488
%token COPY 364
%token CDF_DISPLAY 386 ">>DISPLAY"
%token IN 606
%token NAME 286
%token NUMSTR 305 "numeric literal"
%token NUMSTR 306 "numeric literal"
%token OF 687
%token PSEUDOTEXT 723
%token REPLACING 745
%token LITERAL 298
%token SUPPRESS 377
%token LITERAL 299
%token SUPPRESS 378
%token LSUB 368 "("
%token SUBSCRIPT 376 RSUB 373 ")"
%token LSUB 369 "("
%token SUBSCRIPT 377 RSUB 374 ")"
%token CDF_DEFINE 384 ">>DEFINE"
%token CDF_IF 386 ">>IF"
%token CDF_ELSE 387 ">>ELSE"
%token CDF_END_IF 388 ">>END-IF"
%token CDF_EVALUATE 389 ">>EVALUATE"
%token CDF_WHEN 390 ">>WHEN"
%token CDF_END_EVALUATE 391 ">>END-EVALUATE"
%token CDF_DEFINE 385 ">>DEFINE"
%token CDF_IF 387 ">>IF"
%token CDF_ELSE 388 ">>ELSE"
%token CDF_END_IF 389 ">>END-IF"
%token CDF_EVALUATE 390 ">>EVALUATE"
%token CDF_WHEN 391 ">>WHEN"
%token CDF_END_EVALUATE 392 ">>END-EVALUATE"
%token ALL 451
%token CALL_CONVENTION 392 ">>CALL-CONVENTION"
%token COBOL_WORDS 381 ">>COBOL-WORDS"
%token CDF_PUSH 395 ">>PUSH"
%token CDF_POP 396 ">>POP"
%token SOURCE_FORMAT 397 ">>SOURCE FORMAT"
%token ALL 452
%token CALL_CONVENTION 393 ">>CALL-CONVENTION"
%token COBOL_WORDS 382 ">>COBOL-WORDS"
%token CDF_PUSH 396 ">>PUSH"
%token CDF_POP 397 ">>POP"
%token SOURCE_FORMAT 398 ">>SOURCE FORMAT"
%token AS 469 CONSTANT 362 DEFINED 364
%token AS 470 CONSTANT 363 DEFINED 365
%type <boolean> DEFINED
%token OTHER 699 PARAMETER_kw 369 "PARAMETER"
%token OFF 688 OVERRIDE 370
%token OTHER 699 PARAMETER_kw 370 "PARAMETER"
%token OFF 688 OVERRIDE 371
%token THRU 950
%token TRUE_kw 815 "True"
%token CALL_COBOL 393 "CALL"
%token CALL_VERBATIM 394 "CALL (as C)"
%token CALL_COBOL 394 "CALL"
%token CALL_VERBATIM 395 "CALL (as C)"
%token TURN 817 CHECKING 497 LOCATION 650 ON 690 WITH 844
%token TURN 817 CHECKING 498 LOCATION 650 ON 690 WITH 844
%left OR 951
%left AND 952
%right NOT 953
%left '<' '>' '=' NE 954 LE 955 GE 956
%left '<' '>' EQ 298 "EQUAL" NE 954 LE 955 GE 956
%left '-' '+'
%left '*' '/'
%right NEG 958
@@ -362,7 +362,7 @@ cdf_define: CDF_DEFINE cdf_constant NAME as cdf_expr[value] override
}
}
| CDF_DEFINE cdf_constant NAME '=' cdf_expr[value] override
| CDF_DEFINE cdf_constant NAME EQ cdf_expr[value] override
{ /* accept, but as error */
if( scanner_parsing() ) {
error_msg(@NAME, "CDF error: %s = value invalid", $NAME);
@@ -382,8 +382,9 @@ cdf_define: CDF_DEFINE cdf_constant NAME as cdf_expr[value] override
*/
{
if( 0 == cdf_dictionary().count($NAME) ) {
yywarn("CDF: '%s' is defined AS PARAMETER "
"but was not defined", $NAME);
cbl_message(@NAME, CdfParameterW,
"CDF: '%s' is defined AS PARAMETER "
"but was not defined", $NAME);
}
}
| CDF_DEFINE FEATURE as ON {
@@ -563,7 +564,7 @@ cdf_reloper: cdf_relexpr
cdf_relexpr: cdf_relexpr '<' cdf_expr { $$ = $1(@1) < $3(@3); }
| cdf_relexpr LE cdf_expr { $$ = $1(@1) <= $3(@3); }
| cdf_relexpr '=' cdf_expr {
| cdf_relexpr EQ cdf_expr {
$$ = cdfval_t(false);
if( ( $1.string && $3.string) ||
(!$1.string && !$3.string) )
@@ -612,7 +613,8 @@ cdf_factor: NAME {
$$ = that->second;
} else {
if( ! scanner_parsing() ) {
yywarn("CDF skipping: no such variable '%s' (ignored)", $1);
cbl_message(CdfNotFoundW,
"CDF skipping: no such variable '%s'", $1);
} else {
error_msg(@NAME, "CDF error: no such variable '%s'", $1);
}

View File

@@ -317,7 +317,7 @@ enable_exceptions( bool enable ) {
NULL != (name = strtok(name, ",")); name = NULL ) {
ec_type_t type = ec_type_of(name);
if( type == ec_none_e ) {
yywarn("unrecognized exception '%s' was ignored", name);
cbl_message(EcUnknownW, "unrecognized exception '%s'", name);
continue;
}
ec_disposition_t disposition = ec_type_disposition(type);
@@ -328,17 +328,21 @@ enable_exceptions( bool enable ) {
}
}
void cobol_warning( cbl_diag_id_t id, int yn, bool );
static bool
cobol_langhook_handle_option (size_t scode,
const char *arg ATTRIBUTE_UNUSED,
const char *arg,
HOST_WIDE_INT value,
int kind ATTRIBUTE_UNUSED,
int kind,
location_t loc ATTRIBUTE_UNUSED,
const struct
cl_option_handlers *handlers ATTRIBUTE_UNUSED)
{
// process_command (decoded_options_count, decoded_options);
enum opt_code code = (enum opt_code) scode;
auto super_kind = diagnostics::kind(kind);
bool warning_as_error = super_kind == diagnostics::kind::error;
switch(code)
{
@@ -403,6 +407,8 @@ cobol_langhook_handle_option (size_t scode,
return true;
case OPT_dialect:
// gcc disallows 0 as an enumerated value, so we used 0x10 for iso.
if( cobol_dialect == 0x100 ) cobol_dialect = 0;
cobol_dialect_set(cbl_dialect_t(cobol_dialect));
return true;
@@ -439,6 +445,194 @@ cobol_langhook_handle_option (size_t scode,
cobol_gcobol_feature_set(feature_internal_ebcdic_e);
return true;
// Warnings and errors
case OPT_Wbinary_long_long:
cobol_warning(MfBinaryLongLong, binary_long_long, warning_as_error);
return true;
case OPT_Wcall_giving:
cobol_warning(MfCallGiving, call_giving, warning_as_error);
return true;
case OPT_Wcdf_dollar:
cobol_warning(MfCdfDollar, cdf_dollar, warning_as_error);
return true;
case OPT_Wcomp_6:
cobol_warning(MfComp6, comp_6, warning_as_error);
return true;
case OPT_Wcomp_x:
cobol_warning(MfCompX, comp_x, warning_as_error);
return true;
case OPT_Winspect_trailing:
cobol_warning(MfTrailing, inspect_trailing, warning_as_error);
return true;
case OPT_Wlevel_1_occurs:
cobol_warning(MfLevel_1_Occurs, level_1_occurs, warning_as_error);
return true;
case OPT_Wlevel_78_defined:
cobol_warning(Par78CdfDefinedW, level_78_defined, warning_as_error);
return true;
case OPT_Wmove_pointer:
cobol_warning(MfMovePointer, move_pointer, warning_as_error);
return true;
case OPT_Wlevel_78:
cobol_warning(MfLevel78, level_78, warning_as_error);
return true;
case OPT_Wreturning_number:
cobol_warning(MfReturningNum, returning_number, warning_as_error);
return true;
case OPT_Wusage_typename:
cobol_warning(MfUsageTypename, usage_typename, warning_as_error);
return true;
case OPT_Wbad_line_directive:
cobol_warning(LexLineE, bad_line_directive, warning_as_error);
return true;
case OPT_Wequal_assign:
cobol_warning(IbmEqualAssignE, equal_assign, warning_as_error);
return true;
case OPT_Wbad_numeric:
cobol_warning(ParNumstrW, bad_numeric, warning_as_error);
return true;
case OPT_Wcdf_invalid_parameter:
cobol_warning(CdfParameterW, cdf_invalid_parameter, warning_as_error);
return true;
case OPT_Wcdf_name_not_found:
cobol_warning(CdfNotFoundW, cdf_name_not_found, warning_as_error);
return true;
case OPT_Wcopybook_found:
cobol_warning(LexInputN, copybook_found, warning_as_error);
return true;
case OPT_Wec_unknown:
cobol_warning(EcUnknownW, ec_unknown, warning_as_error);
return true;
case OPT_Wentry_convention:
cobol_warning(ParInfoI, entry_convention, warning_as_error);
return true;
case OPT_Wiconv_error:
cobol_warning(ParIconvE, iconv_error, warning_as_error);
return true;
case OPT_Winclude_file_found:
cobol_warning(LexIncludeOkN, include_file_found, warning_as_error);
return true;
case OPT_Winclude_file_not_found:
cobol_warning(LexIncludeE, include_file_not_found, warning_as_error);
return true;
case OPT_Wliteral_concat:
cobol_warning(ParLiteral2W, literal_concat, warning_as_error);
return true;
case OPT_Wlocale_error:
cobol_warning(ParLocaleW, locale_error, warning_as_error);
return true;
case OPT_Wmove_corresponding:
cobol_warning(ParNoCorrespondingW, warn_corresponding, warning_as_error);
return true;
case OPT_Wnllanginfo_error:
cobol_warning(ParLangInfoW, nllanginfo_error, warning_as_error);
return true;
case OPT_Wlength_of:
cobol_warning(IbmLengthOf, cobol_length_of, warning_as_error);
return true;
case OPT_Wpreprocessor_error:
cobol_warning(ParLangInfoW, preprocessor_error, warning_as_error);
return true;
case OPT_Wprocedure_pointer:
cobol_warning(IbmProcedurePointer, procedure_pointer, warning_as_error);
return true;
case OPT_Wprocedure_not_found:
cobol_warning(ParUnresolvedProcE, procedure_not_found, warning_as_error);
return true;
case OPT_Wreplace_error:
cobol_warning(LexReplaceE, replace_error, warning_as_error);
return true;
case OPT_Wsegment_error:
cobol_warning(IbmSectionRangeE, segment_error, warning_as_error);
return true;
case OPT_Wsegment_negative:
cobol_warning(IbmSectionNegE, segment_negative, warning_as_error);
return true;
case OPT_Wsegment:
cobol_warning(IbmSectionSegmentW, cobol_segment, warning_as_error);
return true;
case OPT_Wcobol_eject:
cobol_warning(IbmEjectE, cobol_eject, warning_as_error);
return true;
case OPT_Woperator_space:
cobol_warning(LexSeparatorE, operator_space, warning_as_error);
return true;
case OPT_Wstop_number:
cobol_warning(IbmStopNumber, stop_number, warning_as_error);
return true;
case OPT_Wstray_indicator:
cobol_warning(LexIndicatorE, stray_indicator, warning_as_error);
return true;
case OPT_Wcobol_volatile:
// If arg is true, the error becoomes a warning
cobol_warning(IbmVolatileE, cobol_volatile, warning_as_error);
cobol_warning(IbmVolatileW, cobol_volatile, warning_as_error);
return true;
case OPT_Wcobol_resume:
cobol_warning(IsoResume, cobol_resume, warning_as_error);
return true;
case OPT_Wapply_commit:
cobol_warning(SynApplyCommit, apply_commit, warning_as_error);
return true;
case OPT_Whigh_order_bit:
cobol_warning(SynHighOrderBit, high_order_bit, warning_as_error);
return true;
case OPT_Wfile_code_set:
cobol_warning(SynFileCodeSet, file_code_set, warning_as_error);
return true;
case OPT_Wset_locale_to:
cobol_warning(SynSetLocaleTo, set_locale_to, warning_as_error);
return true;
case OPT_Wset_to_locale:
cobol_warning(SynSetToLocale, set_to_locale, warning_as_error);
return true;
default:
break;
}
@@ -514,14 +708,6 @@ cobol_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
return NULL;
}
////static tree
////cobol_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED,
//// int unsignedp ATTRIBUTE_UNUSED)
//// {
//// gcc_unreachable ();
//// return NULL;
//// }
/* Record a builtin function. We just ignore builtin functions. */
static tree

View File

@@ -75,15 +75,6 @@ ec_level( ec_type_t ec ) {
return 3;
}
void
cbl_enabled_exception_t::dump( int i ) const {
cbl_message(2, "cbl_enabled_exception_t: %2d {%s, %s, %zu}",
i,
location? "location" : " none",
ec_type_str(ec),
file );
}
void
cbl_enabled_exceptions_t::dump() const {
extern int yydebug;

View File

@@ -77,7 +77,7 @@ class exception_turn_t {
bool add_exception( ec_type_t type, const filelist_t& files = filelist_t() ) {
ec_disposition_t disposition = ec_type_disposition(type);
if( disposition != ec_implemented(disposition) ) {
cbl_unimplementedw("CDF: exception '%s'", ec_type_str(type));
cbl_unimplementedw(EcUnknownW, "exception %qs", ec_type_str(type));
}
auto elem = exceptions.find(type);
if( elem != exceptions.end() ) return false; // cannot add twice

View File

@@ -1,4 +1,4 @@
.ds lang COBOL
.ds lang COBOL
.ds gcobol GCC\ \*[lang]\ Front-end
.ds isostd ISO/IEC 1989:2023
.Dd \& February 2025
@@ -31,12 +31,58 @@
.Op Fl preprocess Ar preprocess-filter
.Op Fl fflex-debug
.Op Fl fyacc-debug
.\" warnings
.Op Fl Wno-apply-commit
.Op Fl Wno-file-code-set
.Op Fl Wno-high-order-bit
.Op Fl Wno-bad-line-directive
.Op Fl Wno-bad-numeric
.Op Fl Wno-binary-long-long
.Op Fl Wno-call-giving
.Op Fl Wno-cdf-dollar
.Op Fl Wno-cdf-invalid-parameter
.Op Fl Wno-cdf-name-not-found
.Op Fl Wno-cobol-eject
.Op Fl Wno-cobol-resume
.Op Fl Wno-cobol-volatile
.Op Fl Wno-comp-6
.Op Fl Wno-comp-x
.Op Fl Wno-copybook-found
.Op Fl Wno-ec-unknown
.Op Fl Wno-entry-convention
.Op Fl Wno-iconv-error
.Op Fl Wno-include-file-found
.Op Fl Wno-include-file-not-found
.Op Fl Wno-inspect-trailing
.Op Fl Wno-length-of
.Op Fl Wno-level-1-occurs
.Op Fl Wno-level-78
.Op Fl Wno-level-78-defined
.Op Fl Wno-literal-concat
.Op Fl Wno-locale-error
.Op Fl Wno-move-corresponding
.Op Fl Wno-move-pointer
.Op Fl Wno-nllanginfo-error
.Op Fl Wno-operator-space
.Op Fl Wno-preprocessor-error
.Op Fl Wno-procedure-not-found
.Op Fl Wno-procedure-pointer
.Op Fl Wno-replace-error
.Op Fl Wno-returning-number
.Op Fl Wno-segment-error
.Op Fl Wno-segment-negative
.Op Fl Wno-stop-number
.Op Fl Wno-stray-indicator
.Op Fl Wno-usage-typename
.Op Fl Wno-recording-mode
.Op Fl Wno-set-locale-to
.Op Fl Wno-set-to-locale
.Ar filename Op ...
.
.Sh DESCRIPTION
.Nm
compiles \*[lang] source code to object code, and optionally produces an
executable binary or shared object. As a GCC component, it accepts
compiles \*[lang] source code to object code, and optionally produces
an executable binary or shared object. As a GCC component, it accepts
all options that affect code-generation and linking. Options specific
to \*[lang] are listed below.
.Bl -tag -width "\0\0debug"
@@ -283,30 +329,66 @@ because its value is determined at run time.
By default,
.Nm
accepts \*[lang] syntax as defined by \*[isostd], with some
extensions for backward compatibility with COBOL-85. To make the
compiler more generally useful, some additional syntax is supported by
this option.
.Pp
The value of
extensions for backward compatibility with COBOL-85. Additional syntax is supported with this option. The value of
.Ar dialect-name
may be
.Bl -tag -compact
.Bl -tag
.It ibm
to indicate IBM COBOL 6.3 syntax, specifically
.D1 STOP <number>.
.It gnu
to indicate GnuCOBOL syntax
.It mf
to indicate MicroFocus syntax, specifically
.Sy LEVEL 78
constants.
to indicate IBM COBOL 6.4 syntax:
.Bl -bullet -compact
.It
.Sy EJECT
.It
.Sy EQUAL
as assignment operator
.It
.Sy "LENGTH OF"
.It
.Sy "PROCEDURE POINTER"
.It
.Sy SECTION
segment
.It
.Sy STOP
<number>
.It
.Sy VOLATILE
.El
.It gnu
to indicate GnuCOBOL syntax, generally compatible with MicroFocus.
.It mf
to indicate MicroFocus syntax:
.Bl -bullet -compact
.It
.Sy BINARY-LONG-LONG
.It
.Sy CALL ... GIVING
.It
.Sy CDF \[Do]IF
.It
.Sy COMPUTATIONAL-6
.It
.Sy COMPUTATIONAL
used with
.Sy PICTURE X
.It
.Sy INSPECT ... TRAILING
.It
.Sy OCCURS
at
.Sy "LEVEL 01"
.It
.Sy LEVEL 78
constants
.It
.Sy MOVE POINTER
.It
.Sy RETURNING
<number>
.It
.Sy USAGE IS TYPENAME
.El
.El
.Pp
Only a few such non-standard constructs are accepted, and
.Nm
makes no claim to emulate other compilers. But to the extent that a
feature is popular but nonstandard, this option provides a way to
support it, or add it.
.
.It Fl include Ar filename
Process
@@ -371,13 +453,117 @@ The
should return a zero exit status, indicating success. If it returns a
nonzero exit status, an error is reported and the compiler is not
invoked.
.
.It Fl fflex-debug Ns Li , Fl fyacc-debug
produce messages useful for compiler development. The
.Fl fflex-debug
option prints the tokenized input stream. The
.Fl fyacc-debug
option shows the shift and reduce actions taken by the parser.
.El
.Ss Diagnostic Messages
.Pp
Many warning options can be used to convert error messages to
warnings, or to suppress messages related to \*[lang] dialects. The
user may mix and match. A group of features may be enabled by
indicating a dialect (or more than one dialect) and individual
features may be enabled as a warning, or error, or suppressed.
.Bl -tag -width Wno-cdf-name-not-found\0\0 -compact
.It Fl Wno-apply-commit
Warn if APPLY COMMIT is used.
.It Fl Wno-bad-line-directive
Warn if malformed %<#line%> directive is encountered.
.It Fl Wno-binary-long-long
Warn if BINARY-LONG-LONG is used.
.It Fl Wno-call_giving
Warn if CALL ... GIVING is used.
.It Fl Wno-cdf-dollar
Warn if CDF \[Do]IF is used.
.It Fl Wno-comp-6
Warn if COMPUTATIONAL-6 is used.
.It Fl Wno-comp-x
Warn if COMPUTATIONAL is used with PICTURE X.
.It Fl Wno-file-code-set
Warn if FILE CODE SET is used.
.It Fl Wno-inspect-trailing
Warn if INSPECT ... TRAILING is used.
.It Fl Wno-level-1-occurs
Warn if Level 01 is used with OCCURS.
.It Fl Wno-level-78-defined
Warn if CDF defines Level 78 constant.
.It Fl Wno-move-pointer
Warn if MOVE POINTER is used.
.It Fl Wno-returning-number
Warn if RETURNING <number> is used.
.It Fl Wno-usage-typename
Warn if USAGE IS TYPENAME is used.
.It Fl Wno-bad-numeric
Warn if numeric string is invalid.
.It Fl Wno-cdf-invalid-parameter
Warn if referenced CDF PARAMETER is not defined.
.It Fl Wno-cdf-name-not-found
Warn if referenced CDF name is not defined.
.It Fl Wno-cobol-eject
Warn if IBM-style EJECT is used (instead of error).
.It Fl Wno-cobol-resume
Warn if ISO RESUME is used with \-dialect ibm (instead of error).
.It Fl Wno-cobol-volatile
Warn if VOLATILE is used (instead of error if -dialect ibm).
.It Fl Wno-copybook-found
Print message when copybook is processed.
.It Fl Wno-ec-unknown
Warn if unimplemented/unknown exception condition is referenced.
.It Fl Wno-entry-convention
Print message when ENTRY CONVENTION is specified.
.It Fl Wno-high-order-bit
Warn if HIGH-ORDER-LEFT HIGH-ORDER-RIGHT is used.
.It Fl Wno-include-file-found
Print message when include file is processed.
.It Fl Wno-length-of
Warn if LENGTH OF is used.
.It Fl Wno-level-78
Warn if Level 78 is used.
.It Fl Wno-literal-concat
Warn if concatenated literals use different encodings.
.It Fl Wno-locale-error
Warn if locale(3) fails.
.It Fl Wno-move-corresponding
Warn if COBOL MOVE has no corresponding fields.
.It Fl Wno-nllanginfo-error
Warn if nlanglanginfo(3) fails.
.It Fl Wno-recording-mode
Warn if RECORDING MODE is used.
.It Fl Wno-segment
Warn if SECTION segments are used.
.It Fl Wno-set-locale-to
Warn if SET LOCALE ... TO is used.
.It Fl Wno-set-to-locale
Warn if SET ... TO LOCALE is used.
.
`.\" convert errors to warnings
Warn if a line directive is malformed (instead of error).
.It Fl Wno-iconv-error
Warn if iconv(3) cannot convert between encodings (instead of error).
.It Fl Wno-include-file-not-found
Warn if include file is not found (instead of error).
.It Fl Wno-operator-space
Warn if relational operator not followed by space (instead of error).
.It Fl Wno-preprocessor-error
Warn if a preprocessor fails (instead of error).
.It Fl Wno-procedure-pointer
Warn if PROCEDURE POINTER is used.
.It Fl Wno-procedure-not-found
Warn if a referenced procedure is not found (instead of error).
.It Fl Wno-replace-error
Warn if REPLACE cannot be processed (instead of error).
.It Fl Wno-segment-error
Warn if a SEGMENT section is invalid (instead of error).
.It Fl Wno-segment-negative
Warn if a SEGMENT range is negative (instead of error).
.It Fl Wno-stop-number
Warn if IBM-style STOP <number> is used (instead of error).
.It Fl Wno-stray-indicator
Warn if indicator column has no recognized meaning (instead of error).
.El
.
.Sh COMPILATION SCENARIOS

View File

@@ -4002,12 +4002,11 @@ public:
dangling.insert(index_of(label));
}
}
bool lay( const cbl_label_t *label ) {
void lay( const cbl_label_t *label ) {
auto ok = lain.insert(index_of(label));
if( ok.second ) {
dangling.erase(index_of(label));
}
return true;
}
bool vet() const { // be always agreeable, for now.
return dangling.empty();
@@ -8222,17 +8221,7 @@ parser_label_label(struct cbl_label_t *label)
CHECK_LABEL(label);
#if 1
// At the present time, label_verify.lay is returning true, so I edited
// out the if( !... ) to quiet cppcheck
label_verify.lay(label);
#else
if( ! label_verify.lay(label) )
{
yywarn("%s: label %qs already exists", __func__, label->name);
gcc_unreachable();
}
#endif
if(strcmp(label->name, "_end_declaratives") == 0 )
{

View File

@@ -523,10 +523,9 @@ gg_find_field_in_struct(const tree base, const char *field_name)
if( !field_decl )
{
yywarn("Somebody asked for the field %s.%s, which does not exist",
cbl_internal_error("Somebody asked for the field %s.%s, which does not exist",
IDENTIFIER_POINTER(DECL_NAME(base)),
field_name);
gcc_unreachable();
}
return field_decl;
@@ -2153,17 +2152,15 @@ gg_printf(const char *format_string, ...)
{
if(nargs >= ARG_LIMIT)
{
yywarn("You *must* be joking");
gcc_unreachable();
cbl_internal_error("You *must* be joking");
}
if( TREE_CODE(arg) >= NUM_TREE_CODES)
{
// Warning: This test is not completely reliable, because a garbage
// byte could have a valid TREE_CODE. But it does help.
yywarn("You forgot to put a %<NULL_TREE%> at the end of a "
"%<gg_printf()%> again");
gcc_unreachable();
cbl_internal_error("You forgot to put a %<NULL_TREE%> at the end of a "
"%<gg_printf()%> again");
}
args[nargs++] = arg;
@@ -2208,8 +2205,7 @@ gg_fprintf(tree fd, int nargs, const char *format_string, ...)
{
if(argc >= ARG_LIMIT)
{
yywarn("You *must* be joking");
gcc_unreachable();
cbl_internal_error("You *must* be joking");
}
args[argc++] = arg;
@@ -2587,9 +2583,8 @@ gg_define_function( tree return_type,
{
// Warning: This test is not completely reliable, because a garbage
// byte could have a valid TREE_CODE. But it does help.
yywarn("You forgot to put a %<NULL_TREE%> at the end of a "
cbl_internal_error("You forgot to put a %<NULL_TREE%> at the end of a "
"%<gg_define_function()%> again");
gcc_unreachable();
}
const char *name = va_arg(params, const char *);
@@ -2599,8 +2594,7 @@ gg_define_function( tree return_type,
nparams += 1;
if(nparams > ARG_LIMIT)
{
yywarn("%d parameters? Really? Are you insane?", ARG_LIMIT+1);
gcc_unreachable();
cbl_internal_error("%d parameters? Really? Are you insane?", ARG_LIMIT+1);
}
}
va_end(params);
@@ -2748,9 +2742,8 @@ gg_get_function_decl(tree return_type, const char *funcname, ...)
{
// Warning: This test is not completely reliable, because a garbage
// byte could have a valid TREE_CODE. But it does help.
yywarn("You forgot to put a %<NULL_TREE%> at the end of a "
cbl_internal_error("You forgot to put a %<NULL_TREE%> at the end of a "
"%<gg_define_function()%> again");
gcc_unreachable();
}
const char *name = va_arg(params, const char *);
@@ -2760,9 +2753,8 @@ gg_get_function_decl(tree return_type, const char *funcname, ...)
nparams += 1;
if(nparams > ARG_LIMIT)
{
yywarn("%d parameters? Really? Are you insane?",
cbl_internal_error("%d parameters? Really? Are you insane?",
ARG_LIMIT+1);
gcc_unreachable();
}
}
va_end(params);
@@ -3040,8 +3032,7 @@ gg_call_expr(tree return_type, const char *function_name, ...)
{
if(nargs >= ARG_LIMIT)
{
yywarn("You *must* be joking");
gcc_unreachable();
cbl_internal_error("You *must* be joking");
}
tree arg = va_arg(ap, tree);
@@ -3096,8 +3087,7 @@ gg_call(tree return_type, const char *function_name, ...)
{
if(nargs >= ARG_LIMIT)
{
yywarn("You *must* be joking");
gcc_unreachable();
cbl_internal_error("You *must* be joking");
}
tree arg = va_arg(ap, tree);

View File

@@ -42,6 +42,52 @@
"%{preprocess} "
"%{dialect} "
"%{include} "
"%{Wno-apply-commit} "
"%{Wno-file-code-set} "
"%{Wno-high-order-bit} "
"%{Wno-bad-line-directive} "
"%{Wno-bad-numeric} "
"%{Wno-binary-long-long} "
"%{Wno-call-giving} "
"%{Wno-cdf-dollar} "
"%{Wno-cdf-invalid-parameter} "
"%{Wno-cdf-name-not-found} "
"%{Wno-cobol-eject} "
"%{Wno-cobol-resume} "
"%{Wno-cobol-volatile} "
"%{Wno-comp-6} "
"%{Wno-comp-x} "
"%{Wno-copybook-found} "
"%{Wno-ec-unknown} "
"%{Wno-entry-convention} "
"%{Wno-iconv-error} "
"%{Wno-include-file-found} "
"%{Wno-include-file-not-found} "
"%{Wno-inspect-trailing} "
"%{Wno-length-of} "
"%{Wno-level-1-occurs} "
"%{Wno-level-78} "
"%{Wno-level-78-defined} "
"%{Wno-literal-concat} "
"%{Wno-locale-error} "
"%{Wno-move-corresponding} "
"%{Wno-move-pointer} "
"%{Wno-nllanginfo-error} "
"%{Wno-operator-space} "
"%{Wno-preprocessor-error} "
"%{Wno-procedure-not-found} "
"%{Wno-procedure-pointer} "
"%{Wno-replace-error} "
"%{Wno-returning-number} "
"%{Wno-segment-error} "
"%{Wno-segment-negative} "
"%{Wno-stop-number} "
"%{Wno-stray-indicator} "
"%{Wno-usage-typename} "
"%{Wno-recording-mode} "
"%{Wno-set-locale-to} "
"%{Wno-set-to-locale} "
"%{nomain} "
"%{!fsyntax-only:%(invoke_as)} "
, 0, 0, 0},

View File

@@ -51,16 +51,19 @@ Enum
Name(dialect_type) Type(int) UnknownError(Unrecognized COBOL dialect name: %qs)
EnumValue
Enum(dialect_type) String(gcc) Value(0x04) Canonical
Enum(dialect_type) String(iso) Value(0x100)
EnumValue
Enum(dialect_type) String(ibm) Value(0x01)
Enum(dialect_type) String(gcc) Value(0x01) Canonical
EnumValue
Enum(dialect_type) String(mf) Value(0x02)
Enum(dialect_type) String(ibm) Value(0x02)
EnumValue
Enum(dialect_type) String(gnu) Value(0x04)
Enum(dialect_type) String(mf) Value(0x04)
EnumValue
Enum(dialect_type) String(gnu) Value(0x08)
fcobol-exceptions
Cobol Joined Separate Var(cobol_exceptions)
@@ -70,6 +73,249 @@ copyext
Cobol Joined Separate Var(cobol_copyext) Init(0)
Define alternative implicit copybook filename extension
;; warnings
; Par78CdfDefinedW
Wlevel-78-defined
Cobol Warning Var(level_78_defined, 1) Init(1)
Warn if CDF defines Level 78 constant
; MfBinaryLongLong
Wbinary-long-long
Cobol Warning Var(binary_long_long, 1) Init(1)
Warn if BINARY-LONG-LONG is used
; MfCallGiving
Wcall-giving
Cobol Warning Var(call_giving, 1) Init(1)
Warn if CALL ... GIVING is used
; MfCdfDollar
Wcdf-dollar
Cobol Warning Var(cdf_dollar, 1) Init(1)
Warn if CDF %<$IF%> is used
; MfComp6
Wcomp-6
Cobol Warning Var(comp_6, 1) Init(1)
Warn if COMPUTATIONAL-6 is used
; MfCompX
Wcomp-x
Cobol Warning Var(comp_x, 1) Init(1)
Warn if COMPUTATIONAL is used with PICTURE X
; MfTrailing
Winspect-trailing
Cobol Warning Var(inspect_trailing, 1) Init(1)
Warn if INSPECT ... TRAILING is used
; MfLevel_1_Occurs
Wlevel-1-occurs
Cobol Warning Var(level_1_occurs, 1) Init(1)
Warn if Level 01 is used with OCCURS
; MfLevel78
Wlevel-78
Cobol Warning Var(level_78, 1) Init(1)
Warn if Level 78 is used
; MfMovePointer
Wmove-pointer
Cobol Warning Var(move_pointer, 1) Init(1)
Warn if MOVE POINTER is used
; MfReturningNum
Wreturning-number
Cobol Warning Var(returning_number, 1) Init(1)
Warn if RETURNING <number> is used
; MfUsageTypename
Wusage-typename
Cobol Warning Var(usage_typename, 1) Init(1)
Warn if USAGE IS TYPENAME is used
; ParNumstrW
Wbad-numeric
Cobol Warning Var(bad_numeric, 1) Init(1)
Warn if numeric string is invalid
; CdfParameterW
Wcdf-invalid-parameter
Cobol Warning Var(cdf_invalid_parameter, 1) Init(1)
Warn if referenced CDF PARAMETER is not defined
; CdfNotFoundW
Wcdf-name-not-found
Cobol Warning Var(cdf_name_not_found, 1) Init(1)
Warn if referenced CDF name is not defined
; LexInputN
Wcopybook-found
Cobol Warning Var(copybook_found, 1) Init(1)
Print message when copybook is processed
; EcUnknownW
Wec-unknown
Cobol Warning Var(ec_unknown, 1) Init(1)
Warn if unimplemented/unknown exception condition is referenced
; ParInfoI
Wentry-convention
Cobol Warning Var(entry_convention, 1) Init(1)
Print message when ENTRY CONVENTION is specified
; LexIncludeOkN
Winclude-file-found
Cobol Warning Var(include_file_found, 1) Init(1)
Print message when include file is processed
; ParLiteral2W
Wliteral-concat
Cobol Warning Var(literal_concat, 1) Init(1)
Warn if concatenated literals use different encodings
; ParLocaleW
Wlocale-error
Cobol Warning Var(locale_error, 1) Init(1)
Warn if locale(3) fails
; ParNoCorrespondingW
Wmove-corresponding
Cobol Warning Var(warn_corresponding, 1) Init(1)
Warn if COBOL MOVE has no corresponding fields.
; ParLangInfoW
Wnllanginfo-error
Cobol Warning Var(nllanginfo_error, 1) Init(1)
Warn if nlanglanginfo(3) fails
; IbmLengthOf
Wlength-of
Cobol Warning Var(cobol_length_of, 1) Init(1)
Warn if LENGTH OF is used
; IbmProcedurePointer
Wprocedure-pointer
Cobol Warning Var(procedure_pointer, 1) Init(1)
Warn if PROCEDURE POINTER is used
; IbmSectionSegmentW
Wsegment
Cobol Warning Var(cobol_segment, 1) Init(1)
Warn if SECTION segments are used
; IsoResume
Wcobol-resume
Cobol Warning Var(cobol_resume, 1) Init(1)
Warn if resume is used (instead of error for IBM)
;; unimplemented syntax
; SynApplyCommit
Wapply-commit
Cobol Warning Var(apply_commit, 1) Init(1)
Warn if APPLY COMMIT is used
; SynHighOrderBit
Whigh-order-bit
Cobol Warning Var(high_order_bit, 1) Init(1)
Warn if HIGH-ORDER-LEFT HIGH-ORDER-RIGHT is used
; SynFileCodeSet
Wfile-code-set
Cobol Warning Var(file_code_set, 1) Init(1)
Warn if FILE CODE SET is used
; SynRecordingMode
Wrecording-mode
Cobol Warning Var(recording_mode, 1) Init(1)
Warn if RECORDING MODE is used
; SynSetLocaleTo
Wset-locale-to
Cobol Warning Var(set_locale_to, 1) Init(1)
Warn if SET LOCALE ... TO is used
; SynSetToLocale
Wset-to-locale
Cobol Warning Var(set_to_locale, 1) Init(1)
Warn if SET ... TO LOCALE is used
;; errors to warnings
; LexLineE
Wbad-line-directive
Cobol Warning Var(bad_line_directive, 1) Init(1)
Warn if a line directive is malformed (instead of error)
; IbmEqualAssignE
Wequal-assign
Cobol Warning Var(equal_assign, 1) Init(1)
Warn if EQUAL used as assignment operator (instead of error)
; ParIconvE
Wiconv-error
Cobol Warning Var(iconv_error, 1) Init(1)
Warn if iconv(3) cannot convert between encodings (instead of error)
; LexIncludeE
Winclude-file-not-found
Cobol Warning Var(include_file_not_found, 1) Init(1)
Warn if include file is not found (instead of error)
; LexPreprocessE
Wpreprocessor-error
Cobol Warning Var(preprocessor_error, 1) Init(1)
Warn if a preprocessor fails (instead of error)
; ParUnresolvedProcE
Wprocedure-not-found
Cobol Warning Var(procedure_not_found, 1) Init(1)
Warn if a referenced procedure is not found (instead of error)
; LexReplaceE
Wreplace-error
Cobol Warning Var(replace_error, 1) Init(1)
Warn if REPLACE cannot be processed (instead of error)
; IbmSectionRangeE
Wsegment-error
Cobol Warning Var(segment_error, 1) Init(1)
Warn if a SEGMENT section is invalid (instead of error)
; IbmSectionNegE
Wsegment-negative
Cobol Warning Var(segment_negative, 1) Init(1)
Warn if a SEGMENT range is negative (instead of error)
; LexIndicatorE
Wstray-indicator
Cobol Warning Var(stray_indicator, 1) Init(1)
Warn if indicator column has no recognized meaning (instead of error)
; LexSeparatorE
Woperator-space
Cobol Warning Var(operator_space, 1) Init(1)
Warn if relational operator not followed by space (instead of error)
; IbmEjectE
Wcobol-eject
Cobol Warning Var(cobol_eject, 1) Init(1)
Warn if IBM-style EJECT is used (instead of error)
; IbmStopNumber
Wstop-number
Cobol Warning Var(stop_number, 1) Init(1)
Warn if IBM-style STOP <number> is used (instead of error)
; IbmVolatileE
Wcobol-volatile
Cobol Warning Var(cobol_volatile, 1) Init(1)
Warn if VOLATILE is used (instead of error if -dialect ibm)
;; end error-suppression options
fdefaultbyte
Cobol RejectNegative Joined Separate UInteger Var(cobol_default_byte)
Set Working-Storage data items to the supplied value

View File

@@ -681,7 +681,8 @@ parse_replacing_term( const char *stmt, const char *estmt ) {
}
if( extraneous_replacing ) {
update_yylloc( cm[0], cm[8] );
yywarn("syntax error: invalid '%.*s'", cm[8].length(), cm[8].first);
cbl_message(LexReplaceE, "syntax error: invalid '%.*s'",
cm[8].length(), cm[8].first);
output.matched = false;
return output;
}
@@ -797,11 +798,11 @@ parse_replacing_pair( const char *stmt, const char *estmt ) {
}
}
if( pair.stmt.p ) {
yywarn("CDF syntax error '%.*s'", (int)pair.stmt.size(), pair.stmt.p);
cbl_message(LexReplaceE, "LEX syntax error '%.*s'", (int)pair.stmt.size(), pair.stmt.p);
}
else {
// This eliminated a compiler warning about "format-overflow"
yywarn("CDF syntax error");
cbl_message(LexReplaceE, "LEX syntax error");
}
pair.stmt = span_t(size_t(0), stmt);
pair.replace = replace_t();
@@ -1466,7 +1467,8 @@ preprocess_filter_add( const char input[] ) {
auto filename = find_filter(filter.c_str());
if( !filename ) {
yywarn("preprocessor '%s/%s' not found", getcwd(NULL, 0), filter.c_str());
cbl_message(LexPreprocessE, "preprocessor '%s/%s' not found",
getcwd(NULL, 0), filter.c_str());
return false;
}
preprocessor_filters.push_back( std::make_pair(xstrdup(filename), options) );
@@ -1477,22 +1479,22 @@ void
cdftext::echo_input( int input, const char filename[] ) {
int fd;
if( -1 == (fd = dup(input)) ) {
yywarn( "could not open preprocessed file %s to echo to standard output",
filename );
cbl_message(LexPreprocessE, "could not open preprocessed file "
"%s to echo to standard output", filename );
return;
}
auto mfile = map_file(fd);
if( -1 == write(STDOUT_FILENO, mfile.data, mfile.size()) ) {
yywarn( "could not write preprocessed file %s to standard output",
cbl_message(LexPreprocessE, "could not write preprocessed file %s to standard output",
filename );
}
if( -1 == munmap(mfile.data, mfile.size()) ) {
yywarn( "could not release mapped file" );
cbl_message(LexPreprocessE, "could not release mapped file" );
}
if( -1 == close(fd) ) {
yywarn( "could not close mapped file" );
cbl_message(LexPreprocessE, "could not close mapped file" );
}
}
@@ -1515,7 +1517,7 @@ cdftext::lex_open( const char filename[] ) {
// Process any files supplied by the -include command-line option.
for( auto name : included_files ) {
if( -1 == (input = open(name, O_RDONLY)) ) {
yyerrorvl(1, "", "cannot open -include file %s", name);
cbl_message(LexIncludeE, "cannot open %<-include%> file %qs", name);
continue;
}
cobol_filename(name, inode_of(input));
@@ -1569,7 +1571,7 @@ cdftext::lex_open( const char filename[] ) {
}
int erc;
if( -1 == (erc = execv(filter, argv.data())) ) {
yywarn("could not execute %s", filter);
cbl_message(LexPreprocessE, "could not execute %s", filter);
}
_exit(erc);
}
@@ -1588,7 +1590,7 @@ cdftext::lex_open( const char filename[] ) {
filter, status);
}
}
yywarn( "applied %s", filter );
cbl_message(LexIncludeOkN, "applied %s", filter );
}
return fdopen( output, "r");
@@ -1604,7 +1606,7 @@ cdftext::open_input( const char filename[] ) {
verbose_file_reader = NULL != getenv("GCOBOL_TEMPDIR");
if( verbose_file_reader ) {
yywarn("verbose: opening %s for input", filename);
cbl_message(LexInputN, "verbose: opening %s for input", filename);
}
return fd;
}

388
gcc/cobol/messages.cc Normal file
View File

@@ -0,0 +1,388 @@
/*
* Copyright (c) 2021-2025 Symas Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the Symas Corporation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Define a table of diagnositic messages, each uniquely identified and
* grouped into dialects. The user can select on the command line which
* ones are in effect.
*/
#include <cobol-system.h>
#include <coretypes.h>
#include <tree.h>
#undef yy_flex_debug
#include <langinfo.h>
#include <coretypes.h>
#include <version.h>
#include <demangle.h>
#include <intl.h>
#include <backtrace.h>
#include <diagnostic.h>
#include <opts.h>
#include "util.h"
#include "cbldiag.h"
#include "cdfval.h"
#include "lexio.h"
#include "../../libgcobol/ec.h"
#include "../../libgcobol/common-defs.h"
#include "symbols.h"
#include "inspect.h"
#include "../../libgcobol/io.h"
#include "genapi.h"
#include "genutil.h"
#include "../../libgcobol/charmaps.h"
/*
* As of now, every diagnositc has one id, one message, one kind, and is
* associated with "one" dialect. The dialect could be ORed. If it is, that
* means among the dialects it belongs to, it is always of the same kind.
*
* The diagnositic mask in force during compilation may include/exclude
* features based on their associated dialect and/or by id. It may stipulate
* that a warning is treated as an error, too, but that's up the diagnostic
* framework. If a feature requires a dialect and is not specifically enabled,
* gcobol emits of message of the associated kind, and names the dialect
* required.
*/
struct cbl_diag_t {
cbl_diag_id_t id;
cbl_name_t option;
diagnostics::kind kind;
cbl_dialect_t dialect;
explicit cbl_diag_t( cbl_diag_id_t id )
: id(id), option(""), kind(diagnostics::kind::ignored), dialect(dialect_gcc_e)
{}
cbl_diag_t( cbl_diag_id_t id,
const char option[],
diagnostics::kind kind,
cbl_dialect_t dialect = dialect_iso_e )
: id(id), option(""), kind(kind), dialect(dialect)
{
gcc_assert(strlen(option) < sizeof(this->option));
strcpy(this->option, option);
}
bool operator<( const cbl_diag_t& that ) const {
return id < that.id;
}
};
/*
* Initially, errors and warnings are set per the default, dialect gcc. If the
* user chooses dialect iso, all dialect-enabled features are turned into
* errors. If the user selects a more generous dialect, features associated
* with it are set to be ignored.
*
* Individual features may also be suppressed, and all warnings may be elevated
* to errors.
*/
const static auto dialect_mf_gnu = cbl_dialect_t(dialect_mf_e | dialect_gnu_e);
const static auto dialect_ibm_mf_gnu = cbl_dialect_t(dialect_ibm_e |
dialect_mf_e |
dialect_gnu_e);
std::set<cbl_diag_t> cbl_diagnostics {
{ CdfNotFoundW, "-Wcdf-name-not-found", diagnostics::kind::warning },
{ CdfParameterW, "-Wcdf-invalid-parameter", diagnostics::kind::warning },
{ EcUnknownW, "-Wec-unknown", diagnostics::kind::warning },
{ IbmEjectE, "-Wcobol-eject", diagnostics::kind::error, dialect_ibm_e },
{ IbmLengthOf, "-Wlength-of", diagnostics::kind::error, dialect_ibm_mf_gnu },
{ IbmEqualAssignE, "-Wequal-assign", diagnostics::kind::error, dialect_ibm_e },
{ IbmProcedurePointer, "-Wprocedure-pointer", diagnostics::kind::error, dialect_ibm_mf_gnu },
{ IbmSectionNegE, "-Wsegment-negative", diagnostics::kind::error, dialect_ibm_e },
{ IbmSectionRangeE, "-Wsegment-error", diagnostics::kind::error, dialect_ibm_e },
{ IbmSectionSegmentW, "-Wsegment", diagnostics::kind::warning, dialect_ibm_e },
{ IbmStopNumber, "-Wstop-number", diagnostics::kind::error, dialect_ibm_e },
{ IbmVolatileE, "-Wcobol-volatile", diagnostics::kind::error, dialect_ibm_e },
{ IbmVolatileW, "-Wcobol-volatile", diagnostics::kind::warning, dialect_ibm_e },
// RESUME not supported by IBM
{ IsoResume, "-Wcobol-resume", diagnostics::kind::error, dialect_ibm_e },
{ MfBinaryLongLong, "-Wbinary-long-long", diagnostics::kind::error, dialect_mf_gnu },
{ MfCallGiving, "-Wcall-giving", diagnostics::kind::error, dialect_mf_gnu },
{ MfCdfDollar, "-Wcdf-dollar", diagnostics::kind::error, dialect_mf_gnu },
{ MfComp6, "-Wcomp-6", diagnostics::kind::error, dialect_mf_gnu },
{ MfCompX, "-Wcomp-x", diagnostics::kind::error, dialect_mf_gnu },
{ MfLevel_1_Occurs, "Wlevel-1-occurs", diagnostics::kind::error, dialect_mf_gnu },
{ MfLevel78, "-Wlevel-78", diagnostics::kind::error, dialect_mf_gnu },
{ MfMovePointer, "-Wmove-pointer", diagnostics::kind::error, dialect_mf_gnu },
{ MfReturningNum, "-Wreturning-number", diagnostics::kind::error, dialect_mf_gnu },
{ MfUsageTypename, "-Wusage-typename", diagnostics::kind::error, dialect_mf_gnu },
{ MfTrailing, "-Winspect-trailing", diagnostics::kind::error, dialect_mf_gnu },
{ LexIncludeE, "-Winclude-file-not-found", diagnostics::kind::error },
{ LexIncludeOkN, "-Winclude-file-found", diagnostics::kind::note },
{ LexIndicatorE, "-Wstray-indicator", diagnostics::kind::error },
{ LexInputN, "-Wcopybook-found", diagnostics::kind::note },
{ LexLineE, "-Wbad-line-directive", diagnostics::kind::error },
{ LexPreprocessE, "-Wpreprocessor-error", diagnostics::kind::error },
{ LexReplaceE, "-Wreplace-error", diagnostics::kind::error },
// mf and gnu do not require whitespace after relational operators
{ LexSeparatorE, "-Woperator-space", diagnostics::kind::error, dialect_mf_gnu },
{ Par78CdfDefinedW, "-Wlevel-78-defined", diagnostics::kind::warning },
{ ParIconvE, "-Wiconv-error", diagnostics::kind::note },
{ ParInfoI, "-Wentry-convention", diagnostics::kind::note },
{ ParLangInfoW, "-Wnllanginfo-error", diagnostics::kind::warning },
{ ParLiteral2W, "-Wliteral-concat", diagnostics::kind::warning },
{ ParLocaleW, "-Wlocale-error", diagnostics::kind::warning },
{ ParNoCorrespondingW, "-Wmove-corresponding", diagnostics::kind::warning },
{ ParNumstrW, "-Wbad-numeric", diagnostics::kind::warning },
{ ParUnresolvedProcE, "-Wprocedure-not-found", diagnostics::kind::error },
// unimplmeneted syntax warnings
{ SynApplyCommit, "-Wapply-commit", diagnostics::kind::warning },
{ SynFileCodeSet, "-Wfile-code-set", diagnostics::kind::warning },
{ SynHighOrderBit, "-Whigh-order-bit", diagnostics::kind::warning },
{ SynRecordingMode, "-Wrecording-mode", diagnostics::kind::warning },
{ SynSetLocaleTo, "-Wset-locale-to", diagnostics::kind::warning },
{ SynSetToLocale, "-Wset-to-locale", diagnostics::kind::warning },
};
static struct set_verify {
set_verify() {
gcc_assert(cbl_diagnostics.size() == DiagDiagDiag);
auto p = std::find_if(cbl_diagnostics.begin(), cbl_diagnostics.end(),
[]( const auto& diag ) {
return '?' == cbl_dialect_str(diag.dialect)[0];
} );
if( p != cbl_diagnostics.end() ) {
fprintf(stderr, "unregconized dialect '%04x (~%04x)'", p->dialect, ~p->dialect);
}
gcc_assert( std::none_of(cbl_diagnostics.begin(), cbl_diagnostics.end(),
[]( const auto& diag ) {
return '?' == cbl_dialect_str(diag.dialect)[0];
} ) );
}
} verify_consistent_message_count;
static inline diagnostics::kind
kind_of( cbl_diag_id_t id ) {
auto diag = cbl_diagnostics.find(cbl_diag_t(id));
if( diag != cbl_diagnostics.end() ) {
return diag->kind;
}
return diagnostics::kind::ice;
}
diagnostics::kind
cbl_diagnostic_kind( cbl_diag_id_t id ) {
return kind_of(id);
}
bool
cbl_diagnostic_kind( cbl_diag_id_t id, diagnostics::kind kind ) {
auto p = cbl_diagnostics.find( cbl_diag_t{id} );
if( p != cbl_diagnostics.end() ) {
auto diag(*p);
diag.kind = kind;
cbl_diagnostics.erase(p);
return cbl_diagnostics.insert(diag).second;
}
return false;
}
bool
cbl_diagnostic_kind( cbl_dialect_t dialect, diagnostics::kind kind ) {
bool ok = true;
for( auto diag : cbl_diagnostics ) {
if( diag.dialect == dialect ) {
if( ! cbl_diagnostic_kind(diag.id, kind) ) ok = false;
}
}
return ok;
}
void
cobol_warning( cbl_diag_id_t id, int yn, bool warning_as_error ) {
gcc_assert( 0 <= yn && yn <= 1 );
diagnostics::kind kind = yn?
diagnostics::kind::warning : diagnostics::kind::ignored;
if( warning_as_error ) {
kind = diagnostics::kind::error;
}
cbl_diagnostic_kind(id, kind);
}
static inline const char *
option_of( cbl_diag_id_t id ) {
auto diag = cbl_diagnostics.find(cbl_diag_t(id));
if( diag != cbl_diagnostics.end() && diag->option[0] ) {
return diag->option;
}
return nullptr;
}
const char *
cbl_diagnostic_option( cbl_diag_id_t id ) {
return option_of(id);
}
/*
* This is the general message looker-upper. It determines whether the
* diagnositic is in force, at what level, and the message text, and invokes
* the framework.
*/
extern int yychar;
extern YYLTYPE yylloc;
static const diagnostics::option_id option_zero;
location_t current_token_location();
location_t current_token_location(const location_t& loc);
bool
cbl_message( cbl_diag_id_t id, const char gmsgid[], ... ) {
auto_diagnostic_group d;
const char *option;
char *msg = nullptr;
diagnostics::kind kind = kind_of(id);
if( kind == diagnostics::kind::ignored ) return false;
if( (option = option_of(id)) != nullptr ) {
msg = xasprintf("%s [%s]", gmsgid, option);
gmsgid = msg;
}
va_list ap;
va_start (ap, gmsgid);
auto ret = emit_diagnostic_valist( kind, current_token_location(),
option_zero, gmsgid, &ap );
va_end (ap);
free(msg);
return ret;
}
bool cbl_message( cbl_loc_t loc, cbl_diag_id_t id, const char gmsgid[], ... ) {
class temp_loc_t { // copied from util.cc
location_t orig;
public:
temp_loc_t() : orig(current_token_location()) {
if( yychar < 3 ) return;
gcc_location_set(yylloc); // use lookahead location
}
explicit temp_loc_t( const YYLTYPE& loc) : orig(current_token_location()) {
gcc_location_set(loc);
}
explicit temp_loc_t( const YDFLTYPE& loc) : orig(current_token_location()) {
gcc_location_set(loc);
}
~temp_loc_t() {
if( orig != current_token_location() ) {
current_token_location(orig);
}
}
};
auto_diagnostic_group d;
const char *option;
char *msg = nullptr;
diagnostics::kind kind = kind_of(id);
if( kind == diagnostics::kind::ignored ) return false;
if( (option = option_of(id)) != nullptr ) {
msg = xasprintf("%s [%s]", gmsgid, option);
gmsgid = msg;
}
temp_loc_t looker(loc);
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, current_token_location());
auto ret = emit_diagnostic_valist( kind,
current_token_location(),
option_zero, gmsgid, &ap );
va_end (ap);
free(msg);
return ret;
}
/*
* Verify the dialect associated with the id (and thus term) is covered by the
* dialects currently in effect. If not, issue a standard message of the kind
* defined by the id. Possible combinations:
* dialect required: ok, dialect matches feature dialect
* dialect prohibits not_ok, dialect matches feature ~dialect
*
* If ok is false, then a match means the dialect prohibits the feature.
*/
bool
dialect_ok( const cbl_loc_t& loc, cbl_diag_id_t id, const char term[], bool ok ) {
auto diag = cbl_diagnostics.find(cbl_diag_t(id));
const char *verb = "requires";
if( diag == cbl_diagnostics.end() ) {
gcc_unreachable();
}
if( diag->kind == diagnostics::kind::ignored ) return true;
if( dialect_has(diag->dialect) ) {
if( ok ) {
return true;
} else {
verb = "prohibits";
}
} else {
if( !ok ) return true; // current dialect correctly does not match the feature
}
cbl_message(loc, id, "%qs %s %<-dialect %s%>",
term, verb, cbl_dialect_str(diag->dialect));
return false;
}

View File

@@ -359,7 +359,7 @@ class locale_tgt_t {
NUMED_CR "NUMERIC-EDITED CR picture"
NUMED_DB "NUMERIC-EDITED DB picture"
%token <number> NINEDOT NINES NINEV PIC_P ONES
%token <string> SPACES
%token <string> SPACES EQ "EQUAL"
%token <literal> LITERAL
%token <number> END EOP
%token <string> FILENAME
@@ -477,8 +477,8 @@ class locale_tgt_t {
DOWN DUPLICATES
DYNAMIC
E EBCDIC EC EGCS ENCODING ENTRY ENVIRONMENT EQUAL EVERY
EXAMINE EXHIBIT EXP EXP10 EXTEND EXTERNAL
E EBCDIC EC EGCS ENCODING ENTRY ENVIRONMENT
EVERY EXAMINE EXHIBIT EXP EXP10 EXTEND EXTERNAL
EXCEPTION_FILE "EXCEPTION-FILE"
EXCEPTION_FILE_N "EXCEPTION-FILE-N"
@@ -1130,7 +1130,7 @@ class locale_tgt_t {
DYNAMIC
E EBCDIC EC EGCS ELEMENT
ENTRY ENVIRONMENT EQUAL ERROR EVERY
ENTRY ENVIRONMENT ERROR EVERY
EXAMINE EXCEPTION EXHIBIT EXP EXP10 EXTEND EXTERNAL
EXCEPTION_FILE
@@ -1336,7 +1336,7 @@ class locale_tgt_t {
%left OR
%left AND
%right NOT
%left '<' '>' '=' NE LE GE
%left '<' '>' EQ NE LE GE
%left '-' '+'
%left '*' '/'
%right POW
@@ -1658,21 +1658,25 @@ opt_round: DEFAULT ROUNDED mode is rounded_type[type] {
}
;
opt_entry: ENTRY_CONVENTION is COBOL {
yywarn("ENTRY-CONVENTION IS COBOL, check");
cbl_message(ParInfoI, "ENTRY-CONVENTION IS COBOL");
}
;
opt_binary: FLOAT_BINARY default_kw is HIGH_ORDER_LEFT
{
cbl_unimplementedw("HIGH-ORDER-LEFT was ignored");
cbl_unimplementedw(SynHighOrderBit,
"HIGH-ORDER-LEFT was ignored");
if( ! current.option_binary(cbl_options_t::high_order_left_e) ) {
error_msg(@3, "unable to set %<HIGH_ORDER_LEFT%>");
cbl_message(@3, SynHighOrderBit,
"unable to set %<HIGH_ORDER_LEFT%>");
}
}
| FLOAT_BINARY default_kw is HIGH_ORDER_RIGHT[opt]
{
cbl_unimplementedw("HIGH-ORDER-RIGHT was ignored");
cbl_unimplementedw(SynHighOrderBit,
"HIGH-ORDER-RIGHT was ignored");
if( ! current.option_binary(cbl_options_t::high_order_right_e) ) {
error_msg(@opt, "unable to set HIGH-ORDER-RIGHT");
cbl_message(@opt, SynHighOrderBit,
"unable to set HIGH-ORDER-RIGHT");
}
}
;
@@ -1681,30 +1685,38 @@ default_kw: %empty
;
opt_decimal: FLOAT_DECIMAL default_kw is HIGH_ORDER_LEFT[opt]
{
cbl_unimplementedw("HIGH-ORDER-LEFT was ignored");
cbl_unimplementedw(SynHighOrderBit,
"HIGH-ORDER-LEFT was ignored");
if( ! current.option_decimal(cbl_options_t::high_order_left_e) ) {
error_msg(@opt, "unable to set HIGH-ORDER-LEFT");
cbl_message(@opt, SynHighOrderBit,
"unable to set HIGH-ORDER-LEFT");
}
}
| FLOAT_DECIMAL default_kw is HIGH_ORDER_RIGHT[opt]
{
cbl_unimplementedw("HIGH-ORDER-RIGHT was ignored");
cbl_unimplementedw(SynHighOrderBit,
"HIGH-ORDER-RIGHT was ignored");
if( ! current.option_decimal(cbl_options_t::high_order_right_e) ) {
error_msg(@opt, "unable to set HIGH-ORDER-RIGHT");
cbl_message(@opt, SynHighOrderBit,
"unable to set HIGH-ORDER-RIGHT");
}
}
| FLOAT_DECIMAL default_kw is BINARY_ENCODING[opt]
{
cbl_unimplementedw("BINARY-ENCODING was ignored");
cbl_unimplementedw(SynHighOrderBit,
"BINARY-ENCODING was ignored");
if( ! current.option(cbl_options_t::binary_encoding_e) ) {
error_msg(@opt, "unable to set BINARY-ENCODING option");
cbl_message(@opt, SynHighOrderBit,
"unable to set BINARY-ENCODING option");
}
}
| FLOAT_DECIMAL default_kw is DECIMAL_ENCODING[opt]
{
cbl_unimplementedw("DECIMAL-ENCODING was ignored");
cbl_unimplementedw(SynHighOrderBit,
"DECIMAL-ENCODING was ignored");
if( ! current.option(cbl_options_t::decimal_encoding_e) ) {
error_msg(@opt, "unable to set DECIMAL-ENCODING option");
cbl_message(@opt, SynHighOrderBit,
"unable to set DECIMAL-ENCODING option");
}
}
;
@@ -1888,7 +1900,8 @@ io_control_clause:
}
| APPLY COMMIT on field_list
{
cbl_unimplementedw("I-O-CONTROL APPLY COMMIT");
cbl_unimplementedw(SynApplyCommit,
"I-O-CONTROL APPLY COMMIT ignored");
}
;
area: %empty
@@ -3160,14 +3173,16 @@ fd_clause: record_desc
error_msg(@NAME, "invalid RECORDING MODE '%s'", $NAME);
YYERROR;
}
cbl_unimplementedw("RECORDING MODE was ignored, not defined by ISO 2023");
cbl_unimplementedw(SynRecordingMode,
"RECORDING MODE ignored");
}
| VALUE OF fd_values
| CODESET is codeset_name[codeset] {
auto f = cbl_file_of(symbol_at(file_section_fd));
f->codeset = cbl_file_t::codeset_t($codeset.encoding,
$codeset.isym);
cbl_unimplementedw("sorry, unimplemented CODE-SET");
cbl_unimplementedw(SynFileCodeSet,
"sorry, unimplemented CODE-SET");
}
| CODESET for alphanational is codeset_name[codeset]
{
@@ -3758,24 +3773,23 @@ data_descr1: level_name
| LEVEL78 NAME[name] VALUE is value78[data]
{
if( ! (dialect_mf() || dialect_gnu()) ) {
dialect_error(@1, "level 78", "mf or gnu");
YYERROR;
}
dialect_ok(@1, MfLevel78, "LEVEL 78");
cbl_field_t field = { FldLiteralA, constant_e, *$data.data,
78, $name, @name.first_line };
if( field.data.initial ) {
field.attr |= quoted_e;
field.codeset.set($data.encoding);
if( !cdf_value(field.name, field.data.initial) ) {
yywarn("%s was defined by CDF", field.name);
cbl_message(Par78CdfDefinedW,
"%s was defined by CDF", field.name);
}
} else {
field.type = FldLiteralN;
field.data.initial = string_of(field.data.value_of());
field.codeset.set($data.encoding);
if( !cdf_value(field.name, field.as_integer()) ) {
yywarn("%s was defined by CDF", field.name);
cbl_message(Par78CdfDefinedW,
"%s was defined by CDF", field.name);
}
}
if( ($$ = field_add(@name, &field)) == NULL ) {
@@ -4062,8 +4076,9 @@ literalism: LITERAL { $$ = $1; }
if( $second.prefix[0] ) { strcpy(output.prefix, $second.prefix); }
if( ! $first.compatible_prefix($second) ) {
yywarn("dissimilar literals, '%s' prevails",
output.prefix);
cbl_message(@$, ParLiteral2W,
"dissimilar literals, '%s' prevails",
output.prefix);
}
}
;
@@ -4173,13 +4188,11 @@ data_clauses: data_clause
if( field->is_binary_integer() && field->data.capacity == 4) {
auto redefined = symbol_redefines(field);
if( redefined && redefined->type == FldPointer ) {
if( yydebug ) {
yywarn("expanding %s size from %u bytes to %wd "
"because it redefines %s with %<USAGE POINTER%>",
field->name, field->size(),
int_size_in_bytes(ptr_type_node),
redefined->name);
}
dbgmsg("expanding %s size from %u bytes to %lu "
"because it redefines %s with USAGE POINTER",
field->name, field->size(),
int_size_in_bytes(ptr_type_node),
redefined->name);
field->embiggen();
}
}
@@ -4213,7 +4226,7 @@ data_clause: any_length { $$ = any_length_e; }
cbl_field_t *field = current_field();
switch( field->level ) {
case 1:
if( dialect_mf() ) break;
if( dialect_ok(@$, MfLevel_1_Occurs, "LEVEL 01 for OCCURS") ) break;
__attribute__((fallthrough));
case 77:
case 88:
@@ -4336,7 +4349,7 @@ picture_clause: PIC signed nps[fore] nines nps[aft]
if( field->type == FldNumericBin5 &&
field->data.capacity == 0xFF &&
(dialect_gnu() || dialect_mf()) )
dialect_ok(@2, MfCompX, "alphanumeric PICTURE with numeric USAGE") )
{ // PIC X COMP-X or COMP-9
if( ! field->has_attr(all_x_e) ) {
error_msg(@2, "COMP PICTURE requires all X%'s or all 9%'s");
@@ -4568,22 +4581,15 @@ usage_clause1: usage BIT
case FldAlphanumeric: // PIC X COMP-5 or COMP-X
assert( field->data.digits == 0 );
assert( field->data.rdigits == 0 );
if( (dialect_mf() || dialect_gnu()) ) {
field->type = $comp.type;
field->clear_attr(signable_e);
} else {
error_msg(@comp, "numeric USAGE invalid "
"with Alphanumeric PICTURE");
dialect_error(@1, "Alphanumeric COMP-5 or COMP-X", "mf or gnu");
YYERROR;
}
dialect_ok(@2, MfCompX, "alphanumeric PICTURE with numeric USAGE");
field->type = $comp.type;
field->clear_attr(signable_e);
break;
case FldNumericDisplay: // PIC 9 COMP-5 or COMP-X
if( $comp.capacity == 0xFF ) { // comp-x is a bit like comp-5
assert( field->data.digits == field->data.capacity );
if( ! (dialect_mf() || dialect_gnu()) ) {
dialect_error(@1, "COMP-X", "mf or gnu");
}
dialect_ok(@2, MfCompX, "alphanumeric PICTURE with numeric USAGE");
}
field->type = $comp.type;
field->data.capacity = type_capacity(field->type,
@@ -4596,9 +4602,7 @@ usage_clause1: usage BIT
case FldPacked: // comp-6 is unsigned comp-3
assert(! $comp.signable); // else PACKED_DECIMAL from scanner
field->attr |= separate_e;
if( ! dialect_mf() ) {
dialect_error(@1, "COMP-6", "mf");
}
dialect_ok(@2, MfComp6, "COMP-6");
if( field->type == FldNumericDisplay ) {// PICTURE before USAGE
infer = false;
assert(field->data.capacity > 0);
@@ -4649,22 +4653,14 @@ usage_clause1: usage BIT
case FldAlphanumeric: // PIC X COMP-5 or COMP-X
assert( field->data.digits == 0 );
assert( field->data.rdigits == 0 );
if( (dialect_mf() || dialect_gnu()) ) {
field->type = $comp.type;
field->clear_attr(signable_e);
} else {
error_msg(@comp, "numeric USAGE invalid "
"with Alphanumeric PICTURE");
dialect_error(@1, "Alphanumeric COMP-5 or COMP-X", "mf or gnu");
YYERROR;
}
dialect_ok(@2, MfCompX, "alphanumeric PICTURE with numeric USAGE");
field->type = $comp.type;
field->clear_attr(signable_e);
break;
case FldNumericDisplay: // PIC 9 COMP-5 or COMP-X
if( $comp.capacity == 0xFF ) { // comp-x is a bit like comp-5
assert( field->data.digits == field->data.capacity );
if( ! (dialect_mf() || dialect_gnu()) ) {
dialect_error(@1, "COMP-X", "mf or gnu");
}
dialect_ok(@2, MfCompX, "alphanumeric PICTURE with numeric USAGE");
}
field->type = $comp.type;
field->data.capacity = type_capacity(field->type,
@@ -4677,9 +4673,7 @@ usage_clause1: usage BIT
case FldPacked: // comp-6 is unsigned comp-3
assert(! $comp.signable); // else PACKED_DECIMAL from scanner
field->attr |= separate_e;
if( ! dialect_mf() ) {
dialect_error(@1, "COMP-6", "mf");
}
dialect_ok(@2, MfComp6, "COMP-6");
if( field->type == FldNumericDisplay ) {// PICTURE before USAGE
infer = false;
assert(field->data.capacity > 0);
@@ -5074,10 +5068,7 @@ type_clause: TYPE to typename
}
| USAGE is typename
{
if( ! dialect_mf() ) {
dialect_error(@typename, "USAGE TYPENAME", "mf");
YYERROR;
}
dialect_ok(@typename, MfUsageTypename, "USAGE TYPENAME");
cbl_field_t *field = current_field();
if( $typename ) {
const auto e = symbol_field_same_as(field, $typename);
@@ -5112,10 +5103,8 @@ typedef_clause: is TYPEDEF strong
volatile_clause:
VOLATILE
{
if( dialect_ibm() ) {
yywarn("VOLATILE has no effect");
} else {
dialect_error(@1, "VOLATILE", "ibm");
if( dialect_ok(@1, IbmVolatileE, "VOLATILE") ) {
cbl_message(@1, IbmVolatileW, "VOLATILE has no effect");
}
}
;
@@ -5272,10 +5261,9 @@ sentence: statements '.'
std::set<std::string> externals = current.end_program();
if( !externals.empty() ) {
for( const auto& name : externals ) {
yywarn("%s calls external symbol '%s'",
dbgmsg("%s calls external symbol '%s'",
prog->name, name.c_str());
}
YYERROR;
}
// pointer still valid because name is in symbol table
ast_end_program(prog->name);
@@ -5692,9 +5680,10 @@ add_body: sum TO rnames
corresponding_arith_fields( $sum->refers.front().field,
rhs.front().refer.field );
if( pairs.empty() ) {
yywarn( "%s and %s have no corresponding fields",
$sum->refers.front().field->name,
rhs.front().refer.field->name );
cbl_message( @$, ParNoCorrespondingW,
"%s and %s have no corresponding fields",
$sum->refers.front().field->name,
rhs.front().refer.field->name );
}
// First src/tgt elements are templates.
// Their subscripts apply to the correspondents.
@@ -5854,21 +5843,16 @@ compute_body: rnames { statement_begin(@$, COMPUTE); } compute_expr[expr] {
$$.expr = $expr;
}
;
compute_expr: '=' {
compute_expr: EQ {
if( $1[0] == 'E' ) { // lexer found EQUALS keyword
dialect_ok(@1, IbmEqualAssignE,
"EQUAL as assignment operator" );
}
current.compute_begin();
} expr {
$$ = $expr;
}
;
| EQUAL {
if( ! dialect_ibm() ) {
dialect_error(@1, "EQUAL invalid as assignment operator", "ibm");
}
current.compute_begin();
} expr {
$$ = $expr;
}
;
display: disp_body end_display[advance]
{
@@ -6079,9 +6063,8 @@ end_program: end_program1[end] '.'
std::set<std::string> externals = current.end_program();
if( !externals.empty() ) {
for( const auto& name : externals ) {
yywarn("%s calls external symbol '%s'", prog->name, name.c_str());
dbgmsg("%s calls external symbol '%s'", prog->name, name.c_str());
}
YYERROR;
}
// pointer still valid because name is in symbol table
ast_end_program(prog->name);
@@ -6192,9 +6175,7 @@ exit_with: %empty
}
| RETURNING stop_status
{
if( ! dialect_mf() ) {
dialect_error(@2, "RETURNING <number>", "mf");
}
dialect_ok(@$, MfReturningNum, "RETURNING <number>");
$$ = $stop_status? $stop_status : new_reference(literally_one);
}
;
@@ -7229,8 +7210,9 @@ move: MOVE scalar TO move_tgts[tgts]
}
if( !move_corresponding(*$to, *$from) ) {
yywarn( "%s and %s have no corresponding fields",
$from->field->name, $to->field->name );
cbl_message( @$, ParNoCorrespondingW,
"%s and %s have no corresponding fields",
$from->field->name, $to->field->name );
}
}
;
@@ -7407,7 +7389,7 @@ arith_err: SIZE_ERROR
relop: '<' { $$ = '<'; }
| LE { $$ = LE; }
| '=' { $$ = '='; }
| EQ { $$ = EQ; }
| NE { $$ = NE; }
| GE { $$ = GE; }
| '>' { $$ = '>'; }
@@ -7442,25 +7424,19 @@ num_value: scalar // might actually be a string
| LENGTH_OF binary_type[size] {
location_set(@1);
$$ = new cbl_refer_t( new_tempnumeric(none_e) );
if( dialect_gcc() ) {
dialect_error(@1, "LENGTH OF", "ibm");
}
dialect_ok(@1, IbmLengthOf, "LENGTH OF");
parser_set_numeric($$->field, $size);
}
| LENGTH_OF name[val] {
location_set(@1);
$$ = new cbl_refer_t( new_tempnumeric(none_e) );
if( dialect_gcc() ) {
dialect_error(@1, "LENGTH OF", "ibm");
}
dialect_ok(@1, IbmLengthOf, "LENGTH OF");
parser_set_numeric($$->field, $val->data.capacity);
}
| LENGTH_OF name[val] subscripts[subs] {
location_set(@1);
$$ = new cbl_refer_t( new_tempnumeric(none_e) );
if( dialect_gcc() ) {
dialect_error(@1, "LENGTH OF", "ibm");
}
dialect_ok(@1, IbmLengthOf, "LENGTH OF");
if( 0 == dimensions($val) ) {
cbl_refer_t r1($val);
subscript_dimension_error( @subs, $subs->refers.size(), &r1 );
@@ -7488,7 +7464,7 @@ num_value: scalar // might actually be a string
/* cce_relexpr: cce_expr */
/* | cce_relexpr '<' cce_expr { $$ = $1 < $3; } */
/* | cce_relexpr LE cce_expr { $$ = $1 <= $3; } */
/* | cce_relexpr '=' cce_expr { $$ = $1 == $3; } */
/* | cce_relexpr EQ cce_expr { $$ = $1 == $3; } */
/* | cce_relexpr NE cce_expr { $$ = $1 != $3; } */
/* | cce_relexpr GE cce_expr { $$ = $1 >= $3; } */
/* | cce_relexpr '>' cce_expr { $$ = $1 > $3; } */
@@ -7553,23 +7529,19 @@ section_name: NAME section_kw '.'
section_kw: SECTION
{
if( $1 ) {
if( $1 && dialect_ok(@1, IbmSectionSegmentW, "SECTION segment") ) {
cbl_message(@1, IbmSectionSegmentW,
"SECTION segment %qs was ignored", $1);
if( *$1 == '-' ) {
error_msg(@1, "SECTION segment %qs is negative", $1);
cbl_message(@1, IbmSectionNegE,
"SECTION segment %qs is negative", $1);
} else {
if( dialect_ibm() ) {
int sectno;
sscanf($1, "%d", &sectno);
if( ! (0 <= sectno && sectno <= 99) ) {
error_msg(@1, "SECTION segment %qs must be 0-99", $1);
} else {
if(false) { // stand-in for warning, someday.
yywarn("SECTION segment %qs was ignored", $1);
}
}
} else {
cbl_unimplemented("SECTION segment %qs is not ISO syntax", $1);
}
int sectno;
sscanf($1, "%d", &sectno);
if( ! (0 <= sectno && sectno <= 99) ) {
cbl_message(@1, IbmSectionRangeE,
"SECTION segment %qs must be 0-99", $1);
}
}
}
}
@@ -7587,10 +7559,7 @@ stop: STOP RUN exit_with
| STOP NUMSTR[status] // IBM syntax
{
statement_begin(@1, STOP);
if( ! dialect_ibm() ) {
dialect_error(@2, "STOP <number> is not ISO syntax,", "ibm");
YYERROR;
}
dialect_ok(@2, IbmStopNumber, "STOP <number>");
cbl_refer_t status( new_literal($status.string, $status.radix) );
parser_see_stop_run( status, NULL );
}
@@ -7674,25 +7643,19 @@ signed_literal: num_literal
| LENGTH_OF binary_type[size] {
location_set(@1);
$$ = new_tempnumeric(none_e);
if( dialect_gcc() ) {
dialect_error(@1, "LENGTH OF", "ibm");
}
dialect_ok(@1, IbmLengthOf, "LENGTH OF");
parser_set_numeric($$, $size);
}
| LENGTH_OF name[val] {
location_set(@1);
$$ = new_tempnumeric(none_e);
if( dialect_gcc() ) {
dialect_error(@1, "LENGTH OF", "ibm");
}
dialect_ok(@1, IbmLengthOf, "LENGTH OF");
parser_set_numeric($$, $val->data.capacity);
}
| LENGTH_OF name[val] subscripts[subs] {
location_set(@1);
$$ = new_tempnumeric(none_e);
if( dialect_gcc() ) {
dialect_error(@1, "LENGTH OF", "ibm");
}
dialect_ok(@1, IbmLengthOf, "LENGTH OF");
if( 0 == dimensions($val) ) {
cbl_refer_t r1($val);
subscript_dimension_error( @subs, $subs->refers.size(), &r1 );
@@ -8198,9 +8161,10 @@ subtract_body: sum FROM rnames
corresponding_arith_fields( $sum->refers.front().field,
rhs.front().refer.field );
if( pairs.empty() ) {
yywarn( "%s and %s have no corresponding fields",
$sum->refers.front().field->name,
rhs.front().refer.field->name );
cbl_message(ParNoCorrespondingW,
"%s and %s have no corresponding fields",
$sum->refers.front().field->name,
rhs.front().refer.field->name );
}
// First src/tgt elements are templates.
// Their subscripts apply to the correspondents.
@@ -8241,25 +8205,19 @@ varg1a: ADDRESS OF scalar {
| LENGTH_OF binary_type[size] {
location_set(@1);
$$ = new cbl_refer_t( new_tempnumeric(none_e) );
if( dialect_gcc() ) {
dialect_error(@1, "LENGTH OF", "ibm");
}
dialect_ok(@1, IbmLengthOf, "LENGTH OF");
parser_set_numeric($$->field, $size);
}
| LENGTH_OF name[val] {
location_set(@1);
$$ = new cbl_refer_t( new_tempnumeric(none_e) );
if( dialect_gcc() ) {
dialect_error(@1, "LENGTH OF", "ibm");
}
dialect_ok(@1, IbmLengthOf, "LENGTH OF");
parser_set_numeric($$->field, $val->size());
}
| LENGTH_OF name[val] subscripts[subs] {
location_set(@1);
$$ = new cbl_refer_t( new_tempnumeric(none_e) );
if( dialect_gcc() ) {
dialect_error(@1, "LENGTH OF", "ibm");
}
dialect_ok(@1, IbmLengthOf, "LENGTH OF");
if( 0 == dimensions($val) ) {
cbl_refer_t r1($val);
subscript_dimension_error( @subs, $subs->refers.size(), &r1 );
@@ -8879,10 +8837,7 @@ start_body: filename[file]
int size = key == 0 ? 0 : $file->keys[key - 1].size();
auto ksize = new_tempnumeric();
parser_set_numeric(ksize, size);
if( yydebug ) {
yywarn("START: key #%d '%s' has size %d",
key, $key->name, size);
}
dbgmsg("START: key #%d '%s' has size %d", key, $key->name, size);
$$ = file_start_args.init(@file, $file);
parser_file_start( $file, relop_of($relop), key, ksize );
}
@@ -9069,7 +9024,8 @@ set: SET set_tgts[tgts] TO set_operand[src]
default:
gcc_unreachable();
}
cbl_unimplementedw("unimplemented: SET TO LOCALE");
cbl_unimplementedw(SynSetToLocale,
"unimplemented: %<SET ... TO LOCALE%>");
}
;
| SET set_tgts[tgts] UP BY num_operand[src]
@@ -9139,7 +9095,8 @@ set: SET set_tgts[tgts] TO set_operand[src]
} else {
// do something $tgt->lc_categories()
}
cbl_unimplementedw("unimplemented: SET LOCALE");
cbl_unimplementedw(SynSetLocaleTo,
"unimplemented: %<SET LOCALE ... TO%>");
}
;
@@ -9260,7 +9217,7 @@ search_1_cases: search_1_case
lookahead = keyword_str(yychar);
}
}
yywarn("Just one case, lookahead is '%s'", lookahead);
dbgmsg("Just one case, lookahead is '%s'", lookahead);
}
}
| search_1_cases search_1_case
@@ -9314,7 +9271,7 @@ search_stmts: statements %prec ADD
search_terms: search_term
| search_terms AND search_term
;
search_term: scalar[key] '=' search_expr[sarg]
search_term: scalar[key] EQ search_expr[sarg]
{
if( $key->nsubscript() == 0 ) {
error_msg(@1, "no index for key");
@@ -9764,9 +9721,7 @@ tally_forth: CHARACTERS insp_mtqual[q] scalar[next_tally]
| TRAILING tally_matches[q]
{ $q->bound = bound_trailing_e;
$$ = $q;
if( ! dialect_mf() ) {
dialect_error(@1, "TRAILING", "mf");
}
dialect_ok(@1, MfTrailing, "TRAILING");
}
;
@@ -9897,9 +9852,7 @@ first_leading: FIRST { $$ = bound_first_e; }
| ALL { $$ = bound_all_e; }
| LEADING { $$ = bound_leading_e; }
| TRAILING { $$ = bound_trailing_e;
if( ! dialect_mf() ) {
dialect_error(@1, "TRAILING", "mf");
}
dialect_ok(@1, MfTrailing, "TRAILING");
}
;
@@ -10089,9 +10042,7 @@ call_body: ffi_name
;
call_returning: RETURNING
| GIVING {
if( !dialect_mf() ) {
dialect_error(@1, "CALL ... GIVING", "mf");
}
dialect_ok(@1, MfCallGiving, "CALL ... GIVING");
}
;
@@ -10343,13 +10294,13 @@ go_to: GOTO labels[args]
resume: RESUME NEXT STATEMENT
{
statement_begin(@1, RESUME);
if( dialect_proscribed( @1, dialect_ibm_e, "RESUME") ) YYERROR;
dialect_not_ok( @1, IsoResume, "RESUME");
parser_clear_exception();
}
| RESUME label_1[tgt]
{
statement_begin(@1, RESUME);
if( dialect_proscribed( @1, dialect_ibm_e, "RESUME") ) YYERROR;
dialect_not_ok( @1, IsoResume, "RESUME");
parser_clear_exception();
$tgt->used = @1.first_line;
parser_goto( cbl_refer_t(), 1, &$tgt );
@@ -12289,7 +12240,7 @@ relop_of(int token) {
switch(token) {
case '<': return lt_op;
case LE: return le_op;
case '=': return eq_op;
case EQ: return eq_op;
case NE: return ne_op;
case GE: return ge_op;
case '>': return gt_op;
@@ -12322,7 +12273,7 @@ relop_debug_str(int token) {
case 0: return "zilch";
case '<': return "<";
case LE: return "LE";
case '=': return "=";
case EQ: return "=";
case NE: return "NE";
case GE: return "GE";
case '>': return ">";
@@ -12336,7 +12287,7 @@ token_of(enum relop_t op) {
switch(op) {
case lt_op: return '<';
case le_op: return LE;
case eq_op: return '=';
case eq_op: return EQ;
case ne_op: return NE;
case ge_op: return GE;
case gt_op: return '>';
@@ -12807,7 +12758,7 @@ struct stringify_src_t : public cbl_string_src_t {
protected:
static void dump_input( const cbl_refer_t& refer ) {
yywarn( "%s: %s", __func__, field_str(refer.field) );
dbgmsg( "%s: %s", __func__, field_str(refer.field) );
}
};
@@ -12817,13 +12768,13 @@ stringify( refer_collection_t *inputs,
cbl_label_t *on_error,
cbl_label_t *not_error )
{
std::vector <stringify_src_t> sources(inputs->lists.size());
if( inputs->lists.back().marker == NULL ) {
inputs->lists.back().marker = cbl_refer_t::empty();
}
assert( inputs->lists.back().marker );
std::copy( inputs->lists.begin(), inputs->lists.end(), sources.begin() );
std::vector <stringify_src_t> sources(inputs->lists.begin(), inputs->lists.end());
parser_string( into, pointer, sources.size(), sources.data(), on_error, not_error );
}
@@ -13114,7 +13065,7 @@ numstr2i( const char input[], radix_t radix ) {
case boolean_e:
for( const char *p = input; *p != '\0'; p++ ) {
if( ssize_t(8 * sizeof(integer) - 1) < p - input ) {
yywarn("'%s' was accepted as %zu", input, integer);
dbgmsg("'%s' was accepted as %lu", input, (unsigned long)integer);
break;
}
switch(*p) {
@@ -13124,7 +13075,7 @@ numstr2i( const char input[], radix_t radix ) {
integer |= ((*p) == '0' ? 0 : 1);
break;
default:
yywarn("'%s' was accepted as %zu", input, integer);
dbgmsg("'%s' was accepted as %lu", input, (unsigned long)integer);
break;
}
}
@@ -13132,7 +13083,7 @@ numstr2i( const char input[], radix_t radix ) {
return output;
}
if( erc == -1 ) {
yywarn("'%s' was accepted as %zu", input, integer);
cbl_message(ParNumstrW, "'%s' was accepted as %zu", input, integer);
}
return output;
}
@@ -13843,6 +13794,7 @@ mode_syntax_only() {
void
cobol_dialect_set( cbl_dialect_t dialect ) {
switch(dialect) {
case dialect_iso_e:
case dialect_gcc_e:
break;
case dialect_ibm_e:

View File

@@ -189,16 +189,6 @@ has_clause( int data_clauses, data_clause_t clause ) {
return clause == (data_clauses & clause);
}
static bool
dialect_proscribed( const YYLTYPE& loc, cbl_dialect_t dialect, const char msg[] ) {
if( dialect == cbl_dialects ) {
error_msg(loc, "dialect %s does not allow syntax: %qs",
cbl_dialect_str(dialect), msg);
return true;
}
return false;
}
static bool
is_cobol_charset( const char name[] ) {
auto eoname = name + strlen(name);
@@ -2072,21 +2062,14 @@ static class current_t {
parser_leave_section( programs.top().section );
programs.pop();
#if 0
if( programs.empty() ) {
// The default encoding can be changed only with -finternal-ebcdic, and
// remains in effect for all programs while the compiler runs.
// This comment here to remind us.
default_encoding = prog_descr_t::encoding_t::encoding_base_t();
}
#endif
debugging_clients.clear();
error_clients.clear();
exception_clients.clear();
if( ref ) {
yywarn("could not resolve paragraph (or section) '%s' at line %d",
ref->paragraph(), ref->line_number());
cbl_message(ParUnresolvedProcE,
"could not resolve paragraph (or section) '%s' at line %d",
ref->paragraph(), ref->line_number());
// add string to indicate ambiguity error
externals.insert(":ambiguous:");
}
@@ -2227,11 +2210,10 @@ static class current_t {
}
void antecedent_dump() const {
if( ! yydebug ) return;
if( ! antecedent_cache.operand ) {
yywarn( "Antecedent: none" );
dbgmsg( "Antecedent: none" );
} else {
yywarn( "Antecedent: %c %s %s %c",
dbgmsg( "Antecedent: %c %s %s %c",
antecedent_cache.invert? '!':' ',
name_of(antecedent_cache.operand->field),
relop_str(antecedent_cache.relop),
@@ -3139,8 +3121,7 @@ parser_move_carefully( const char */*F*/, int /*L*/,
if( ! valid_move( tgt.field, src.field ) ) {
if( src.field->type == FldPointer &&
tgt.field->type == FldPointer ) {
if( dialect_mf() || dialect_gnu() ) return true;
dialect_error(src.loc, "MOVE POINTER", "mf");
dialect_ok(src.loc, MfMovePointer, "MOVE POINTER");
}
if( ! is_index ) {
char ach[16];
@@ -3612,7 +3593,7 @@ goodnight_gracie() {
if( !externals.empty() ) {
for( const auto& name : externals ) {
yywarn("%s calls external symbol '%s'",
dbgmsg("%s calls external symbol '%s'",
prog->name, name.c_str());
}
return false;

View File

@@ -762,7 +762,9 @@ EVERY { return EVERY; }
ERROR { return ERROR; }
EVALUATE { return EVALUATE; }
EQUALS? { return '='; }
EQUALS? { ydflval.string = yylval.string = xstrdup(yytext);
return '='; }
ENVIRONMENT[[:blank:]]+DIVISION { return ENVIRONMENT_DIV; }
ENTRY { return ENTRY; }
@@ -900,11 +902,7 @@ ACCESS { return ACCESS; }
ACCEPT { return ACCEPT; }
DELETE { return DELETE; }
EJECT{DOTEOL}? {
if( ! dialect_ibm() ) {
dialect_error(yylloc, "EJECT is not ISO syntax,", "ibm");
}
}
EJECT{DOTEOL}? { dialect_ok(yylloc, IbmEjectE, "EJECT"); }
INSERTT { return INSERTT; }
LABEL { return LABEL; }
PROCESS { return PROCESS; }
@@ -1007,9 +1005,7 @@ USE({SPC}FOR)? { return USE; }
BINARY-SHORT { return bcomputable(FldNumericBin5, 2); }
BINARY-LONG { return bcomputable(FldNumericBin5, 4); }
BINARY-DOUBLE { return bcomputable(FldNumericBin5, 8); }
BINARY-LONG-LONG { if( ! dialect_mf() ) {
dialect_error(yylloc, yytext, "mf");
}
BINARY-LONG-LONG { dialect_ok(yylloc, MfBinaryLongLong, "BINARY-LONG-LONG");
return bcomputable(FldNumericBin5, 8);
}
@@ -1044,9 +1040,8 @@ USE({SPC}FOR)? { return USE; }
PROGRAM-POINTER { yylval.field_attr = prog_ptr_e; return POINTER; }
POINTER { yylval.field_attr = none_e; return POINTER; }
PROCEDURE-POINTER { if( dialect_gcc() ) {
dialect_error(yylloc, yytext, "ibm or mf");
}
PROCEDURE-POINTER {
dialect_ok(yylloc, IbmProcedurePointer, yytext);
yylval.field_attr = prog_ptr_e;
return POINTER; // return it anyway
}
@@ -1086,13 +1081,11 @@ USE({SPC}FOR)? { return USE; }
DEPENDING { return DEPENDING; }
DESCENDING { return DESCENDING; }
DISPLAY { return DISPLAY; }
EJECT{DOTEOL}? {
if( ! dialect_ibm() ) {
dialect_error(yylloc, "EJECT is not ISO syntax,", "ibm");
}
auto len = yyleng - 1;
if( yytext[len] == '\f' ) myless(--len);
}
EJECT{DOTEOL}? {
dialect_ok(yylloc, IbmEjectE, "EJECT");
auto len = yyleng - 1;
if( yytext[len] == '\f' ) myless(--len);
}
EXTERNAL { return EXTERNAL; }
FALSE { return FALSE_kw; }
FROM { return FROM; }
@@ -1506,16 +1499,21 @@ USE({SPC}FOR)? { return USE; }
<cdf_state,procedure_div>{
(IS{SPC})?"<" { return '<'; }
(IS{SPC})?"<=" { return LE; }
(IS{SPC})?"=" { return '='; }
(IS{SPC})?"=" { static char eq[] = "=";
ydflval.string = yylval.string = eq;
return EQ; }
(IS{SPC})?"<>" { return NE; }
(IS{SPC})?">=" { return GE; }
(IS{SPC})?">" { return '>'; }
{LESS_THAN} { return '<'; }
{LESS_THAN} { return '<'; }
{LESS_THAN}{SPC}{OR_EQUAL}/[[:space:]] { return LE; }
(IS{SPC})?EQUALS?({SPC}TO)?/[[:space:]] { return '='; }
(IS{SPC})?EQUALS?({SPC}TO)?/[[:space:]] {
static char eq[] = "EQUAL";
ydflval.string = yylval.string = eq;
return EQ; }
{GREATER_THAN}{SPC}{OR_EQUAL}/[[:space:]] { return GE; }
{GREATER_THAN} { return '>'; }
{GREATER_THAN} { return '>'; }
{ISNT}{OSPC}">=" { verify_ws(yytext[yyleng - 3]); return '<'; }
{ISNT}{OSPC}">" { verify_ws(yytext[yyleng - 2]); return LE; }
@@ -1992,7 +1990,8 @@ BASIS { yy_push_state(basis); return BASIS; }
{STRING} { yy_pop_state();
yypush_buffer_state( yy_create_buffer(yyin, YY_BUF_SIZE) );
if( (yyin = cdftext::lex_open(yytext)) == NULL ) {
yywarn("could not open BASIS file '%s'", yytext);
cbl_message(yylloc, LexIncludeE,
"could not open BASIS file '%s'", yytext);
yyterminate();
}
}
@@ -2003,7 +2002,8 @@ BASIS { yy_push_state(basis); return BASIS; }
}
<procedure_div>{
EQUALS?{OSPC}/[(] { return '='; }
EQUALS?{OSPC}/[(] { ydflval.string = yylval.string = xstrdup(yytext);
return EQ; }
{NAME}{OSPC}/[(] { /* If /{OSPC}, "dangerous trailing context" "*/
if( is_integer_token() ) return numstr_of(yytext);
@@ -2084,21 +2084,15 @@ BASIS { yy_push_state(basis); return BASIS; }
^[ ]*>>{OBLANK}ELSE { return CDF_ELSE; }
^[ ]*>>{OBLANK}END-IF { return CDF_END_IF; }
^[ ]*[$]{OBLANK}IF { if( ! dialect_mf() ) {
dialect_error(yylloc, yytext, "mf");
}
^[ ]*[$]{OBLANK}IF { dialect_ok(yylloc, MfCdfDollar, yytext);
yy_push_state(cdf_state); return CDF_IF; }
^[ ]*[$]{OBLANK}ELSE { if( ! dialect_mf() ) {
dialect_error(yylloc, yytext, "mf");
}
^[ ]*[$]{OBLANK}ELSE { dialect_ok(yylloc, MfCdfDollar, yytext);
return CDF_ELSE; }
^[ ]*[$]{OBLANK}END { if( ! dialect_mf() ) {
dialect_error(yylloc, yytext, "mf");
}
^[ ]*[$]{OBLANK}END { dialect_ok(yylloc, MfCdfDollar, yytext);
return CDF_END_IF; }
^[ ]*[$]{OBLANK}SET({SPC}CONSTANT)? {
if( ! dialect_mf() ) dialect_error(yylloc, yytext, "mf");
dialect_ok(yylloc, MfCdfDollar, yytext);
yy_push_state(cdf_state); return CDF_DEFINE; }
^[ ]*>>{OBLANK}EVALUATE { return CDF_EVALUATE; }
@@ -2293,7 +2287,8 @@ BASIS { yy_push_state(basis); return BASIS; }
END-SUBTRACT { return END_SUBTRACT; }
END-WRITE { return END_WRITE; }
ENVIRONMENT { return ENVIRONMENT; }
EQUAL { return EQUAL; }
EQUAL { ydflval.string = yylval.string = xstrdup(yytext);
return EQ; }
ERROR { return ERROR; }
EVALUATE { return EVALUATE; }
EXCEPTION { return EXCEPTION; }

View File

@@ -295,7 +295,7 @@ static class parsing_status_t : public std::stack<cdf_status_t> {
void splat() const {
int i=0;
for( const auto& status : c ) {
yywarn( "%d %s", ++i, status.str() );
dbgmsg( "%d %s", ++i, status.str() );
}
}
} parsing;
@@ -316,11 +316,9 @@ bool scanner_normal() { return parsing.normal(); }
void scanner_parsing( int token, bool tf ) {
parsing.push( cdf_status_t(token, tf) );
if( yydebug ) {
yywarn("%s: parsing now %s, depth %zu",
keyword_str(token), boolalpha(parsing.on()), parsing.size());
parsing.splat();
}
dbgmsg("%s: parsing now %s, depth %zu",
keyword_str(token), boolalpha(parsing.on()), parsing.size());
parsing.splat();
}
void scanner_parsing_toggle() {
if( parsing.empty() ) {
@@ -328,10 +326,8 @@ void scanner_parsing_toggle() {
return;
}
parsing.top().toggle();
if( yydebug ) {
yywarn("%s: parsing now %s",
keyword_str(CDF_ELSE), boolalpha(parsing.on()));
}
dbgmsg("%s: parsing now %s",
keyword_str(CDF_ELSE), boolalpha(parsing.on()));
}
void scanner_parsing_pop() {
if( parsing.empty() ) {
@@ -339,12 +335,10 @@ void scanner_parsing_pop() {
return;
}
parsing.pop();
if( yydebug ) {
yywarn("%s: parsing now %s, depth %zu",
keyword_str(CDF_END_IF), boolalpha(parsing.on()),
parsing.size());
parsing.splat();
}
dbgmsg("%s: parsing now %s, depth %zu",
keyword_str(CDF_END_IF), boolalpha(parsing.on()),
parsing.size());
parsing.splat();
}
@@ -640,11 +634,9 @@ binary_integer_usage( const char name[]) {
}
static void
verify_ws( const YYLTYPE& loc, const char input[], char ch ) {
verify_ws( const YYLTYPE& loc, const char [] /* input[] */, char ch ) {
if( ! fisspace(ch) ) {
if( ! (dialect_mf() || dialect_gnu()) ) {
dialect_error(loc, "separator space required in %qs", input);
}
dialect_ok(loc, LexSeparatorE, "missing separator space");
}
}
#define verify_ws(C) verify_ws(yylloc, yytext, C)
@@ -676,7 +668,7 @@ level_of( const char input[] ) {
if( input[0] == '0' ) input++;
if( 1 != sscanf(input, "%u", &output) ) {
yywarn( "%s:%d: invalid level '%s'", __func__, __LINE__, input );
cbl_internal_error( "%s:%d: invalid level '%s'", __func__, __LINE__, input );
}
return output;
@@ -1221,7 +1213,7 @@ typed_name( const char name[] ) {
return cbl_field_of(e)->level == 88? NAME88 : CLASS_NAME;
break;
default:
yywarn("%s:%d: invalid symbol type %s for symbol %qs",
cbl_internal_error("%s:%d: invalid symbol type %s for symbol %qs",
__func__, __LINE__, cbl_field_type_str(type), name);
return NAME;
}
@@ -1253,8 +1245,14 @@ integer_of( const char input[], bool is_hex = false) {
if( input[0] == '0' ) input++;
if( 1 != sscanf(input, fmt, &output) ) {
yywarn( "%s:%d: invalid integer '%s'", __func__, __LINE__, input );
cbl_internal_error( "%s:%d: invalid integer '%s'", __func__, __LINE__, input );
}
return output;
}

View File

@@ -120,7 +120,8 @@ datetime_format_of( const char input[] ) {
if( 0 != (erc = regcomp(&p->re, p->regex, cflags)) ) {
static char msg[80];
regerror(erc, &p->re, msg, sizeof(msg));
yywarn("%s:%d: %s: %s", __func__, __LINE__, keyword_str(p->token), msg);
cbl_internal_error("%s:%d: %s: %s", __func__, __LINE__,
keyword_str(p->token), msg);
}
}
}
@@ -293,12 +294,12 @@ prelex() {
if( YY_START == field_state && level_needed() ) {
switch( token ) {
case NUMSTR:
if( yy_flex_debug ) yywarn("final token is NUMSTR");
dbgmsg("final token is NUMSTR");
yylval.number = level_of(yylval.numstr.string);
token = LEVEL;
break;
case YDF_NUMBER:
if( yy_flex_debug ) yywarn("final token is %<YDF_NUMBER%>");
dbgmsg("final token is YDF_NUMBER");
yylval.number = ydflval.number;
token = LEVEL;
break;

View File

@@ -449,19 +449,15 @@ extern bool cursor_at_sol;
do { \
if(!a) \
{ \
yywarn("%s: parameter %<" #a "%> is NULL", __func__); \
gcc_unreachable(); \
abort(); \
cbl_internal_error("%s: parameter %<" #a "%> is NULL", __func__); \
} \
if( !a->var_decl_node ) \
{ \
yywarn("%s: parameter %<" #a "%> is variable " \
cbl_internal_error("%s: parameter %<" #a "%> is variable " \
"%s<%s> with NULL %<var_decl_node%>", \
__func__, \
a->name, \
cbl_field_type_str(a->type) ); \
gcc_unreachable(); \
abort(); \
} \
} while(0);
@@ -470,19 +466,15 @@ extern bool cursor_at_sol;
do { \
if(!a) \
{ \
yywarn("%s: parameter %<" #a "%> is NULL", __func__); \
gcc_unreachable(); \
abort(); \
cbl_internal_error("%s: parameter %<" #a "%> is NULL", __func__); \
} \
if( !a->var_decl_node && a->type != FldConditional && a->type != FldLiteralA) \
{ \
yywarn("%s: parameter %<" #a "%> is variable " \
cbl_internal_error("%s: parameter %<" #a "%> is variable " \
"%s<%s> with NULL %<var_decl_node%>", \
__func__, \
a->name, \
cbl_field_type_str(a->type) ); \
gcc_unreachable(); \
abort(); \
} \
} while(0);
@@ -491,9 +483,7 @@ extern bool cursor_at_sol;
do{ \
if(!a) \
{ \
yywarn("%s: parameter %<" #a "%> is NULL", __func__); \
gcc_unreachable(); \
abort(); \
cbl_internal_error("%s: parameter %<" #a "%> is NULL", __func__); \
} \
}while(0);

View File

@@ -1318,7 +1318,7 @@ static struct symbol_elem_t *
switch( group->level ) {
case 1: case 77:
if( dialect_mf() && is_table(group) ) {
if( is_table(group) ) {
size_t elem_size = std::max(group->data.memsize, group->data.memsize);
group->data.memsize = elem_size * group->occurs.ntimes();
}
@@ -1783,7 +1783,7 @@ symbols_update( size_t first, bool parsed_ok ) {
break;
case 1:
pend = calculate_capacity(p);
if( dialect_mf() && is_table(field) ) {
if( is_table(field) ) {
if( field->data.memsize < field->size() ) {
field->data.memsize = field->size();
}
@@ -3858,7 +3858,9 @@ cbl_field_t::internalize() {
iconv_t cd = tocodes[toname];
if (cd == (iconv_t)-1) {
yywarn("failed %<iconv_open%> tocode = %qs fromcode = %qs", tocode, fromcode);
cbl_message(ParIconvE,
"failed %<iconv_open%> tocode = %qs fromcode = %qs",
tocode, fromcode);
}
if( fromcode == tocode || has_attr(hex_encoded_e) ) {

View File

@@ -51,20 +51,28 @@
extern const char *numed_message;
enum cbl_dialect_t {
dialect_gcc_e = 0x00,
dialect_ibm_e = 0x01,
dialect_mf_e = 0x02,
dialect_gnu_e = 0x04,
dialect_iso_e = 0x00,
dialect_gcc_e = 0x01,
dialect_ibm_e = 0x02,
dialect_mf_e = 0x04,
dialect_gnu_e = 0x08,
};
static inline const char *
cbl_dialect_str(cbl_dialect_t dialect) {
switch(dialect) {
case dialect_iso_e: return "iso";
case dialect_gcc_e: return "gcc";
case dialect_ibm_e: return "ibm";
case dialect_mf_e: return "mf";
case dialect_gnu_e: return "gnu";
}
switch(size_t(dialect)) {
case dialect_mf_e | dialect_gnu_e: return "mf or gnu";
case dialect_ibm_e | dialect_mf_e | dialect_gnu_e: return "ibm or mf or gnu";
}
return "???";
};
@@ -86,6 +94,15 @@ static inline bool dialect_gnu() {
return dialect_gnu_e == (cbl_dialects & dialect_gnu_e );
}
static inline bool dialect_has( cbl_dialect_t dialect) {
return 0 < (cbl_dialects & dialect);
}
#ifdef GCC_DIAGNOSTIC_H
bool cbl_diagnostic_kind( cbl_diag_id_t id, diagnostics::kind kind );
bool cbl_dialect_kind( cbl_dialect_t dialect, diagnostics::kind kind );
#endif
enum cbl_gcobol_feature_t {
feature_gcc_e = 0x00,
feature_internal_ebcdic_e = 0x01,
@@ -1715,9 +1732,9 @@ struct cbl_alphabet_t {
}
void dump() const {
yywarn("%qs: %s, %<%c%> to %<%c%> (low 0x%x, high 0x%x)",
name, encoding_str(encoding),
low_index, last_index, low_index, high_index);
dbgmsg("%s: '%s', '%c' to '%c' (low 0x%x, high 0x%x)",
name, encoding_str(encoding),
low_index, last_index, low_index, high_index);
if( encoding == custom_encoding_e ) {
fprintf(stderr, "\t"
" 0 1 2 3 4 5 6 7"

File diff suppressed because it is too large Load Diff

View File

@@ -100,7 +100,7 @@ get_current_dir_name ()
unsigned long
gb4( size_t input ) {
if( input != static_cast<unsigned long>(input) ) {
yywarn("size too large to print: %lx:%lx",
dbgmsg("size too large to print: %lx:%lx",
(unsigned long)(input >> (4 * sizeof(unsigned long))),
static_cast<unsigned long>(input));
}
@@ -2147,6 +2147,9 @@ static location_t token_location_minus_1 = 0;
static location_t token_location = 0;
location_t current_token_location() { return token_location; }
location_t current_token_location(const location_t& loc) {
return token_location = loc;
}
location_t current_location_minus_one() { return token_location_minus_1; }
void current_location_minus_one_clear()
{
@@ -2360,18 +2363,6 @@ yyerror( const char gmsgid[], ... ) {
global_dc->end_group();
}
bool
yywarn( const char gmsgid[], ... ) {
verify_format(gmsgid);
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
auto ret = emit_diagnostic_valist( diagnostics::kind::warning, token_location,
option_zero, gmsgid, &ap );
va_end (ap);
return ret;
}
/*
* Sometimes during parsing an error is noticed late. This message refers back
* to an arbitrary file and line number.
@@ -2430,9 +2421,11 @@ cobol_fileline_set( const char line[] ) {
*filename = xstrndup(line + pmatch[2].rm_so, matched_length(pmatch[2]));
int fileline;
if( 1 != sscanf(line_str, "%d", &fileline) )
yywarn("could not parse line number %s from %<#line%> directive", line_str);
if( 1 != sscanf(line_str, "%d", &fileline) ) {
cbl_message(LexLineE,
"could not parse line number %s from %<#line%> directive",
line_str);
}
input_file_t input_file( filename, ino_t(0), fileline ); // constructor sets inode
if( input_filenames.empty() ) {
@@ -2525,11 +2518,11 @@ cobol_parse_files (int nfile, const char **files)
{
const char * opaque = setlocale(LC_CTYPE, "");
if( ! opaque ) {
yywarn("setlocale: unable to initialize LOCALE");
cbl_message(ParLocaleW, "setlocale: unable to initialize LOCALE");
} else {
char *codeset = nl_langinfo(CODESET);
if( ! codeset ) {
yywarn("%<nl_langinfo%> failed after %<setlocale()%> succeeded");
cbl_message(ParLangInfoW, "%<nl_langinfo%> failed after %<setlocale()%> succeeded");
} else {
os_locale.codeset = codeset;
}
@@ -2541,20 +2534,6 @@ cobol_parse_files (int nfile, const char **files)
}
}
/* Outputs the formatted string onto the file descriptor */
void
cbl_message(int fd, const char *format_string, ...)
{
va_list ap;
va_start(ap, format_string);
char *ostring = xvasprintf(format_string, ap);
va_end(ap);
write(fd, ostring, strlen(ostring));
write(fd, "\n", 1);
free(ostring);
}
/* Uses the GCC internal_error () to output the formatted string. Processing
ends with a stack trace */
@@ -2571,15 +2550,30 @@ cbl_internal_error(const char *gmsgid, ...) {
// // doesn't cause a warning.
}
diagnostics::kind cbl_diagnostic_kind( cbl_diag_id_t id );
const char * cbl_diagnostic_option( cbl_diag_id_t id );
void
cbl_unimplementedw(const char *gmsgid, ...) {
cbl_unimplementedw(cbl_diag_id_t id, const char *gmsgid, ...) {
verify_format(gmsgid);
auto_diagnostic_group d;
const char *option;
char *msg = nullptr;
diagnostics::kind kind = cbl_diagnostic_kind(id);
if( kind == diagnostics::kind::ignored ) return;
if( (option = cbl_diagnostic_option(id)) != nullptr ) {
msg = xasprintf("%s [%s]", gmsgid, option);
gmsgid = msg;
}
va_list ap;
va_start(ap, gmsgid);
emit_diagnostic_valist( diagnostics::kind::warning,
token_location, option_zero, gmsgid, &ap );
emit_diagnostic_valist( kind, token_location, option_zero, gmsgid, &ap );
va_end(ap);
free(msg);
}
void
@@ -2635,6 +2629,13 @@ cbl_errx(const char *gmsgid, ...) {
va_end(ap);
}
/*
* For a function that uses host *printf, %zu or %td or %wu are not ok, sadly.
* not all supported host arches support those. So, for *printf family one
* needs to use macros like HOST_WIDE_INT_PRINT_DEC (for HOST_WIDE_INT
* argument), or HOST_SIZE_T_PRINT_UNSIGNED (for size_t, with casts to
* (fmt_size_t)).
*/
void
dbgmsg(const char *msg, ...) {
if( yy_flex_debug || yydebug ) {
@@ -2647,12 +2648,6 @@ dbgmsg(const char *msg, ...) {
}
}
void
dialect_error( const YYLTYPE& loc, const char term[], const char dialect[] ) {
error_msg(loc, "%s is not ISO syntax, requires %<-dialect %s%>",
term, dialect);
}
bool fisdigit(int c)
{
return ISDIGIT(c);

View File

@@ -31,8 +31,6 @@
#ifndef _UTIL_H_
#define _UTIL_H_
void cbl_message(int fd, const char *format_string, ...)
ATTRIBUTE_PRINTF_2;
[[noreturn]] void cbl_internal_error(const char *format_string, ...)
ATTRIBUTE_GCOBOL_DIAG(1, 2);