Merge remote-tracking branch 'origin/maint'

* origin/maint:
  misc: pacify the Tiny C Compiler
  cpp: make the check of Flex version portable
  misc: require getline
  c++: support wide strings for file names
  doc: document carets
  tests: enhance existing tests with carets
  errors: show carets
  getargs: add support for --flags/-f

Conflicts:
	doc/bison.texi
	m4/.gitignore
	src/complain.c
	src/flex-scanner.h
	src/getargs.c
	src/getargs.h
	src/gram.c
	src/main.c
	tests/headers.at
This commit is contained in:
Theophile Ranquet
2012-12-06 11:43:02 +01:00
24 changed files with 519 additions and 43 deletions

View File

@@ -110,12 +110,15 @@ error_message (const location *loc, warnings flags, const char *prefix,
warnings_print_categories (flags);
{
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);
if (loc && feature_flag & feature_caret)
location_caret (stderr, *loc);
}
}
fflush (stderr);
}
/** Raise a complaint. That can be a fatal error, a complaint or just a

View File

@@ -23,18 +23,18 @@
/* Whether this version of Flex is (strictly) greater than
Major.Minor.Subminor. */
#define FLEX_VERSION_GT(Major, Minor, Subminor) \
(defined YY_FLEX_MAJOR_VERSION \
&& (Major < YY_FLEX_MAJOR_VERSION \
|| (Major == YY_FLEX_MAJOR_VERSION \
&& (defined YY_FLEX_MINOR_VERSION \
&& (Minor < YY_FLEX_MINOR_VERSION \
|| (Minor == YY_FLEX_MINOR_VERSION \
&& defined YY_FLEX_SUBMINOR_VERSION \
&& Subminor < YY_FLEX_SUBMINOR_VERSION))))))
#ifdef YY_FLEX_SUBMINOR_VERSION
# define FLEX_VERSION \
(YY_FLEX_MAJOR_VERSION) * 1000000 \
+ (YY_FLEX_MINOR_VERSION) * 1000 \
+ (YY_FLEX_SUBMINOR_VERSION)
#else
# define FLEX_VERSION \
(YY_FLEX_MAJOR_VERSION) * 1000000 \
+ (YY_FLEX_MINOR_VERSION) * 1000
#endif
/* Pacify "gcc -Wmissing-prototypes" when flex 2.5.31 is used. */
#if ! FLEX_VERSION_GT (2, 5, 31)
# if FLEX_VERSION <= 2005031
int FLEX_PREFIX (get_lineno) (void);
FILE *FLEX_PREFIX (get_in) (void);
FILE *FLEX_PREFIX (get_out) (void);
@@ -65,7 +65,7 @@ int FLEX_PREFIX (lex_destroy) (void);
versions according to the Flex manual) leak memory if yylex_destroy is not
invoked. However, yylex_destroy is not defined before Flex 2.5.9, so give
an implementation here that at least appears to work with Flex 2.5.4. */
#if ! FLEX_VERSION_GT (2, 5, 9)
#if FLEX_VERSION <= 2005009
# define yylex_destroy() yy_delete_buffer (YY_CURRENT_BUFFER)
#endif

View File

