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