c: improve port of stdint.h usage to pre-C99
[bison.git] / src / muscle-tab.c
blob02c83530946ea28f1d11b529f1de22d2e13fdc02
1 /* Muscle table manager for Bison.
3 Copyright (C) 2001-2015, 2018-2019 Free Software Foundation, Inc.
5 This file is part of Bison, the GNU Compiler Compiler.
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.
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.
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/>. */
20 #include <config.h>
21 #include "system.h"
23 #include <hash.h>
25 #include "complain.h"
26 #include "files.h"
27 #include "fixits.h"
28 #include "getargs.h"
29 #include "muscle-tab.h"
30 #include "quote.h"
32 muscle_kind
33 muscle_kind_new (char const *k)
35 if (STREQ (k, "code"))
36 return muscle_code;
37 else if (STREQ (k, "keyword"))
38 return muscle_keyword;
39 else if (STREQ (k, "string"))
40 return muscle_string;
41 abort ();
44 char const *
45 muscle_kind_string (muscle_kind k)
47 switch (k)
49 case muscle_code: return "code";
50 case muscle_keyword: return "keyword";
51 case muscle_string: return "string";
53 abort ();
57 /* A key-value pair, along with storage that can be reclaimed when
58 this pair is no longer needed. */
59 typedef struct
61 char const *key;
62 char const *value;
63 char *storage;
64 muscle_kind kind;
65 } muscle_entry;
68 /* The name of muscle for the %define variable VAR (corresponding to
69 FIELD, if defined). */
70 static uniqstr
71 muscle_name (char const *var, char const *field)
73 if (field)
74 return UNIQSTR_CONCAT ("percent_define_", field, "(", var, ")");
75 else
76 return UNIQSTR_CONCAT ("percent_define(", var, ")");
79 /* An obstack used to create some entries. */
80 struct obstack muscle_obstack;
82 /* Initial capacity of muscles hash table. */
83 #define HT_INITIAL_CAPACITY 257
85 static struct hash_table *muscle_table = NULL;
87 static bool
88 hash_compare_muscles (void const *x, void const *y)
90 muscle_entry const *m1 = x;
91 muscle_entry const *m2 = y;
92 return STREQ (m1->key, m2->key);
95 static size_t
96 hash_muscle (const void *x, size_t tablesize)
98 muscle_entry const *m = x;
99 return hash_string (m->key, tablesize);
102 /* Create a fresh muscle name KEY, and insert in the hash table. */
103 static void *
104 muscle_entry_new (char const *key)
106 muscle_entry *res = xmalloc (sizeof *res);
107 res->key = key;
108 res->value = NULL;
109 res->storage = NULL;
110 if (!hash_insert (muscle_table, res))
111 xalloc_die ();
112 return res;
115 static void
116 muscle_entry_free (void *entry)
118 muscle_entry *mentry = entry;
119 free (mentry->storage);
120 free (mentry);
123 void
124 muscle_init (void)
126 /* Initialize the muscle obstack. */
127 obstack_init (&muscle_obstack);
129 muscle_table = hash_xinitialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
130 hash_compare_muscles, muscle_entry_free);
132 /* Version and input file. */
133 MUSCLE_INSERT_STRING ("version", VERSION);
137 void
138 muscle_free (void)
140 hash_free (muscle_table);
141 obstack_free (&muscle_obstack, NULL);
144 /* Look for the muscle named KEY. Return NULL if does not exist. */
145 static
146 muscle_entry *
147 muscle_lookup (char const *key)
149 muscle_entry probe;
150 probe.key = key;
151 return hash_lookup (muscle_table, &probe);
155 void
156 muscle_insert (char const *key, char const *value)
158 muscle_entry *entry = muscle_lookup (key);
159 if (entry)
160 free (entry->storage);
161 else
162 /* First insertion in the hash. */
163 entry = muscle_entry_new (key);
164 entry->value = value;
165 entry->storage = NULL;
169 /* Append VALUE to the current value of KEY. If KEY did not already
170 exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously
171 associated value. Copy VALUE and SEPARATOR. If VALUE does not end
172 with TERMINATOR, append one. */
174 static void
175 muscle_grow (const char *key, const char *val,
176 const char *separator, const char *terminator)
178 muscle_entry *entry = muscle_lookup (key);
179 if (entry)
181 obstack_sgrow (&muscle_obstack, entry->value);
182 obstack_sgrow (&muscle_obstack, separator);
183 free (entry->storage);
185 else
186 entry = muscle_entry_new (key);
188 obstack_sgrow (&muscle_obstack, val);
190 size_t vals = strlen (val);
191 size_t terms = strlen (terminator);
192 if (terms <= vals
193 && STRNEQ (val + vals - terms, terminator))
194 obstack_sgrow (&muscle_obstack, terminator);
197 char const *new_val = obstack_finish0 (&muscle_obstack);
198 entry->value = entry->storage = xstrdup (new_val);
199 obstack_free (&muscle_obstack, new_val);
203 /*------------------------------------------------------------------.
204 | Using muscle_grow, append a synchronization line for the location |
205 | LOC to the current value of KEY. |
206 `------------------------------------------------------------------*/
208 static void
209 muscle_syncline_grow (char const *key, location loc)
211 obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
212 obstack_quote (&muscle_obstack,
213 quotearg_style (c_quoting_style, loc.start.file));
214 obstack_sgrow (&muscle_obstack, ")dnl\n[");
215 char const *extension = obstack_finish0 (&muscle_obstack);
216 muscle_grow (key, extension, "", "");
217 obstack_free (&muscle_obstack, extension);
220 /*------------------------------------------------------------------.
221 | Append VALUE to the current value of KEY, using muscle_grow. But |
222 | in addition, issue a synchronization line for the location LOC |
223 | using muscle_syncline_grow. |
224 `------------------------------------------------------------------*/
226 void
227 muscle_code_grow (const char *key, const char *val, location loc)
229 muscle_syncline_grow (key, loc);
230 muscle_grow (key, val, "", "\n");
234 void
235 muscle_pair_list_grow (const char *muscle,
236 const char *a1, const char *a2)
238 obstack_sgrow (&muscle_obstack, "[");
239 obstack_quote (&muscle_obstack, a1);
240 obstack_sgrow (&muscle_obstack, ", ");
241 obstack_quote (&muscle_obstack, a2);
242 obstack_sgrow (&muscle_obstack, "]");
243 char const *pair = obstack_finish0 (&muscle_obstack);
244 muscle_grow (muscle, pair, ",\n", "");
245 obstack_free (&muscle_obstack, pair);
249 char const *
250 muscle_find_const (char const *key)
252 muscle_entry *entry = muscle_lookup (key);
253 return entry ? entry->value : NULL;
257 char *
258 muscle_find (char const *key)
260 muscle_entry *entry = muscle_lookup (key);
261 if (entry)
263 aver (entry->value == entry->storage);
264 return entry->storage;
266 return NULL;
270 /* In the format 'file_name:line.column', append BOUND to MUSCLE. Use
271 digraphs for special characters in the file name. */
273 static void
274 muscle_boundary_grow (char const *key, boundary bound)
276 obstack_sgrow (&muscle_obstack, "[[");
277 obstack_escape (&muscle_obstack, bound.file);
278 obstack_printf (&muscle_obstack, ":%d.%d@@%d]]", bound.line, bound.column, bound.byte);
279 char const *extension = obstack_finish0 (&muscle_obstack);
280 muscle_grow (key, extension, "", "");
281 obstack_free (&muscle_obstack, extension);
285 void
286 muscle_location_grow (char const *key, location loc)
288 muscle_boundary_grow (key, loc.start);
289 muscle_grow (key, "", ", ", "");
290 muscle_boundary_grow (key, loc.end);
293 #define COMMON_DECODE(Value) \
294 case '$': \
295 ++(Value); aver (*(Value) == '['); \
296 ++(Value); aver (*(Value) == ']'); \
297 ++(Value); aver (*(Value) == '['); \
298 obstack_sgrow (&muscle_obstack, "$"); \
299 break; \
300 case '@': \
301 switch (*++(Value)) \
303 case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
304 case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
305 case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
306 default: aver (false); break; \
308 break; \
309 default: \
310 obstack_1grow (&muscle_obstack, *(Value)); \
311 break;
313 /* Reverse of obstack_escape. */
314 static char *
315 string_decode (char const *key)
317 char const *value = muscle_find_const (key);
318 if (!value)
319 return NULL;
320 do {
321 switch (*value)
323 COMMON_DECODE (value)
324 case '[':
325 case ']':
326 aver (false);
327 break;
329 } while (*value++);
330 char const *value_decoded = obstack_finish (&muscle_obstack);
331 char *res = xstrdup (value_decoded);
332 obstack_free (&muscle_obstack, value_decoded);
333 return res;
336 /* Reverse of muscle_location_grow. */
337 static location
338 location_decode (char const *value)
340 aver (value);
341 aver (*value == '[');
342 ++value; aver (*value == '[');
343 location loc;
344 while (*++value)
345 switch (*value)
347 COMMON_DECODE (value)
348 case '[':
349 aver (false);
350 break;
351 case ']':
352 ++value; aver (*value == ']');
353 char *boundary_str = obstack_finish0 (&muscle_obstack);
354 switch (*++value)
356 case ',':
357 boundary_set_from_string (&loc.start, boundary_str);
358 obstack_free (&muscle_obstack, boundary_str);
359 ++value; aver (*value == ' ');
360 ++value; aver (*value == '[');
361 ++value; 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;
372 break;
374 aver (false);
375 return loc;
378 void
379 muscle_user_name_list_grow (char const *key, char const *user_name,
380 location loc)
382 muscle_grow (key, "[[[[", ",", "");
383 muscle_grow (key, user_name, "", "");
384 muscle_grow (key, "]], ", "", "");
385 muscle_location_grow (key, loc);
386 muscle_grow (key, "]]", "", "");
390 /** Return an allocated string that represents the %define directive
391 that performs the assignment.
393 @param assignment "VAR", or "VAR=VAL".
394 @param value default value if VAL \a assignment has no '='.
396 For instance:
397 "foo", NULL => "%define foo"
398 "foo", "baz" => "%define foo baz"
399 "foo=bar", NULL => "%define foo bar"
400 "foo=bar", "baz" => "%define foo bar"
401 "foo=", NULL => "%define foo"
402 "foo=", "baz" => "%define foo"
405 static
406 char *
407 define_directive (char const *assignment,
408 muscle_kind kind,
409 char const *value)
411 char *eq = strchr (assignment, '=');
412 char const *fmt
413 = eq || !value || !*value ? "%%define %s"
414 : kind == muscle_code ? "%%define %s {%s}"
415 : kind == muscle_string ? "%%define %s \"%s\""
416 : "%%define %s %s";
417 char *res = xmalloc (strlen (fmt) + strlen (assignment)
418 + (value ? strlen (value) : 0));
419 sprintf (res, fmt, assignment, value);
420 eq = strchr (res, '=');
421 if (eq)
422 *eq = eq[1] ? ' ' : '\0';
423 return res;
426 /** If the \a variable name is obsolete, return the name to use,
427 * otherwise \a variable. If the \a value is obsolete, update it too.
429 * Allocates the returned value if needed, otherwise the returned
430 * value is exactly \a variable. */
431 static
432 char const *
433 muscle_percent_variable_update (char const *variable,
434 muscle_kind kind,
435 char const **value,
436 char **old, char **upd)
438 typedef struct
440 const char *obsolete;
441 const char *updated;
442 muscle_kind kind;
443 } conversion_type;
444 const conversion_type conversion[] =
446 { "%error-verbose", "parse.error=verbose", muscle_keyword },
447 { "%error_verbose", "parse.error=verbose", muscle_keyword },
448 { "abstract", "api.parser.abstract", muscle_keyword },
449 { "annotations", "api.parser.annotations", muscle_code },
450 { "api.push_pull", "api.push-pull", muscle_keyword },
451 { "api.tokens.prefix", "api.token.prefix", muscle_code },
452 { "extends", "api.parser.extends", muscle_keyword },
453 { "final", "api.parser.final", muscle_keyword },
454 { "implements", "api.parser.implements", muscle_keyword },
455 { "lex_symbol", "api.token.constructor", -1 },
456 { "location_type", "api.location.type", muscle_code },
457 { "lr.default-reductions", "lr.default-reduction", muscle_keyword },
458 { "lr.keep-unreachable-states", "lr.keep-unreachable-state", muscle_keyword },
459 { "lr.keep_unreachable_states", "lr.keep-unreachable-state", muscle_keyword },
460 { "namespace", "api.namespace", muscle_code },
461 { "parser_class_name", "api.parser.class", muscle_code },
462 { "public", "api.parser.public", muscle_keyword },
463 { "strictfp", "api.parser.strictfp", muscle_keyword },
464 { "stype", "api.value.type", -1 },
465 { "variant=", "api.value.type=variant", -1 },
466 { "variant=true", "api.value.type=variant", -1 },
467 { NULL, NULL, -1, }
470 for (conversion_type const *c = conversion; c->obsolete; ++c)
472 char const *eq = strchr (c->obsolete, '=');
473 if (eq
474 ? (!strncmp (c->obsolete, variable, eq - c->obsolete)
475 && STREQ (eq + 1, *value))
476 : STREQ (c->obsolete, variable))
478 /* Generate the deprecation warning. */
479 *old = c->obsolete[0] == '%'
480 ? xstrdup (c->obsolete)
481 : define_directive (c->obsolete, kind, *value);
482 *upd = define_directive (c->updated, c->kind, *value);
483 /* Update the variable and its value. */
485 char *res = xstrdup (c->updated);
486 char *eq2 = strchr (res, '=');
487 if (eq2)
489 *eq2 = '\0';
490 *value = eq2 + 1;
492 return res;
496 return variable;
499 void
500 muscle_percent_define_insert (char const *var, location variable_loc,
501 muscle_kind kind,
502 char const *value,
503 muscle_percent_define_how how)
505 /* Backward compatibility. */
506 char *old = NULL;
507 char *upd = NULL;
508 char const *variable
509 = muscle_percent_variable_update (var, kind,
510 &value, &old, &upd);
511 uniqstr name = muscle_name (variable, NULL);
512 uniqstr loc_name = muscle_name (variable, "loc");
513 uniqstr syncline_name = muscle_name (variable, "syncline");
514 uniqstr how_name = muscle_name (variable, "how");
515 uniqstr kind_name = muscle_name (variable, "kind");
517 /* Command-line options are processed before the grammar file. */
518 bool warned = false;
519 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE)
521 char const *current_value = muscle_find_const (name);
522 if (current_value)
524 muscle_percent_define_how how_old
525 = atoi (muscle_find_const (how_name));
526 if (how_old == MUSCLE_PERCENT_DEFINE_F)
527 goto end;
528 int i = 0;
529 /* If assigning the same value, make it a warning. */
530 warnings warn = STREQ (value, current_value) ? Wother : complaint;
531 complain_indent (&variable_loc, warn, &i,
532 _("%%define variable %s redefined"),
533 quote (variable));
534 i += SUB_INDENT;
535 location loc = muscle_percent_define_get_loc (variable);
536 complain_indent (&loc, warn, &i, _("previous definition"));
537 fixits_register (&variable_loc, "");
538 warned = true;
542 if (!warned && old && upd)
543 deprecated_directive (&variable_loc, old, upd);
545 MUSCLE_INSERT_STRING (name, value);
546 muscle_insert (loc_name, "");
547 muscle_location_grow (loc_name, variable_loc);
548 muscle_insert (syncline_name, "");
549 muscle_syncline_grow (syncline_name, variable_loc);
550 muscle_user_name_list_grow ("percent_define_user_variables", variable,
551 variable_loc);
552 MUSCLE_INSERT_INT (how_name, how);
553 MUSCLE_INSERT_STRING (kind_name, muscle_kind_string (kind));
554 end:
555 free (old);
556 free (upd);
557 if (variable != var)
558 free ((char *) variable);
561 /* This is used for backward compatibility, e.g., "%define api.pure"
562 supersedes "%pure-parser". */
563 void
564 muscle_percent_define_ensure (char const *variable, location loc,
565 bool value)
567 uniqstr name = muscle_name (variable, NULL);
568 char const *val = value ? "" : "false";
570 /* Don't complain is VARIABLE is already defined, but be sure to set
571 its value to VAL. */
572 if (!muscle_find_const (name)
573 || muscle_percent_define_flag_if (variable) != value)
574 muscle_percent_define_insert (variable, loc, muscle_keyword, val,
575 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
578 /* Mark %define VARIABLE as used. */
579 static void
580 muscle_percent_define_use (char const *variable)
582 muscle_insert (muscle_name (variable, "bison_variables"), "");
585 /* The value of %define variable VARIABLE (corresponding to FIELD, if
586 defined). Do not register as used, but diagnose unset variables. */
588 static
589 char const *
590 muscle_percent_define_get_raw (char const *variable, char const *field)
592 uniqstr name = muscle_name (variable, field);
593 char const *res = muscle_find_const (name);
594 if (!res)
595 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
596 "muscle_percent_define_get_raw", quote (variable));
597 return res;
600 char *
601 muscle_percent_define_get (char const *variable)
603 uniqstr name = muscle_name (variable, NULL);
604 char *value = string_decode (name);
605 if (!value)
606 value = xstrdup ("");
607 muscle_percent_define_use (variable);
608 return value;
611 /* The kind of VARIABLE. An error if undefined. */
612 static muscle_kind
613 muscle_percent_define_get_kind (char const *variable)
615 return muscle_kind_new (muscle_percent_define_get_raw (variable, "kind"));
618 /* Check the kind of VARIABLE. An error if undefined. */
619 static void
620 muscle_percent_define_check_kind (char const *variable, muscle_kind kind)
622 if (muscle_percent_define_get_kind (variable) != kind)
624 location loc = muscle_percent_define_get_loc (variable);
625 switch (kind)
627 case muscle_code:
628 complain (&loc, Wdeprecated,
629 "%%define variable '%s' requires '{...}' values",
630 variable);
631 break;
632 case muscle_keyword:
633 complain (&loc, Wdeprecated,
634 "%%define variable '%s' requires keyword values",
635 variable);
636 break;
637 case muscle_string:
638 complain (&loc, Wdeprecated,
639 "%%define variable '%s' requires '\"...\"' values",
640 variable);
641 break;
647 location
648 muscle_percent_define_get_loc (char const *variable)
650 return location_decode (muscle_percent_define_get_raw (variable, "loc"));
653 char const *
654 muscle_percent_define_get_syncline (char const *variable)
656 return muscle_percent_define_get_raw (variable, "syncline");
659 bool
660 muscle_percent_define_ifdef (char const *variable)
662 if (muscle_find_const (muscle_name (variable, NULL)))
664 muscle_percent_define_use (variable);
665 return true;
667 else
668 return false;
671 bool
672 muscle_percent_define_flag_if (char const *variable)
674 uniqstr invalid_boolean_name = muscle_name (variable, "invalid_boolean");
675 bool res = false;
677 if (muscle_percent_define_ifdef (variable))
679 char *value = muscle_percent_define_get (variable);
680 muscle_percent_define_check_kind (variable, muscle_keyword);
681 if (value[0] == '\0' || STREQ (value, "true"))
682 res = true;
683 else if (STREQ (value, "false"))
684 res = false;
685 else if (!muscle_find_const (invalid_boolean_name))
687 muscle_insert (invalid_boolean_name, "");
688 location loc = muscle_percent_define_get_loc (variable);
689 complain (&loc, complaint,
690 _("invalid value for %%define Boolean variable %s"),
691 quote (variable));
693 free (value);
695 else
696 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
697 "muscle_percent_define_flag", quote (variable));
699 return res;
702 void
703 muscle_percent_define_default (char const *variable, char const *value)
705 uniqstr name = muscle_name (variable, NULL);
706 if (!muscle_find_const (name))
708 MUSCLE_INSERT_STRING (name, value);
709 MUSCLE_INSERT_STRING (muscle_name (variable, "kind"), "keyword");
711 uniqstr loc_name = muscle_name (variable, "loc");
712 location loc;
713 loc.start.file = "<default value>";
714 loc.start.line = -1;
715 loc.start.column = -1;
716 loc.start.byte = -1;
717 loc.end = loc.start;
718 muscle_insert (loc_name, "");
719 muscle_location_grow (loc_name, loc);
721 muscle_insert (muscle_name (variable, "syncline"), "");
725 void
726 muscle_percent_define_check_values (char const * const *values)
728 for (; *values; ++values)
730 char const * const *variablep = values;
731 uniqstr name = muscle_name (*variablep, NULL);
732 char *value = string_decode (name);
733 muscle_percent_define_check_kind (*variablep, muscle_keyword);
734 if (value)
736 for (++values; *values; ++values)
737 if (STREQ (value, *values))
738 break;
739 if (!*values)
741 location loc = muscle_percent_define_get_loc (*variablep);
742 int i = 0;
743 complain_indent (&loc, complaint, &i,
744 _("invalid value for %%define variable %s: %s"),
745 quote (*variablep), quote_n (1, value));
746 i += SUB_INDENT;
747 for (values = variablep + 1; *values; ++values)
748 complain_indent (&loc, complaint | no_caret | silent, &i,
749 _("accepted value: %s"), quote (*values));
751 else
752 while (*values)
753 ++values;
754 free (value);
756 else
757 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
758 "muscle_percent_define_check_values", quote (*variablep));
762 void
763 muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
764 char const *code, location code_loc)
766 char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
767 muscle_code_grow (name, code, code_loc);
768 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
769 qualifier_loc);
773 /*------------------------------------------------.
774 | Output the definition of ENTRY as a m4_define. |
775 `------------------------------------------------*/
777 static inline bool
778 muscle_m4_output (muscle_entry *entry, FILE *out)
780 fprintf (out,
781 "m4_define([b4_%s],\n"
782 "[[%s]])\n\n\n", entry->key, entry->value);
783 return true;
786 static bool
787 muscle_m4_output_processor (void *entry, void *out)
789 return muscle_m4_output (entry, out);
793 void
794 muscles_m4_output (FILE *out)
796 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);