@@ -46,6 +46,7 @@ bool yacc_flag; /* for -y */
bool nondeterministic_parser = false;
bool glr_parser = false;
int feature_flag = feature_none;
int report_flag = report_none;
int trace_flag = trace_none;
@@ -272,6 +273,27 @@ static const int warnings_types[] =
ARGMATCH_VERIFY (warnings_args, warnings_types);
/*-----------------------.
| --feature's handling. |
`-----------------------*/
static const char * const feature_args[] =
{
"none",
"caret", "diagnostics-show-caret",
"all",
0
};
static const int feature_types[] =
{
feature_none,
feature_caret, feature_caret,
feature_all
};
ARGMATCH_VERIFY (feature_args, feature_types);
/*-------------------------------------------.
| Display the help message and exit STATUS. |
`-------------------------------------------*/
@@ -315,6 +337,7 @@ Operation modes:\n\
--print-datadir output directory containing skeletons and XSLT\n\
-y, --yacc emulate POSIX Yacc\n\
-W, --warnings[=CATEGORY] report the warnings falling in CATEGORY\n\
-f, --feature[=FEATURE] activate miscellaneous features\n\
\n\
"), stdout);
@@ -331,8 +354,8 @@ Parser:\n\
deprecated by '-Dapi.prefix=PREFIX'\n\
-l, --no-lines don't generate '#line' directives\n\
-k, --token-table include a table of token names\n\
\n\
"), stdout);
putc ('\n', stdout);
/* Keep -d and --defines separate so that ../build-aux/cross-options.pl
* won't assume that -d also takes an argument. */
@@ -348,8 +371,8 @@ Output:\n\
-g, --graph[=FILE] also output a graph of the automaton\n\
-x, --xml[=FILE] also output an XML report of the automaton\n\
(the XML schema is experimental)\n\
\n\
"), stdout);
putc ('\n', stdout);
fputs (_("\
Warning categories include:\n\
@@ -375,6 +398,14 @@ THINGS is a list of comma separated words that can include:\n\
`all' include all the above information\n\
`none' disable the report\n\
"), stdout);
putc ('\n', stdout);
fputs (_("\
FEATURE is a list of comma separated words that can include:\n\
`caret' show errors with carets\n\
`all' all of the above\n\
`none' disable all of the above\n\
"), stdout);
putc ('\n', stdout);
printf (_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
@@ -485,6 +516,7 @@ static char const short_options[] =
"W::"
"b:"
"d"
"f::"
"e"
"g::"
"h"
@@ -537,6 +569,7 @@ static struct option const long_options[] =
/* Output. */
{ "defines", optional_argument, 0, 'd' },
{ "feature", optional_argument, 0, 'f' },
/* Operation modes. */
{ "fixed-output-files", no_argument, 0, 'y' },
@@ -629,6 +662,10 @@ getargs (int argc, char *argv[])
version ();
exit (EXIT_SUCCESS);
case 'f':
FLAGS_ARGMATCH (feature, optarg, feature_all);
break;
case 'W':
FLAGS_ARGMATCH (warnings, optarg, Wall);
break;

View File

@@ -108,6 +108,18 @@ enum trace
/** What debug items bison displays during its run. */
extern int trace_flag;
/*-------------.
| --features. |
`-------------*/
enum feature
{
feature_none = 0, /**< No additional feature. */
feature_caret = 1 << 0, /**< Enhance the output of errors with carets. */
feature_all = ~0 /**< All above features. */
};
/** What additional features to use. */
extern int feature_flag;
/** Process the command line arguments.
*

View File

@@ -312,10 +312,15 @@ grammar_rules_useless_report (const char *message)
for (r = 0; r < nrules ; ++r)
if (!rules[r].useful)
{
complain (&rules[r].location, w | silent, "%s: ", message);
rule_print (&rules[r], stderr);
warnings_print_categories (w);
fprintf (stderr, "\n");
if (feature_flag & feature_caret)
complain (&rules[r].location, w, "%s", message);
else
{
complain (&rules[r].location, w | silent, "%s: ", message);
rule_print (&rules[r], stderr);
warnings_print_categories (w);
fprintf (stderr, "\n");
}
}
}
}

View File

@@ -103,7 +103,7 @@ conclude_red (struct obstack *out, int source, rule_number ruleno,
/* If no lookahead tokens were valid transitions, this reduction is
actually hidden, so cancel everything. */
if (first)
return (void) obstack_finish0 (out);
(void) obstack_finish0 (out);
else
{
char const *ed = enabled ? "" : "d";

View File

@@ -138,6 +138,89 @@ location_print (FILE *out, location loc)
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
boundary_set_from_string (boundary *bound, char *loc_str)
{

View File

@@ -102,6 +102,13 @@ void location_compute (location *loc,
characters. */
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
after b. */
static inline int

View File

@@ -215,5 +215,7 @@ main (int argc, char *argv[])
timevar_stop (TV_TOTAL);
timevar_print (stderr);
cleanup_caret ();
return complaint_status ? EXIT_FAILURE : EXIT_SUCCESS;
}