Skip to content

Commit

Permalink
Add -fdiagnostics-show-caret to display the context of an error
Browse files Browse the repository at this point in the history
When a warning or error is printed, prints the source context with the
line of the error, plus 2 lines before and after.
COBC_DIAGNOSTICS_SHOW_CARET can be used to set the option globally.
Also option `-fno-diagnostics-show-line-numbers` to not print
line numbers in carets.
  • Loading branch information
lefessan committed May 26, 2023
1 parent 1992539 commit 2537121
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 34 deletions.
13 changes: 10 additions & 3 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,19 @@ NEWS - user visible changes -*- outline -*-
dialect configuration options accompanying each specificity
introduced by the dialect.

** new compiler flags to improve diagnostics -fdiagnostics-show-caret and
-fno-diagnostics-show-line-numbers: with -fdiagnostics-show-caret,
the content of lines surrounding error locations are displayed after
the error message. With -fno-diagnostics-show-line-numbers, the line
numbers are not printed within the content.

* Important Bugfixes:

** for dialects other than the GnuCOBOL default different reserved "alias" words
were not usable, for example SYNCHRONIZED or COMPUTATIONAL. This was fixed
and reserved words updated for the dialects "acu" (to ACUCOBOL-GT 10.4),
"ibm" (to Enterprise COBOL 6.3) and "mf" (to Micro Focus Visual COBOL 6.0)
were not usable, for example SYNCHRONIZED or COMPUTATIONAL. This
was fixed and reserved words updated for the dialects "acu" (to
ACUCOBOL-GT 10.4), "ibm" (to Enterprise COBOL 6.3) and "mf" (to
Micro Focus Visual COBOL 6.0)

** for all "lax" updates SYNC was handled even if commonly ignored by the strict
dialects, this was fixed so SYNC is ignored depending on the dialect
Expand Down
15 changes: 15 additions & 0 deletions cobc/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@

2023-02-16 Fabrice Le Fessant <fabrice.le_fessant@ocamlpro.com>

* flag.def (cb_diagnostics_show_caret), error.c
(diagnostics_show_caret): add argument `-fdiagnostics-show-caret`
to display the source context of the error/warning (2 lines before
and after the location). Add argument
`-fno-diagnostics-show-line-numbers` to disable printing of
line numbers in carets. Rename `cb_diagnostic_show_option` into
`cb_diagnostics_show_option` to match the argument name.
* error.c (cb_error_kind): replace all occurrences of a
error/warning/note string by a symbolic enum.
* cobc.c (set_cobc_defaults): add env variable
`COBC_DIAGNOSTICS_SHOW_CARET` to enable show caret. Special value
`-L` can be used to disable line numbers in carets.

2023-05-23 Simon Sobisch <simonsobisch@gnu.org>

* parser.y (control_source): allow both an alphanumeric identifier or
Expand Down
13 changes: 13 additions & 0 deletions cobc/cobc.c
Original file line number Diff line number Diff line change
Expand Up @@ -8658,6 +8658,19 @@ set_cobc_defaults (void)
*p == '1')) {
cb_unix_lf = 1;
}

p = cobc_getenv ("COBC_DIAGNOSTICS_SHOW_CARET");
if (p){
cb_diagnostics_show_caret =
(*p == 'Y' || *p == 'y' ||
*p == 'O' || *p == 'o' ||
*p == 'T' || *p == 't' ||
*p == 'E' || *p == 'e' ||
*p == '1') ? 1 : 0;
/* Use '-L' to disable line numbers in caret */
cb_diagnostics_show_line_numbers =
(*p == '-' && *(p+1) == 'L') ? 0 : 1;
}
}

/* Setup for the C compiler/linker */
Expand Down
135 changes: 113 additions & 22 deletions cobc/error.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@
#include "cobc.h"
#include "tree.h"

enum cb_error_kind {
CB_KIND_ERROR,
CB_KIND_WARNING,
CB_KIND_NOTE,
CB_KIND_OTHER
};

static char *errnamebuff = NULL;
static struct cb_label *last_section = NULL;
static struct cb_label *last_paragraph = NULL;
Expand Down Expand Up @@ -63,10 +70,80 @@ print_error_prefix (const char *file, int line, const char *prefix)
}
}

/* Display a context around the location of the error/warning, only if
* cb_diagnostics_show_caret is true
Only display two lines before and after. No caret yet for the column as
we only have the line. Since we directly use the file, source is printed
before any REPLACE.
*/

