doc: fix spello
[bison.git] / src / muscle-tab.c
blob0654a3f103dbb6409e23bf20c457b01a8c9fd790
1 /* Muscle table manager for Bison.
3 Copyright (C) 2001-2015, 2018-2021 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 <https://www.gnu.org/licenses/>. */
20 #include <config.h>
21 #include "system.h"
23 #include <hash.h>
24 #include <quote.h>
26 #include "complain.h"
27 #include "files.h"
28 #include "fixits.h"
29 #include "getargs.h"
30 #include "muscle-tab.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 hash_xinsert (muscle_table, res);
111 return res;
114 static void
115 muscle_entry_free (void *entry)
117 muscle_entry *mentry = entry;
118 free (mentry->storage);
119 free (mentry);
122 void
123 muscle_init (void)
125 /* Initialize the muscle obstack. */
126 obstack_init (&muscle_obstack);
128 muscle_table = hash_xinitialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
129 hash_compare_muscles, muscle_entry_free);
133 void
134 muscle_free (void)
136 hash_free (muscle_table);
137 obstack_free (&muscle_obstack, NULL);
140 /* Look for the muscle named KEY. Return NULL if does not exist. */
141 static muscle_entry *
142 muscle_lookup (char const *key)
144 muscle_entry probe;
145 probe.key = key;
146 return hash_lookup (muscle_table, &probe);
150 void
151 muscle_insert (char const *key, char const *value)
153 muscle_entry *entry = muscle_lookup (key);
154 if (entry)
155 free (entry->storage);
156 else
157 /* First insertion in the hash. */
158 entry = muscle_entry_new (key);
159 entry->value = value;
160 entry->storage = NULL;
164 /* Append VALUE to the current value of KEY. If KEY did not already
165 exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously
166 associated value. Copy VALUE and SEPARATOR. If VALUE does not end
167 with TERMINATOR, append one. */
169 static void
170 muscle_grow (const char *key, const char *val,
171 const char *separator, const char *terminator)
173 muscle_entry *entry = muscle_lookup (key);
174 if (entry)
176 obstack_sgrow (&muscle_obstack, entry->value);
177 obstack_sgrow (&muscle_obstack, separator);
178 free (entry->storage);
180 else
181 entry = muscle_entry_new (key);
183 obstack_sgrow (&muscle_obstack, val);
185 size_t vals = strlen (val);
186 size_t terms = strlen (terminator);
187 if (terms <= vals
188 && STRNEQ (val + vals - terms, terminator))
189 obstack_sgrow (&muscle_obstack, terminator);
192 char const *new_val = obstack_finish0 (&muscle_obstack);
193 entry->value = entry->storage = xstrdup (new_val);
194 obstack_free (&muscle_obstack, new_val);
198 /*------------------------------------------------------------------.
199 | Using muscle_grow, append a synchronization line for the location |
200 | LOC to the current value of KEY. |
201 `------------------------------------------------------------------*/
203 static void
204 muscle_syncline_grow (char const *key, location loc)
206 obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
207 obstack_quote (&muscle_obstack,
208 quotearg_style (c_quoting_style, map_file_name (loc.start.file)));
209 obstack_sgrow (&muscle_obstack, ")dnl\n[");
210 char const *extension = obstack_finish0 (&muscle_obstack);
211 muscle_grow (key, extension, "", "");
212 obstack_free (&muscle_obstack, extension);
215 /*------------------------------------------------------------------.
216 | Append VALUE to the current value of KEY, using muscle_grow. But |
217 | in addition, issue a synchronization line for the location LOC |
218 | using muscle_syncline_grow. |
219 `------------------------------------------------------------------*/
221 void
222 muscle_code_grow (const char *key, const char *val, location loc)
224 muscle_syncline_grow (key, loc);
225 muscle_grow (key, val, "", "\n");
229 void
230 muscle_pair_list_grow (const char *muscle,
231 const char *a1, const char *a2)
233 obstack_sgrow (&muscle_obstack, "[");
234 obstack_quote (&muscle_obstack, a1);
235 obstack_sgrow (&muscle_obstack, ", ");
236 obstack_quote (&muscle_obstack, a2);
237 obstack_sgrow (&muscle_obstack, "]");
238 char const *pair = obstack_finish0 (&muscle_obstack);
239 muscle_grow (muscle, pair, ",\n", "");
240 obstack_free (&muscle_obstack, pair);
244 char const *
245 muscle_find_const (char const *key)
247 muscle_entry *entry = muscle_lookup (key);
248 return entry ? entry->value : NULL;
252 char *
253 muscle_find (char const *key)
255 muscle_entry *entry = muscle_lookup (key);
256 if (entry)
258 aver (entry->value == entry->storage);
259 return entry->storage;
261 return NULL;
265 /* In the format 'file_name:line.column', append BOUND to MUSCLE. Use
266 digraphs for special characters in the file name. */
268 static void
269 muscle_boundary_grow (char const *key, boundary bound)
271 obstack_sgrow (&muscle_obstack, "[[");
272 obstack_escape (&muscle_obstack, bound.file);
273 obstack_printf (&muscle_obstack, ":%d.%d@@%d]]", bound.line, bound.column, bound.byte);
274 char const *extension = obstack_finish0 (&muscle_obstack);
275 muscle_grow (key, extension, "", "");
276 obstack_free (&muscle_obstack, extension);
280 void
281 muscle_location_grow (char const *key, location loc)
283 muscle_boundary_grow (key, loc.start);
284 muscle_grow (key, "", ", ", "");
285 muscle_boundary_grow (key, loc.end);
288 #define COMMON_DECODE(Value) \
289 case '$': \
290 ++(Value); aver (*(Value) == ']'); \
291 ++(Value); aver (*(Value) == '['); \
292 obstack_sgrow (&muscle_obstack, "$"); \
293 break; \
294 case '@': \
295 switch (*++(Value)) \
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; \
302 break; \
303 default: \
304 obstack_1grow (&muscle_obstack, *(Value)); \
305 break;
307 /* Reverse of obstack_escape. */
308 static char *
309 string_decode (char const *key)
311 char const *value = muscle_find_const (key);
312 if (!value)
313 return NULL;
314 do {
315 switch (*value)
317 COMMON_DECODE (value)
318 case '[':
319 case ']':
320 aver (false);
321 break;
323 } while (*value++);
324 char const *value_decoded = obstack_finish (&muscle_obstack);
325 char *res = xstrdup (value_decoded);
326 obstack_free (&muscle_obstack, value_decoded);
327 return res;
330 /* Reverse of muscle_location_grow. */
331 static location
332 location_decode (char const *value)
334 aver (value);
335 aver (*value == '[');
336 ++value; aver (*value == '[');
337 location loc;
338 while (*++value)
339 switch (*value)
341 COMMON_DECODE (value)
342 case '[':
343 aver (false);
344 break;
345 case ']':
346 ++value; aver (*value == ']');
347 char *boundary_str = obstack_finish0 (&muscle_obstack);
348 switch (*++value)
350 case ',':
351 boundary_set_from_string (&loc.start, boundary_str);
352 obstack_free (&muscle_obstack, boundary_str);
353 ++value; aver (*value == ' ');
354 ++value; aver (*value == '[');
355 ++value; 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;
366 break;
368 aver (false);
369 return loc;
372 void
373 muscle_user_name_list_grow (char const *key, char const *user_name,
374 location loc)
376 muscle_grow (key, "[[[[", ",", "");
377 muscle_grow (key, user_name, "", "");
378 muscle_grow (key, "]], ", "", "");
379 muscle_location_grow (key, loc);
380 muscle_grow (key, "]]", "", "");
384 /** Return an allocated string that represents the %define directive
385 that performs the assignment.
387 @param assignment "VAR", or "VAR=VAL".
388 @param value default value if VAL \a assignment has no '='.
390 For instance:
391 "foo", NULL => "%define foo"
392 "foo", "baz" => "%define foo baz"
393 "foo=bar", NULL => "%define foo bar"
394 "foo=bar", "baz" => "%define foo bar"
395 "foo=", NULL => "%define foo"
396 "foo=", "baz" => "%define foo"
399 static
400 char *
401 define_directive (char const *assignment,
402 muscle_kind kind,
403 char const *value)
405 char *eq = strchr (assignment, '=');
406 char const *fmt
407 = eq || !value || !*value ? "%%define %s"
408 : kind == muscle_code ? "%%define %s {%s}"
409 : kind == muscle_string ? "%%define %s \"%s\""
410 : "%%define %s %s";
411 char *res = xmalloc (strlen (fmt) + strlen (assignment)
412 + (value ? strlen (value) : 0));
413 sprintf (res, fmt, assignment, value);
414 eq = strchr (res, '=');
415 if (eq)
416 *eq = eq[1] ? ' ' : '\0';
417 return res;
420 /** If the \a variable name is obsolete, return the name to use,
421 * otherwise \a variable. If the \a value is obsolete, update it too.
423 * Allocates the returned value if needed, otherwise the returned
424 * value is exactly \a variable. */
425 static
426 char const *
427 muscle_percent_variable_update (char const *variable,
428 muscle_kind kind,
429 char const **value,
430 char **old, char **upd)
432 typedef struct
434 const char *obsolete;
435 const char *updated;
436 muscle_kind kind;
437 } conversion_type;
438 const conversion_type conversion[] =
440 { "%error-verbose", "parse.error=verbose", muscle_keyword },
441 { "%error_verbose", "parse.error=verbose", muscle_keyword },
442 { "abstract", "api.parser.abstract", muscle_keyword },
443 { "annotations", "api.parser.annotations", muscle_code },
444 { "api.push_pull", "api.push-pull", muscle_keyword },
445 { "api.tokens.prefix", "api.token.prefix", muscle_code },
446 { "extends", "api.parser.extends", muscle_keyword },
447 { "filename_type", "api.filename.type", muscle_code },
448 { "final", "api.parser.final", muscle_keyword },
449 { "implements", "api.parser.implements", muscle_keyword },
450 { "lex_symbol", "api.token.constructor", -1 },
451 { "location_type", "api.location.type", muscle_code },
452 { "lr.default-reductions", "lr.default-reduction", muscle_keyword },
453 { "lr.keep-unreachable-states", "lr.keep-unreachable-state", muscle_keyword },
454 { "lr.keep_unreachable_states", "lr.keep-unreachable-state", muscle_keyword },
455 { "namespace", "api.namespace", muscle_code },
456 { "package", "api.package", muscle_code },
457 { "parser_class_name", "api.parser.class", muscle_code },
458 { "public", "api.parser.public", muscle_keyword },
459 { "strictfp", "api.parser.strictfp", muscle_keyword },
460 { "stype", "api.value.type", -1 },
461 { "variant=", "api.value.type=variant", -1 },
462 { "variant=true", "api.value.type=variant", -1 },
463 { NULL, NULL, -1, }
466 for (conversion_type const *c = conversion; c->obsolete; ++c)
468 char const *eq = strchr (c->obsolete, '=');
469 if (eq
470 ? (!strncmp (c->obsolete, variable, eq - c->obsolete)
471 && STREQ (eq + 1, *value))
472 : STREQ (c->obsolete, variable))
474 /* Generate the deprecation warning. */
475 *old = c->obsolete[0] == '%'
476 ? xstrdup (c->obsolete)
477 : define_directive (c->obsolete, kind, *value);
478 *upd = define_directive (c->updated, c->kind, *value);
479 /* Update the variable and its value. */
481 char *res = xstrdup (c->updated);
482 char *eq2 = strchr (res, '=');
483 if (eq2)
485 *eq2 = '\0';
486 *value = eq2 + 1;
488 return res;
492 return variable;
495 void
496 muscle_percent_define_insert (char const *var, location variable_loc,
497 muscle_kind kind,
498 char const *value,
499 muscle_percent_define_how how)
501 /* Backward compatibility. */
502 char *old = NULL;
503 char *upd = NULL;
504 char const *variable
505 = muscle_percent_variable_update (var, kind,
506 &value, &old, &upd);
507 uniqstr name = muscle_name (variable, NULL);
508 uniqstr loc_name = muscle_name (variable, "loc");
509 uniqstr syncline_name = muscle_name (variable, "syncline");
510 uniqstr how_name = muscle_name (variable, "how");
511 uniqstr kind_name = muscle_name (variable, "kind");
513 /* Command-line options are processed before the grammar file. */
514 bool warned = false;
515 if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE)
517 char const *current_value = muscle_find_const (name);
518 if (current_value)
520 muscle_percent_define_how how_old
521 = atoi (muscle_find_const (how_name));
522 if (how_old == MUSCLE_PERCENT_DEFINE_F)
523 goto end;
524 /* If assigning the same value, make it a warning. */
525 warnings warn = STREQ (value, current_value) ? Wother : complaint;
526 complain (&variable_loc, warn,
527 _("%%define variable %s redefined"),
528 quote (variable));
529 location loc = muscle_percent_define_get_loc (variable);
530 subcomplain (&loc, warn, _("previous definition"));
531 fixits_register (&variable_loc, "");
532 warned = true;
536 if (!warned && old && upd)
537 deprecated_directive (&variable_loc, old, upd);
539 MUSCLE_INSERT_STRING (name, value);
540 muscle_insert (loc_name, "");
541 muscle_location_grow (loc_name, variable_loc);
542 muscle_insert (syncline_name, "");
543 muscle_syncline_grow (syncline_name, variable_loc);
544 muscle_user_name_list_grow ("percent_define_user_variables", variable,
545 variable_loc);
546 MUSCLE_INSERT_INT (how_name, how);
547 MUSCLE_INSERT_STRING (kind_name, muscle_kind_string (kind));
548 end:
549 free (old);
550 free (upd);
551 if (variable != var)
552 free ((char *) variable);
555 /* This is used for backward compatibility, e.g., "%define api.pure"
556 supersedes "%pure-parser". */
557 void
558 muscle_percent_define_ensure (char const *variable, location loc,
559 bool value)
561 uniqstr name = muscle_name (variable, NULL);
562 char const *val = value ? "" : "false";
564 /* Don't complain is VARIABLE is already defined, but be sure to set
565 its value to VAL. */
566 if (!muscle_find_const (name)
567 || muscle_percent_define_flag_if (variable) != value)
568 muscle_percent_define_insert (variable, loc, muscle_keyword, val,
569 MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
572 /* Mark %define VARIABLE as used. */
573 static void
574 muscle_percent_define_use (char const *variable)
576 muscle_insert (muscle_name (variable, "bison_variables"), "");
579 /* The value of %define variable VARIABLE (corresponding to FIELD, if
580 defined). Do not register as used, but diagnose unset variables. */
582 static
583 char const *
584 muscle_percent_define_get_raw (char const *variable, char const *field)
586 uniqstr name = muscle_name (variable, field);
587 char const *res = muscle_find_const (name);
588 if (!res)
589 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
590 "muscle_percent_define_get_raw", quote (variable));
591 return res;
594 char *
595 muscle_percent_define_get (char const *variable)
597 uniqstr name = muscle_name (variable, NULL);
598 char *value = string_decode (name);
599 if (!value)
600 value = xstrdup ("");
601 muscle_percent_define_use (variable);
602 return value;
605 /* The kind of VARIABLE. An error if undefined. */
606 static muscle_kind
607 muscle_percent_define_get_kind (char const *variable)
609 return muscle_kind_new (muscle_percent_define_get_raw (variable, "kind"));
612 /* Check the kind of VARIABLE. An error if undefined. */
613 static void
614 muscle_percent_define_check_kind (char const *variable, muscle_kind kind)
616 if (muscle_percent_define_get_kind (variable) != kind)
618 location loc = muscle_percent_define_get_loc (variable);
619 switch (kind)
621 case muscle_code:
622 complain (&loc, Wdeprecated,
623 _("%%define variable '%s' requires '{...}' values"),
624 variable);
625 break;
626 case muscle_keyword:
627 complain (&loc, Wdeprecated,
628 _("%%define variable '%s' requires keyword values"),
629 variable);
630 break;
631 case muscle_string:
632 complain (&loc, Wdeprecated,
633 _("%%define variable '%s' requires '\"...\"' values"),
634 variable);
635 break;
641 location
642 muscle_percent_define_get_loc (char const *variable)
644 return location_decode (muscle_percent_define_get_raw (variable, "loc"));
647 char const *
648 muscle_percent_define_get_syncline (char const *variable)
650 return muscle_percent_define_get_raw (variable, "syncline");
653 bool
654 muscle_percent_define_ifdef (char const *variable)
656 if (muscle_find_const (muscle_name (variable, NULL)))
658 muscle_percent_define_use (variable);
659 return true;
661 else
662 return false;
665 bool
666 muscle_percent_define_flag_if (char const *variable)
668 uniqstr invalid_boolean_name = muscle_name (variable, "invalid_boolean");
669 bool res = false;
671 if (muscle_percent_define_ifdef (variable))
673 char *value = muscle_percent_define_get (variable);
674 muscle_percent_define_check_kind (variable, muscle_keyword);
675 if (value[0] == '\0' || STREQ (value, "true"))
676 res = true;
677 else if (STREQ (value, "false"))
678 res = false;
679 else if (!muscle_find_const (invalid_boolean_name))
681 muscle_insert (invalid_boolean_name, "");
682 location loc = muscle_percent_define_get_loc (variable);
683 complain (&loc, complaint,
684 _("invalid value for %%define Boolean variable %s"),
685 quote (variable));
687 free (value);
689 else
690 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
691 "muscle_percent_define_flag", quote (variable));
693 return res;
696 void
697 muscle_percent_define_default (char const *variable, char const *value)
699 uniqstr name = muscle_name (variable, NULL);
700 if (!muscle_find_const (name))
702 MUSCLE_INSERT_STRING (name, value);
703 MUSCLE_INSERT_STRING (muscle_name (variable, "kind"), "keyword");
705 uniqstr loc_name = muscle_name (variable, "loc");
706 location loc;
707 loc.start.file = "<default value>";
708 loc.start.line = -1;
709 loc.start.column = -1;
710 loc.start.byte = -1;
711 loc.end = loc.start;
712 muscle_insert (loc_name, "");
713 muscle_location_grow (loc_name, loc);
715 muscle_insert (muscle_name (variable, "syncline"), "");
719 void
720 muscle_percent_define_check_values (char const * const *values)
722 for (; *values; ++values)
724 char const * const *variablep = values;
725 uniqstr name = muscle_name (*variablep, NULL);
726 char *value = string_decode (name);
727 muscle_percent_define_check_kind (*variablep, muscle_keyword);
728 if (value)
730 for (++values; *values; ++values)
731 if (STREQ (value, *values))
732 break;
733 if (!*values)
735 location loc = muscle_percent_define_get_loc (*variablep);
736 complain (&loc, complaint,
737 _("invalid value for %%define variable %s: %s"),
738 quote (*variablep), quote_n (1, value));
739 for (values = variablep + 1; *values; ++values)
740 subcomplain (&loc, complaint | no_caret | silent,
741 _("accepted value: %s"), quote (*values));
743 else
744 while (*values)
745 ++values;
746 free (value);
748 else
749 complain (NULL, fatal, _("%s: undefined %%define variable %s"),
750 "muscle_percent_define_check_values", quote (*variablep));
754 void
755 muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
756 char const *code, location code_loc)
758 char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
759 muscle_code_grow (name, code, code_loc);
760 muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
761 qualifier_loc);
765 /*------------------------------------------------.
766 | Output the definition of ENTRY as a m4_define. |
767 `------------------------------------------------*/
769 static inline bool
770 muscle_m4_output (muscle_entry *entry, FILE *out)
772 fprintf (out,
773 "m4_define([b4_%s],\n"
774 "[[%s]])\n\n\n", entry->key, entry->value);
775 return true;
778 static bool
779 muscle_m4_output_processor (void *entry, void *out)
781 return muscle_m4_output (entry, out);
785 void
786 muscles_m4_output (FILE *out)
788 hash_do_for_each (muscle_table, muscle_m4_output_processor, out);