mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
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.
568 lines
22 KiB
C++
568 lines
22 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
#ifndef SHOW_PARSE_H_
|
|
#define SHOW_PARSE_H_
|
|
|
|
// These macros provide information about what the compiler is doing,
|
|
// and about what the compiled code is doing.
|
|
|
|
// SHOW_PARSE gives information when parser_xxx functions are entered, and
|
|
// then attempts to give as much information as it can at compile time about
|
|
// variables and their characteristics, the contents of literals, and such. It
|
|
// doesn't affect the executable at all.
|
|
|
|
// TRACE1 lays down code for run-time tracing.
|
|
|
|
// SHOW_PARSE must be followed by a bracketed set of instructions, no semicolon
|
|
|
|
extern bool bSHOW_PARSE;
|
|
extern bool show_parse_sol;
|
|
extern int show_parse_indent;
|
|
|
|
extern char const *bTRACE1;
|
|
extern tree trace_handle;
|
|
extern tree trace_indent;
|
|
extern bool cursor_at_sol;
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
|
|
|
/*
|
|
* In syntax-only mode, return immediately. By using these macros, the parser
|
|
* can call code-generation functions unconditionally because it does not rely
|
|
* on the results.
|
|
*/
|
|
#define RETURN_IF_PARSE_ONLY \
|
|
do { if( mode_syntax_only() ) return; } while(0)
|
|
|
|
#define RETURN_XX_PARSE_ONLY(XX) \
|
|
do { if( mode_syntax_only() ) return XX; } while(0)
|
|
|
|
#define SHOW_PARSE1 if(bSHOW_PARSE)
|
|
#define SHOW_PARSE RETURN_IF_PARSE_ONLY; if(bSHOW_PARSE)
|
|
#define SHOW_IF_PARSE(XX) RETURN_XX_PARSE_ONLY((XX)); if(bSHOW_PARSE)
|
|
|
|
// _HEADER and _END are generally the first and last things inside the
|
|
// SHOW_PARSE statement. They don't have to be; SHOW_PARSE can be used
|
|
// anywhere
|
|
#define SHOW_PARSE_HEADER do \
|
|
{ \
|
|
if(!show_parse_sol){fprintf(stderr, "\n");} \
|
|
show_parse_indent=fprintf(stderr, \
|
|
"( %d ) %s():" , \
|
|
(CURRENT_LINE_NUMBER), __func__); \
|
|
show_parse_sol=false; \
|
|
}while(0);
|
|
#define SHOW_PARSE_END do{fprintf(stderr, "\n");show_parse_sol=true;}while(0);
|
|
|
|
// This does one simple text string
|
|
#define SHOW_PARSE_TEXT(a) do \
|
|
{ \
|
|
fprintf(stderr, "%s", a); \
|
|
show_parse_sol=false; \
|
|
}while(0);
|
|
|
|
#define SHOW_PARSE_INDENT do{ \
|
|
if(!show_parse_sol){fprintf(stderr, "\n");} \
|
|
for(int i=0; i<show_parse_indent-1; i++) \
|
|
{fprintf(stderr, " ");} \
|
|
fprintf(stderr, ": "); \
|
|
show_parse_sol=false; \
|
|
}while(0);
|
|
|
|
// This does three simple text strings.
|
|
#define SHOW_PARSE_TEXT_AB(pre, a, post) do \
|
|
{ \
|
|
SHOW_PARSE_TEXT(pre);SHOW_PARSE_TEXT(a);SHOW_PARSE_TEXT(post) \
|
|
}while(0);
|
|
|
|
//
|
|
#define SHOW_PARSE_FIELD(pre, b) \
|
|
do \
|
|
{ \
|
|
fprintf(stderr, "%s", pre); \
|
|
if( !(b) ) \
|
|
{ \
|
|
fprintf(stderr, "parameter " #b " is NULL"); \
|
|
} \
|
|
else \
|
|
{ \
|
|
fprintf(stderr, "%s", (b)->name); \
|
|
if( (b)->type == FldLiteralA || (b)->type == FldLiteralN ) \
|
|
{ \
|
|
fprintf(stderr, " \"%s\"", (b)->data.initial); \
|
|
} \
|
|
else \
|
|
{ \
|
|
fprintf(stderr, "<%s>", cbl_field_type_str((b)->type)); \
|
|
} \
|
|
} \
|
|
show_parse_sol = false; \
|
|
} while(0);
|
|
|
|
#define SHOW_PARSE_REF(pre, b) \
|
|
do \
|
|
{ \
|
|
fprintf(stderr, "%s", pre); \
|
|
if( !(b).field ) \
|
|
{ \
|
|
fprintf(stderr, "parameter " #b".field is NULL"); \
|
|
} \
|
|
else \
|
|
{ \
|
|
fprintf(stderr, "%s", (b).field->name); \
|
|
if( (b).field->type == FldLiteralA || (b).field->type == FldLiteralN ) \
|
|
{ \
|
|
size_t nbytes; \
|
|
const char *literal = __gg__iconverter((b).field->codeset.encoding, \
|
|
DEFAULT_SOURCE_ENCODING, \
|
|
(b).field->data.initial, \
|
|
strlen((b).field->data.initial), \
|
|
&nbytes); \
|
|
fprintf(stderr, " \"%s\"", literal); \
|
|
} \
|
|
else \
|
|
{ \
|
|
fprintf(stderr, "<%s>", cbl_field_type_str((b).field->type)); \
|
|
} \
|
|
} \
|
|
if( (b).nsubscript()) \
|
|
{ \
|
|
fprintf(stderr,"("); \
|
|
for(size_t jjj=0; jjj<(b).nsubscript(); jjj++) \
|
|
{ \
|
|
if(jjj) \
|
|
{ \
|
|
SHOW_PARSE_FIELD(" ", (b).subscripts[jjj].field) \
|
|
} \
|
|
else \
|
|
{ \
|
|
SHOW_PARSE_FIELD("", (b).subscripts[jjj].field) \
|
|
} \
|
|
} \
|
|
fprintf(stderr,")"); \
|
|
} \
|
|
show_parse_sol = false; \
|
|
} while(0);
|
|
|
|
#define SHOW_PARSE_LABEL(a, b) \
|
|
do \
|
|
{ \
|
|
fprintf(stderr, "%s", a); \
|
|
if( !b ) \
|
|
{ \
|
|
fprintf(stderr, "label " #b " is NULL"); \
|
|
} \
|
|
else \
|
|
{ \
|
|
fprintf(stderr, " %p:%s (%s)", static_cast<void*>(b), b->name, b->type_str()); \
|
|
} \
|
|
show_parse_sol = false; \
|
|
} while(0);
|
|
|
|
// Use this version when b is known to be valid. This is necessary to quiet
|
|
// cppcheck nullPointerRedundantCheck warnings
|
|
#define SHOW_PARSE_LABEL_OK(a, b) \
|
|
do \
|
|
{ \
|
|
fprintf(stderr, "%s", a); \
|
|
fprintf(stderr, " %p:%s (%s)", static_cast<void*>(b), b->name, b->type_str()); \
|
|
show_parse_sol = false; \
|
|
} while(0);
|
|
|
|
#define TRACE1 if(bTRACE1)
|
|
#define TRACE1_HEADER do \
|
|
{ \
|
|
if(!cursor_at_sol){gg_fprintf(trace_handle , 0, "\n");} \
|
|
gg_assign(trace_indent, \
|
|
gg_fprintf( trace_handle , \
|
|
2, \
|
|
">>>>>>( %d )(%s) ", \
|
|
build_int_cst_type(INT, CURRENT_LINE_NUMBER), \
|
|
gg_string_literal(__func__))); \
|
|
}while(0);
|
|
|
|
#define TRACE1_INDENT do{ \
|
|
if(!cursor_at_sol){gg_fprintf(trace_handle , 0, "\n");} \
|
|
tree counter = gg_define_int(); \
|
|
gg_assign(counter, integer_zero_node); \
|
|
WHILE(counter, lt_op, trace_indent) \
|
|
gg_fprintf(trace_handle , 0, " "); \
|
|
gg_increment(counter); \
|
|
WEND \
|
|
}while(0);
|
|
|
|
#define TRACE1_END do{gg_fprintf(trace_handle, 0, "\n");cursor_at_sol=true;}while(0);
|
|
|
|
#define TRACE1_TEXT(a) do{cursor_at_sol=false;gg_fprintf(trace_handle, 1, "%s", gg_string_literal(a));}while(0);
|
|
#define TRACE1_TEXT_ABC(a,b,c) do{TRACE1_TEXT(a);TRACE1_TEXT(b);TRACE1_TEXT(c)}while(0);
|
|
|
|
#define TRACE1_FIELD_VALUE(a, field, b) \
|
|
do \
|
|
{ \
|
|
gcc_assert(field); \
|
|
cursor_at_sol=false; \
|
|
if ( field->type == FldConditional ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s \"", gg_string_literal(a)); \
|
|
parser_display_internal_field(trace_handle, field, false); \
|
|
gg_fprintf(trace_handle, 1, "\" %s", gg_string_literal(b)); \
|
|
} \
|
|
else \
|
|
{ \
|
|
IF( member(field->var_decl_node, "data"), eq_op, gg_cast(UCHAR_P, null_pointer_node) ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s ", gg_string_literal(a)); \
|
|
gg_fprintf(trace_handle, 0, "NULL"); \
|
|
gg_fprintf(trace_handle, 1, " %s", gg_string_literal(b)); \
|
|
} \
|
|
ELSE \
|
|
{ \
|
|
if( field->type == FldGroup \
|
|
|| field->type == FldAlphanumeric \
|
|
|| field->type == FldAlphaEdited \
|
|
|| field->type == FldLiteralA ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s \"", gg_string_literal(a)); \
|
|
parser_display_internal_field(trace_handle, field, false); \
|
|
gg_fprintf(trace_handle, 1, "\" %s", gg_string_literal(b)); \
|
|
} \
|
|
else \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s [", gg_string_literal(a)); \
|
|
parser_display_internal_field(trace_handle, field, false); \
|
|
gg_fprintf(trace_handle, 1, "] %s", gg_string_literal(b)); \
|
|
} \
|
|
} \
|
|
ENDIF \
|
|
} \
|
|
}while(0);
|
|
|
|
#define TRACE1_REFER_VALUE(a, refer, b) \
|
|
do \
|
|
{ \
|
|
if( refer.field ) \
|
|
{ \
|
|
cursor_at_sol=false; \
|
|
IF( member(refer.field->var_decl_node, "data"), eq_op, gg_cast(UCHAR_P, null_pointer_node) ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s ", gg_string_literal(a)); \
|
|
gg_fprintf(trace_handle, 0, "NULL"); \
|
|
gg_fprintf(trace_handle, 1, " %s", gg_string_literal(b)); \
|
|
} \
|
|
ELSE \
|
|
{ \
|
|
if( refer.field->type == FldGroup \
|
|
|| refer.field->type == FldAlphanumeric \
|
|
|| refer.field->type == FldAlphaEdited \
|
|
|| refer.field->type == FldLiteralA ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s \"", gg_string_literal(a)); \
|
|
parser_display_internal(trace_handle, refer, false); \
|
|
gg_fprintf(trace_handle, 1, "\" %s", gg_string_literal(b)); \
|
|
} \
|
|
else \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s [", gg_string_literal(a)); \
|
|
parser_display_internal(trace_handle, refer, false); \
|
|
gg_fprintf(trace_handle, 1, "] %s", gg_string_literal(b)); \
|
|
} \
|
|
} \
|
|
ENDIF \
|
|
} \
|
|
else \
|
|
{ \
|
|
gg_fprintf(trace_handle, 0, "refer.field is NULL"); \
|
|
} \
|
|
}while(0);
|
|
|
|
#define TRACE1_FIELD_INFO(pre, b) \
|
|
do{ \
|
|
cursor_at_sol=false; \
|
|
gg_fprintf(trace_handle, 1, "%s", gg_string_literal(pre)); \
|
|
if( !b ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 0, "field " #b " is NULL"); \
|
|
} \
|
|
else \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s", gg_string_literal(b->name)); \
|
|
gg_fprintf(trace_handle, 1, " (%s", gg_string_literal(cbl_field_type_str((b)->type))); \
|
|
if( b->type != FldLiteralN && b->type != FldConditional ) \
|
|
{ \
|
|
cbl_field_t* B(b); \
|
|
if( !b->var_decl_node ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 0, #b "->var_decl_node is NULL", NULL_TREE); \
|
|
} \
|
|
else \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, " attr 0x%lx", member(B, "attr" )); \
|
|
gg_fprintf(trace_handle, 1, " c:o:d:r %ld", member(B, "capacity")); \
|
|
gg_fprintf(trace_handle, 1, ":%ld", member(B, "offset" )); \
|
|
gg_fprintf(trace_handle, 1, ":%d", gg_cast(INT, (member(B, "digits" )))); \
|
|
gg_fprintf(trace_handle, 1, ":%d", gg_cast(INT, (member(B, "rdigits" )))); \
|
|
} \
|
|
} \
|
|
else if( b->type == FldLiteralN ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, " attr 0x%lx", build_int_cst_type(SIZE_T, b->attr)); \
|
|
gg_fprintf(trace_handle, 1, " c:o:d:r %ld", build_int_cst_type(SIZE_T, b->data.capacity)); \
|
|
gg_fprintf(trace_handle, 1, ":%ld", build_int_cst_type(SIZE_T, b->offset)); \
|
|
gg_fprintf(trace_handle, 1, ":%d", build_int_cst_type(INT, b->data.digits)); \
|
|
gg_fprintf(trace_handle, 1, ":%d", build_int_cst_type(INT, b->data.rdigits)); \
|
|
} \
|
|
gg_fprintf(trace_handle, 0, ")"); \
|
|
} \
|
|
}while(0);
|
|
|
|
#define TRACE1_REFER_INFO(pre, b) \
|
|
do{ \
|
|
cursor_at_sol=false; \
|
|
gg_fprintf(trace_handle, 1, "%s", gg_string_literal(pre)); \
|
|
if( !(b).field ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 0, #b ".field is NULL"); \
|
|
} \
|
|
else \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s", gg_string_literal( (b).field->name ? (b).field->name:"")); \
|
|
if( b.nsubscript() ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 0, "("); \
|
|
for(unsigned int i=0; i<b.nsubscript(); i++) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s", gg_string_literal( b.subscripts[i].field->name ? b.subscripts[i].field->name : "" )); \
|
|
if( i<b.nsubscript()-1 ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 0, " "); \
|
|
} \
|
|
} \
|
|
if( b.refmod.from || b.refmod.len ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 0, "("); \
|
|
if( b.refmod.from ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s", gg_string_literal( b.refmod.from->name() ? b.refmod.from->name() : "" )); \
|
|
} \
|
|
gg_fprintf(trace_handle, 0, ":"); \
|
|
if( b.refmod.len ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, "%s", gg_string_literal( b.refmod.len->name() ? b.refmod.len->name() : "" )); \
|
|
} \
|
|
gg_fprintf(trace_handle, 0, "("); \
|
|
} \
|
|
gg_fprintf(trace_handle, 0, ")"); \
|
|
} \
|
|
gg_fprintf(trace_handle, 1, " (%s", gg_string_literal(cbl_field_type_str((b).field->type))); \
|
|
if( (b).field->type != FldLiteralN && (b).field->type != FldConditional ) \
|
|
{ \
|
|
if( !(b).field->var_decl_node ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 0, #b ".field->var_decl_node is NULL", NULL_TREE); \
|
|
} \
|
|
else \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, " attr 0x%lx", member(b.field, "attr" )); \
|
|
gg_fprintf(trace_handle, 1, " c:o:d:r %ld", member(b.field, "capacity")); \
|
|
gg_fprintf(trace_handle, 1, ":%ld", member(b.field, "offset" )); \
|
|
gg_fprintf(trace_handle, 1, ":%d", gg_cast(INT, (member(b.field, "digits" )))); \
|
|
gg_fprintf(trace_handle, 1, ":%d)", gg_cast(INT, (member(b.field, "rdigits" )))); \
|
|
} \
|
|
} \
|
|
else if( (b).field->type == FldLiteralN ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 1, " attr 0x%lx", build_int_cst_type(SIZE_T, (b).field->attr)); \
|
|
gg_fprintf(trace_handle, 1, " c:o:d:r %ld", build_int_cst_type(SIZE_T, (b).field->data.capacity)); \
|
|
gg_fprintf(trace_handle, 1, ":%ld", build_int_cst_type(SIZE_T, (b).field->offset)); \
|
|
gg_fprintf(trace_handle, 1, ":%d", build_int_cst_type(INT, (b).field->data.digits)); \
|
|
gg_fprintf(trace_handle, 1, ":%d)", build_int_cst_type(INT, (b).field->data.rdigits)); \
|
|
} \
|
|
} \
|
|
}while(0);
|
|
|
|
#define TRACE1_FIELD(a, b, c) \
|
|
do{ \
|
|
TRACE1_FIELD_INFO(a, b) \
|
|
TRACE1_FIELD_VALUE("", b, c) \
|
|
}while(0);
|
|
|
|
#define TRACE1_REFER(a, b, c) \
|
|
do{ \
|
|
TRACE1_REFER_INFO(a, b) \
|
|
TRACE1_REFER_VALUE("", b, c) \
|
|
}while(0);
|
|
|
|
#define TRACE1_LABEL(a, b, c) \
|
|
do{ \
|
|
cursor_at_sol=false; \
|
|
gg_fprintf(trace_handle, 1, "%s", gg_string_literal(a)); \
|
|
if( !b ) \
|
|
{ \
|
|
gg_fprintf(trace_handle, 0, "label " #b " is NULL"); \
|
|
} \
|
|
else \
|
|
{ \
|
|
gg_fprintf(trace_handle, 2, \
|
|
"%s (%s)", \
|
|
gg_string_literal(b->name), \
|
|
gg_string_literal(b->type_str()), \
|
|
NULL_TREE); \
|
|
} \
|
|
gg_fprintf(trace_handle, 1, "%s", gg_string_literal(c)); \
|
|
} while(0);
|
|
|
|
// Use CHECK_FIELD when a should be non-null, and a->var_decl_node also should
|
|
// by non-null. (The useless calls to abort() are because cppcheck doesn't
|
|
// understand that gcc_unreachable doesn't return);
|
|
|
|
// Use this after doing any SHOW_PARSE stuff, to avoid cppcheck complaints
|
|
// about nullPointerRedundantCheck
|
|
#define CHECK_FIELD(a) \
|
|
do { \
|
|
if(!a) \
|
|
{ \
|
|
cbl_internal_error("%s: parameter %<" #a "%> is NULL", __func__); \
|
|
} \
|
|
if( !a->var_decl_node ) \
|
|
{ \
|
|
cbl_internal_error("%s: parameter %<" #a "%> is variable " \
|
|
"%s<%s> with NULL %<var_decl_node%>", \
|
|
__func__, \
|
|
a->name, \
|
|
cbl_field_type_str(a->type) ); \
|
|
} \
|
|
} while(0);
|
|
|
|
// This version is a bit more lax, for special cases
|
|
#define CHECK_FIELD2(a) \
|
|
do { \
|
|
if(!a) \
|
|
{ \
|
|
cbl_internal_error("%s: parameter %<" #a "%> is NULL", __func__); \
|
|
} \
|
|
if( !a->var_decl_node && a->type != FldConditional && a->type != FldLiteralA) \
|
|
{ \
|
|
cbl_internal_error("%s: parameter %<" #a "%> is variable " \
|
|
"%s<%s> with NULL %<var_decl_node%>", \
|
|
__func__, \
|
|
a->name, \
|
|
cbl_field_type_str(a->type) ); \
|
|
} \
|
|
} while(0);
|
|
|
|
|
|
#define CHECK_LABEL(a) \
|
|
do{ \
|
|
if(!a) \
|
|
{ \
|
|
cbl_internal_error("%s: parameter %<" #a "%> is NULL", __func__); \
|
|
} \
|
|
}while(0);
|
|
|
|
#ifdef INCORPORATE_ANALYZER
|
|
// The analyzer requires a C++17 compiler because of the inline static variable
|
|
class ANALYZE
|
|
{
|
|
private:
|
|
const char *func;
|
|
int level;
|
|
inline static int analyze_level=1;
|
|
public:
|
|
ANALYZE(const char *func_) : func(func_) // cppcheck-suppress noExplicitConstructor
|
|
{
|
|
level = 0;
|
|
if( getenv("Analyze") )
|
|
{
|
|
level = analyze_level++;
|
|
char ach[128];
|
|
snprintf(ach, sizeof(ach), "# %s analyze_enter %d", func, level);
|
|
if( !mode_syntax_only() )
|
|
{
|
|
gg_insert_into_assembler(ach);
|
|
}
|
|
}
|
|
}
|
|
~ANALYZE()
|
|
{
|
|
ExitMessage();
|
|
}
|
|
void ExitMessage()
|
|
{
|
|
if( getenv("Analyze") )
|
|
{
|
|
char ach[128];
|
|
snprintf(ach, sizeof(ach), "# %s analyze_exit %d", func, level);
|
|
if( !mode_syntax_only() )
|
|
{
|
|
gg_insert_into_assembler(ach);
|
|
}
|
|
}
|
|
}
|
|
void Message(const char *msg)
|
|
{
|
|
if( getenv("Analyze") )
|
|
{
|
|
char ach[128];
|
|
snprintf(ach, sizeof(ach), "# %s %s %d", func, msg, level);
|
|
if( !mode_syntax_only() )
|
|
{
|
|
gg_insert_into_assembler(ach);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
#else
|
|
// cppcheck-suppress ctuOneDefinitionRuleViolation
|
|
class ANALYZE
|
|
{
|
|
public:
|
|
explicit ANALYZE(const char *)
|
|
{
|
|
}
|
|
~ANALYZE()
|
|
{
|
|
ExitMessage();
|
|
}
|
|
void ExitMessage()
|
|
{
|
|
}
|
|
void Message(const char *)
|
|
{
|
|
}
|
|
};
|
|
#endif
|
|
|
|
#define Analyze() ANALYZE Analyzer(__func__);
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#endif
|