123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789 |
- /* Muscle table manager for Bison.
- Copyright (C) 2001-2015, 2018-2021 Free Software Foundation, Inc.
- This file is part of Bison, the GNU Compiler Compiler.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>. */
- #include <config.h>
- #include "system.h"
- #include <hash.h>
- #include <quote.h>
- #include "complain.h"
- #include "files.h"
- #include "fixits.h"
- #include "getargs.h"
- #include "muscle-tab.h"
- muscle_kind
- muscle_kind_new (char const *k)
- {
- if (STREQ (k, "code"))
- return muscle_code;
- else if (STREQ (k, "keyword"))
- return muscle_keyword;
- else if (STREQ (k, "string"))
- return muscle_string;
- abort ();
- }
- char const *
- muscle_kind_string (muscle_kind k)
- {
- switch (k)
- {
- case muscle_code: return "code";
- case muscle_keyword: return "keyword";
- case muscle_string: return "string";
- }
- abort ();
- }
- /* A key-value pair, along with storage that can be reclaimed when
- this pair is no longer needed. */
- typedef struct
- {
- char const *key;
- char const *value;
- char *storage;
- muscle_kind kind;
- } muscle_entry;
- /* The name of muscle for the %define variable VAR (corresponding to
- FIELD, if defined). */
- static uniqstr
- muscle_name (char const *var, char const *field)
- {
- if (field)
- return UNIQSTR_CONCAT ("percent_define_", field, "(", var, ")");
- else
- return UNIQSTR_CONCAT ("percent_define(", var, ")");
- }
- /* An obstack used to create some entries. */
- struct obstack muscle_obstack;
- /* Initial capacity of muscles hash table. */
- #define HT_INITIAL_CAPACITY 257
- static struct hash_table *muscle_table = NULL;
- static bool
- hash_compare_muscles (void const *x, void const *y)
- {
- muscle_entry const *m1 = x;
- muscle_entry const *m2 = y;
- return STREQ (m1->key, m2->key);
- }
- static size_t
- hash_muscle (const void *x, size_t tablesize)
- {
- muscle_entry const *m = x;
- return hash_string (m->key, tablesize);
- }
- /* Create a fresh muscle name KEY, and insert in the hash table. */
- static void *
- muscle_entry_new (char const *key)
- {
- muscle_entry *res = xmalloc (sizeof *res);
- res->key = key;
- res->value = NULL;
- res->storage = NULL;
- hash_xinsert (muscle_table, res);
- return res;
- }
- static void
- muscle_entry_free (void *entry)
- {
- muscle_entry *mentry = entry;
- free (mentry->storage);
- free (mentry);
- }
- void
- muscle_init (void)
- {
- /* Initialize the muscle obstack. */
- obstack_init (&muscle_obstack);
- muscle_table = hash_xinitialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
- hash_compare_muscles, muscle_entry_free);
- }
- void
- muscle_free (void)
- {
- hash_free (muscle_table);
- obstack_free (&muscle_obstack, NULL);
- }
- /* Look for the muscle named KEY. Return NULL if does not exist. */
- static muscle_entry *
- muscle_lookup (char const *key)
- {
- muscle_entry probe;
- probe.key = key;
- return hash_lookup (muscle_table, &probe);
- }
- void
- muscle_insert (char const *key, char const *value)
- {
- muscle_entry *entry = muscle_lookup (key);
- if (entry)
- free (entry->storage);
- else
- /* First insertion in the hash. */
- entry = muscle_entry_new (key);
- entry->value = value;
- entry->storage = NULL;
- }
- /* Append VALUE to the current value of KEY. If KEY did not already
- exist, create it. Use MUSCLE_OBSTACK. De-allocate the previously
- associated value. Copy VALUE and SEPARATOR. If VALUE does not end
- with TERMINATOR, append one. */
- static void
- muscle_grow (const char *key, const char *val,
- const char *separator, const char *terminator)
- {
- muscle_entry *entry = muscle_lookup (key);
- if (entry)
- {
- obstack_sgrow (&muscle_obstack, entry->value);
- obstack_sgrow (&muscle_obstack, separator);
- free (entry->storage);
- }
- else
- entry = muscle_entry_new (key);
- obstack_sgrow (&muscle_obstack, val);
- size_t vals = strlen (val);
- size_t terms = strlen (terminator);
- if (terms <= vals
- && STRNEQ (val + vals - terms, terminator))
- obstack_sgrow (&muscle_obstack, terminator);
- {
- char const *new_val = obstack_finish0 (&muscle_obstack);
- entry->value = entry->storage = xstrdup (new_val);
- obstack_free (&muscle_obstack, new_val);
- }
- }
- /*------------------------------------------------------------------.
- | Using muscle_grow, append a synchronization line for the location |
- | LOC to the current value of KEY. |
- `------------------------------------------------------------------*/
- static void
- muscle_syncline_grow (char const *key, location loc)
- {
- obstack_printf (&muscle_obstack, "]b4_syncline(%d, ", loc.start.line);
- obstack_quote (&muscle_obstack,
- quotearg_style (c_quoting_style, loc.start.file));
- obstack_sgrow (&muscle_obstack, ")dnl\n[");
- char const *extension = obstack_finish0 (&muscle_obstack);
- muscle_grow (key, extension, "", "");
- obstack_free (&muscle_obstack, extension);
- }
- /*------------------------------------------------------------------.
- | Append VALUE to the current value of KEY, using muscle_grow. But |
- | in addition, issue a synchronization line for the location LOC |
- | using muscle_syncline_grow. |
- `------------------------------------------------------------------*/
- void
- muscle_code_grow (const char *key, const char *val, location loc)
- {
- muscle_syncline_grow (key, loc);
- muscle_grow (key, val, "", "\n");
- }
- void
- muscle_pair_list_grow (const char *muscle,
- const char *a1, const char *a2)
- {
- obstack_sgrow (&muscle_obstack, "[");
- obstack_quote (&muscle_obstack, a1);
- obstack_sgrow (&muscle_obstack, ", ");
- obstack_quote (&muscle_obstack, a2);
- obstack_sgrow (&muscle_obstack, "]");
- char const *pair = obstack_finish0 (&muscle_obstack);
- muscle_grow (muscle, pair, ",\n", "");
- obstack_free (&muscle_obstack, pair);
- }
- char const *
- muscle_find_const (char const *key)
- {
- muscle_entry *entry = muscle_lookup (key);
- return entry ? entry->value : NULL;
- }
- char *
- muscle_find (char const *key)
- {
- muscle_entry *entry = muscle_lookup (key);
- if (entry)
- {
- aver (entry->value == entry->storage);
- return entry->storage;
- }
- return NULL;
- }
- /* In the format 'file_name:line.column', append BOUND to MUSCLE. Use
- digraphs for special characters in the file name. */
- static void
- muscle_boundary_grow (char const *key, boundary bound)
- {
- obstack_sgrow (&muscle_obstack, "[[");
- obstack_escape (&muscle_obstack, bound.file);
- obstack_printf (&muscle_obstack, ":%d.%d@@%d]]", bound.line, bound.column, bound.byte);
- char const *extension = obstack_finish0 (&muscle_obstack);
- muscle_grow (key, extension, "", "");
- obstack_free (&muscle_obstack, extension);
- }
- void
- muscle_location_grow (char const *key, location loc)
- {
- muscle_boundary_grow (key, loc.start);
- muscle_grow (key, "", ", ", "");
- muscle_boundary_grow (key, loc.end);
- }
- #define COMMON_DECODE(Value) \
- case '$': \
- ++(Value); aver (*(Value) == ']'); \
- ++(Value); aver (*(Value) == '['); \
- obstack_sgrow (&muscle_obstack, "$"); \
- break; \
- case '@': \
- switch (*++(Value)) \
- { \
- case '@': obstack_sgrow (&muscle_obstack, "@" ); break; \
- case '{': obstack_sgrow (&muscle_obstack, "[" ); break; \
- case '}': obstack_sgrow (&muscle_obstack, "]" ); break; \
- default: aver (false); break; \
- } \
- break; \
- default: \
- obstack_1grow (&muscle_obstack, *(Value)); \
- break;
- /* Reverse of obstack_escape. */
- static char *
- string_decode (char const *key)
- {
- char const *value = muscle_find_const (key);
- if (!value)
- return NULL;
- do {
- switch (*value)
- {
- COMMON_DECODE (value)
- case '[':
- case ']':
- aver (false);
- break;
- }
- } while (*value++);
- char const *value_decoded = obstack_finish (&muscle_obstack);
- char *res = xstrdup (value_decoded);
- obstack_free (&muscle_obstack, value_decoded);
- return res;
- }
- /* Reverse of muscle_location_grow. */
- static location
- location_decode (char const *value)
- {
- aver (value);
- aver (*value == '[');
- ++value; aver (*value == '[');
- location loc;
- while (*++value)
- switch (*value)
- {
- COMMON_DECODE (value)
- case '[':
- aver (false);
- break;
- case ']':
- ++value; aver (*value == ']');
- char *boundary_str = obstack_finish0 (&muscle_obstack);
- switch (*++value)
- {
- case ',':
- boundary_set_from_string (&loc.start, boundary_str);
- obstack_free (&muscle_obstack, boundary_str);
- ++value; aver (*value == ' ');
- ++value; aver (*value == '[');
- ++value; aver (*value == '[');
- break;
- case '\0':
- boundary_set_from_string (&loc.end, boundary_str);
- obstack_free (&muscle_obstack, boundary_str);
- return loc;
- break;
- default:
- aver (false);
- break;
- }
- break;
- }
- aver (false);
- return loc;
- }
- void
- muscle_user_name_list_grow (char const *key, char const *user_name,
- location loc)
- {
- muscle_grow (key, "[[[[", ",", "");
- muscle_grow (key, user_name, "", "");
- muscle_grow (key, "]], ", "", "");
- muscle_location_grow (key, loc);
- muscle_grow (key, "]]", "", "");
- }
- /** Return an allocated string that represents the %define directive
- that performs the assignment.
- @param assignment "VAR", or "VAR=VAL".
- @param value default value if VAL \a assignment has no '='.
- For instance:
- "foo", NULL => "%define foo"
- "foo", "baz" => "%define foo baz"
- "foo=bar", NULL => "%define foo bar"
- "foo=bar", "baz" => "%define foo bar"
- "foo=", NULL => "%define foo"
- "foo=", "baz" => "%define foo"
- */
- static
- char *
- define_directive (char const *assignment,
- muscle_kind kind,
- char const *value)
- {
- char *eq = strchr (assignment, '=');
- char const *fmt
- = eq || !value || !*value ? "%%define %s"
- : kind == muscle_code ? "%%define %s {%s}"
- : kind == muscle_string ? "%%define %s \"%s\""
- : "%%define %s %s";
- char *res = xmalloc (strlen (fmt) + strlen (assignment)
- + (value ? strlen (value) : 0));
- sprintf (res, fmt, assignment, value);
- eq = strchr (res, '=');
- if (eq)
- *eq = eq[1] ? ' ' : '\0';
- return res;
- }
- /** If the \a variable name is obsolete, return the name to use,
- * otherwise \a variable. If the \a value is obsolete, update it too.
- *
- * Allocates the returned value if needed, otherwise the returned
- * value is exactly \a variable. */
- static
- char const *
- muscle_percent_variable_update (char const *variable,
- muscle_kind kind,
- char const **value,
- char **old, char **upd)
- {
- typedef struct
- {
- const char *obsolete;
- const char *updated;
- muscle_kind kind;
- } conversion_type;
- const conversion_type conversion[] =
- {
- { "%error-verbose", "parse.error=verbose", muscle_keyword },
- { "%error_verbose", "parse.error=verbose", muscle_keyword },
- { "abstract", "api.parser.abstract", muscle_keyword },
- { "annotations", "api.parser.annotations", muscle_code },
- { "api.push_pull", "api.push-pull", muscle_keyword },
- { "api.tokens.prefix", "api.token.prefix", muscle_code },
- { "extends", "api.parser.extends", muscle_keyword },
- { "filename_type", "api.filename.type", muscle_code },
- { "final", "api.parser.final", muscle_keyword },
- { "implements", "api.parser.implements", muscle_keyword },
- { "lex_symbol", "api.token.constructor", -1 },
- { "location_type", "api.location.type", muscle_code },
- { "lr.default-reductions", "lr.default-reduction", muscle_keyword },
- { "lr.keep-unreachable-states", "lr.keep-unreachable-state", muscle_keyword },
- { "lr.keep_unreachable_states", "lr.keep-unreachable-state", muscle_keyword },
- { "namespace", "api.namespace", muscle_code },
- { "package", "api.package", muscle_code },
- { "parser_class_name", "api.parser.class", muscle_code },
- { "public", "api.parser.public", muscle_keyword },
- { "strictfp", "api.parser.strictfp", muscle_keyword },
- { "stype", "api.value.type", -1 },
- { "variant=", "api.value.type=variant", -1 },
- { "variant=true", "api.value.type=variant", -1 },
- { NULL, NULL, -1, }
- };
- for (conversion_type const *c = conversion; c->obsolete; ++c)
- {
- char const *eq = strchr (c->obsolete, '=');
- if (eq
- ? (!strncmp (c->obsolete, variable, eq - c->obsolete)
- && STREQ (eq + 1, *value))
- : STREQ (c->obsolete, variable))
- {
- /* Generate the deprecation warning. */
- *old = c->obsolete[0] == '%'
- ? xstrdup (c->obsolete)
- : define_directive (c->obsolete, kind, *value);
- *upd = define_directive (c->updated, c->kind, *value);
- /* Update the variable and its value. */
- {
- char *res = xstrdup (c->updated);
- char *eq2 = strchr (res, '=');
- if (eq2)
- {
- *eq2 = '\0';
- *value = eq2 + 1;
- }
- return res;
- }
- }
- }
- return variable;
- }
- void
- muscle_percent_define_insert (char const *var, location variable_loc,
- muscle_kind kind,
- char const *value,
- muscle_percent_define_how how)
- {
- /* Backward compatibility. */
- char *old = NULL;
- char *upd = NULL;
- char const *variable
- = muscle_percent_variable_update (var, kind,
- &value, &old, &upd);
- uniqstr name = muscle_name (variable, NULL);
- uniqstr loc_name = muscle_name (variable, "loc");
- uniqstr syncline_name = muscle_name (variable, "syncline");
- uniqstr how_name = muscle_name (variable, "how");
- uniqstr kind_name = muscle_name (variable, "kind");
- /* Command-line options are processed before the grammar file. */
- bool warned = false;
- if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE)
- {
- char const *current_value = muscle_find_const (name);
- if (current_value)
- {
- muscle_percent_define_how how_old
- = atoi (muscle_find_const (how_name));
- if (how_old == MUSCLE_PERCENT_DEFINE_F)
- goto end;
- /* If assigning the same value, make it a warning. */
- warnings warn = STREQ (value, current_value) ? Wother : complaint;
- complain (&variable_loc, warn,
- _("%%define variable %s redefined"),
- quote (variable));
- location loc = muscle_percent_define_get_loc (variable);
- subcomplain (&loc, warn, _("previous definition"));
- fixits_register (&variable_loc, "");
- warned = true;
- }
- }
- if (!warned && old && upd)
- deprecated_directive (&variable_loc, old, upd);
- MUSCLE_INSERT_STRING (name, value);
- muscle_insert (loc_name, "");
- muscle_location_grow (loc_name, variable_loc);
- muscle_insert (syncline_name, "");
- muscle_syncline_grow (syncline_name, variable_loc);
- muscle_user_name_list_grow ("percent_define_user_variables", variable,
- variable_loc);
- MUSCLE_INSERT_INT (how_name, how);
- MUSCLE_INSERT_STRING (kind_name, muscle_kind_string (kind));
- end:
- free (old);
- free (upd);
- if (variable != var)
- free ((char *) variable);
- }
- /* This is used for backward compatibility, e.g., "%define api.pure"
- supersedes "%pure-parser". */
- void
- muscle_percent_define_ensure (char const *variable, location loc,
- bool value)
- {
- uniqstr name = muscle_name (variable, NULL);
- char const *val = value ? "" : "false";
- /* Don't complain is VARIABLE is already defined, but be sure to set
- its value to VAL. */
- if (!muscle_find_const (name)
- || muscle_percent_define_flag_if (variable) != value)
- muscle_percent_define_insert (variable, loc, muscle_keyword, val,
- MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
- }
- /* Mark %define VARIABLE as used. */
- static void
- muscle_percent_define_use (char const *variable)
- {
- muscle_insert (muscle_name (variable, "bison_variables"), "");
- }
- /* The value of %define variable VARIABLE (corresponding to FIELD, if
- defined). Do not register as used, but diagnose unset variables. */
- static
- char const *
- muscle_percent_define_get_raw (char const *variable, char const *field)
- {
- uniqstr name = muscle_name (variable, field);
- char const *res = muscle_find_const (name);
- if (!res)
- complain (NULL, fatal, _("%s: undefined %%define variable %s"),
- "muscle_percent_define_get_raw", quote (variable));
- return res;
- }
- char *
- muscle_percent_define_get (char const *variable)
- {
- uniqstr name = muscle_name (variable, NULL);
- char *value = string_decode (name);
- if (!value)
- value = xstrdup ("");
- muscle_percent_define_use (variable);
- return value;
- }
- /* The kind of VARIABLE. An error if undefined. */
- static muscle_kind
- muscle_percent_define_get_kind (char const *variable)
- {
- return muscle_kind_new (muscle_percent_define_get_raw (variable, "kind"));
- }
- /* Check the kind of VARIABLE. An error if undefined. */
- static void
- muscle_percent_define_check_kind (char const *variable, muscle_kind kind)
- {
- if (muscle_percent_define_get_kind (variable) != kind)
- {
- location loc = muscle_percent_define_get_loc (variable);
- switch (kind)
- {
- case muscle_code:
- complain (&loc, Wdeprecated,
- _("%%define variable '%s' requires '{...}' values"),
- variable);
- break;
- case muscle_keyword:
- complain (&loc, Wdeprecated,
- _("%%define variable '%s' requires keyword values"),
- variable);
- break;
- case muscle_string:
- complain (&loc, Wdeprecated,
- _("%%define variable '%s' requires '\"...\"' values"),
- variable);
- break;
- }
- }
- }
- location
- muscle_percent_define_get_loc (char const *variable)
- {
- return location_decode (muscle_percent_define_get_raw (variable, "loc"));
- }
- char const *
- muscle_percent_define_get_syncline (char const *variable)
- {
- return muscle_percent_define_get_raw (variable, "syncline");
- }
- bool
- muscle_percent_define_ifdef (char const *variable)
- {
- if (muscle_find_const (muscle_name (variable, NULL)))
- {
- muscle_percent_define_use (variable);
- return true;
- }
- else
- return false;
- }
- bool
- muscle_percent_define_flag_if (char const *variable)
- {
- uniqstr invalid_boolean_name = muscle_name (variable, "invalid_boolean");
- bool res = false;
- if (muscle_percent_define_ifdef (variable))
- {
- char *value = muscle_percent_define_get (variable);
- muscle_percent_define_check_kind (variable, muscle_keyword);
- if (value[0] == '\0' || STREQ (value, "true"))
- res = true;
- else if (STREQ (value, "false"))
- res = false;
- else if (!muscle_find_const (invalid_boolean_name))
- {
- muscle_insert (invalid_boolean_name, "");
- location loc = muscle_percent_define_get_loc (variable);
- complain (&loc, complaint,
- _("invalid value for %%define Boolean variable %s"),
- quote (variable));
- }
- free (value);
- }
- else
- complain (NULL, fatal, _("%s: undefined %%define variable %s"),
- "muscle_percent_define_flag", quote (variable));
- return res;
- }
- void
- muscle_percent_define_default (char const *variable, char const *value)
- {
- uniqstr name = muscle_name (variable, NULL);
- if (!muscle_find_const (name))
- {
- MUSCLE_INSERT_STRING (name, value);
- MUSCLE_INSERT_STRING (muscle_name (variable, "kind"), "keyword");
- {
- uniqstr loc_name = muscle_name (variable, "loc");
- location loc;
- loc.start.file = "<default value>";
- loc.start.line = -1;
- loc.start.column = -1;
- loc.start.byte = -1;
- loc.end = loc.start;
- muscle_insert (loc_name, "");
- muscle_location_grow (loc_name, loc);
- }
- muscle_insert (muscle_name (variable, "syncline"), "");
- }
- }
- void
- muscle_percent_define_check_values (char const * const *values)
- {
- for (; *values; ++values)
- {
- char const * const *variablep = values;
- uniqstr name = muscle_name (*variablep, NULL);
- char *value = string_decode (name);
- muscle_percent_define_check_kind (*variablep, muscle_keyword);
- if (value)
- {
- for (++values; *values; ++values)
- if (STREQ (value, *values))
- break;
- if (!*values)
- {
- location loc = muscle_percent_define_get_loc (*variablep);
- complain (&loc, complaint,
- _("invalid value for %%define variable %s: %s"),
- quote (*variablep), quote_n (1, value));
- for (values = variablep + 1; *values; ++values)
- subcomplain (&loc, complaint | no_caret | silent,
- _("accepted value: %s"), quote (*values));
- }
- else
- while (*values)
- ++values;
- free (value);
- }
- else
- complain (NULL, fatal, _("%s: undefined %%define variable %s"),
- "muscle_percent_define_check_values", quote (*variablep));
- }
- }
- void
- muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
- char const *code, location code_loc)
- {
- char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
- muscle_code_grow (name, code, code_loc);
- muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
- qualifier_loc);
- }
- /*------------------------------------------------.
- | Output the definition of ENTRY as a m4_define. |
- `------------------------------------------------*/
- static inline bool
- muscle_m4_output (muscle_entry *entry, FILE *out)
- {
- fprintf (out,
- "m4_define([b4_%s],\n"
- "[[%s]])\n\n\n", entry->key, entry->value);
- return true;
- }
- static bool
- muscle_m4_output_processor (void *entry, void *out)
- {
- return muscle_m4_output (entry, out);
- }
- void
- muscles_m4_output (FILE *out)
- {
- hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
- }
|