| /* Allocate input grammar variables for Bison. |
| |
| Copyright (C) 1984, 1986, 1989, 2001-2003, 2005-2012 Free Software |
| Foundation, Inc. |
| |
| This file is part of Bison, the GNU Compiler Compiler. |
| |
| This program 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 3 of the License, or |
| (at your option) any later version. |
| |
| This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #include <config.h> |
| #include "system.h" |
| |
| #include "complain.h" |
| #include "getargs.h" |
| #include "gram.h" |
| #include "print-xml.h" |
| #include "reader.h" |
| #include "reduce.h" |
| #include "symtab.h" |
| |
| /* Comments for these variables are in gram.h. */ |
| |
| item_number *ritem = NULL; |
| unsigned int nritems = 0; |
| |
| rule *rules = NULL; |
| rule_number nrules = 0; |
| |
| symbol **symbols = NULL; |
| int nsyms = 0; |
| int ntokens = 1; |
| int nvars = 0; |
| |
| symbol_number *token_translations = NULL; |
| |
| int max_user_token_number = 256; |
| |
| bool |
| rule_useful_in_grammar_p (rule *r) |
| { |
| return r->number < nrules; |
| } |
| |
| bool |
| rule_useless_in_grammar_p (rule *r) |
| { |
| return !rule_useful_in_grammar_p (r); |
| } |
| |
| bool |
| rule_useless_in_parser_p (rule *r) |
| { |
| return !r->useful && rule_useful_in_grammar_p (r); |
| } |
| |
| void |
| rule_lhs_print (rule *r, symbol *previous_lhs, FILE *out) |
| { |
| fprintf (out, " %3d ", r->number); |
| if (previous_lhs != r->lhs) |
| { |
| fprintf (out, "%s:", r->lhs->tag); |
| } |
| else |
| { |
| int n; |
| for (n = strlen (previous_lhs->tag); n > 0; --n) |
| fputc (' ', out); |
| fputc ('|', out); |
| } |
| } |
| |
| void |
| rule_lhs_print_xml (rule *r, FILE *out, int level) |
| { |
| xml_printf (out, level, "<lhs>%s</lhs>", r->lhs->tag); |
| } |
| |
| int |
| rule_rhs_length (rule *r) |
| { |
| int res = 0; |
| item_number *rhsp; |
| for (rhsp = r->rhs; *rhsp >= 0; ++rhsp) |
| ++res; |
| return res; |
| } |
| |
| void |
| rule_rhs_print (rule *r, FILE *out) |
| { |
| if (*r->rhs >= 0) |
| { |
| item_number *rp; |
| for (rp = r->rhs; *rp >= 0; rp++) |
| fprintf (out, " %s", symbols[*rp]->tag); |
| fputc ('\n', out); |
| } |
| else |
| { |
| fprintf (out, " /* %s */\n", _("empty")); |
| } |
| } |
| |
| 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>%s</symbol>", |
| 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>"); |
| } |
| } |
| |
| void |
| rule_print (rule *r, FILE *out) |
| { |
| fprintf (out, "%s:", r->lhs->tag); |
| rule_rhs_print (r, out); |
| } |
| |
| void |
| ritem_print (FILE *out) |
| { |
| unsigned int i; |
| fputs ("RITEM\n", out); |
| for (i = 0; i < nritems; ++i) |
| if (ritem[i] >= 0) |
| fprintf (out, " %s", symbols[ritem[i]]->tag); |
| else |
| fprintf (out, " (rule %d)\n", item_number_as_rule_number (ritem[i])); |
| fputs ("\n\n", out); |
| } |
| |
| size_t |
| ritem_longest_rhs (void) |
| { |
| int max = 0; |
| rule_number r; |
| |
| for (r = 0; r < nrules; ++r) |
| { |
| int length = rule_rhs_length (&rules[r]); |
| if (length > max) |
| max = length; |
| } |
| |
| return max; |
| } |
| |
| void |
| grammar_rules_partial_print (FILE *out, const char *title, |
| rule_filter filter) |
| { |
| rule_number r; |
| bool first = true; |
| symbol *previous_lhs = NULL; |
| |
| /* rule # : LHS -> RHS */ |
| for (r = 0; r < nrules + nuseless_productions; r++) |
| { |
| if (filter && !filter (&rules[r])) |
| continue; |
| if (first) |
| fprintf (out, "%s\n\n", title); |
| else if (previous_lhs && previous_lhs != rules[r].lhs) |
| fputc ('\n', out); |
| first = false; |
| rule_lhs_print (&rules[r], previous_lhs, out); |
| rule_rhs_print (&rules[r], out); |
| previous_lhs = rules[r].lhs; |
| } |
| if (!first) |
| fputs ("\n\n", out); |
| } |
| |
| void |
| grammar_rules_print (FILE *out) |
| { |
| grammar_rules_partial_print (out, _("Grammar"), rule_useful_in_grammar_p); |
| } |
| |
| void |
| grammar_rules_print_xml (FILE *out, int level) |
| { |
| rule_number r; |
| bool first = true; |
| |
| for (r = 0; r < nrules + nuseless_productions; r++) |
| { |
| if (first) |
| xml_puts (out, level + 1, "<rules>"); |
| first = false; |
| { |
| char const *usefulness; |
| if (rule_useless_in_grammar_p (&rules[r])) |
| usefulness = "useless-in-grammar"; |
| else if (rule_useless_in_parser_p (&rules[r])) |
| usefulness = "useless-in-parser"; |
| else |
| usefulness = "useful"; |
| xml_indent (out, level + 2); |
| fprintf (out, "<rule number=\"%d\" usefulness=\"%s\"", |
| rules[r].number, usefulness); |
| if (rules[r].precsym) |
| fprintf (out, " percent_prec=\"%s\"", |
| xml_escape (rules[r].precsym->tag)); |
| fputs (">\n", out); |
| } |
| 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 (!first) |
| xml_puts (out, level + 1, "</rules>"); |
| else |
| xml_puts (out, level + 1, "<rules/>"); |
| } |
| |
| void |
| grammar_dump (FILE *out, const char *title) |
| { |
| fprintf (out, "%s\n\n", title); |
| fprintf (out, |
| "ntokens = %d, nvars = %d, nsyms = %d, nrules = %d, nritems = %d\n\n", |
| ntokens, nvars, nsyms, nrules, nritems); |
| |
| |
| fprintf (out, "Variables\n---------\n\n"); |
| { |
| symbol_number i; |
| fprintf (out, "Value Sprec Sassoc Tag\n"); |
| |
| for (i = ntokens; i < nsyms; i++) |
| fprintf (out, "%5d %5d %5d %s\n", |
| i, |
| symbols[i]->prec, symbols[i]->assoc, |
| symbols[i]->tag); |
| fprintf (out, "\n\n"); |
| } |
| |
| fprintf (out, "Rules\n-----\n\n"); |
| { |
| rule_number i; |
| fprintf (out, "Num (Prec, Assoc, Useful, Ritem Range) Lhs -> Rhs (Ritem range) [Num]\n"); |
| for (i = 0; i < nrules + nuseless_productions; i++) |
| { |
| rule *rule_i = &rules[i]; |
| item_number *rp = NULL; |
| unsigned int rhs_itemno = rule_i->rhs - ritem; |
| unsigned int rhs_count = 0; |
| /* Find the last RHS index in ritems. */ |
| for (rp = rule_i->rhs; *rp >= 0; ++rp) |
| ++rhs_count; |
| fprintf (out, "%3d (%2d, %2d, %2d, %2u-%2u) %2d ->", |
| i, |
| rule_i->prec ? rule_i->prec->prec : 0, |
| rule_i->prec ? rule_i->prec->assoc : 0, |
| rule_i->useful, |
| rhs_itemno, |
| rhs_itemno + rhs_count - 1, |
| rule_i->lhs->number); |
| /* Dumped the RHS. */ |
| for (rp = rule_i->rhs; *rp >= 0; rp++) |
| fprintf (out, " %3d", *rp); |
| fprintf (out, " [%d]\n", item_number_as_rule_number (*rp)); |
| } |
| } |
| fprintf (out, "\n\n"); |
| |
| fprintf (out, "Rules interpreted\n-----------------\n\n"); |
| { |
| rule_number r; |
| for (r = 0; r < nrules + nuseless_productions; r++) |
| { |
| fprintf (out, "%-5d ", r); |
| rule_print (&rules[r], out); |
| } |
| } |
| fprintf (out, "\n\n"); |
| } |
| |
| void |
| grammar_rules_useless_report (const char *message) |
| { |
| rule_number r; |
| for (r = 0; r < nrules ; ++r) |
| if (!rules[r].useful) |
| { |
| if (feature_flag & feature_caret) |
| warn_at (rules[r].location, "%s", message); |
| else |
| { |
| warn_at (rules[r].location, "%s: ", message); |
| if (warnings_flag & warnings_other) |
| { |
| rule_print (&rules[r], stderr); |
| fflush (stderr); |
| } |
| } |
| } |
| } |
| |
| void |
| grammar_free (void) |
| { |
| if (ritem) |
| free (ritem - 1); |
| free (rules); |
| free (token_translations); |
| /* Free the symbol table data structure. */ |
| symbols_free (); |
| free_merger_functions (); |
| } |