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