* src/gram.c (rule_rhs_print_xml): Now static, since it isn't used

elsewhere.
* src/print-xml.c: Prefer "const" after types; that's more consistent.
(xml_printf): Indent just 1 space for level.
(e_char, xlate_char): Remove.
(xml_escape_string): Rewrite to avoid undefined behavior (used
storage that was freed from the stack).
(xml_escape_n): Don't bother checking for subscript error.

2007-09-21  Wojciech Polak <polak@gnu.org>

Add support for an -x option to generate an XML report.
It is not documented yet.
* src/print-xml.c: New file.
* src/print-xml.h: Likewise.
* lib/timevar.def (TV_XML): New var.
* src/Makefile.am (bison_SOURCES): Add print-xml.c, print-xml.h.
* src/conflicts.c: Include print-xml.h.
(solved_conflicts_xml_obstack): New var.
(log_resolution, conflicts_solve, conflicts_free):
Add support for XML report.
(conflicts_output_val): New function.
* src/conflicts.h (conflicts_output_val): New decl.
* src/files.c (spec_xml_file): New var.
(compute_output_file_names, output_file_names_free): Add XML support.
* src/files.h (spec_xml_file): New decl.
* src/getargs.c (xml_flag): New var.
(usage, short_options, long_options, getargs): Add XML support.
* src/getargs.h (xml_flag): New decl.
* src/gram.c: Include print-xml.h.
(rule_lhs_print_xml, rule_rhs_print_xml):
(grammar_rules_partial_print_xml, grammar_rules_print_xml):
New functions.
* src/gram.h: Declare external ones.
* src/main.c: Include print-xml.h.
(main): Add XML support.
* src/reduce.c: Include print-xml.h.
(reduce_xml): New function.
* src/reduce.h: Declare it.
* src/state.c: Include print-xml.h.
(state_new): Add XML support.
(state_rule_lookahead_tokens_print_xml): New function.
* src/state.h: Declare it.
(struct state): New member solved_conflicts_xml.
* src/symtab.c (symbol_class_get_string): New function.
* src/symtab.h: Declare it.

2007-09-21  Paul Eggert  <eggert@cs.ucla.edu>
This commit is contained in:
Paul Eggert
2007-09-21 22:53:58 +00:00
parent 6d8e724de2
commit 41d7a5f24d
20 changed files with 1045 additions and 15 deletions

View File

@@ -50,6 +50,7 @@ bison_SOURCES = \
parse-gram.h parse-gram.y \
print.c print.h \
print_graph.c print_graph.h \
print-xml.c print-xml.h \
reader.c reader.h \
reduce.c reduce.h \
revision.c revision.h \

View File

