Home | History | Annotate | Download | only in src
      1 /* Muscle table manager for Bison.
      2 
      3    Copyright (C) 2001-2012 Free Software Foundation, Inc.
      4 
      5    This file is part of Bison, the GNU Compiler Compiler.
      6 
      7    This program is free software: you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation, either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 #include <config.h>
     21 #include "system.h"
     22 
     23 #include <hash.h>
     24 
     25 #include "complain.h"
     26 #include "files.h"
     27 #include "getargs.h"
     28 #include "muscle-tab.h"
     29 #include "quote.h"
     30 
     31 /* A key-value pair, along with storage that can be reclaimed when
     32    this pair is no longer needed.  */
     33 typedef struct
     34 {
     35   char const *key;
     36   char const *value;
     37   char *storage;
     38 } muscle_entry;
     39 
     40 /* An obstack used to create some entries.  */
     41 struct obstack muscle_obstack;
     42 
     43 /* Initial capacity of muscles hash table.  */
     44 #define HT_INITIAL_CAPACITY 257
     45 
     46 static struct hash_table *muscle_table = NULL;
     47 
     48 static bool
     49 hash_compare_muscles (void const *x, void const *y)
     50 {
     51   muscle_entry const *m1 = x;
     52   muscle_entry const *m2 = y;
     53   return strcmp (m1->key, m2->key) == 0;
     54 }
     55 
     56 static size_t
     57 hash_muscle (const void *x, size_t tablesize)
     58 {
     59   muscle_entry const *m = x;
     60   return hash_string (m->key, tablesize);
     61 }
     62 
     63 /*-----------------------------------------------------------------.
     64 | Create the MUSCLE_TABLE, and initialize it with default values.  |
     65 | Also set up the MUSCLE_OBSTACK.                                  |
     66 `-----------------------------------------------------------------*/
     67 
     68 static void
     69 muscle_entry_free (void *entry)
     70 {
     71   muscle_entry *mentry = entry;
     72   free (mentry->storage);
     73   free (mentry);
     74 }
     75 
     76 void
     77 muscle_init (void)
     78 {
     79   /* Initialize the muscle obstack.  */
     80   obstack_init (&muscle_obstack);
     81 
     82   muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
     83 				  hash_compare_muscles, muscle_entry_free);
     84 
     85   /* Version and input file.  */
     86   MUSCLE_INSERT_STRING ("version", VERSION);
     87 }
     88 
     89 
     90 /*------------------------------------------------------------.
     91 | Free all the memory consumed by the muscle machinery only.  |
     92 `------------------------------------------------------------*/
     93 
     94 void
     95 muscle_free (void)
     96 {
     97   hash_free (muscle_table);
     98   obstack_free (&muscle_obstack, NULL);
     99 }
    100 
    101 
    102 
    103 /*------------------------------------------------------------.
    104 | Insert (KEY, VALUE).  If KEY already existed, overwrite the |
    105 | previous value.                                             |
    106 `------------------------------------------------------------*/
    107 
    108 void
    109 muscle_insert (char const *key, char const *value)
    110 {
    111   muscle_entry probe;
    112   muscle_entry *entry;
    113 
    114   probe.key = key;
    115   entry = hash_lookup (muscle_table, &probe);
    116 
    117   if (!entry)
    118     {
    119       /* First insertion in the hash. */
    120       entry = xmalloc (sizeof *entry);
    121       entry->key = key;
    122       if (!hash_insert (muscle_table, entry))
    123         xalloc_die ();
    124     }
    125   else
    126     free (entry->storage);
    127   entry->value = value;
    128   entry->storage = NULL;
    129 }
    130 
    131 
    132 /*-------------------------------------------------------------------.
    133 | Append VALUE to the current value of KEY.  If KEY did not already  |
    134 | exist, create it.  Use MUSCLE_OBSTACK.  De-allocate the previously |
    135 | associated value.  Copy VALUE and SEPARATOR.                       |
    136 `-------------------------------------------------------------------*/
    137 
    138 void
    139 muscle_grow (const char *key, const char *val, const char *separator)
    140 {
    141   muscle_entry probe;
    142   muscle_entry *entry = NULL;
    143 
    144   probe.key = key;
    145   entry = hash_lookup (muscle_table, &probe);
    146 
    147   if (!entry)
    148     {
    149       /* First insertion in the hash. */
    150       entry = xmalloc (sizeof *entry);
    151       entry->key = key;
    152       if (!hash_insert (muscle_table, entry))
    153         xalloc_die ();
    154       entry->value = entry->storage = xstrdup (val);
    155     }
    156   else
    157     {
    158       /* Grow the current value. */
    159       char *new_val;
    160       obstack_sgrow (&muscle_obstack, entry->value);
    161       free (entry->storage);
    162       obstack_sgrow (&muscle_obstack, separator);
    163       obstack_sgrow (&muscle_obstack, val);
    164       obstack_1grow (&muscle_obstack, 0);
    165       new_val = obstack_finish (&muscle_obstack);
    166       entry->value = entry->storage = xstrdup (new_val);
    167       obstack_free (&muscle_obstack, new_val);
    168     }
    169 }
    170 
    171 /*------------------------------------------------------------------.
    172 | Using muscle_grow, append a synchronization line for the location |
    173 | LOC to the current value of KEY.                                  |
    174 `------------------------------------------------------------------*/
    175 
    176 static void
    177 muscle_syncline_grow (char const *key, location loc)
    178 {
    179   char *extension = NULL;
    180   obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
    181   obstack_quote (&muscle_obstack,
    182                  quotearg_style (c_quoting_style, loc.start.file));
    183   obstack_sgrow (&muscle_obstack, ")[");
    184   obstack_1grow (&muscle_obstack, 0);
    185   extension = obstack_finish (&muscle_obstack);
    186   muscle_grow (key, extension, "");
    187   obstack_free (&muscle_obstack, extension);
    188 }
    189 
    190 /*------------------------------------------------------------------.
    191 | Append VALUE to the current value of KEY, using muscle_grow.  But |
    192 | in addition, issue a synchronization line for the location LOC    |
    193 | using muscle_syncline_grow.                                       |
    194 `------------------------------------------------------------------*/
    195 
    196 void
    197 muscle_code_grow (const char *key, const char *val, location loc)
    198 {
    199   muscle_syncline_grow (key, loc);
    200   muscle_grow (key, val, "\n");
    201 }
    202 
    203 
    204 void muscle_pair_list_grow (const char *muscle,
    205 			    const char *a1, const char *a2)
    206 {
    207   char *pair;
    208   obstack_sgrow (&muscle_obstack, "[");
    209   obstack_quote (&muscle_obstack, a1);
    210   obstack_sgrow (&muscle_obstack, ", ");
    211   obstack_quote (&muscle_obstack, a2);
    212   obstack_sgrow (&muscle_obstack, "]");
    213   obstack_1grow (&muscle_obstack, 0);
    214   pair = obstack_finish (&muscle_obstack);
    215   muscle_grow (muscle, pair, ",\n");
    216   obstack_free (&muscle_obstack, pair);
    217 }
    218 
    219 
    220 /*----------------------------------------------------------------------------.
    221 | Find the value of muscle KEY.  Unlike MUSCLE_FIND, this is always reliable  |
    222 | to determine whether KEY has a value.                                       |
    223 `----------------------------------------------------------------------------*/
    224 
    225 char const *
    226 muscle_find_const (char const *key)
    227 {
    228   muscle_entry probe;
    229   muscle_entry *result = NULL;
    230 
    231   probe.key = key;
    232   result = hash_lookup (muscle_table, &probe);
    233   if (result)
    234     return result->value;
    235   return NULL;
    236 }
    237 
    238 
    239 /*----------------------------------------------------------------------------.
    240 | Find the value of muscle KEY.  Abort if muscle_insert was invoked more      |
    241 | recently than muscle_grow for KEY since muscle_find can't return a          |
    242 | char const *.                                                               |
    243 `----------------------------------------------------------------------------*/
    244 
    245 char *
    246 muscle_find (char const *key)
    247 {
    248   muscle_entry probe;
    249   muscle_entry *result = NULL;
    250 
    251   probe.key = key;
    252   result = hash_lookup (muscle_table, &probe);
    253   if (result)
    254     {
    255       aver (result->value == result->storage);
    256       return result->storage;
    257     }
    258   return NULL;
    259 }
    260 
    261 
    262 /* In the format `file_name:line.column', append BOUND to MUSCLE.  Use
    263    digraphs for special characters in the file name.  */
    264 
    265 static void
    266 muscle_boundary_grow (char const *key, boundary bound)
    267 {
    268   char *extension;
    269   obstack_sgrow  (&muscle_obstack, "[[");
    270   obstack_escape (&muscle_obstack, bound.file);
    271   obstack_1grow  (&muscle_obstack, ':');
    272   obstack_printf (&muscle_obstack, "%d", bound.line);
    273   obstack_1grow  (&muscle_obstack, '.');
    274   obstack_printf (&muscle_obstack, "%d", bound.column);
    275   obstack_sgrow  (&muscle_obstack, "]]");
    276   obstack_1grow  (&muscle_obstack, '\0');
    277   extension = obstack_finish (&muscle_obstack);
    278   muscle_grow (key, extension, "");
    279   obstack_free (&muscle_obstack, extension);
    280 }
    281 
    282 
    283 /* In the format `[[file_name:line.column]], [[file_name:line.column]]',
    284    append LOC to MUSCLE.  Use digraphs for special characters in each
    285    file name.  */
    286 
    287 static void
    288 muscle_location_grow (char const *key, location loc)
    289 {
    290   muscle_boundary_grow (key, loc.start);
    291   muscle_grow (key, "", ", ");
    292   muscle_boundary_grow (key, loc.end);
    293 }
    294 
    295 #define COMMON_DECODE(Value)                                    \
    296   case '$':                                                     \
    297     aver (*++(Value) == ']');                                   \
    298     aver (*++(Value) == '[');                                   \
    299     obstack_sgrow (&muscle_obstack, "$");                       \
    300     break;                                                      \
    301   case '@':                                                     \
    302     switch (*++(Value))                                         \
    303       {                                                         \
    304         case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
    305         case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
    306         case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
    307         default: aver (false); break;                           \
    308       }                                                         \
    309     break;                                                      \
    310   default:                                                      \
    311     obstack_1grow (&muscle_obstack, *(Value));                  \
    312     break;
    313 
    314 /* Reverse of obstack_escape.  */
    315 static char *
    316 string_decode (char const *key)
    317 {
    318   char const *value;
    319   char *value_decoded;
    320   char *result;
    321 
    322   value = muscle_find_const (key);
    323   if (!value)
    324     return NULL;
    325   do {
    326     switch (*value)
    327       {
    328         COMMON_DECODE (value)
    329         case '[':
    330         case ']':
    331           aver (false);
    332           break;
    333       }
    334   } while (*value++);
    335   value_decoded = obstack_finish (&muscle_obstack);
    336   result = xstrdup (value_decoded);
    337   obstack_free (&muscle_obstack, value_decoded);
    338   return result;
    339 }
    340 
    341 /* Reverse of muscle_location_grow.  */
    342 static location
    343 location_decode (char const *key)
    344 {
    345   location loc;
    346   char const *value = muscle_find_const (key);
    347   aver (value);
    348   aver (*value == '[');
    349   aver (*++value == '[');
    350   while (*++value)
    351     switch (*value)
    352       {
    353         COMMON_DECODE (value)
    354         case '[':
    355           aver (false);
    356           break;
    357         case ']':
    358           {
    359             char *boundary_str;
    360             aver (*++value == ']');
    361             obstack_1grow (&muscle_obstack, '\0');
    362             boundary_str = obstack_finish (&muscle_obstack);
    363             switch (*++value)
    364               {
    365                 case ',':
    366                   boundary_set_from_string (&loc.start, boundary_str);
    367                   obstack_free (&muscle_obstack, boundary_str);
    368                   aver (*++value == ' ');
    369                   aver (*++value == '[');
    370                   aver (*++value == '[');
    371                   break;
    372                 case '\0':
    373                   boundary_set_from_string (&loc.end, boundary_str);
    374                   obstack_free (&muscle_obstack, boundary_str);
    375                   return loc;
    376                   break;
    377                 default:
    378                   aver (false);
    379                   break;
    380               }
    381           }
    382           break;
    383       }
    384   aver (false);
    385   return loc;
    386 }
    387 
    388 void
    389 muscle_user_name_list_grow (char const *key, char const *user_name,
    390                             location loc)
    391 {
    392   muscle_grow (key, "[[[[", ",");
    393   muscle_grow (key, user_name, "");
    394   muscle_grow (key, "]], ", "");
    395   muscle_location_grow (key, loc);
    396   muscle_grow (key, "]]", "");
    397 }
    398 
    399 /** If the \a variable name is obsolete, return the name to use,
    400  * otherwise \a variable. */
    401 static
    402 char const *
    403 muscle_percent_variable_update (char const *variable)
    404 {
    405   typedef struct
    406   {
    407     const char *obsolete;
    408     const char *updated;
    409   } conversion_type;
    410   const conversion_type conversion[] =
    411     {
    412       { "api.push_pull", "api.push-pull", },
    413       { "location_type", "api.location.type", },
    414       { "lr.keep_unreachable_states", "lr.keep-unreachable-states", },
    415     };
    416   char const *res = variable;
    417   int i;
    418   for (i = 0; i < ARRAY_CARDINALITY (conversion); ++i)
    419     if (STREQ (conversion[i].obsolete, variable))
    420       {
    421         res = conversion[i].updated;
    422         break;
    423       }
    424   return res;
    425 }
    426 
    427 void
    428 muscle_percent_define_insert (char const *var, location variable_loc,
    429                               char const *value,
    430                               muscle_percent_define_how how)
    431 {
    432   /* Backward compatibility.  */
    433   char const *variable = muscle_percent_variable_update (var);
    434   char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
    435   char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
    436   char const *syncline_name =
    437     UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
    438   char const *how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")");
    439 
    440   /* Command-line options are processed before the grammar file.  */
    441   if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
    442       && muscle_find_const (name))
    443     {
    444       unsigned i = 0;
    445       muscle_percent_define_how how_old =
    446         atoi (muscle_find_const (how_name));
    447       if (how_old == MUSCLE_PERCENT_DEFINE_F)
    448         return;
    449       complain_at_indent (variable_loc, &i,
    450                           _("%%define variable %s redefined"), quote (variable));
    451       i += SUB_INDENT;
    452       complain_at_indent (muscle_percent_define_get_loc (variable), &i,
    453                           _("previous definition"));
    454     }
    455 
    456   MUSCLE_INSERT_STRING (name, value);
    457   muscle_insert (loc_name, "");
    458   muscle_location_grow (loc_name, variable_loc);
    459   muscle_insert (syncline_name, "");
    460   muscle_syncline_grow (syncline_name, variable_loc);
    461   muscle_user_name_list_grow ("percent_define_user_variables", variable,
    462                               variable_loc);
    463   MUSCLE_INSERT_INT (how_name, how);
    464 }
    465 
    466 char *
    467 muscle_percent_define_get (char const *variable)
    468 {
    469   char const *name;
    470   char const *usage_name;
    471   char *value;
    472 
    473   name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
    474   usage_name = UNIQSTR_CONCAT ("percent_define_bison_variables(",
    475                                variable, ")");
    476 
    477   muscle_insert (usage_name, "");
    478   value = string_decode (name);
    479   if (!value)
    480     value = xstrdup ("");
    481   return value;
    482 }
    483 
    484 location
    485 muscle_percent_define_get_loc (char const *variable)
    486 {
    487   char const *loc_name;
    488   loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
    489   if (!muscle_find_const (loc_name))
    490     fatal(_("%s: undefined %%define variable %s"),
    491           "muscle_percent_define_get_loc", quote (variable));
    492   return location_decode (loc_name);
    493 }
    494 
    495 char const *
    496 muscle_percent_define_get_syncline (char const *variable)
    497 {
    498   char const *syncline_name;
    499   char const *syncline;
    500   syncline_name =
    501     UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
    502   syncline = muscle_find_const (syncline_name);
    503   if (!syncline)
    504     fatal(_("%s: undefined %%define variable %s"),
    505           "muscle_percent_define_get_syncline", quote (variable));
    506   return syncline;
    507 }
    508 
    509 bool
    510 muscle_percent_define_ifdef (char const *variable)
    511 {
    512   char const *name;
    513   char const *usage_name;
    514   char const *value;
    515 
    516   name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
    517   usage_name =
    518     UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
    519 
    520   value = muscle_find_const (name);
    521   if (value)
    522     {
    523       muscle_insert (usage_name, "");
    524       return true;
    525     }
    526 
    527   return false;
    528 }
    529 
    530 bool
    531 muscle_percent_define_flag_if (char const *variable)
    532 {
    533   char const *invalid_boolean_name;
    534   bool result = false;
    535 
    536   invalid_boolean_name =
    537     UNIQSTR_CONCAT ("percent_define_invalid_boolean(", variable, ")");
    538 
    539   if (muscle_percent_define_ifdef (variable))
    540     {
    541       char *value = muscle_percent_define_get (variable);
    542       if (value[0] == '\0' || 0 == strcmp (value, "true"))
    543         result = true;
    544       else if (0 == strcmp (value, "false"))
    545         result = false;
    546       else if (!muscle_find_const (invalid_boolean_name))
    547         {
    548           muscle_insert (invalid_boolean_name, "");
    549           complain_at(muscle_percent_define_get_loc (variable),
    550                       _("invalid value for %%define Boolean variable %s"),
    551                       quote (variable));
    552         }
    553       free (value);
    554     }
    555   else
    556     fatal(_("%s: undefined %%define variable %s"),
    557           "muscle_percent_define_flag", quote (variable));
    558 
    559   return result;
    560 }
    561 
    562 void
    563 muscle_percent_define_default (char const *variable, char const *value)
    564 {
    565   char const *name;
    566   char const *loc_name;
    567   char const *syncline_name;
    568   name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
    569   loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
    570   syncline_name =
    571     UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
    572   if (!muscle_find_const (name))
    573     {
    574       location loc;
    575       MUSCLE_INSERT_STRING (name, value);
    576       loc.start.file = loc.end.file = "<default value>";
    577       loc.start.line = loc.end.line = -1;
    578       loc.start.column = loc.end.column = -1;
    579       muscle_insert (loc_name, "");
    580       muscle_location_grow (loc_name, loc);
    581       muscle_insert (syncline_name, "");
    582     }
    583 }
    584 
    585 void
    586 muscle_percent_define_check_values (char const * const *values)
    587 {
    588   for (; *values; ++values)
    589     {
    590       char const * const *variablep = values;
    591       char const *name;
    592       char *value;
    593 
    594       name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
    595 
    596       value = string_decode (name);
    597       if (value)
    598         {
    599           for (++values; *values; ++values)
    600             {
    601               if (0 == strcmp (value, *values))
    602                 break;
    603             }
    604           if (!*values)
    605             {
    606               unsigned i = 0;
    607               location loc = muscle_percent_define_get_loc (*variablep);
    608               complain_at_indent (loc, &i,
    609                                 _("invalid value for %%define variable %s: %s"),
    610                                   quote (*variablep), quote_n (1, value));
    611               i += SUB_INDENT;
    612               for (values = variablep + 1; *values; ++values)
    613                 complain_at_indent (loc, &i, _("accepted value: %s"),
    614                                     quote (*values));
    615             }
    616           else
    617             {
    618               while (*values)
    619                 ++values;
    620             }
    621           free (value);
    622         }
    623       else
    624         fatal (_("%s: undefined %%define variable %s"),
    625                "muscle_percent_define_check_values", quote (*variablep));
    626     }
    627 }
    628 
    629 void
    630 muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
    631                           char const *code, location code_loc)
    632 {
    633   char const *name;
    634   name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
    635   muscle_code_grow (name, code, code_loc);
    636   muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
    637                                qualifier_loc);
    638 }
    639 
    640 
    641 /*------------------------------------------------.
    642 | Output the definition of ENTRY as a m4_define.  |
    643 `------------------------------------------------*/
    644 
    645 static inline bool
    646 muscle_m4_output (muscle_entry *entry, FILE *out)
    647 {
    648   fprintf (out, "m4_define([b4_%s],\n", entry->key);
    649   fprintf (out, "[[%s]])\n\n\n", entry->value);
    650   return true;
    651 }
    652 
    653 static bool
    654 muscle_m4_output_processor (void *entry, void *out)
    655 {
    656   return muscle_m4_output (entry, out);
    657 }
    658 
    659 
    660 /*----------------------------------------------------------------.
    661 | Output the definition of all the current muscles into a list of |
    662 | m4_defines.                                                     |
    663 `----------------------------------------------------------------*/
    664 
    665 void
    666 muscles_m4_output (FILE *out)
    667 {
    668   hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
    669 }
    670