diff options
-rw-r--r-- | ChangeLog | 50 | ||||
-rw-r--r-- | lib/timevar.def | 3 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/conflicts.c | 138 | ||||
-rw-r--r-- | src/conflicts.h | 1 | ||||
-rw-r--r-- | src/files.c | 9 | ||||
-rw-r--r-- | src/files.h | 3 | ||||
-rw-r--r-- | src/getargs.c | 12 | ||||
-rw-r--r-- | src/getargs.h | 1 | ||||
-rw-r--r-- | src/gram.c | 71 | ||||
-rw-r--r-- | src/gram.h | 6 | ||||
-rw-r--r-- | src/main.c | 9 | ||||
-rw-r--r-- | src/print-xml.c | 613 | ||||
-rw-r--r-- | src/print-xml.h | 31 | ||||
-rw-r--r-- | src/reduce.c | 59 | ||||
-rw-r--r-- | src/reduce.h | 3 | ||||
-rw-r--r-- | src/state.c | 27 | ||||
-rw-r--r-- | src/state.h | 3 | ||||
-rw-r--r-- | src/symtab.c | 17 | ||||
-rw-r--r-- | src/symtab.h | 3 |
20 files changed, 1045 insertions, 15 deletions
@@ -1,5 +1,54 @@ 2007-09-21 Paul Eggert <eggert@cs.ucla.edu> + * 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> + * GNUmakefile: Switch to coreutils's version. * bootstrap: Likewise. * Makefile.cfg: Adjust to new GNUmakefile. @@ -13,7 +62,6 @@ * m4/bison-i18n.m4 (BISON_I18N): Also handle the case where yacc exists and is a script that invokes bison. Tighten the code. Add comments. - 2007-08-28 Joel E. Denny <jdenny@ces.clemson.edu> Spell "boolean" as "Boolean". Reported by Akim Demaille. diff --git a/lib/timevar.def b/lib/timevar.def index ee68ed4e..3a4128f2 100644 --- a/lib/timevar.def +++ b/lib/timevar.def @@ -1,6 +1,6 @@ /* This file contains the definitions for timing variables used to -*- C -*- measure run-time performance of the compiler. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2007 Free Software Foundation, Inc. Contributed by Akim Demaille <akim@freefriends.org>. This file is part of Bison, the GNU Compiler Compiler. @@ -46,6 +46,7 @@ DEFTIMEVAR (TV_CONFLICTS , "conflicts") /* Time spent outputing results. */ DEFTIMEVAR (TV_REPORT , "outputing report") DEFTIMEVAR (TV_GRAPH , "outputing graph") +DEFTIMEVAR (TV_XML , "outputing xml") DEFTIMEVAR (TV_ACTIONS , "parser action tables") DEFTIMEVAR (TV_PARSER , "outputing parser") DEFTIMEVAR (TV_M4 , "running m4") diff --git a/src/Makefile.am b/src/Makefile.am index a7cbb339..9f74c0b2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/conflicts.c b/src/conflicts.c index b50922e0..3a8edba4 100644 --- a/src/conflicts.c +++ b/src/conflicts.c @@ -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 < %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 < %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); } diff --git a/src/conflicts.h b/src/conflicts.h index d8264cca..c6497ca7 100644 --- a/src/conflicts.h +++ b/src/conflicts.h @@ -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? */ diff --git a/src/files.c b/src/files.c index 806b5729..c6aca453 100644 --- a/src/files.c +++ b/src/files.c @@ -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); diff --git a/src/files.h b/src/files.h index ea1a9146..3a72193b 100644 --- a/src/files.h +++ b/src/files.h @@ -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; diff --git a/src/getargs.c b/src/getargs.c index 981e5d53..4e095eb2 100644 --- a/src/getargs.c +++ b/src/getargs.c @@ -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); diff --git a/src/getargs.h b/src/getargs.h index 4f62d3dc..c7370d77 100644 --- a/src/getargs.h +++ b/src/getargs.h @@ -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 */ @@ -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. | @@ -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); @@ -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) diff --git a/src/print-xml.c b/src/print-xml.c new file mode 100644 index 00000000..be6bb56a --- /dev/null +++ b/src/print-xml.c @@ -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 """ - 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, "&" ); break; + case '<': p = stpcpy (p, "<" ); break; + case '>': p = stpcpy (p, ">" ); break; + case '"': p = stpcpy (p, """); 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); +} diff --git a/src/print-xml.h b/src/print-xml.h new file mode 100644 index 00000000..b0bbe196 --- /dev/null +++ b/src/print-xml.h @@ -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_ */ diff --git a/src/reduce.c b/src/reduce.c index b3e0cd01..0f17bb05 100644 --- a/src/reduce.c +++ b/src/reduce.c @@ -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. | diff --git a/src/reduce.h b/src/reduce.h index de590808..aaa2bab1 100644 --- a/src/reduce.h +++ b/src/reduce.h @@ -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; diff --git a/src/state.c b/src/state.c index 076600c6..8fb769aa 100644 --- a/src/state.c +++ b/src/state.c @@ -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. | diff --git a/src/state.h b/src/state.h index 1641106d..4afc1f00 100644 --- a/src/state.h +++ b/src/state.h @@ -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); diff --git a/src/symtab.c b/src/symtab.c index 83851351..e438e4fc 100644 --- a/src/symtab.c +++ b/src/symtab.c @@ -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. | diff --git a/src/symtab.h b/src/symtab.h index 5dc65002..fe37716a 100644 --- a/src/symtab.h +++ b/src/symtab.h @@ -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); |