@@ -30,6 +30,7 @@
#include "getargs.h"
#include "gram.h"
#include "lalr.h"
#include "print-xml.h"
#include "reader.h"
#include "state.h"
#include "symtab.h"
@@ -39,6 +40,7 @@ int expected_sr_conflicts = -1;
int expected_rr_conflicts = -1;
static char *conflicts;
static struct obstack solved_conflicts_obstack;
static struct obstack solved_conflicts_xml_obstack;
static bitset shift_set;
static bitset lookahead_set;
@@ -72,23 +74,25 @@ log_resolution (rule *r, symbol_number token,
case shift_resolution:
case right_resolution:
obstack_fgrow2 (&solved_conflicts_obstack,
_("\
Conflict between rule %d and token %s resolved as shift"),
_(" Conflict between rule %d and token %s"
" resolved as shift"),
r->number,
symbols[token]->tag);
break;
case reduce_resolution:
case left_resolution:
obstack_fgrow2 (&solved_conflicts_obstack,
_("\
Conflict between rule %d and token %s resolved as reduce"),
_(" Conflict between rule %d and token %s"
" resolved as reduce"),
r->number,
symbols[token]->tag);
break;
case nonassoc_resolution:
obstack_fgrow2 (&solved_conflicts_obstack,
_("\
Conflict between rule %d and token %s resolved as an error"),
_(" Conflict between rule %d and token %s"
" resolved as an error"),
r->number,
symbols[token]->tag);
break;
@@ -122,13 +126,87 @@ log_resolution (rule *r, symbol_number token,
" (%%right %s)",
symbols[token]->tag);
break;
case nonassoc_resolution:
obstack_fgrow1 (&solved_conflicts_obstack,
" (%%nonassoc %s)",
symbols[token]->tag);
break;
}
obstack_sgrow (&solved_conflicts_obstack, ".\n");
/* XML report */
if (xml_flag)
{
/* The description of the resolution. */
switch (resolution)
{
case shift_resolution:
case right_resolution:
obstack_fgrow2 (&solved_conflicts_xml_obstack,
"<resolution rule=\"%d\" symbol=\"%s\""
" type=\"shift\">",
r->number,
xml_escape (symbols[token]->tag));
break;
case reduce_resolution:
case left_resolution:
obstack_fgrow2 (&solved_conflicts_xml_obstack,
"<resolution rule=\"%d\" symbol=\"%s\""
" type=\"reduce\">",
r->number,
xml_escape (symbols[token]->tag));
break;
case nonassoc_resolution:
obstack_fgrow2 (&solved_conflicts_xml_obstack,
"<resolution rule=\"%d\" symbol=\"%s\""
" type=\"error\">",
r->number,
xml_escape (symbols[token]->tag));
break;
}
/* The reason. */
switch (resolution)
{
case shift_resolution:
obstack_fgrow2 (&solved_conflicts_xml_obstack,
"%s &lt; %s",
xml_escape_n (0, r->prec->tag),
xml_escape_n (1, symbols[token]->tag));
break;
case reduce_resolution:
obstack_fgrow2 (&solved_conflicts_xml_obstack,
"%s &lt; %s",
xml_escape_n (0, symbols[token]->tag),
xml_escape_n (1, r->prec->tag));
break;
case left_resolution:
obstack_fgrow1 (&solved_conflicts_xml_obstack,
"%%left %s",
xml_escape (symbols[token]->tag));
break;
case right_resolution:
obstack_fgrow1 (&solved_conflicts_xml_obstack,
"%%right %s",
xml_escape (symbols[token]->tag));
break;
case nonassoc_resolution:
obstack_fgrow1 (&solved_conflicts_xml_obstack,
"%%nonassoc %s",
xml_escape (symbols[token]->tag));
break;
}
obstack_sgrow (&solved_conflicts_xml_obstack, "</resolution>\n");
}
}
}
@@ -281,6 +359,11 @@ set_conflicts (state *s, symbol **errors)
obstack_1grow (&solved_conflicts_obstack, '\0');
s->solved_conflicts = obstack_finish (&solved_conflicts_obstack);
}
if (obstack_object_size (&solved_conflicts_xml_obstack))
{
obstack_1grow (&solved_conflicts_xml_obstack, '\0');
s->solved_conflicts_xml = obstack_finish (&solved_conflicts_xml_obstack);
}
/* Loop over all rules which require lookahead in this state. Check
for conflicts not resolved above. */
@@ -309,6 +392,7 @@ conflicts_solve (void)
shift_set = bitset_create (ntokens, BITSET_FIXED);
lookahead_set = bitset_create (ntokens, BITSET_FIXED);
obstack_init (&solved_conflicts_obstack);
obstack_init (&solved_conflicts_xml_obstack);
for (i = 0; i < nstates; i++)
{
@@ -438,6 +522,47 @@ conflicts_output (FILE *out)
fputs ("\n\n", out);
}
void
conflicts_output_xml (FILE *out, int level)
{
bool printed_sth = false;
state_number i;
int src_num;
int rrc_num;
for (i = 0; i < nstates; i++)
{
state *s = states[i];
if (conflicts[i])
{
if (!printed_sth) {
fputc ('\n', out);
xml_puts (out, level, "<conflicts>");
}
src_num = count_sr_conflicts (s);
rrc_num = count_rr_conflicts (s, true);
if (src_num)
xml_printf (out, level + 1,
"<conflict state=\"%d\" num=\"%d\""
" type=\"shift/reduce\"/>",
i, src_num);
if (rrc_num)
xml_printf (out, level + 1,
"<conflict state=\"%d\" num=\"%d\""
" type=\"reduce/reduce\"/>",
i, rrc_num);
printed_sth = true;
}
}
if (printed_sth)
xml_puts (out, level, "</conflicts>");
else
xml_puts (out, level, "<conflicts/>");
}
/*--------------------------------------------------------.
| Total the number of S/R and R/R conflicts. Unlike the |
| code in conflicts_output, however, count EACH pair of |
@@ -540,4 +665,5 @@ conflicts_free (void)
bitset_free (shift_set);
bitset_free (lookahead_set);
obstack_free (&solved_conflicts_obstack, NULL);
obstack_free (&solved_conflicts_xml_obstack, NULL);
}

View File

@@ -37,6 +37,7 @@ void conflicts_update_state_numbers (state_number old_to_new[],
void conflicts_print (void);
int conflicts_total_count (void);
void conflicts_output (FILE *out);
void conflicts_output_xml (FILE *out, int level);
void conflicts_free (void);
/* Were there conflicts? */

View File