#define CARET_MAX_COLS 73
static void
diagnostics_show_caret (const char *file, int line)
{
FILE* fd = fopen(file, "r");
if (fd == NULL) return;
char buffer[ CARET_MAX_COLS+1 ];
int line_pos = 1;
int char_pos = 0;
int printed = 0; /* nothing printed */
while(1){
int c = fgetc (fd);
if ( c == EOF ){
if (printed){
fprintf(stderr, "\n");
}
fclose(fd);
return ;
}
buffer[char_pos] = c ;
if (c == '\n' || char_pos == CARET_MAX_COLS){
buffer[char_pos] = 0;
if (line_pos > line-3 && line_pos < line+3){
if (line_pos == line-2) fprintf(stderr, "\n");
printed = 1;
fprintf (stderr, " ");
if (cb_diagnostics_show_line_numbers){
fprintf (stderr, "%04d ",
line_pos);
}
fprintf (stderr, "%c %s%s\n",
line == line_pos ? '>' : ' ',
c == '\n' ? "" : ".." ,
buffer);
if (line_pos == line+2){
fprintf(stderr, "\n");
fclose(fd);
return;
}
}
while (c != '\n'){
/* skip end of line too long */
c = fgetc (fd);
if( c == EOF ) { fclose(fd); return ; }
}
line_pos++;
char_pos=0;
} else {
char_pos++;
}
}
}

static void
print_error (const char *file, int line, const char *prefix,
print_error (const char *file, int line, enum cb_error_kind kind,
const char *fmt, va_list ap, const char *diagnostic_option)
{
const char *prefix;

switch( kind ){
case CB_KIND_ERROR: prefix = _("error: "); break;
case CB_KIND_WARNING: prefix = _("warning: "); break;
case CB_KIND_NOTE: prefix = _("note: "); break;
case CB_KIND_OTHER: prefix = ""; break;
}

if (!file) {
file = cb_source_file;
}
Expand Down Expand Up @@ -119,12 +196,26 @@ print_error (const char *file, int line, const char *prefix,
}
cb_add_error_to_listing (file, line, prefix, errmsg);
}

static const char* last_caret_file = NULL ;
static int last_caret_line = -1 ;
if (cb_diagnostics_show_caret
&& file != NULL
&& strcmp (file, COB_DASH) != 0
&& line
&& (last_caret_file != file || last_caret_line != line)
){
/* remember last printed location to avoid reprinting it */
last_caret_file = file;
last_caret_line = line;
diagnostics_show_caret (file, line);
}
}

