mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-21 02:03:03 +00:00
errors: show carets
* src/locations.c (caret_info): New, persistant information useful for... (location_caret): New, print a caret. (cleanup_caret): Release caret_info cleanly, call it... * src/main.c (main): Here. * src/complain.c (error_message): Call location_caret here.
This commit is contained in:
@@ -74,11 +74,15 @@ error_message (location *loc,
|
|||||||
vfprintf (stderr, message, args);
|
vfprintf (stderr, message, args);
|
||||||
{
|
{
|
||||||
size_t l = strlen (message);
|
size_t l = strlen (message);
|
||||||
if (l < 2 || message[l-2] != ':' || message[l-1] != ' ') {
|
if (l < 2 || message[l - 2] != ':' || message[l - 1] != ' ')
|
||||||
putc ('\n', stderr);
|
{
|
||||||
fflush (stderr);
|
putc ('\n', stderr);
|
||||||
}
|
fflush (stderr);
|
||||||
|
if (loc && feature_flag & feature_caret)
|
||||||
|
location_caret (stderr, *loc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
fflush (stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Wrap error_message() with varargs handling. */
|
/** Wrap error_message() with varargs handling. */
|
||||||
|
|||||||
@@ -646,7 +646,7 @@ getargs (int argc, char *argv[])
|
|||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
FLAGS_ARGMATCH (flag, optarg);
|
FLAGS_ARGMATCH (feature, optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'W':
|
case 'W':
|
||||||
|
|||||||
13
src/gram.c
13
src/gram.c
@@ -308,11 +308,16 @@ grammar_rules_useless_report (const char *message)
|
|||||||
for (r = 0; r < nrules ; ++r)
|
for (r = 0; r < nrules ; ++r)
|
||||||
if (!rules[r].useful)
|
if (!rules[r].useful)
|
||||||
{
|
{
|
||||||
warn_at (rules[r].location, "%s: ", message);
|
if (feature_flag & feature_caret)
|
||||||
if (warnings_flag & warnings_other)
|
warn_at (rules[r].location, "%s", message);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
rule_print (&rules[r], stderr);
|
warn_at (rules[r].location, "%s: ", message);
|
||||||
fflush (stderr);
|
if (warnings_flag & warnings_other)
|
||||||
|
{
|
||||||
|
rule_print (&rules[r], stderr);
|
||||||
|
fflush (stderr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,6 +138,89 @@ location_print (FILE *out, location loc)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Persistant data used by location_caret to avoid reopening and rereading the
|
||||||
|
same file all over for each error. */
|
||||||
|
struct caret_info
|
||||||
|
{
|
||||||
|
FILE* source;
|
||||||
|
size_t line;
|
||||||
|
size_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct caret_info caret_info = { NULL, 1, 0 };
|
||||||
|
|
||||||
|
/* Free any allocated ressources and close any open file handles that are
|
||||||
|
left-over by the usage of location_caret. */
|
||||||
|
void
|
||||||
|
cleanup_caret ()
|
||||||
|
{
|
||||||
|
if (caret_info.source)
|
||||||
|
fclose (caret_info.source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output to OUT the line and caret corresponding to location LOC. */
|
||||||
|
void
|
||||||
|
location_caret (FILE *out, location loc)
|
||||||
|
{
|
||||||
|
/* FIXME: find a way to support X-file locations, and only open once each
|
||||||
|
file. That would make the procedure future-proof. */
|
||||||
|
if (! (caret_info.source
|
||||||
|
|| (caret_info.source = fopen (loc.start.file, "r")))
|
||||||
|
|| loc.start.column == -1 || loc.start.line == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If the line we want to quote is seekable (the same line as the previous
|
||||||
|
location), just seek it. If it was before, we lost track of it, so
|
||||||
|
return to the start of file. */
|
||||||
|
if (caret_info.line <= loc.start.line)
|
||||||
|
fseek (caret_info.source, caret_info.offset, SEEK_SET);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
caret_info.line = 1;
|
||||||
|
caret_info.offset = 0;
|
||||||
|
fseek (caret_info.source, caret_info.offset, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance to the line's position, keeping track of the offset. */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = caret_info.line; i < loc.start.line; caret_info.offset++)
|
||||||
|
if (fgetc (caret_info.source) == '\n')
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
caret_info.line = loc.start.line;
|
||||||
|
|
||||||
|
/* Read the actual line. Don't update the offset, so that we keep a pointer
|
||||||
|
to the start of the line. */
|
||||||
|
{
|
||||||
|
ssize_t len = 0;
|
||||||
|
char *buf = NULL;
|
||||||
|
if ((len = getline (&buf, (size_t*) &len, caret_info.source)) != -1)
|
||||||
|
{
|
||||||
|
/* The caret of a multiline location ends with the first line. */
|
||||||
|
int end = loc.start.line != loc.end.line ? len : loc.end.column;
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
int i = loc.start.column;
|
||||||
|
/* Quote the file, indent by a single column. */
|
||||||
|
fputc (' ', out);
|
||||||
|
fwrite (buf, 1, len, out);
|
||||||
|
|
||||||
|
/* Print the caret, with the same indent as above. */
|
||||||
|
fputc (' ', out);
|
||||||
|
fprintf (out, "%*s", loc.start.column - 1, "");
|
||||||
|
do {
|
||||||
|
fputc ('^', out);
|
||||||
|
} while (++i < end);
|
||||||
|
}
|
||||||
|
fputc ('\n', out);
|
||||||
|
free (buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
boundary_set_from_string (boundary *bound, char *loc_str)
|
boundary_set_from_string (boundary *bound, char *loc_str)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -102,6 +102,13 @@ void location_compute (location *loc,
|
|||||||
characters. */
|
characters. */
|
||||||
unsigned location_print (FILE *out, location loc);
|
unsigned location_print (FILE *out, location loc);
|
||||||
|
|
||||||
|
/* Free any allocated ressources and close any open file handles that are
|
||||||
|
left-over by the usage of location_caret. */
|
||||||
|
void cleanup_caret (void);
|
||||||
|
|
||||||
|
/* Output to OUT the line and caret corresponding to location LOC. */
|
||||||
|
void location_caret (FILE *out, location loc);
|
||||||
|
|
||||||
/* Return -1, 0, 1, depending whether a is before, equal, or
|
/* Return -1, 0, 1, depending whether a is before, equal, or
|
||||||
after b. */
|
after b. */
|
||||||
static inline int
|
static inline int
|
||||||
|
|||||||
@@ -216,5 +216,7 @@ main (int argc, char *argv[])
|
|||||||
timevar_stop (TV_TOTAL);
|
timevar_stop (TV_TOTAL);
|
||||||
timevar_print (stderr);
|
timevar_print (stderr);
|
||||||
|
|
||||||
|
cleanup_caret ();
|
||||||
|
|
||||||
return complaint_issued ? EXIT_FAILURE : EXIT_SUCCESS;
|
return complaint_issued ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user