@@ -45,6 +45,7 @@ char const *spec_file_prefix = NULL; /* for -b. */
char const *spec_name_prefix = NULL; /* for -p. */
char *spec_verbose_file = NULL; /* for --verbose. */
char *spec_graph_file = NULL; /* for -g. */
char *spec_xml_file = NULL; /* for -x. */
char *spec_defines_file = NULL; /* for --defines. */
char *parser_file_name;
@@ -328,6 +329,13 @@ compute_output_file_names (void)
output_file_name_check (spec_graph_file);
}
if (xml_flag)
{
if (! spec_xml_file)
spec_xml_file = concat2 (all_but_tab_ext, ".xml");
output_file_name_check (spec_xml_file);
}
if (report_flag)
{
spec_verbose_file = concat2 (all_but_tab_ext, OUTPUT_EXT);
@@ -358,6 +366,7 @@ output_file_names_free (void)
free (all_but_ext);
free (spec_verbose_file);
free (spec_graph_file);
free (spec_xml_file);
free (spec_defines_file);
free (parser_file_name);
free (dir_prefix);

View File

@@ -41,6 +41,9 @@ extern char *spec_verbose_file;
/* File name specified for the output graph. */
extern char *spec_graph_file;
/* File name specified for the xml output. */
extern char *spec_xml_file;
/* File name specified with --defines. */
extern char *spec_defines_file;

View File

@@ -48,6 +48,7 @@
bool debug_flag;
bool defines_flag;
bool graph_flag;
bool xml_flag;
bool locations_flag;
bool no_lines_flag;
bool token_table_flag;
@@ -285,6 +286,7 @@ Output:\n\
-b, --file-prefix=PREFIX specify a PREFIX for output files\n\
-o, --output=FILE leave output to FILE\n\
-g, --graph also output a graph of the automaton\n\
-x, --xml also output an xml of the automaton\n\
\n\
"), stdout);
@@ -387,7 +389,7 @@ language_argmatch (char const *arg, int prio, location const *loc)
`----------------------*/
/* Shorts options. */
static char const short_options[] = "yvegdhr:L:ltknVo:b:p:S:T::W";
static char const short_options[] = "yvegxdhr:L:ltknVo:b:p:S:T::W";
/* Values for long options that do not have single-letter equivalents. */
enum
@@ -413,6 +415,7 @@ static struct option const long_options[] =
{ "output", required_argument, 0, 'o' },
{ "output-file", required_argument, 0, 'o' },
{ "graph", optional_argument, 0, 'g' },
{ "xml", optional_argument, 0, 'x' },
{ "report", required_argument, 0, 'r' },
{ "verbose", no_argument, 0, 'v' },
@@ -470,6 +473,13 @@ getargs (int argc, char *argv[])
spec_graph_file = xstrdup (AS_FILE_NAME (optarg));
break;
case 'x':
/* Here, the -x and --xml=FILE options are differentiated. */
xml_flag = true;
if (optarg)
spec_xml_file = xstrdup (AS_FILE_NAME (optarg));
break;
case 'h':
usage (EXIT_SUCCESS);

View File

@@ -36,6 +36,7 @@ extern char const *include;
extern bool debug_flag; /* for -t */
extern bool defines_flag; /* for -d */
extern bool graph_flag; /* for -g */
extern bool xml_flag; /* for -x */
extern bool locations_flag;
extern bool no_lines_flag; /* for -l */
extern bool token_table_flag; /* for -k */

View File

@@ -1,7 +1,7 @@
/* Allocate input grammar variables for Bison.
Copyright (C) 1984, 1986, 1989, 2001, 2002, 2003, 2005, 2006 Free
Software Foundation, Inc.
Copyright (C) 1984, 1986, 1989, 2001, 2002, 2003, 2005, 2006
2007 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
@@ -27,6 +27,7 @@
#include "reader.h"
#include "reduce.h"
#include "symtab.h"
#include "print-xml.h"
/* Comments for these variables are in gram.h. */
@@ -102,6 +103,12 @@ rule_lhs_print (rule *r, symbol *previous_lhs, FILE *out)
}
}
void
rule_lhs_print_xml (rule *r, FILE *out, int level)
{
xml_printf (out, level, "<lhs>%s</lhs>", r->lhs->tag);
}
/*--------------------------------------.
| Return the number of symbols in RHS. |
@@ -138,6 +145,26 @@ rule_rhs_print (rule *r, FILE *out)
}
}
static void
rule_rhs_print_xml (rule *r, FILE *out, int level)
{
if (*r->rhs >= 0)
{
item_number *rp;
xml_puts (out, level, "<rhs>");
for (rp = r->rhs; *rp >= 0; rp++)
xml_printf (out, level + 1, "<symbol class=\"%s\">%s</symbol>",
symbol_class_get_string (symbols[*rp]),
xml_escape (symbols[*rp]->tag));
xml_puts (out, level, "</rhs>");
}
else
{
xml_puts (out, level, "<rhs>");
xml_puts (out, level + 1, "<empty/>");
xml_puts (out, level, "</rhs>");
}
}
/*-------------------------.
| Print this rule on OUT. |
@@ -221,6 +248,40 @@ grammar_rules_partial_print (FILE *out, const char *title,
}
/*----------------------------------------------------------.
| Print the grammar's rules that match FILTER on OUT (XML). |
`-----------------------------------------------------------*/
void
grammar_rules_partial_print_xml (FILE *out, int level, bool rtag,
rule_filter filter)
{
rule_number r;
bool first = true;
for (r = 0; r < nrules + nuseless_productions; r++)
{
if (filter && !filter (&rules[r]))
continue;
if (rtag && first)
xml_puts (out, level + 1, "<rules>");
first = false;
xml_printf (out, level + 2, "<rule number=\"%d\">",
rules[r].number);
rule_lhs_print_xml (&rules[r], out, level + 3);
rule_rhs_print_xml (&rules[r], out, level + 3);
xml_puts (out, level + 2, "</rule>");
}
if (rtag)
{
if (!first)
xml_puts (out, level + 1, "</rules>");
else
xml_puts (out, level + 1, "<rules/>");
}
}
/*------------------------------------------.
| Print the grammar's useful rules on OUT. |
`------------------------------------------*/
@@ -231,6 +292,12 @@ grammar_rules_print (FILE *out)
grammar_rules_partial_print (out, _("Grammar"), rule_useful_p);
}
void
grammar_rules_print_xml (FILE *out, int level)
{
grammar_rules_partial_print_xml (out, level, true, rule_useful_p);
}
/*-------------------.
| Dump the grammar. |

View File

@@ -1,7 +1,7 @@
/* Data definitions for internal representation of Bison's input.
Copyright (C) 1984, 1986, 1989, 1992, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
2007 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
@@ -218,6 +218,7 @@ bool rule_never_reduced_p (rule *r);
already displayed (by a previous call for another rule), avoid
useless repetitions. */
void rule_lhs_print (rule *r, symbol *previous_lhs, FILE *out);
void rule_lhs_print_xml (rule *r, FILE *out, int level);
/* Return the length of the RHS. */
int rule_rhs_length (rule *r);
@@ -252,9 +253,12 @@ size_t ritem_longest_rhs (void);
(exclusive) on OUT under TITLE. */
void grammar_rules_partial_print (FILE *out, const char *title,
rule_filter filter);
void grammar_rules_partial_print_xml (FILE *out, int level, bool rtag,
rule_filter filter);
/* Print the grammar's rules on OUT. */
void grammar_rules_print (FILE *out);
void grammar_rules_print_xml (FILE *out, int level);
/* Dump the grammar. */
void grammar_dump (FILE *out, const char *title);

