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
hash_compare_muscles(void const * x,void const * y)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
hash_muscle(const void * x,size_t tablesize)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
muscle_entry_free(void * entry)69 muscle_entry_free (void *entry)
70 {
71   muscle_entry *mentry = entry;
72   free (mentry->storage);
73   free (mentry);
74 }
75 
76 void
muscle_init(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
muscle_free(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
muscle_insert(char const * key,char const * value)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
muscle_grow(const char * key,const char * val,const char * separator)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
muscle_syncline_grow(char const * key,location loc)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
muscle_code_grow(const char * key,const char * val,location loc)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 
muscle_pair_list_grow(const char * muscle,const char * a1,const char * a2)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 *
muscle_find_const(char const * key)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 *
muscle_find(char const * key)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
muscle_boundary_grow(char const * key,boundary bound)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
muscle_location_grow(char const * key,location loc)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 *
string_decode(char const * key)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
location_decode(char const * key)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
muscle_user_name_list_grow(char const * key,char const * user_name,location loc)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 *
muscle_percent_variable_update(char const * variable)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
muscle_percent_define_insert(char const * var,location variable_loc,char const * value,muscle_percent_define_how how)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 *
muscle_percent_define_get(char const * variable)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
muscle_percent_define_get_loc(char const * variable)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 *
muscle_percent_define_get_syncline(char const * variable)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
muscle_percent_define_ifdef(char const * variable)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
muscle_percent_define_flag_if(char const * variable)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
muscle_percent_define_default(char const * variable,char const * value)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
muscle_percent_define_check_values(char const * const * values)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
muscle_percent_code_grow(char const * qualifier,location qualifier_loc,char const * code,location code_loc)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
muscle_m4_output(muscle_entry * entry,FILE * out)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
muscle_m4_output_processor(void * entry,void * out)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
muscles_m4_output(FILE * out)666 muscles_m4_output (FILE *out)
667 {
668   hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
669 }
670