(root)/
bison-3.8.2/
src/
muscle-tab.c
       1  /* Muscle table manager for Bison.
       2  
       3     Copyright (C) 2001-2015, 2018-2021 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 <https://www.gnu.org/licenses/>.  */
      19  
      20  #include <config.h>
      21  #include "system.h"
      22  
      23  #include <hash.h>
      24  #include <quote.h>
      25  
      26  #include "complain.h"
      27  #include "files.h"
      28  #include "fixits.h"
      29  #include "getargs.h"
      30  #include "muscle-tab.h"
      31  
      32  muscle_kind
      33  muscle_kind_new (char const *k)
      34  {
      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 ();
      42  }
      43  
      44  char const *
      45  muscle_kind_string (muscle_kind k)
      46  {
      47    switch (k)
      48      {
      49      case muscle_code:    return "code";
      50      case muscle_keyword: return "keyword";
      51      case muscle_string:  return "string";
      52      }
      53    abort ();
      54  }
      55  
      56  
      57  /* A key-value pair, along with storage that can be reclaimed when
      58     this pair is no longer needed.  */
      59  typedef struct
      60  {
      61    char const *key;
      62    char const *value;
      63    char *storage;
      64    muscle_kind kind;
      65  } muscle_entry;
      66  
      67  
      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)
      72  {
      73    if (field)
      74      return UNIQSTR_CONCAT ("percent_define_", field, "(", var, ")");
      75    else
      76      return UNIQSTR_CONCAT ("percent_define(", var, ")");
      77  }
      78  
      79  /* An obstack used to create some entries.  */
      80  struct obstack muscle_obstack;
      81  
      82  /* Initial capacity of muscles hash table.  */
      83  #define HT_INITIAL_CAPACITY 257
      84  
      85  static struct hash_table *muscle_table = NULL;
      86  
      87  static bool
      88  hash_compare_muscles (void const *x, void const *y)
      89  {
      90    muscle_entry const *m1 = x;
      91    muscle_entry const *m2 = y;
      92    return STREQ (m1->key, m2->key);
      93  }
      94  
      95  static size_t
      96  hash_muscle (const void *x, size_t tablesize)
      97  {
      98    muscle_entry const *m = x;
      99    return hash_string (m->key, tablesize);
     100  }
     101  
     102  /* Create a fresh muscle name KEY, and insert in the hash table.  */
     103  static void *
     104  muscle_entry_new (char const *key)
     105  {
     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;
     112  }
     113  
     114  static void
     115  muscle_entry_free (void *entry)
     116  {
     117    muscle_entry *mentry = entry;
     118    free (mentry->storage);
     119    free (mentry);
     120  }
     121  
     122  void
     123  muscle_init (void)
     124  {
     125    /* Initialize the muscle obstack.  */
     126    obstack_init (&muscle_obstack);
     127  
     128    muscle_table = hash_xinitialize (HT_INITIAL_CAPACITY, NULL, hash_muscle,
     129                                     hash_compare_muscles, muscle_entry_free);
     130  }
     131  
     132  
     133  void
     134  muscle_free (void)
     135  {
     136    hash_free (muscle_table);
     137    obstack_free (&muscle_obstack, NULL);
     138  }
     139  
     140  /* Look for the muscle named KEY.  Return NULL if does not exist.  */
     141  static muscle_entry *
     142  muscle_lookup (char const *key)
     143  {
     144    muscle_entry probe;
     145    probe.key = key;
     146    return hash_lookup (muscle_table, &probe);
     147  }
     148  
     149  
     150  void
     151  muscle_insert (char const *key, char const *value)
     152  {
     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;
     161  }
     162  
     163  
     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.  */
     168  
     169  static void
     170  muscle_grow (const char *key, const char *val,
     171               const char *separator, const char *terminator)
     172  {
     173    muscle_entry *entry = muscle_lookup (key);
     174    if (entry)
     175      {
     176        obstack_sgrow (&muscle_obstack, entry->value);
     177        obstack_sgrow (&muscle_obstack, separator);
     178        free (entry->storage);
     179      }
     180    else
     181      entry = muscle_entry_new (key);
     182  
     183    obstack_sgrow (&muscle_obstack, val);
     184  
     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);
     190  
     191    {
     192      char const *new_val = obstack_finish0 (&muscle_obstack);
     193      entry->value = entry->storage = xstrdup (new_val);
     194      obstack_free (&muscle_obstack, new_val);
     195    }
     196  }
     197  
     198  /*------------------------------------------------------------------.
     199  | Using muscle_grow, append a synchronization line for the location |
     200  | LOC to the current value of KEY.                                  |
     201  `------------------------------------------------------------------*/
     202  
     203  static void
     204  muscle_syncline_grow (char const *key, location loc)
     205  {
     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);
     213  }
     214  
     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  `------------------------------------------------------------------*/
     220  
     221  void
     222  muscle_code_grow (const char *key, const char *val, location loc)
     223  {
     224    muscle_syncline_grow (key, loc);
     225    muscle_grow (key, val, "", "\n");
     226  }
     227  
     228  
     229  void
     230  muscle_pair_list_grow (const char *muscle,
     231                         const char *a1, const char *a2)
     232  {
     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);
     241  }
     242  
     243  
     244  char const *
     245  muscle_find_const (char const *key)
     246  {
     247    muscle_entry *entry = muscle_lookup (key);
     248    return entry ? entry->value : NULL;
     249  }
     250  
     251  
     252  char *
     253  muscle_find (char const *key)
     254  {
     255    muscle_entry *entry = muscle_lookup (key);
     256    if (entry)
     257      {
     258        aver (entry->value == entry->storage);
     259        return entry->storage;
     260      }
     261    return NULL;
     262  }
     263  
     264  
     265  /* In the format 'file_name:line.column', append BOUND to MUSCLE.  Use
     266     digraphs for special characters in the file name.  */
     267  
     268  static void
     269  muscle_boundary_grow (char const *key, boundary bound)
     270  {
     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);
     277  }
     278  
     279  
     280  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      ++(Value); aver (*(Value) == ']');                          \
     291      ++(Value); 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    if (!value)
     313      return NULL;
     314    do {
     315      switch (*value)
     316        {
     317          COMMON_DECODE (value)
     318          case '[':
     319          case ']':
     320            aver (false);
     321            break;
     322        }
     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;
     328  }
     329  
     330  /* Reverse of muscle_location_grow.  */
     331  static location
     332  location_decode (char const *value)
     333  {
     334    aver (value);
     335    aver (*value == '[');
     336    ++value; aver (*value == '[');
     337    location loc;
     338    while (*++value)
     339      switch (*value)
     340        {
     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)
     349              {
     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;
     365              }
     366            break;
     367        }
     368    aver (false);
     369    return loc;
     370  }
     371  
     372  void
     373  muscle_user_name_list_grow (char const *key, char const *user_name,
     374                              location loc)
     375  {
     376    muscle_grow (key, "[[[[", ",", "");
     377    muscle_grow (key, user_name, "", "");
     378    muscle_grow (key, "]], ", "", "");
     379    muscle_location_grow (key, loc);
     380    muscle_grow (key, "]]", "", "");
     381  }
     382  
     383  
     384  /** Return an allocated string that represents the %define directive
     385      that performs the assignment.
     386  
     387      @param assignment "VAR", or "VAR=VAL".
     388      @param value      default value if VAL \a assignment has no '='.
     389  
     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"
     397   */
     398  
     399  static
     400  char *
     401  define_directive (char const *assignment,
     402                    muscle_kind kind,
     403                    char const *value)
     404  {
     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;
     418  }
     419  
     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.
     422   *
     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)
     431  {
     432    typedef struct
     433    {
     434      const char *obsolete;
     435      const char *updated;
     436      muscle_kind kind;
     437    } conversion_type;
     438    const conversion_type conversion[] =
     439    {
     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, }
     464    };
     465  
     466    for (conversion_type const *c = conversion; c->obsolete; ++c)
     467      {
     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))
     473          {
     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.  */
     480            {
     481              char *res = xstrdup (c->updated);
     482              char *eq2 = strchr (res, '=');
     483              if (eq2)
     484                {
     485                  *eq2 = '\0';
     486                  *value = eq2 + 1;
     487                }
     488              return res;
     489            }
     490          }
     491      }
     492    return variable;
     493  }
     494  
     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)
     500  {
     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");
     512  
     513    /* Command-line options are processed before the grammar file.  */
     514    bool warned = false;
     515    if (how == MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE)
     516      {
     517        char const *current_value = muscle_find_const (name);
     518        if (current_value)
     519          {
     520            long l = strtol (muscle_find_const (how_name), NULL, 10);
     521            muscle_percent_define_how how_old
     522              = 0 <= l && l <= INT_MAX ? l : INT_MAX;
     523            if (how_old == MUSCLE_PERCENT_DEFINE_F)
     524              goto end;
     525            /* If assigning the same value, make it a warning.  */
     526            warnings warn = STREQ (value, current_value) ? Wother : complaint;
     527            complain (&variable_loc, warn,
     528                      _("%%define variable %s redefined"),
     529                      quote (variable));
     530            location loc = muscle_percent_define_get_loc (variable);
     531            subcomplain (&loc, warn, _("previous definition"));
     532            fixits_register (&variable_loc, "");
     533            warned = true;
     534          }
     535      }
     536  
     537    if (!warned && old && upd)
     538      deprecated_directive (&variable_loc, old, upd);
     539  
     540    MUSCLE_INSERT_STRING (name, value);
     541    muscle_insert (loc_name, "");
     542    muscle_location_grow (loc_name, variable_loc);
     543    muscle_insert (syncline_name, "");
     544    muscle_syncline_grow (syncline_name, variable_loc);
     545    muscle_user_name_list_grow ("percent_define_user_variables", variable,
     546                                variable_loc);
     547    MUSCLE_INSERT_INT (how_name, how);
     548    MUSCLE_INSERT_STRING (kind_name, muscle_kind_string (kind));
     549   end:
     550    free (old);
     551    free (upd);
     552    if (variable != var)
     553      free ((char *) variable);
     554  }
     555  
     556  /* This is used for backward compatibility, e.g., "%define api.pure"
     557     supersedes "%pure-parser".  */
     558  void
     559  muscle_percent_define_ensure (char const *variable, location loc,
     560                                bool value)
     561  {
     562    uniqstr name = muscle_name (variable, NULL);
     563    char const *val = value ? "" : "false";
     564  
     565    /* Don't complain is VARIABLE is already defined, but be sure to set
     566       its value to VAL.  */
     567    if (!muscle_find_const (name)
     568        || muscle_percent_define_flag_if (variable) != value)
     569      muscle_percent_define_insert (variable, loc, muscle_keyword, val,
     570                                    MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
     571  }
     572  
     573  /* Mark %define VARIABLE as used.  */
     574  static void
     575  muscle_percent_define_use (char const *variable)
     576  {
     577    muscle_insert (muscle_name (variable, "bison_variables"), "");
     578  }
     579  
     580  /* The value of %define variable VARIABLE (corresponding to FIELD, if
     581     defined).  Do not register as used, but diagnose unset variables.  */
     582  
     583  static
     584  char const *
     585  muscle_percent_define_get_raw (char const *variable, char const *field)
     586  {
     587    uniqstr name = muscle_name (variable, field);
     588    char const *res = muscle_find_const (name);
     589    if (!res)
     590      complain (NULL, fatal, _("%s: undefined %%define variable %s"),
     591                "muscle_percent_define_get_raw", quote (variable));
     592    return res;
     593  }
     594  
     595  char *
     596  muscle_percent_define_get (char const *variable)
     597  {
     598    uniqstr name = muscle_name (variable, NULL);
     599    char *value = string_decode (name);
     600    if (!value)
     601      value = xstrdup ("");
     602    muscle_percent_define_use (variable);
     603    return value;
     604  }
     605  
     606  /* The kind of VARIABLE.  An error if undefined.  */
     607  static muscle_kind
     608  muscle_percent_define_get_kind (char const *variable)
     609  {
     610    return muscle_kind_new (muscle_percent_define_get_raw (variable, "kind"));
     611  }
     612  
     613  /* Check the kind of VARIABLE.  An error if undefined.  */
     614  static void
     615  muscle_percent_define_check_kind (char const *variable, muscle_kind kind)
     616  {
     617    if (muscle_percent_define_get_kind (variable) != kind)
     618      {
     619        location loc = muscle_percent_define_get_loc (variable);
     620        switch (kind)
     621          {
     622          case muscle_code:
     623            complain (&loc, Wdeprecated,
     624                      _("%%define variable '%s' requires '{...}' values"),
     625                      variable);
     626            break;
     627          case muscle_keyword:
     628            complain (&loc, Wdeprecated,
     629                      _("%%define variable '%s' requires keyword values"),
     630                      variable);
     631            break;
     632          case muscle_string:
     633            complain (&loc, Wdeprecated,
     634                      _("%%define variable '%s' requires '\"...\"' values"),
     635                      variable);
     636            break;
     637          }
     638      }
     639  }
     640  
     641  
     642  location
     643  muscle_percent_define_get_loc (char const *variable)
     644  {
     645    return location_decode (muscle_percent_define_get_raw (variable, "loc"));
     646  }
     647  
     648  char const *
     649  muscle_percent_define_get_syncline (char const *variable)
     650  {
     651    return muscle_percent_define_get_raw (variable, "syncline");
     652  }
     653  
     654  bool
     655  muscle_percent_define_ifdef (char const *variable)
     656  {
     657    if (muscle_find_const (muscle_name (variable, NULL)))
     658      {
     659        muscle_percent_define_use (variable);
     660        return true;
     661      }
     662    else
     663      return false;
     664  }
     665  
     666  bool
     667  muscle_percent_define_flag_if (char const *variable)
     668  {
     669    uniqstr invalid_boolean_name = muscle_name (variable, "invalid_boolean");
     670    bool res = false;
     671  
     672    if (muscle_percent_define_ifdef (variable))
     673      {
     674        char *value = muscle_percent_define_get (variable);
     675        muscle_percent_define_check_kind (variable, muscle_keyword);
     676        if (value[0] == '\0' || STREQ (value, "true"))
     677          res = true;
     678        else if (STREQ (value, "false"))
     679          res = false;
     680        else if (!muscle_find_const (invalid_boolean_name))
     681          {
     682            muscle_insert (invalid_boolean_name, "");
     683            location loc = muscle_percent_define_get_loc (variable);
     684            complain (&loc, complaint,
     685                      _("invalid value for %%define Boolean variable %s"),
     686                      quote (variable));
     687          }
     688        free (value);
     689      }
     690    else
     691      complain (NULL, fatal, _("%s: undefined %%define variable %s"),
     692                "muscle_percent_define_flag", quote (variable));
     693  
     694    return res;
     695  }
     696  
     697  void
     698  muscle_percent_define_default (char const *variable, char const *value)
     699  {
     700    uniqstr name = muscle_name (variable, NULL);
     701    if (!muscle_find_const (name))
     702      {
     703        MUSCLE_INSERT_STRING (name, value);
     704        MUSCLE_INSERT_STRING (muscle_name (variable, "kind"), "keyword");
     705        {
     706          uniqstr loc_name = muscle_name (variable, "loc");
     707          location loc;
     708          loc.start.file = "<default value>";
     709          loc.start.line = -1;
     710          loc.start.column = -1;
     711          loc.start.byte = -1;
     712          loc.end = loc.start;
     713          muscle_insert (loc_name, "");
     714          muscle_location_grow (loc_name, loc);
     715        }
     716        muscle_insert (muscle_name (variable, "syncline"), "");
     717      }
     718  }
     719  
     720  void
     721  muscle_percent_define_check_values (char const * const *values)
     722  {
     723    for (; *values; ++values)
     724      {
     725        char const * const *variablep = values;
     726        uniqstr name = muscle_name (*variablep, NULL);
     727        char *value = string_decode (name);
     728        muscle_percent_define_check_kind (*variablep, muscle_keyword);
     729        if (value)
     730          {
     731            for (++values; *values; ++values)
     732              if (STREQ (value, *values))
     733                break;
     734            if (!*values)
     735              {
     736                location loc = muscle_percent_define_get_loc (*variablep);
     737                complain (&loc, complaint,
     738                          _("invalid value for %%define variable %s: %s"),
     739                          quote (*variablep), quote_n (1, value));
     740                for (values = variablep + 1; *values; ++values)
     741                  subcomplain (&loc, complaint | no_caret | silent,
     742                               _("accepted value: %s"), quote (*values));
     743              }
     744            else
     745              while (*values)
     746                ++values;
     747            free (value);
     748          }
     749        else
     750          complain (NULL, fatal, _("%s: undefined %%define variable %s"),
     751                    "muscle_percent_define_check_values", quote (*variablep));
     752      }
     753  }
     754  
     755  void
     756  muscle_percent_code_grow (char const *qualifier, location qualifier_loc,
     757                            char const *code, location code_loc)
     758  {
     759    char const *name = UNIQSTR_CONCAT ("percent_code(", qualifier, ")");
     760    muscle_code_grow (name, code, code_loc);
     761    muscle_user_name_list_grow ("percent_code_user_qualifiers", qualifier,
     762                                 qualifier_loc);
     763  }
     764  
     765  
     766  /*------------------------------------------------.
     767  | Output the definition of ENTRY as a m4_define.  |
     768  `------------------------------------------------*/
     769  
     770  static inline bool
     771  muscle_m4_output (muscle_entry *entry, FILE *out)
     772  {
     773    fprintf (out,
     774             "m4_define([b4_%s],\n"
     775             "[[%s]])\n\n\n", entry->key, entry->value);
     776    return true;
     777  }
     778  
     779  static bool
     780  muscle_m4_output_processor (void *entry, void *out)
     781  {
     782    return muscle_m4_output (entry, out);
     783  }
     784  
     785  
     786  void
     787  muscles_m4_output (FILE *out)
     788  {
     789    hash_do_for_each (muscle_table, muscle_m4_output_processor, out);
     790  }