View File

@@ -40,6 +40,7 @@
#include "output.h"
#include "print.h"
#include "print_graph.h"
#include "print-xml.h"
#include "reader.h"
#include "reduce.h"
#include "scan-code.h"
@@ -151,6 +152,14 @@ main (int argc, char *argv[])
timevar_pop (TV_GRAPH);
}
/* Output xml. */
if (xml_flag)
{
timevar_push (TV_XML);
print_xml ();
timevar_pop (TV_XML);
}
/* Stop if there were errors, to avoid trashing previous output
files. */
if (complaint_issued)

613
src/print-xml.c Normal file
View File

@@ -0,0 +1,613 @@
/* Print an xml on generated parser, for Bison,
Copyright (C) 2007 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
Bison is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Bison is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bison; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
#include <config.h>
#include "system.h"
#include <stdarg.h>
#include <bitset.h>
#include <quotearg.h>
#include "LR0.h"
#include "closure.h"
#include "conflicts.h"
#include "files.h"
#include "getargs.h"
#include "gram.h"
#include "lalr.h"
#include "print.h"
#include "print-xml.h"
#include "reader.h"
#include "reduce.h"
#include "state.h"
#include "symtab.h"
#include "tables.h"
static bitset no_reduce_set;
/*----------------------------.
| Print rules never reduced. |
`-----------------------------*/
static void
print_rules_never_reduced (FILE *out, int level)
{
rule_number r;
bool count = false;
for (r = 0; r < nrules + nuseless_productions; r++)
{
if (rule_never_reduced_p (&rules[r]))
{
count = true;
break;
}
}
if (count) {
xml_puts (out, level, "<rules-never-reduced>");
grammar_rules_partial_print_xml (out, level - 1,
false, rule_never_reduced_p);
xml_puts (out, level, "</rules-never-reduced>");
}
else
xml_puts (out, level, "<rules-never-reduced/>");
}
/*--------------------------------.
| Report information on a state. |
`--------------------------------*/
static void
print_core (FILE *out, int level, state *s)
{
size_t i;
item_number *sitems = s->items;
size_t snritems = s->nitems;
/* Output all the items of a state, not only its kernel. */
if (report_flag & report_itemsets)
{
closure (sitems, snritems);
sitems = itemset;
snritems = nitemset;
}
if (!snritems) {
xml_puts (out, level, "<itemset/>");
return;
}
xml_puts (out, level, "<itemset>");
for (i = 0; i < snritems; i++)
{
item_number *sp;
item_number *sp1;
rule_number r;
sp1 = sp = ritem + sitems[i];
while (*sp >= 0)
sp++;
r = item_number_as_rule_number (*sp);
xml_printf (out, level + 1, "<rule number=\"%d\">",
rules[r].number);
rule_lhs_print_xml (&rules[r], out, level + 2);
xml_puts (out, level + 2, "<rhs>");
for (sp = rules[r].rhs; sp < sp1; sp++)
xml_printf (out, level + 3, "<symbol class=\"%s\">%s</symbol>",
symbol_class_get_string (symbols[*sp]),
xml_escape (symbols[*sp]->tag));
xml_puts (out, level + 3, "<point/>");
for (/* Nothing */; *sp >= 0; ++sp)
xml_printf (out, level + 3, "<symbol class=\"%s\">%s</symbol>",
symbol_class_get_string (symbols[*sp]),
xml_escape (symbols[*sp]->tag));
xml_puts (out, level + 2, "</rhs>");
/* Display the lookahead tokens? */
if (report_flag & report_lookahead_tokens)
state_rule_lookahead_tokens_print_xml (s, &rules[r], out, level + 2);
xml_puts (out, level + 1, "</rule>");
}
xml_puts (out, level, "</itemset>");
}
/*-----------------------------------------------------------.
| Report the shifts if DISPLAY_SHIFTS_P or the gotos of S on |
| OUT. |
`-----------------------------------------------------------*/
static void
print_transitions (state *s, FILE *out, int level)
{
transitions *trans = s->transitions;
int n = 0;
int i;
for (i = 0; i < trans->num; i++)
if (!TRANSITION_IS_DISABLED (trans, i))
{
n++;
}
/* Nothing to report. */
if (!n) {
xml_puts (out, level, "<transitions/>");
return;
}
/* Report lookahead tokens and shifts. */
xml_puts (out, level, "<transitions>");
for (i = 0; i < trans->num; i++)
if (!TRANSITION_IS_DISABLED (trans, i)
&& TRANSITION_IS_SHIFT (trans, i))
{
symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
char const *tag = sym->tag;
state *s1 = trans->states[i];
xml_printf (out, level + 1,
"<transition type=\"shift\" symbol=\"%s\" state=\"%d\"/>",
xml_escape (tag), s1->number);
}
for (i = 0; i < trans->num; i++)
if (!TRANSITION_IS_DISABLED (trans, i)
&& !TRANSITION_IS_SHIFT (trans, i))
{
symbol *sym = symbols[TRANSITION_SYMBOL (trans, i)];
char const *tag = sym->tag;
state *s1 = trans->states[i];
xml_printf (out, level + 1,
"<transition type=\"goto\" symbol=\"%s\" state=\"%d\"/>",
xml_escape (tag), s1->number);
}
xml_puts (out, level, "</transitions>");
}
/*--------------------------------------------------------.
| Report the explicit errors of S raised from %nonassoc. |
`--------------------------------------------------------*/
static void
print_errs (FILE *out, int level, state *s)
{
errs *errp = s->errs;
bool count = false;
int i;
for (i = 0; i < errp->num; ++i)
if (errp->symbols[i])
count = true;
/* Nothing to report. */
if (!count) {
xml_puts (out, level, "<errors/>");
return;
}
/* Report lookahead tokens and errors. */
xml_puts (out, level, "<errors>");
for (i = 0; i < errp->num; ++i)
if (errp->symbols[i])
{
char const *tag = errp->symbols[i]->tag;
xml_printf (out, level + 1,
"<error symbol=\"%s\">nonassociative</error>",
xml_escape (tag));
}
xml_puts (out, level, "</errors>");
}
/*-------------------------------------------------------------------------.
| Report a reduction of RULE on LOOKAHEAD_TOKEN (which can be `default'). |
| If not ENABLED, the rule is masked by a shift or a reduce (S/R and |
| R/R conflicts). |
`-------------------------------------------------------------------------*/
static void
print_reduction (FILE *out, int level, char const *lookahead_token,
rule *r, bool enabled)
{
if (r->number)
xml_printf (out, level,
"<reduction symbol=\"%s\" rule=\"%d\" enabled=\"%s\"/>",
xml_escape (lookahead_token),
r->number,
enabled ? "true" : "false");
else
xml_printf (out, level,
"<reduction symbol=\"%s\" rule=\"accept\" enabled=\"%s\"/>",
xml_escape (lookahead_token),
enabled ? "true" : "false");
}
/*-------------------------------------------.
| Report on OUT the reduction actions of S. |
`-------------------------------------------*/
static void
print_reductions (FILE *out, int level, state *s)
{
transitions *trans = s->transitions;
reductions *reds = s->reductions;
rule *default_rule = NULL;
int report = false;
int i, j;
if (reds->num == 0) {
xml_puts (out, level, "<reductions/>");
return;
}
if (yydefact[s->number] != 0)
default_rule = &rules[yydefact[s->number] - 1];
bitset_zero (no_reduce_set);
FOR_EACH_SHIFT (trans, i)
bitset_set (no_reduce_set, TRANSITION_SYMBOL (trans, i));
for (i = 0; i < s->errs->num; ++i)
if (s->errs->symbols[i])
bitset_set (no_reduce_set, s->errs->symbols[i]->number);
if (default_rule)
report = true;
if (reds->lookahead_tokens)
for (i = 0; i < ntokens; i++)
{
bool count = bitset_test (no_reduce_set, i);
for (j = 0; j < reds->num; ++j)
if (bitset_test (reds->lookahead_tokens[j], i))
{
if (! count)
{
if (reds->rules[j] != default_rule)
report = true;
count = true;
}
else
{
report = true;
}
}
}
/* Nothing to report. */
if (!report) {
xml_puts (out, level, "<reductions/>");
return;
}
xml_puts (out, level, "<reductions>");
/* Report lookahead tokens (or $default) and reductions. */
if (reds->lookahead_tokens)
for (i = 0; i < ntokens; i++)
{
bool defaulted = false;
bool count = bitset_test (no_reduce_set, i);
for (j = 0; j < reds->num; ++j)
if (bitset_test (reds->lookahead_tokens[j], i))
{
if (! count)
{
if (reds->rules[j] != default_rule)
print_reduction (out, level + 1, symbols[i]->tag,
reds->rules[j], true);
else
defaulted = true;
count = true;
}
else
{
if (defaulted)
print_reduction (out, level + 1, symbols[i]->tag,
default_rule, true);
defaulted = false;
print_reduction (out, level + 1, symbols[i]->tag,
reds->rules[j], false);
}
}
}
if (default_rule)
print_reduction (out, level + 1,
"$default", default_rule, true);
xml_puts (out, level, "</reductions>");
}
/*--------------------------------------------------------------.
| Report on OUT all the actions (shifts, gotos, reductions, and |
| explicit erros from %nonassoc) of S. |
`--------------------------------------------------------------*/
static void
print_actions (FILE *out, int level, state *s)
{
xml_puts (out, level, "<actions>");
print_transitions (s, out, level + 1);
print_errs (out, level + 1, s);
print_reductions (out, level + 1, s);
xml_puts (out, level, "</actions>");
}
/*----------------------------------.
| Report all the data on S on OUT. |
`----------------------------------*/
static void
print_state (FILE *out, int level, state *s)
{
fputc ('\n', out);
xml_printf (out, level, "<state number=\"%d\">", s->number);
print_core (out, level + 1, s);
print_actions (out, level + 1, s);
if ((report_flag & report_solved_conflicts) && s->solved_conflicts_xml)
{
xml_puts (out, level + 1, "<solved-conflicts>");
fputs (s->solved_conflicts_xml, out);
xml_puts (out, level + 1, "</solved-conflicts>");
}
else
xml_puts (out, level + 1, "<solved-conflicts/>");
xml_puts (out, level, "</state>");
}
/*-----------------------------------------.
| Print information on the whole grammar. |
`-----------------------------------------*/
static void
print_grammar (FILE *out, int level)
{
symbol_number i;
fputc ('\n', out);
xml_puts (out, level, "<grammar>");
grammar_rules_print_xml (out, level);
/* Terminals */
xml_puts (out, level + 1, "<terminals>");
for (i = 0; i < max_user_token_number + 1; i++)
if (token_translations[i] != undeftoken->number)
{
char const *tag = symbols[token_translations[i]]->tag;
rule_number r;
item_number *rhsp;
xml_printf (out, level + 2,
"<terminal type=\"%d\" symbol=\"%s\">",
i, xml_escape (tag));
for (r = 0; r < nrules; r++)
for (rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
if (item_number_as_symbol_number (*rhsp) == token_translations[i])
{
xml_printf (out, level + 3, "<rule>%d</rule>", r);
break;
}
xml_puts (out, level + 2, "</terminal>");
}
xml_puts (out, level + 1, "</terminals>");
/* Nonterminals */
xml_puts (out, level + 1, "<nonterminals>");
for (i = ntokens; i < nsyms; i++)
{
int left_count = 0, right_count = 0;
rule_number r;
char const *tag = symbols[i]->tag;
for (r = 0; r < nrules; r++)
{
item_number *rhsp;
if (rules[r].lhs->number == i)
left_count++;
for (rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
if (item_number_as_symbol_number (*rhsp) == i)
{
right_count++;
break;
}
}
xml_printf (out, level + 2,
"<nonterminal type=\"%d\" symbol=\"%s\">",
i, xml_escape (tag));
if (left_count > 0)
{
xml_puts (out, level + 3, "<left>");
for (r = 0; r < nrules; r++)
{
if (rules[r].lhs->number == i)
xml_printf (out, level + 4, "<rule>%d</rule>", r);
}
xml_puts (out, level + 3, "</left>");
}
if (right_count > 0)
{
xml_puts (out, level + 3, "<right>");
for (r = 0; r < nrules; r++)
{
item_number *rhsp;
for (rhsp = rules[r].rhs; *rhsp >= 0; rhsp++)
if (item_number_as_symbol_number (*rhsp) == i)
{
xml_printf (out, level + 4, "<rule>%d</rule>", r);
break;
}
}
xml_puts (out, level + 3, "</right>");
}
xml_puts (out, level + 2, "</nonterminal>");
}
xml_puts (out, level + 1, "</nonterminals>");
xml_puts (out, level, "</grammar>");
}
void
xml_puts (FILE *out, int level, char *s)
{
int i;
level *= 2;
for (i = 0; i < level; i++)
fputc (' ', out);
fputs (s, out);
fputc ('\n', out);
}
void
xml_printf (FILE *out, int level, char const *fmt, ...)
{
int i;
va_list arglist;
for (i = 0; i < level; i++)
fputc (' ', out);
va_start (arglist, fmt);
vfprintf (out, fmt, arglist);
va_end (arglist);
fputc ('\n', out);
}
struct escape_buf
{
char *ptr;
size_t size;
};
static char const *
xml_escape_string (struct escape_buf *buf, char const *str)
{
size_t len = strlen (str);
size_t max_expansion = sizeof "&quot;" - 1;
char *p;
if (buf->size <= max_expansion * len)
{
buf->size = max_expansion * len + 1;
buf->ptr = x2realloc (buf->ptr, &buf->size);
}
p = buf->ptr;
for (; *str; str++)
switch (*str)
{
default: *p++ = *str; break;
case '&': p = stpcpy (p, "&amp;" ); break;
case '<': p = stpcpy (p, "&lt;" ); break;
case '>': p = stpcpy (p, "&gt;" ); break;
case '"': p = stpcpy (p, "&quot;"); break;
}
*p = '\0';
return buf->ptr;
}
char const *
xml_escape_n (int n, char const *str)
{
static struct escape_buf buf[2];
return xml_escape_string (buf + n, str);
}
char const *
xml_escape (char const *str)
{
return xml_escape_n (0, str);
}
void
print_xml (void)
{
state_number i;
int level = 0;
FILE *out = xfopen (spec_xml_file, "w");
fputs ("<?xml version=\"1.0\"?>\n\n", out);
xml_printf (out, level, "<bison-xml-report version=\"%s\">",
xml_escape (VERSION));
fputc ('\n', out);
xml_printf (out, level + 1, "<filename>%s</filename>",
xml_escape (grammar_file));
/* print reductions */
reduce_xml (out, level + 1);
/* print rules never reduced */
print_rules_never_reduced (out, level + 1);
/* print conflicts */
conflicts_output_xml (out, level + 1);
/* print grammar */
print_grammar (out, level + 1);
if (report_flag & report_itemsets)
new_closure (nritems);
no_reduce_set = bitset_create (ntokens, BITSET_FIXED);
/* print automaton */
fputc ('\n', out);
xml_puts (out, level + 1, "<automaton>");
for (i = 0; i < nstates; i++)
print_state (out, level + 2, states[i]);
xml_puts (out, level + 1, "</automaton>");
bitset_free (no_reduce_set);
if (report_flag & report_itemsets)
free_closure ();
xml_puts (out, 0, "</bison-xml-report>");
xfclose (out);
}

31
src/print-xml.h Normal file
View File

@@ -0,0 +1,31 @@
/* Output an xml of the generated parser, for Bison.
Copyright (C) 2007 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
Bison is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Bison is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bison; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
#ifndef PRINT_XML_H_
# define PRINT_XML_H_
void xml_puts (FILE *, int, char *);
void xml_printf (FILE *, int, char const *, ...);
char const *xml_escape_n (int n, char const *str);
char const *xml_escape (char const *str);
void print_xml (void);
#endif /* !PRINT_XML_H_ */

View File

@@ -1,7 +1,7 @@
/* Grammar reduction for Bison.
Copyright (C) 1988, 1989, 2000, 2001, 2002, 2003, 2005, 2006 Free
Software Foundation, Inc.
Copyright (C) 1988, 1989, 2000, 2001, 2002, 2003, 2005, 2006,
2007 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
@@ -35,6 +35,7 @@
#include "files.h"
#include "getargs.h"
#include "gram.h"
#include "print-xml.h"
#include "reader.h"
#include "reduce.h"
#include "symtab.h"
@@ -374,8 +375,62 @@ reduce_output (FILE *out)
}
/*--------------------------------------------------------------.
| Output the detailed results of the reductions. For FILE.xml. |
`---------------------------------------------------------------*/
void
reduce_xml (FILE *out, int level)
{
fputc ('\n', out);
xml_puts (out, level, "<reductions>");
xml_puts (out, level + 1, "<useless>");
if (nuseless_nonterminals > 0)
{
int i;
xml_puts (out, level + 2, "<nonterminals>");
for (i = 0; i < nuseless_nonterminals; ++i)
xml_printf (out, level + 3,
"<nonterminal>%s</nonterminal>",
symbols[nsyms + i]->tag);
xml_puts (out, level + 2, "</nonterminals>");
}
else
xml_puts (out, level + 2, "<nonterminals/>");
if (nuseless_productions > 0)
grammar_rules_partial_print_xml (out, level + 1, true, rule_useless_p);
else
xml_puts (out, level + 2, "<rules/>");
xml_puts (out, level + 1, "</useless>");
xml_puts (out, level + 1, "<unused>");
{
bool b = false;
int i;
for (i = 0; i < ntokens; i++)
if (!bitset_test (V, i) && !bitset_test (V1, i))
{
if (!b)
xml_puts (out, level + 2, "<terminals>");
b = true;
xml_printf (out, level + 3,
"<terminal>%s</terminal>",
symbols[i]->tag);
}
if (b)
xml_puts (out, level + 2, "</terminals>");
else
xml_puts (out, level + 2, "<terminals/>");
}
xml_puts (out, level + 1, "</unused>");
xml_puts (out, level, "</reductions>");
fputc ('\n', out);
}
/*-------------------------------.
| Report the results to STDERR. |

View File

@@ -1,6 +1,6 @@
/* Grammar reduction for Bison.
Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
Copyright (C) 2000, 2001, 2002, 2007 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
@@ -22,6 +22,7 @@
void reduce_grammar (void);
void reduce_output (FILE *out);
void reduce_xml (FILE *out, int level);
void reduce_free (void);
extern symbol_number nuseless_nonterminals;

View File

@@ -26,6 +26,7 @@
#include "complain.h"
#include "gram.h"
#include "state.h"
#include "print-xml.h"
/*-------------------.
@@ -143,6 +144,7 @@ state_new (symbol_number accessing_symbol,
res->errs = NULL;
res->consistent = 0;
res->solved_conflicts = NULL;
res->solved_conflicts_xml = NULL;
res->nitems = nitems;
memcpy (res->items, core, items_size);
@@ -244,6 +246,31 @@ state_rule_lookahead_tokens_print (state *s, rule *r, FILE *out)
}
}
void
state_rule_lookahead_tokens_print_xml (state *s, rule *r,
FILE *out, int level)
{
/* Find the reduction we are handling. */
reductions *reds = s->reductions;
int red = state_reduction_find (s, r);
/* Print them if there are. */
if (reds->lookahead_tokens && red != -1)
{
bitset_iterator biter;
int k;
char const *sep = "";
xml_puts (out, level, "<lookaheads>");
BITSET_FOR_EACH (biter, reds->lookahead_tokens[red], k, 0)
{
xml_printf (out, level + 1, "<symbol class=\"%s\">%s</symbol>",
symbol_class_get_string (symbols[k]),
xml_escape (symbols[k]->tag));
}
xml_puts (out, level, "</lookaheads>");
}
}
/*---------------------.
| A state hash table. |

View File

@@ -208,6 +208,7 @@ struct state
/* If some conflicts were solved thanks to precedence/associativity,
a human readable description of the resolution. */
const char *solved_conflicts;
const char *solved_conflicts_xml;
/* Its items. Must be last, since ITEMS can be arbitrarily large. Sorted
ascendingly on item index in RITEM, which is sorted on rule number. */
@@ -236,6 +237,8 @@ void state_errs_set (state *s, int num, symbol **errors);
/* Print on OUT all the lookahead tokens such that this STATE wants to
reduce R. */
void state_rule_lookahead_tokens_print (state *s, rule *r, FILE *out);
void state_rule_lookahead_tokens_print_xml (state *s, rule *r,
FILE *out, int level);
/* Create/destroy the states hash table. */
void state_hash_new (void);

View File

@@ -168,6 +168,23 @@ symbol_type_set (symbol *sym, uniqstr type_name, location loc)
}
}
/*-----------------------------------.
| Get the CLASS associated with SYM. |
`-----------------------------------*/
const char *
symbol_class_get_string (symbol *sym)
{
if (sym->class)
{
if (sym->class == token_sym)
return "terminal";
else if (sym->class == nterm_sym)
return "nonterminal";
}
return "unknown";
}
/*-----------------------------------------.
| Set the DESTRUCTOR associated with SYM. |

View File

@@ -130,6 +130,9 @@ void symbol_make_alias (symbol *sym, symbol *symval, location loc);
Do nothing if passed 0 as \c type_name. */
void symbol_type_set (symbol *sym, uniqstr type_name, location loc);
/** Get the \c class string associated with \c sym. */
const char *symbol_class_get_string (symbol *sym);
/** Set the \c destructor associated with \c sym. */
void symbol_destructor_set (symbol *sym, code_props const *destructor);