static void
cobc_too_many_errors (void)
{
if (!cb_diagnostic_show_option) {
if (!cb_diagnostics_show_option) {
fprintf (stderr, "cobc: %s\n",
_("too many errors"));
} else
Expand Down Expand Up @@ -306,7 +397,7 @@ static char *warning_option_text (const enum cb_warn_opt opt, const enum cb_warn
{
const char *opt_name;

if (!cb_diagnostic_show_option) {
if (!cb_diagnostics_show_option) {
return NULL;
}
switch (opt) {
Expand Down Expand Up @@ -343,9 +434,9 @@ cb_warning_internal (const enum cb_warn_opt opt, const char *fmt, va_list ap)
}

if (pref != COBC_WARN_AS_ERROR) {
print_error (NULL, 0, _("warning: "), fmt, ap, warning_option_text (opt, pref));
print_error (NULL, 0, CB_KIND_WARNING, fmt, ap, warning_option_text (opt, pref));
} else {
print_error (NULL, 0, _("error: "), fmt, ap, warning_option_text (opt, pref));
print_error (NULL, 0, CB_KIND_ERROR, fmt, ap, warning_option_text (opt, pref));
}

if (sav_lst_file) {
Expand Down Expand Up @@ -379,7 +470,7 @@ cb_error_always (const char *fmt, ...)

cobc_in_repository = 0;
va_start (ap, fmt);
print_error (NULL, 0, _("error: "), fmt, ap, NULL);
print_error (NULL, 0, CB_KIND_ERROR, fmt, ap, NULL);
va_end (ap);

if (sav_lst_file) {
Expand All @@ -405,12 +496,12 @@ cb_error_internal (const char *fmt, va_list ap)
}

if (!ignore_error) {
print_error (NULL, 0, _("error: "), fmt, ap, NULL);
print_error (NULL, 0, CB_KIND_ERROR, fmt, ap, NULL);
ret = COBC_WARN_AS_ERROR;
} else if (pref == COBC_WARN_AS_ERROR) {
print_error (NULL, 0, _("error: "), fmt, ap, warning_option_text (opt, pref));
print_error (NULL, 0, CB_KIND_ERROR, fmt, ap, warning_option_text (opt, pref));
} else {
print_error (NULL, 0, _("warning: "), fmt, ap, warning_option_text (opt, pref));
print_error (NULL, 0, CB_KIND_WARNING, fmt, ap, warning_option_text (opt, pref));
}

if (sav_lst_file) {
Expand Down Expand Up @@ -447,7 +538,7 @@ cb_perror (const int config_error, const char *fmt, ...)
}

va_start (ap, fmt);
print_error (NULL, 0, "", fmt, ap, NULL);
print_error (NULL, 0, CB_KIND_OTHER, fmt, ap, NULL);
va_end (ap);


Expand All @@ -472,9 +563,9 @@ cb_plex_warning (const enum cb_warn_opt opt, const size_t sline, const char *fmt

va_start (ap, fmt);
if (pref != COBC_WARN_AS_ERROR) {
print_error (NULL, cb_source_line + (int)sline, _("warning: "), fmt, ap, warning_option_text (opt, pref));
print_error (NULL, cb_source_line + (int)sline, CB_KIND_WARNING, fmt, ap, warning_option_text (opt, pref));
} else {
print_error (NULL, cb_source_line + (int)sline, _("error: "), fmt, ap, warning_option_text (opt, pref));
print_error (NULL, cb_source_line + (int)sline, CB_KIND_ERROR, fmt, ap, warning_option_text (opt, pref));
}
va_end (ap);

Expand All @@ -496,7 +587,7 @@ cb_plex_error (const size_t sline, const char *fmt, ...)
va_list ap;

va_start (ap, fmt);
print_error (NULL, cb_source_line + (int)sline, ("error: "), fmt, ap, NULL);
print_error (NULL, cb_source_line + (int)sline, CB_KIND_ERROR, fmt, ap, NULL);
va_end (ap);

if (sav_lst_file) {
Expand Down Expand Up @@ -628,7 +719,7 @@ cb_warning_x_internal (const enum cb_warn_opt opt, cb_tree x, const char *fmt, v
}

print_error (x->source_file, x->source_line,
pref == COBC_WARN_AS_ERROR ? _("error: ") : _("warning: "),
pref == COBC_WARN_AS_ERROR ? CB_KIND_ERROR : CB_KIND_WARNING,
fmt, ap, warning_option_text (opt, pref));

if (sav_lst_file) {
Expand Down Expand Up @@ -672,7 +763,7 @@ cb_warning_dialect_x (const enum cb_support tag, cb_tree x, const char *fmt, ...

va_start (ap, fmt);
print_error (x->source_file, x->source_line,
ret == COBC_WARN_AS_ERROR ? _("error: ") : _("warning: "),
ret == COBC_WARN_AS_ERROR ? CB_KIND_ERROR : CB_KIND_WARNING,
fmt, ap, NULL);
va_end (ap);

Expand Down Expand Up @@ -725,10 +816,10 @@ cb_note_x (const enum cb_warn_opt opt, cb_tree x, const char *fmt, ...)
listprint_suppress ();
va_start (ap, fmt);
if (opt != COB_WARNOPT_NONE) {
print_error (x->source_file, x->source_line, _("note: "),
print_error (x->source_file, x->source_line, CB_KIND_NOTE,
fmt, ap, warning_option_text (opt, pref));
} else {
print_error (x->source_file, x->source_line, _("note: "),
print_error (x->source_file, x->source_line, CB_KIND_NOTE,
fmt, ap, NULL);
}
va_end (ap);
Expand All @@ -752,10 +843,10 @@ cb_note (const enum cb_warn_opt opt, const int suppress_listing, const char *fmt
}
va_start (ap, fmt);
if (opt != COB_WARNOPT_NONE) {
print_error (NULL, 0, _("note: "),
print_error (NULL, 0, CB_KIND_NOTE,
fmt, ap, warning_option_text (opt, pref));
} else {
print_error (NULL, 0, _("note: "),
print_error (NULL, 0, CB_KIND_NOTE,
fmt, ap, NULL);
}
va_end (ap);
Expand All @@ -776,13 +867,13 @@ cb_error_x_internal (cb_tree x, const char *fmt, va_list ap)
}

if (!ignore_error) {
print_error (x->source_file, x->source_line, _("error: "),
print_error (x->source_file, x->source_line, CB_KIND_ERROR,
fmt, ap, NULL);
} else if (pref == COBC_WARN_AS_ERROR) {
print_error (x->source_file, x->source_line, _("error: "),
print_error (x->source_file, x->source_line, CB_KIND_ERROR,
fmt, ap, warning_option_text (opt, pref));
} else {
print_error (x->source_file, x->source_line, _("warning: "),
print_error (x->source_file, x->source_line, CB_KIND_WARNING,
fmt, ap, warning_option_text (opt, pref));
ret = COBC_WARN_ENABLED;
}
Expand Down
12 changes: 11 additions & 1 deletion cobc/flag.def
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,16 @@ CB_FLAG (cb_listing_symbols, 1, "tsymbols",
CB_FLAG (cb_listing_cmd, 1, "tcmd",
_(" -ftcmd specify command line in listing"))

CB_FLAG_ON (cb_diagnostic_show_option, 1, "diagnostics-show-option",
CB_FLAG_ON (cb_diagnostics_show_option, 1, "diagnostics-show-option",
_(" -fno-diagnostics-show-option\tsuppress output of option that directly\n"
" controls the diagnostic"))

CB_FLAG (cb_diagnostics_show_caret, 1, "diagnostics-show-caret",
_(" -fdiagnostics-show-caret display source context on warning/error diagnostic\n"
" (the source is displayed without any REPLACE performed."
))

CB_FLAG_ON (cb_diagnostics_show_line_numbers, 1, "diagnostics-show-caret-line-numbers",
_(" -fno-diagnostics-show-line-numbers suppress display of line numbers in diagnostics"

))
Loading

0 comments on commit 2537121

Please sign in to comment.