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