]> git.saurik.com Git - bison.git/blob - src/muscle-tab.c
4d5dd0acfb504bf2f925a5e15380c8571dea0d88
[bison.git] / src / muscle-tab.c
1 /* Muscle table manager for Bison.
2
3 Copyright (C) 2001-2013 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 STREQ (m1->key, m2->key);
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 /* Create a fresh muscle name KEY, and insert in the hash table. */
64 static void *
65 muscle_entry_new (char const *key)
66 {
67 muscle_entry *res = xmalloc (sizeof *res);
68 res->key = key;
69 res->value = NULL;
70 res->storage = NULL;
71 if (!hash_insert (muscle_table, res))
72 xalloc_die ();
73 return res;
74 }
75
76 static void
77 muscle_entry_free (void *entry)
78 {
79 muscle_entry *mentry = entry;
80 free (mentry->storage);
81 free (mentry);
82 }
83
84 void
85 muscle_init (void)
86 {
87 /* Initialize the muscle obstack. */
88 obstack_init (&muscle_obstack);
89
90 muscle_table = hash_initialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
91 hash_compare_muscles, muscle_entry_free);
92
93 /* Version and input file. */
94 MUSCLE_INSERT_STRING ("version", VERSION);
95 }
96
97
98 void
99 muscle_free (void)
100 {
101 hash_free (muscle_table);
102 obstack_free (&muscle_obstack, NULL);
103 }
104
105 /* Look for the muscle named KEY. Return NULL if does not exist. */
106 static
107 muscle_entry *
108 muscle_lookup (char const *key)
109 {
110 muscle_entry probe;
111 probe.key = key;
112 return hash_lookup (muscle_table, &probe);
113 }
114
115
116 void
117 muscle_insert (char const *key, char const *value)
118 {
119 muscle_entry *entry = muscle_lookup (key);
120 if (entry)
121 free (entry->storage);
122 else
123 /* First insertion in the hash. */
124 entry = muscle_entry_new (key);
125 entry->value = value;
126 entry->storage = NULL;
127 }
128
129
130 /*-------------------------------------------------------------------.
131 | Append VALUE to the current value of KEY. If KEY did not already |
132 | exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously |
133 | associated value. Copy VALUE and SEPARATOR. |
134 `-------------------------------------------------------------------*/
135
136 void
137 muscle_grow (const char *key, const char *val, const char *separator)
138 {
139 muscle_entry *entry = muscle_lookup (key);
140
141 if (entry)
142 {
143 /* Grow the current value. */
144 char *new_val;
145 obstack_printf (&muscle_obstack, "%s%s%s", entry->value, separator, val);
146 free (entry->storage);
147 new_val = obstack_finish0 (&muscle_obstack);
148 entry->value = entry->storage = xstrdup (new_val);
149 obstack_free (&muscle_obstack, new_val);
150 }
151 else
152 {
153 /* First insertion in the hash. */
154 entry = muscle_entry_new (key);
155 entry->value = entry->storage = xstrdup (val);
156 }
157 }
158
159 /*------------------------------------------------------------------.
160 | Using muscle_grow, append a synchronization line for the location |
161 | LOC to the current value of KEY. |
162 `------------------------------------------------------------------*/
163
164 static void
165 muscle_syncline_grow (char const *key, location loc)
166 {
167 char *extension = NULL;
168 obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
169 obstack_quote (&muscle_obstack,
170 quotearg_style (c_quoting_style, loc.start.file));
171 obstack_sgrow (&muscle_obstack, ")[");
172 extension = obstack_finish0 (&muscle_obstack);
173 muscle_grow (key, extension, "");
174 obstack_free (&muscle_obstack, extension);
175 }
176
177 /*------------------------------------------------------------------.
178 | Append VALUE to the current value of KEY, using muscle_grow. But |
179 | in addition, issue a synchronization line for the location LOC |
180 | using muscle_syncline_grow. |
181 `------------------------------------------------------------------*/
182
183 void
184 muscle_code_grow (const char *key, const char *val, location loc)
185 {
186 muscle_syncline_grow (key, loc);
187 muscle_grow (key, val, "\n");
188 }
189
190
191 void
192 muscle_pair_list_grow (const char *muscle,
193 const char *a1, const char *a2)
194 {
195 char *pair;
196 obstack_sgrow (&muscle_obstack, "[");
197 obstack_quote (&muscle_obstack, a1);
198 obstack_sgrow (&muscle_obstack, ", ");
199 obstack_quote (&muscle_obstack, a2);
200 obstack_sgrow (&muscle_obstack, "]");
201 pair = obstack_finish0 (&muscle_obstack);
202 muscle_grow (muscle, pair, ",\n");
203 obstack_free (&muscle_obstack, pair);
204 }
205
206
207 char const *
208 muscle_find_const (char const *key)
209 {
210 muscle_entry *entry = muscle_lookup (key);
211 return entry ? entry->value : NULL;
212 }
213
214
215 char *
216 muscle_find (char const *key)
217 {
218 muscle_entry *entry = muscle_lookup (key);
219 if (entry)
220 {
221 aver (entry->value == entry->storage);
222 return entry->storage;
223 }
224 return NULL;
225 }
226
227
228 /* In the format 'file_name:line.column', append BOUND to MUSCLE. Use
229 digraphs for special characters in the file name. */
230
231 static void
232 muscle_boundary_grow (char const *key, boundary bound)
233 {
234 char *extension;
235 obstack_sgrow (&muscle_obstack, "[[");
236 obstack_escape (&muscle_obstack, bound.file);
237 obstack_printf (&muscle_obstack, ":%d.%d]]", bound.line, bound.column);
238 extension = obstack_finish0 (&muscle_obstack);
239 muscle_grow (key, extension, "");
240 obstack_free (&muscle_obstack, extension);
241 }
242
243
244 /* In the format '[[file_name:line.column]], [[file_name:line.column]]',
245 append LOC to MUSCLE. Use digraphs for special characters in each
246 file name. */
247
248 static void
249 muscle_location_grow (char const *key, location loc)
250 {
251 muscle_boundary_grow (key, loc.start);
252 muscle_grow (key, "", ", ");
253 muscle_boundary_grow (key, loc.end);
254 }
255
256 #define COMMON_DECODE(Value) \
257 case '$': \
258 aver (*++(Value) == ']'); \
259 aver (*++(Value) == '['); \
260 obstack_sgrow (&muscle_obstack, "$"); \
261 break; \
262 case '@': \
263 switch (*++(Value)) \
264 { \
265 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
266 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
267 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
268 default: aver (false); break; \
269 } \
270 break; \
271 default: \
272 obstack_1grow (&muscle_obstack, *(Value)); \
273 break;
274
275 /* Reverse of obstack_escape. */
276 static char *
277 string_decode (char const *key)
278 {
279 char const *value = muscle_find_const (key);
280 char *value_decoded;
281 char *result;
282
283 if (!value)
284 return NULL;
285 do {
286 switch (*value)
287 {
288 COMMON_DECODE (value)
289 case '[':
290 case ']':
291 aver (false);
292 break;
293 }
294 } while (*value++);
295 value_decoded = obstack_finish (&muscle_obstack);
296 result = xstrdup (value_decoded);
297 obstack_free (&muscle_obstack, value_decoded);
298 return result;
299 }
300
301 /* Reverse of muscle_location_grow. */
302 static location
303 location_decode (char const *key)
304 {
305 location loc;
306 char const *value = muscle_find_const (key);
307 aver (value);
308 aver (*value == '[');
309 aver (*++value == '[');
310 while (*++value)
311 switch (*value)
312 {
313 COMMON_DECODE (value)
314 case '[':
315 aver (false);
316 break;
317 case ']':
318 {
319 char *boundary_str;
320 aver (*++value == ']');
321 boundary_str = obstack_finish0 (&muscle_obstack);
322 switch (*++value)
323 {
324 case ',':
325 boundary_set_from_string (&loc.start, boundary_str);
326 obstack_free (&muscle_obstack, boundary_str);
327 aver (*++value == ' ');
328 aver (*++value == '[');
329 aver (*++value == '[');
330 break;
331 case '\0':
332 boundary_set_from_string (&loc.end, boundary_str);
333 obstack_free (&muscle_obstack, boundary_str);
334 return loc;
335 break;
336 default:
337 aver (false);
338 break;
339 }
340 }
341 break;
342 }
343 aver (false);
344 return loc;
345 }
346
347 void
348 muscle_user_name_list_grow (char const *key, char const *user_name,
349 location loc)
350 {
351 muscle_grow (key, "[[[[", ",");
352 muscle_grow (key, user_name, "");
353 muscle_grow (key, "]], ", "");
354 muscle_location_grow (key, loc);
355 muscle_grow (key, "]]", "");
356 }
357
358
359 /** Return an allocated string that represents the %define directive
360 that performs the assignment.
361
362 @param assignment "VAR", or "VAR=VAL".
363 @param value default value if VAL \a assignment has no '='.
364
365 For instance:
366 "foo", NULL => "%define foo"
367 "foo", "baz" => "%define foo baz"
368 "foo=bar", NULL => "%define foo bar"
369 "foo=bar", "baz" => "%define foo bar"
370 "foo=", NULL => "%define foo"
371 "foo=", "baz" => "%define foo"
372 */
373
374 static
375 char *
376 define_directive (char const *assignment, char const *value)
377 {
378 char *eq = strchr (assignment, '=');
379 char const *fmt = !eq && value && *value ? "%%define %s %s" : "%%define %s";
380 char *res = xmalloc (strlen (fmt) + strlen (assignment)
381 + (value ? strlen (value) : 0));
382 sprintf (res, fmt, assignment, value);
383 eq = strchr (res, '=');
384 if (eq)
385 *eq = eq[1] ? ' ' : '\0';
386 return res;
387 }
388
389 /** If the \a variable name is obsolete, return the name to use,
390 * otherwise \a variable. If the \a value is obsolete, update it too.
391 *
392 * Allocates the returned value. */
393 static
394 char *
395 muscle_percent_variable_update (char const *variable, location variable_loc,
396 char const **value)
397 {
398 typedef struct
399 {
400 const char *obsolete;
401 const char *updated;
402 } conversion_type;
403 const conversion_type conversion[] =
404 {
405 { "api.push_pull", "api.push-pull", },
406 { "api.tokens.prefix", "api.token.prefix", },
407 { "lex_symbol", "api.token.constructor", },
408 { "location_type", "api.location.type", },
409 { "lr.default-reductions", "lr.default-reduction", },
410 { "lr.keep-unreachable-states", "lr.keep-unreachable-state", },
411 { "lr.keep_unreachable_states", "lr.keep-unreachable-state", },
412 { "namespace", "api.namespace", },
413 { "stype", "api.value.type", },
414 { "variant=", "api.value.type=variant", },
415 { "variant=true", "api.value.type=variant", },
416 { NULL, NULL, }
417 };
418 conversion_type const *c;
419 for (c = conversion; c->obsolete; ++c)
420 {
421 char const *eq = strchr (c->obsolete, '=');
422 if (eq
423 ? (!strncmp (c->obsolete, variable, eq - c->obsolete)
424 && STREQ (eq + 1, *value))
425 : STREQ (c->obsolete, variable))
426 {
427 char *old = define_directive (c->obsolete, *value);
428 char *upd = define_directive (c->updated, *value);
429 deprecated_directive (&variable_loc, old, upd);
430 free (old);
431 free (upd);
432 char *res = xstrdup (c->updated);
433 {
434 char *eq2 = strchr (res, '=');
435 if (eq2)
436 {
437 *eq2 = '\0';
438 *value = eq2 + 1;
439 }
440 }
441 return res;
442 }
443 }
444 return xstrdup (variable);
445 }
446
447 void
448 muscle_percent_define_insert (char const *var, location variable_loc,
449 char const *value,
450 muscle_percent_define_how how)
451 {
452 /* Backward compatibility. */
453 char *variable = muscle_percent_variable_update (var, variable_loc, &value);
454 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
455 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
456 char const *syncline_name =
457 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
458 char const *how_name = UNIQSTR_CONCAT ("percent_define_how(", variable, ")");
459
460 /* Command-line options are processed before the grammar file. */
461 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE
462 && muscle_find_const (name))
463 {
464 muscle_percent_define_how how_old = atoi (muscle_find_const (how_name));
465 unsigned i = 0;
466 if (how_old == MUSCLE_PERCENT_DEFINE_F)
467 goto end;
468 complain_indent (&variable_loc, complaint, &i,
469 _("%%define variable %s redefined"),
470 quote (variable));
471 i += SUB_INDENT;
472 location loc = muscle_percent_define_get_loc (variable);
473 complain_indent (&loc, complaint, &i, _("previous definition"));
474 }
475
476 MUSCLE_INSERT_STRING (name, value);
477 muscle_insert (loc_name, "");
478 muscle_location_grow (loc_name, variable_loc);
479 muscle_insert (syncline_name, "");
480 muscle_syncline_grow (syncline_name, variable_loc);
481 muscle_user_name_list_grow ("percent_define_user_variables", variable,
482 variable_loc);
483 MUSCLE_INSERT_INT (how_name, how);
484 end:
485 free (variable);
486 }
487
488 /* This is used for backward compatibility, e.g., "%define api.pure"
489 supersedes "%pure-parser". */
490 void
491 muscle_percent_define_ensure (char const *variable, location loc,
492 bool value)
493 {
494 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
495 char const *val = value ? "" : "false";
496
497 /* Don't complain is VARIABLE is already defined, but be sure to set
498 its value to VAL. */
499 if (!muscle_find_const (name))
500 muscle_percent_define_insert (variable, loc, val,
501 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
502 if (muscle_percent_define_flag_if (variable) != value)
503 muscle_percent_define_insert (variable, loc, val,
504 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
505 }
506
507 char *
508 muscle_percent_define_get (char const *variable)
509 {
510 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
511 char const *usage_name =
512 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
513 char *value = string_decode (name);
514 if (!value)
515 value = xstrdup ("");
516
517 muscle_insert (usage_name, "");
518 return value;
519 }
520
521 location
522 muscle_percent_define_get_loc (char const *variable)
523 {
524 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
525 if (!muscle_find_const (loc_name))
526 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
527 "muscle_percent_define_get_loc", quote (variable));
528 return location_decode (loc_name);
529 }
530
531 char const *
532 muscle_percent_define_get_syncline (char const *variable)
533 {
534 char const *syncline_name =
535 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
536 char const *syncline = muscle_find_const (syncline_name);
537 if (!syncline)
538 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
539 "muscle_percent_define_get_syncline", quote (variable));
540 return syncline;
541 }
542
543 bool
544 muscle_percent_define_ifdef (char const *variable)
545 {
546 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
547 char const *usage_name =
548 UNIQSTR_CONCAT ("percent_define_bison_variables(", variable, ")");
549 char const *value = muscle_find_const (name);
550 if (value)
551 {
552 muscle_insert (usage_name, "");
553 return true;
554 }
555
556 return false;
557 }
558
559 bool
560 muscle_percent_define_flag_if (char const *variable)
561 {
562 char const *invalid_boolean_name =
563 UNIQSTR_CONCAT ("percent_define_invalid_boolean(", variable, ")");
564 bool result = false;
565
566 if (muscle_percent_define_ifdef (variable))
567 {
568 char *value = muscle_percent_define_get (variable);
569 if (value[0] == '\0' || STREQ (value, "true"))
570 result = true;
571 else if (STREQ (value, "false"))
572 result = false;
573 else if (!muscle_find_const (invalid_boolean_name))
574 {
575 muscle_insert (invalid_boolean_name, "");
576 location loc = muscle_percent_define_get_loc (variable);
577 complain (&loc, complaint,
578 _("invalid value for %%define Boolean variable %s"),
579 quote (variable));
580 }
581 free (value);
582 }
583 else
584 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
585 "muscle_percent_define_flag", quote (variable));
586
587 return result;
588 }
589
590 void
591 muscle_percent_define_default (char const *variable, char const *value)
592 {
593 char const *name = UNIQSTR_CONCAT ("percent_define(", variable, ")");
594 char const *loc_name = UNIQSTR_CONCAT ("percent_define_loc(", variable, ")");
595 char const *syncline_name =
596 UNIQSTR_CONCAT ("percent_define_syncline(", variable, ")");
597 if (!muscle_find_const (name))
598 {
599 location loc;
600 MUSCLE_INSERT_STRING (name, value);
601 loc.start.file = loc.end.file = "<default value>";
602 loc.start.line = loc.end.line = -1;
603 loc.start.column = loc.end.column = -1;
604 muscle_insert (loc_name, "");
605 muscle_location_grow (loc_name, loc);
606 muscle_insert (syncline_name, "");
607 }
608 }
609
610 void
611 muscle_percent_define_check_values (char const * const *values)
612 {
613 for (; *values; ++values)
614 {
615 char const * const *variablep = values;
616 char const *name = UNIQSTR_CONCAT ("percent_define(", *variablep, ")");
617 char *value = string_decode (name);
618 if (value)
619 {
620 for (++values; *values; ++values)
621 {
622 if (STREQ (value, *values))
623 break;
624 }
625 if (!*values)
626 {
627 unsigned i = 0;
628 location loc = muscle_percent_define_get_loc (*variablep);
629 complain_indent (&loc, complaint, &i,
630 _("invalid value for %%define variable %s: %s"),
631 quote (*variablep), quote_n (1, value));
632 i += SUB_INDENT;
633 for (values = variablep + 1; *values; ++values)
634 complain_indent (&loc, complaint | no_caret | silent, &i,
635 _("accepted value: %s"), quote (*values));
636 }
637 else
638 {
639 while (*values)
640 ++values;
641 }
642 free (value);
643 }
644 else
645 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
646 "muscle_percent_define_check_values", quote (*variablep));
647 }
648 }
649
650 void
651 muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
652 char const *code, location code_loc)
653 {
654 char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
655 muscle_code_grow (name, code, code_loc);
656 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
657 qualifier_loc);
658 }
659
660
661 /*------------------------------------------------.
662 | Output the definition of ENTRY as a m4_define. |
663 `------------------------------------------------*/
664
665 static inline bool
666 muscle_m4_output (muscle_entry *entry, FILE *out)
667 {
668 fprintf (out,
669 "m4_define([b4_%s],\n"
670 "[[%s]])\n\n\n", entry->key, entry->value);
671 return true;
672 }
673
674 static bool
675 muscle_m4_output_processor (void *entry, void *out)
676 {
677 return muscle_m4_output (entry, out);
678 }
679
680
681 void
682 muscles_m4_output (FILE *out)
683 {
684 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
685 }